| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "views/widget/widget_gtk.h" | 5 #include "views/widget/widget_gtk.h" |
| 6 | 6 |
| 7 #include <gdk/gdk.h> | 7 #include <gdk/gdk.h> |
| 8 #include <gdk/gdkx.h> | 8 #include <gdk/gdkx.h> |
| 9 #include <X11/extensions/shape.h> | 9 #include <X11/extensions/shape.h> |
| 10 #include <X11/Xatom.h> | 10 #include <X11/Xatom.h> |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 return drag_widget; | 276 return drag_widget; |
| 277 } | 277 } |
| 278 | 278 |
| 279 // static | 279 // static |
| 280 GtkWidget* WidgetGtk::null_parent_ = NULL; | 280 GtkWidget* WidgetGtk::null_parent_ = NULL; |
| 281 bool WidgetGtk::debug_paint_enabled_ = false; | 281 bool WidgetGtk::debug_paint_enabled_ = false; |
| 282 | 282 |
| 283 //////////////////////////////////////////////////////////////////////////////// | 283 //////////////////////////////////////////////////////////////////////////////// |
| 284 // WidgetGtk, public: | 284 // WidgetGtk, public: |
| 285 | 285 |
| 286 WidgetGtk::WidgetGtk(Type type) | 286 WidgetGtk::WidgetGtk() |
| 287 : is_window_(false), | 287 : is_window_(false), |
| 288 ALLOW_THIS_IN_INITIALIZER_LIST(delegate_(this)), | 288 ALLOW_THIS_IN_INITIALIZER_LIST(delegate_(this)), |
| 289 type_(type), | |
| 290 widget_(NULL), | 289 widget_(NULL), |
| 291 window_contents_(NULL), | 290 window_contents_(NULL), |
| 291 child_(false), |
| 292 ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)), | 292 ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)), |
| 293 delete_on_destroy_(true), | 293 delete_on_destroy_(true), |
| 294 transparent_(false), | 294 transparent_(false), |
| 295 ignore_events_(false), | 295 ignore_events_(false), |
| 296 ignore_drag_leave_(false), | 296 ignore_drag_leave_(false), |
| 297 opacity_(255), | 297 opacity_(255), |
| 298 drag_data_(NULL), | 298 drag_data_(NULL), |
| 299 is_active_(false), | 299 is_active_(false), |
| 300 transient_to_parent_(false), | 300 transient_to_parent_(false), |
| 301 got_initial_focus_in_(false), | 301 got_initial_focus_in_(false), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 319 loop->AddObserver(DropObserver::GetInstance()); | 319 loop->AddObserver(DropObserver::GetInstance()); |
| 320 } | 320 } |
| 321 } | 321 } |
| 322 | 322 |
| 323 WidgetGtk::~WidgetGtk() { | 323 WidgetGtk::~WidgetGtk() { |
| 324 // We need to delete the input method before calling DestroyRootView(), | 324 // We need to delete the input method before calling DestroyRootView(), |
| 325 // because it'll set focus_manager_ to NULL. | 325 // because it'll set focus_manager_ to NULL. |
| 326 input_method_.reset(); | 326 input_method_.reset(); |
| 327 DestroyRootView(); | 327 DestroyRootView(); |
| 328 DCHECK(delete_on_destroy_ || widget_ == NULL); | 328 DCHECK(delete_on_destroy_ || widget_ == NULL); |
| 329 if (type_ != TYPE_CHILD) | |
| 330 ActiveWindowWatcherX::RemoveObserver(this); | |
| 331 } | 329 } |
| 332 | 330 |
| 333 GtkWindow* WidgetGtk::GetTransientParent() const { | 331 GtkWindow* WidgetGtk::GetTransientParent() const { |
| 334 return (type_ != TYPE_CHILD && widget_) ? | 332 return (!child_ && widget_) ? |
| 335 gtk_window_get_transient_for(GTK_WINDOW(widget_)) : NULL; | 333 gtk_window_get_transient_for(GTK_WINDOW(widget_)) : NULL; |
| 336 } | 334 } |
| 337 | 335 |
| 338 bool WidgetGtk::MakeTransparent() { | 336 bool WidgetGtk::MakeTransparent() { |
| 339 // Transparency can only be enabled only if we haven't realized the widget. | 337 // Transparency can only be enabled only if we haven't realized the widget. |
| 340 DCHECK(!widget_); | 338 DCHECK(!widget_); |
| 341 | 339 |
| 342 if (!gdk_screen_is_composited(gdk_screen_get_default())) { | 340 if (!gdk_screen_is_composited(gdk_screen_get_default())) { |
| 343 // Transparency is only supported for compositing window managers. | 341 // Transparency is only supported for compositing window managers. |
| 344 // NOTE: there's a race during ChromeOS startup such that X might think | 342 // NOTE: there's a race during ChromeOS startup such that X might think |
| (...skipping 14 matching lines...) Expand all Loading... |
| 359 void WidgetGtk::EnableDoubleBuffer(bool enabled) { | 357 void WidgetGtk::EnableDoubleBuffer(bool enabled) { |
| 360 is_double_buffered_ = enabled; | 358 is_double_buffered_ = enabled; |
| 361 if (window_contents_) { | 359 if (window_contents_) { |
| 362 if (is_double_buffered_) | 360 if (is_double_buffered_) |
| 363 GTK_WIDGET_SET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED); | 361 GTK_WIDGET_SET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED); |
| 364 else | 362 else |
| 365 GTK_WIDGET_UNSET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED); | 363 GTK_WIDGET_UNSET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED); |
| 366 } | 364 } |
| 367 } | 365 } |
| 368 | 366 |
| 369 bool WidgetGtk::MakeIgnoreEvents() { | |
| 370 // Transparency can only be enabled for windows/popups and only if we haven't | |
| 371 // realized the widget. | |
| 372 DCHECK(!widget_ && type_ != TYPE_CHILD); | |
| 373 | |
| 374 ignore_events_ = true; | |
| 375 return true; | |
| 376 } | |
| 377 | |
| 378 void WidgetGtk::AddChild(GtkWidget* child) { | 367 void WidgetGtk::AddChild(GtkWidget* child) { |
| 379 gtk_container_add(GTK_CONTAINER(window_contents_), child); | 368 gtk_container_add(GTK_CONTAINER(window_contents_), child); |
| 380 } | 369 } |
| 381 | 370 |
| 382 void WidgetGtk::RemoveChild(GtkWidget* child) { | 371 void WidgetGtk::RemoveChild(GtkWidget* child) { |
| 383 // We can be called after the contents widget has been destroyed, e.g. any | 372 // We can be called after the contents widget has been destroyed, e.g. any |
| 384 // NativeViewHost not removed from the view hierarchy before the window is | 373 // NativeViewHost not removed from the view hierarchy before the window is |
| 385 // closed. | 374 // closed. |
| 386 if (GTK_IS_CONTAINER(window_contents_)) { | 375 if (GTK_IS_CONTAINER(window_contents_)) { |
| 387 gtk_container_remove(GTK_CONTAINER(window_contents_), child); | 376 gtk_container_remove(GTK_CONTAINER(window_contents_), child); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 | 472 |
| 484 //////////////////////////////////////////////////////////////////////////////// | 473 //////////////////////////////////////////////////////////////////////////////// |
| 485 // WidgetGtk, ActiveWindowWatcherX::Observer implementation: | 474 // WidgetGtk, ActiveWindowWatcherX::Observer implementation: |
| 486 | 475 |
| 487 void WidgetGtk::ActiveWindowChanged(GdkWindow* active_window) { | 476 void WidgetGtk::ActiveWindowChanged(GdkWindow* active_window) { |
| 488 if (!GetNativeView()) | 477 if (!GetNativeView()) |
| 489 return; | 478 return; |
| 490 | 479 |
| 491 bool was_active = IsActive(); | 480 bool was_active = IsActive(); |
| 492 is_active_ = (active_window == GTK_WIDGET(GetNativeView())->window); | 481 is_active_ = (active_window == GTK_WIDGET(GetNativeView())->window); |
| 493 if (!is_active_ && active_window && type_ != TYPE_CHILD) { | 482 if (!is_active_ && active_window && !child_) { |
| 494 // We're not active, but the force the window to be rendered as active if | 483 // We're not active, but the force the window to be rendered as active if |
| 495 // a child window is transient to us. | 484 // a child window is transient to us. |
| 496 gpointer data = NULL; | 485 gpointer data = NULL; |
| 497 gdk_window_get_user_data(active_window, &data); | 486 gdk_window_get_user_data(active_window, &data); |
| 498 GtkWidget* widget = reinterpret_cast<GtkWidget*>(data); | 487 GtkWidget* widget = reinterpret_cast<GtkWidget*>(data); |
| 499 is_active_ = | 488 is_active_ = |
| 500 (widget && GTK_IS_WINDOW(widget) && | 489 (widget && GTK_IS_WINDOW(widget) && |
| 501 gtk_window_get_transient_for(GTK_WINDOW(widget)) == GTK_WINDOW( | 490 gtk_window_get_transient_for(GTK_WINDOW(widget)) == GTK_WINDOW( |
| 502 widget_)); | 491 widget_)); |
| 503 } | 492 } |
| 504 if (was_active != IsActive()) { | 493 if (was_active != IsActive()) { |
| 505 IsActiveChanged(); | 494 IsActiveChanged(); |
| 506 GetRootView()->SchedulePaint(); | 495 GetRootView()->SchedulePaint(); |
| 507 } | 496 } |
| 508 } | 497 } |
| 509 | 498 |
| 510 //////////////////////////////////////////////////////////////////////////////// | 499 //////////////////////////////////////////////////////////////////////////////// |
| 511 // WidgetGtk, Widget implementation: | 500 // WidgetGtk, Widget implementation: |
| 512 | 501 |
| 513 void WidgetGtk::InitWithWidget(Widget* parent, | |
| 514 const gfx::Rect& bounds) { | |
| 515 WidgetGtk* parent_gtk = static_cast<WidgetGtk*>(parent); | |
| 516 GtkWidget* native_parent = NULL; | |
| 517 if (parent != NULL) { | |
| 518 if (type_ != TYPE_CHILD) { | |
| 519 // window's parent has to be window. | |
| 520 native_parent = parent_gtk->GetNativeView(); | |
| 521 } else { | |
| 522 native_parent = parent_gtk->window_contents(); | |
| 523 } | |
| 524 } | |
| 525 Init(native_parent, bounds); | |
| 526 } | |
| 527 | |
| 528 void WidgetGtk::Init(GtkWidget* parent, | |
| 529 const gfx::Rect& bounds) { | |
| 530 Widget::Init(parent, bounds); | |
| 531 if (type_ != TYPE_CHILD) | |
| 532 ActiveWindowWatcherX::AddObserver(this); | |
| 533 | |
| 534 // Make container here. | |
| 535 CreateGtkWidget(parent, bounds); | |
| 536 delegate_->OnNativeWidgetCreated(); | |
| 537 | |
| 538 // Creates input method for toplevel widget after calling | |
| 539 // delegate_->OnNativeWidgetCreated(), to make sure that focus manager is | |
| 540 // already created at this point. | |
| 541 // TODO(suzhe): Always enable input method when we start to use | |
| 542 // RenderWidgetHostViewViews in normal ChromeOS. | |
| 543 #if defined(TOUCH_UI) && defined(HAVE_IBUS) | |
| 544 if (type_ != TYPE_CHILD) { | |
| 545 input_method_.reset(new InputMethodIBus(this)); | |
| 546 #else | |
| 547 if (type_ != TYPE_CHILD && NativeTextfieldViews::IsTextfieldViewsEnabled()) { | |
| 548 input_method_.reset(new InputMethodGtk(this)); | |
| 549 #endif | |
| 550 input_method_->Init(GetWidget()); | |
| 551 } | |
| 552 | |
| 553 if (opacity_ != 255) | |
| 554 SetOpacity(opacity_); | |
| 555 | |
| 556 // Make sure we receive our motion events. | |
| 557 | |
| 558 // In general we register most events on the parent of all widgets. At a | |
| 559 // minimum we need painting to happen on the parent (otherwise painting | |
| 560 // doesn't work at all), and similarly we need mouse release events on the | |
| 561 // parent as windows don't get mouse releases. | |
| 562 gtk_widget_add_events(window_contents_, | |
| 563 GDK_ENTER_NOTIFY_MASK | | |
| 564 GDK_LEAVE_NOTIFY_MASK | | |
| 565 GDK_BUTTON_PRESS_MASK | | |
| 566 GDK_BUTTON_RELEASE_MASK | | |
| 567 GDK_POINTER_MOTION_MASK | | |
| 568 GDK_KEY_PRESS_MASK | | |
| 569 GDK_KEY_RELEASE_MASK); | |
| 570 | |
| 571 g_signal_connect_after(G_OBJECT(window_contents_), "size_request", | |
| 572 G_CALLBACK(&OnSizeRequestThunk), this); | |
| 573 g_signal_connect_after(G_OBJECT(window_contents_), "size_allocate", | |
| 574 G_CALLBACK(&OnSizeAllocateThunk), this); | |
| 575 gtk_widget_set_app_paintable(window_contents_, true); | |
| 576 g_signal_connect(window_contents_, "expose_event", | |
| 577 G_CALLBACK(&OnPaintThunk), this); | |
| 578 g_signal_connect(window_contents_, "enter_notify_event", | |
| 579 G_CALLBACK(&OnEnterNotifyThunk), this); | |
| 580 g_signal_connect(window_contents_, "leave_notify_event", | |
| 581 G_CALLBACK(&OnLeaveNotifyThunk), this); | |
| 582 g_signal_connect(window_contents_, "motion_notify_event", | |
| 583 G_CALLBACK(&OnMotionNotifyThunk), this); | |
| 584 g_signal_connect(window_contents_, "button_press_event", | |
| 585 G_CALLBACK(&OnButtonPressThunk), this); | |
| 586 g_signal_connect(window_contents_, "button_release_event", | |
| 587 G_CALLBACK(&OnButtonReleaseThunk), this); | |
| 588 g_signal_connect(window_contents_, "grab_broken_event", | |
| 589 G_CALLBACK(&OnGrabBrokeEventThunk), this); | |
| 590 g_signal_connect(window_contents_, "grab_notify", | |
| 591 G_CALLBACK(&OnGrabNotifyThunk), this); | |
| 592 g_signal_connect(window_contents_, "scroll_event", | |
| 593 G_CALLBACK(&OnScrollThunk), this); | |
| 594 g_signal_connect(window_contents_, "visibility_notify_event", | |
| 595 G_CALLBACK(&OnVisibilityNotifyThunk), this); | |
| 596 | |
| 597 // In order to receive notification when the window is no longer the front | |
| 598 // window, we need to install these on the widget. | |
| 599 // NOTE: this doesn't work with focus follows mouse. | |
| 600 g_signal_connect(widget_, "focus_in_event", | |
| 601 G_CALLBACK(&OnFocusInThunk), this); | |
| 602 g_signal_connect(widget_, "focus_out_event", | |
| 603 G_CALLBACK(&OnFocusOutThunk), this); | |
| 604 g_signal_connect(widget_, "destroy", | |
| 605 G_CALLBACK(&OnDestroyThunk), this); | |
| 606 g_signal_connect(widget_, "show", | |
| 607 G_CALLBACK(&OnShowThunk), this); | |
| 608 g_signal_connect(widget_, "map", | |
| 609 G_CALLBACK(&OnMapThunk), this); | |
| 610 g_signal_connect(widget_, "hide", | |
| 611 G_CALLBACK(&OnHideThunk), this); | |
| 612 | |
| 613 // Views/FocusManager (re)sets the focus to the root window, | |
| 614 // so we need to connect signal handlers to the gtk window. | |
| 615 // See views::Views::Focus and views::FocusManager::ClearNativeFocus | |
| 616 // for more details. | |
| 617 g_signal_connect(widget_, "key_press_event", | |
| 618 G_CALLBACK(&OnEventKeyThunk), this); | |
| 619 g_signal_connect(widget_, "key_release_event", | |
| 620 G_CALLBACK(&OnEventKeyThunk), this); | |
| 621 | |
| 622 // Drag and drop. | |
| 623 gtk_drag_dest_set(window_contents_, static_cast<GtkDestDefaults>(0), | |
| 624 NULL, 0, GDK_ACTION_COPY); | |
| 625 g_signal_connect(window_contents_, "drag_motion", | |
| 626 G_CALLBACK(&OnDragMotionThunk), this); | |
| 627 g_signal_connect(window_contents_, "drag_data_received", | |
| 628 G_CALLBACK(&OnDragDataReceivedThunk), this); | |
| 629 g_signal_connect(window_contents_, "drag_drop", | |
| 630 G_CALLBACK(&OnDragDropThunk), this); | |
| 631 g_signal_connect(window_contents_, "drag_leave", | |
| 632 G_CALLBACK(&OnDragLeaveThunk), this); | |
| 633 g_signal_connect(window_contents_, "drag_data_get", | |
| 634 G_CALLBACK(&OnDragDataGetThunk), this); | |
| 635 g_signal_connect(window_contents_, "drag_end", | |
| 636 G_CALLBACK(&OnDragEndThunk), this); | |
| 637 g_signal_connect(window_contents_, "drag_failed", | |
| 638 G_CALLBACK(&OnDragFailedThunk), this); | |
| 639 | |
| 640 tooltip_manager_.reset(new TooltipManagerGtk(this)); | |
| 641 | |
| 642 // Register for tooltips. | |
| 643 g_object_set(G_OBJECT(window_contents_), "has-tooltip", TRUE, NULL); | |
| 644 g_signal_connect(window_contents_, "query_tooltip", | |
| 645 G_CALLBACK(&OnQueryTooltipThunk), this); | |
| 646 | |
| 647 if (type_ == TYPE_CHILD) { | |
| 648 if (parent) { | |
| 649 SetBounds(bounds); | |
| 650 } | |
| 651 } else { | |
| 652 if (bounds.width() > 0 && bounds.height() > 0) | |
| 653 gtk_window_resize(GTK_WINDOW(widget_), bounds.width(), bounds.height()); | |
| 654 gtk_window_move(GTK_WINDOW(widget_), bounds.x(), bounds.y()); | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 gfx::NativeView WidgetGtk::GetNativeView() const { | 502 gfx::NativeView WidgetGtk::GetNativeView() const { |
| 659 return widget_; | 503 return widget_; |
| 660 } | 504 } |
| 661 | 505 |
| 662 bool WidgetGtk::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { | 506 bool WidgetGtk::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { |
| 663 NOTIMPLEMENTED(); | 507 NOTIMPLEMENTED(); |
| 664 return false; | 508 return false; |
| 665 } | 509 } |
| 666 | 510 |
| 667 Window* WidgetGtk::GetWindow() { | 511 Window* WidgetGtk::GetWindow() { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 684 bool send_native_event) { | 528 bool send_native_event) { |
| 685 // Send the notification to the delegate. | 529 // Send the notification to the delegate. |
| 686 if (ViewsDelegate::views_delegate) | 530 if (ViewsDelegate::views_delegate) |
| 687 ViewsDelegate::views_delegate->NotifyAccessibilityEvent(view, event_type); | 531 ViewsDelegate::views_delegate->NotifyAccessibilityEvent(view, event_type); |
| 688 | 532 |
| 689 // In the future if we add native GTK accessibility support, the | 533 // In the future if we add native GTK accessibility support, the |
| 690 // notification should be sent here. | 534 // notification should be sent here. |
| 691 } | 535 } |
| 692 | 536 |
| 693 void WidgetGtk::ClearNativeFocus() { | 537 void WidgetGtk::ClearNativeFocus() { |
| 694 DCHECK(type_ != TYPE_CHILD); | 538 DCHECK(!child_); |
| 695 if (!GetNativeView()) { | 539 if (!GetNativeView()) { |
| 696 NOTREACHED(); | 540 NOTREACHED(); |
| 697 return; | 541 return; |
| 698 } | 542 } |
| 699 gtk_window_set_focus(GTK_WINDOW(GetNativeView()), NULL); | 543 gtk_window_set_focus(GTK_WINDOW(GetNativeView()), NULL); |
| 700 } | 544 } |
| 701 | 545 |
| 702 bool WidgetGtk::HandleKeyboardEvent(const KeyEvent& key) { | 546 bool WidgetGtk::HandleKeyboardEvent(const KeyEvent& key) { |
| 703 if (!GetFocusManager()) | 547 if (!GetFocusManager()) |
| 704 return false; | 548 return false; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 RemoveExposeHandlerIfExists(child); | 611 RemoveExposeHandlerIfExists(child); |
| 768 gulong id = g_signal_connect_after(child, "expose-event", | 612 gulong id = g_signal_connect_after(child, "expose-event", |
| 769 G_CALLBACK(&ChildExposeHandler), NULL); | 613 G_CALLBACK(&ChildExposeHandler), NULL); |
| 770 g_object_set_data(G_OBJECT(child), kExposeHandlerIdKey, | 614 g_object_set_data(G_OBJECT(child), kExposeHandlerIdKey, |
| 771 reinterpret_cast<void*>(id)); | 615 reinterpret_cast<void*>(id)); |
| 772 } | 616 } |
| 773 | 617 |
| 774 //////////////////////////////////////////////////////////////////////////////// | 618 //////////////////////////////////////////////////////////////////////////////// |
| 775 // WidgetGtk, NativeWidget implementation: | 619 // WidgetGtk, NativeWidget implementation: |
| 776 | 620 |
| 777 void WidgetGtk::SetCreateParams(const CreateParams& params) { | 621 void WidgetGtk::InitNativeWidget(const CreateParams& params) { |
| 778 DCHECK(!GetNativeView()); | 622 SetCreateParams(params); |
| 779 | 623 |
| 780 // Set non-style attributes. | 624 CreateParams modified_params = params; |
| 781 set_delete_on_destroy(params.delete_on_destroy); | 625 gfx::NativeView parent = params.parent; |
| 626 if (params.parent_widget) { |
| 627 WidgetGtk* parent_gtk = |
| 628 static_cast<WidgetGtk*>(params.parent_widget->native_widget()); |
| 629 modified_params.parent = child_ ? parent_gtk->window_contents() |
| 630 : params.parent_widget->GetNativeView(); |
| 631 } |
| 782 | 632 |
| 783 if (params.transparent) | 633 if (!child_) |
| 784 MakeTransparent(); | 634 ActiveWindowWatcherX::AddObserver(this); |
| 785 if (!params.accept_events) | |
| 786 MakeIgnoreEvents(); | |
| 787 | 635 |
| 788 if (params.type == CreateParams::TYPE_MENU) { | 636 // Make container here. |
| 789 GdkEvent* event = gtk_get_current_event(); | 637 CreateGtkWidget(modified_params); |
| 790 if (event) { | 638 delegate_->OnNativeWidgetCreated(); |
| 791 is_mouse_button_pressed_ = event->type == GDK_BUTTON_PRESS || | 639 |
| 792 event->type == GDK_2BUTTON_PRESS || | 640 // Creates input method for toplevel widget after calling |
| 793 event->type == GDK_3BUTTON_PRESS; | 641 // delegate_->OnNativeWidgetCreated(), to make sure that focus manager is |
| 794 gdk_event_free(event); | 642 // already created at this point. |
| 795 } | 643 // TODO(suzhe): Always enable input method when we start to use |
| 644 // RenderWidgetHostViewViews in normal ChromeOS. |
| 645 #if defined(TOUCH_UI) && defined(HAVE_IBUS) |
| 646 if (!child_) { |
| 647 input_method_.reset(new InputMethodIBus(this)); |
| 648 #else |
| 649 if (!child_ && NativeTextfieldViews::IsTextfieldViewsEnabled()) { |
| 650 input_method_.reset(new InputMethodGtk(this)); |
| 651 #endif |
| 652 input_method_->Init(GetWidget()); |
| 653 } |
| 654 |
| 655 if (opacity_ != 255) |
| 656 SetOpacity(opacity_); |
| 657 |
| 658 // Make sure we receive our motion events. |
| 659 |
| 660 // In general we register most events on the parent of all widgets. At a |
| 661 // minimum we need painting to happen on the parent (otherwise painting |
| 662 // doesn't work at all), and similarly we need mouse release events on the |
| 663 // parent as windows don't get mouse releases. |
| 664 gtk_widget_add_events(window_contents_, |
| 665 GDK_ENTER_NOTIFY_MASK | |
| 666 GDK_LEAVE_NOTIFY_MASK | |
| 667 GDK_BUTTON_PRESS_MASK | |
| 668 GDK_BUTTON_RELEASE_MASK | |
| 669 GDK_POINTER_MOTION_MASK | |
| 670 GDK_KEY_PRESS_MASK | |
| 671 GDK_KEY_RELEASE_MASK); |
| 672 |
| 673 g_signal_connect_after(G_OBJECT(window_contents_), "size_request", |
| 674 G_CALLBACK(&OnSizeRequestThunk), this); |
| 675 g_signal_connect_after(G_OBJECT(window_contents_), "size_allocate", |
| 676 G_CALLBACK(&OnSizeAllocateThunk), this); |
| 677 gtk_widget_set_app_paintable(window_contents_, true); |
| 678 g_signal_connect(window_contents_, "expose_event", |
| 679 G_CALLBACK(&OnPaintThunk), this); |
| 680 g_signal_connect(window_contents_, "enter_notify_event", |
| 681 G_CALLBACK(&OnEnterNotifyThunk), this); |
| 682 g_signal_connect(window_contents_, "leave_notify_event", |
| 683 G_CALLBACK(&OnLeaveNotifyThunk), this); |
| 684 g_signal_connect(window_contents_, "motion_notify_event", |
| 685 G_CALLBACK(&OnMotionNotifyThunk), this); |
| 686 g_signal_connect(window_contents_, "button_press_event", |
| 687 G_CALLBACK(&OnButtonPressThunk), this); |
| 688 g_signal_connect(window_contents_, "button_release_event", |
| 689 G_CALLBACK(&OnButtonReleaseThunk), this); |
| 690 g_signal_connect(window_contents_, "grab_broken_event", |
| 691 G_CALLBACK(&OnGrabBrokeEventThunk), this); |
| 692 g_signal_connect(window_contents_, "grab_notify", |
| 693 G_CALLBACK(&OnGrabNotifyThunk), this); |
| 694 g_signal_connect(window_contents_, "scroll_event", |
| 695 G_CALLBACK(&OnScrollThunk), this); |
| 696 g_signal_connect(window_contents_, "visibility_notify_event", |
| 697 G_CALLBACK(&OnVisibilityNotifyThunk), this); |
| 698 |
| 699 // In order to receive notification when the window is no longer the front |
| 700 // window, we need to install these on the widget. |
| 701 // NOTE: this doesn't work with focus follows mouse. |
| 702 g_signal_connect(widget_, "focus_in_event", |
| 703 G_CALLBACK(&OnFocusInThunk), this); |
| 704 g_signal_connect(widget_, "focus_out_event", |
| 705 G_CALLBACK(&OnFocusOutThunk), this); |
| 706 g_signal_connect(widget_, "destroy", |
| 707 G_CALLBACK(&OnDestroyThunk), this); |
| 708 g_signal_connect(widget_, "show", |
| 709 G_CALLBACK(&OnShowThunk), this); |
| 710 g_signal_connect(widget_, "map", |
| 711 G_CALLBACK(&OnMapThunk), this); |
| 712 g_signal_connect(widget_, "hide", |
| 713 G_CALLBACK(&OnHideThunk), this); |
| 714 |
| 715 // Views/FocusManager (re)sets the focus to the root window, |
| 716 // so we need to connect signal handlers to the gtk window. |
| 717 // See views::Views::Focus and views::FocusManager::ClearNativeFocus |
| 718 // for more details. |
| 719 g_signal_connect(widget_, "key_press_event", |
| 720 G_CALLBACK(&OnEventKeyThunk), this); |
| 721 g_signal_connect(widget_, "key_release_event", |
| 722 G_CALLBACK(&OnEventKeyThunk), this); |
| 723 |
| 724 // Drag and drop. |
| 725 gtk_drag_dest_set(window_contents_, static_cast<GtkDestDefaults>(0), |
| 726 NULL, 0, GDK_ACTION_COPY); |
| 727 g_signal_connect(window_contents_, "drag_motion", |
| 728 G_CALLBACK(&OnDragMotionThunk), this); |
| 729 g_signal_connect(window_contents_, "drag_data_received", |
| 730 G_CALLBACK(&OnDragDataReceivedThunk), this); |
| 731 g_signal_connect(window_contents_, "drag_drop", |
| 732 G_CALLBACK(&OnDragDropThunk), this); |
| 733 g_signal_connect(window_contents_, "drag_leave", |
| 734 G_CALLBACK(&OnDragLeaveThunk), this); |
| 735 g_signal_connect(window_contents_, "drag_data_get", |
| 736 G_CALLBACK(&OnDragDataGetThunk), this); |
| 737 g_signal_connect(window_contents_, "drag_end", |
| 738 G_CALLBACK(&OnDragEndThunk), this); |
| 739 g_signal_connect(window_contents_, "drag_failed", |
| 740 G_CALLBACK(&OnDragFailedThunk), this); |
| 741 |
| 742 tooltip_manager_.reset(new TooltipManagerGtk(this)); |
| 743 |
| 744 // Register for tooltips. |
| 745 g_object_set(G_OBJECT(window_contents_), "has-tooltip", TRUE, NULL); |
| 746 g_signal_connect(window_contents_, "query_tooltip", |
| 747 G_CALLBACK(&OnQueryTooltipThunk), this); |
| 748 |
| 749 if (child_) { |
| 750 if (parent) |
| 751 SetBounds(params.bounds); |
| 752 } else { |
| 753 if (params.bounds.width() > 0 && params.bounds.height() > 0) |
| 754 gtk_window_resize(GTK_WINDOW(widget_), params.bounds.width(), |
| 755 params.bounds.height()); |
| 756 gtk_window_move(GTK_WINDOW(widget_), params.bounds.x(), params.bounds.y()); |
| 796 } | 757 } |
| 797 } | 758 } |
| 798 | 759 |
| 799 Widget* WidgetGtk::GetWidget() { | 760 Widget* WidgetGtk::GetWidget() { |
| 800 return this; | 761 return this; |
| 801 } | 762 } |
| 802 | 763 |
| 803 void WidgetGtk::SetNativeWindowProperty(const char* name, void* value) { | 764 void WidgetGtk::SetNativeWindowProperty(const char* name, void* value) { |
| 804 g_object_set_data(G_OBJECT(widget_), name, value); | 765 g_object_set_data(G_OBJECT(widget_), name, value); |
| 805 } | 766 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 gtk_window_get_size(GTK_WINDOW(widget_), &w, &h); | 824 gtk_window_get_size(GTK_WINDOW(widget_), &w, &h); |
| 864 } else { | 825 } else { |
| 865 GetWidgetPositionOnScreen(widget_, &x, &y); | 826 GetWidgetPositionOnScreen(widget_, &x, &y); |
| 866 w = widget_->allocation.width; | 827 w = widget_->allocation.width; |
| 867 h = widget_->allocation.height; | 828 h = widget_->allocation.height; |
| 868 } | 829 } |
| 869 return gfx::Rect(x, y, w, h); | 830 return gfx::Rect(x, y, w, h); |
| 870 } | 831 } |
| 871 | 832 |
| 872 void WidgetGtk::SetBounds(const gfx::Rect& bounds) { | 833 void WidgetGtk::SetBounds(const gfx::Rect& bounds) { |
| 873 if (type_ == TYPE_CHILD) { | 834 if (child_) { |
| 874 GtkWidget* parent = gtk_widget_get_parent(widget_); | 835 GtkWidget* parent = gtk_widget_get_parent(widget_); |
| 875 if (GTK_IS_VIEWS_FIXED(parent)) { | 836 if (GTK_IS_VIEWS_FIXED(parent)) { |
| 876 WidgetGtk* parent_widget = static_cast<WidgetGtk*>( | 837 WidgetGtk* parent_widget = static_cast<WidgetGtk*>( |
| 877 NativeWidget::GetNativeWidgetForNativeView(parent)); | 838 NativeWidget::GetNativeWidgetForNativeView(parent)); |
| 878 parent_widget->PositionChild(widget_, bounds.x(), bounds.y(), | 839 parent_widget->PositionChild(widget_, bounds.x(), bounds.y(), |
| 879 bounds.width(), bounds.height()); | 840 bounds.width(), bounds.height()); |
| 880 } else { | 841 } else { |
| 881 DCHECK(GTK_IS_FIXED(parent)) | 842 DCHECK(GTK_IS_FIXED(parent)) |
| 882 << "Parent of WidgetGtk has to be Fixed or ViewsFixed"; | 843 << "Parent of WidgetGtk has to be Fixed or ViewsFixed"; |
| 883 // Just request the size if the parent is not WidgetGtk but plain | 844 // Just request the size if the parent is not WidgetGtk but plain |
| (...skipping 17 matching lines...) Expand all Loading... |
| 901 // TODO: this may need to set an initial size if not showing. | 862 // TODO: this may need to set an initial size if not showing. |
| 902 // TODO: need to constrain based on screen size. | 863 // TODO: need to constrain based on screen size. |
| 903 if (!bounds.IsEmpty()) { | 864 if (!bounds.IsEmpty()) { |
| 904 gtk_window_resize(gtk_window, bounds.width(), bounds.height()); | 865 gtk_window_resize(gtk_window, bounds.width(), bounds.height()); |
| 905 } | 866 } |
| 906 gtk_window_move(gtk_window, bounds.x(), bounds.y()); | 867 gtk_window_move(gtk_window, bounds.x(), bounds.y()); |
| 907 } | 868 } |
| 908 } | 869 } |
| 909 | 870 |
| 910 void WidgetGtk::SetSize(const gfx::Size& size) { | 871 void WidgetGtk::SetSize(const gfx::Size& size) { |
| 911 if (type_ == TYPE_CHILD) { | 872 if (child_) { |
| 912 GtkWidget* parent = gtk_widget_get_parent(widget_); | 873 GtkWidget* parent = gtk_widget_get_parent(widget_); |
| 913 if (GTK_IS_VIEWS_FIXED(parent)) { | 874 if (GTK_IS_VIEWS_FIXED(parent)) { |
| 914 gtk_views_fixed_set_widget_size(widget_, size.width(), size.height()); | 875 gtk_views_fixed_set_widget_size(widget_, size.width(), size.height()); |
| 915 } else { | 876 } else { |
| 916 DCHECK(GTK_IS_FIXED(parent)) | 877 DCHECK(GTK_IS_FIXED(parent)) |
| 917 << "Parent of WidgetGtk has to be Fixed or ViewsFixed"; | 878 << "Parent of WidgetGtk has to be Fixed or ViewsFixed"; |
| 918 gtk_widget_set_size_request(widget_, size.width(), size.height()); | 879 gtk_widget_set_size_request(widget_, size.width(), size.height()); |
| 919 } | 880 } |
| 920 } else { | 881 } else { |
| 921 if (GTK_WIDGET_MAPPED(widget_)) | 882 if (GTK_WIDGET_MAPPED(widget_)) |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 void WidgetGtk::SetOpacity(unsigned char opacity) { | 938 void WidgetGtk::SetOpacity(unsigned char opacity) { |
| 978 opacity_ = opacity; | 939 opacity_ = opacity; |
| 979 if (widget_) { | 940 if (widget_) { |
| 980 // We can only set the opacity when the widget has been realized. | 941 // We can only set the opacity when the widget has been realized. |
| 981 gdk_window_set_opacity(widget_->window, static_cast<gdouble>(opacity) / | 942 gdk_window_set_opacity(widget_->window, static_cast<gdouble>(opacity) / |
| 982 static_cast<gdouble>(255)); | 943 static_cast<gdouble>(255)); |
| 983 } | 944 } |
| 984 } | 945 } |
| 985 | 946 |
| 986 void WidgetGtk::SetAlwaysOnTop(bool on_top) { | 947 void WidgetGtk::SetAlwaysOnTop(bool on_top) { |
| 987 DCHECK(type_ != TYPE_CHILD); | 948 DCHECK(!child_); |
| 988 always_on_top_ = on_top; | 949 always_on_top_ = on_top; |
| 989 if (widget_) | 950 if (widget_) |
| 990 gtk_window_set_keep_above(GTK_WINDOW(widget_), on_top); | 951 gtk_window_set_keep_above(GTK_WINDOW(widget_), on_top); |
| 991 } | 952 } |
| 992 | 953 |
| 993 bool WidgetGtk::IsVisible() const { | 954 bool WidgetGtk::IsVisible() const { |
| 994 return GTK_WIDGET_VISIBLE(widget_); | 955 return GTK_WIDGET_VISIBLE(widget_); |
| 995 } | 956 } |
| 996 | 957 |
| 997 bool WidgetGtk::IsActive() const { | 958 bool WidgetGtk::IsActive() const { |
| 998 DCHECK(type_ != TYPE_CHILD); | 959 DCHECK(!child_); |
| 999 return is_active_; | 960 return is_active_; |
| 1000 } | 961 } |
| 1001 | 962 |
| 1002 bool WidgetGtk::IsAccessibleWidget() const { | 963 bool WidgetGtk::IsAccessibleWidget() const { |
| 1003 return false; | 964 return false; |
| 1004 } | 965 } |
| 1005 | 966 |
| 1006 bool WidgetGtk::ContainsNativeView(gfx::NativeView native_view) const { | 967 bool WidgetGtk::ContainsNativeView(gfx::NativeView native_view) const { |
| 1007 // TODO(port) See implementation in WidgetWin::ContainsNativeView. | 968 // TODO(port) See implementation in WidgetWin::ContainsNativeView. |
| 1008 NOTREACHED() << "WidgetGtk::ContainsNativeView is not implemented."; | 969 NOTREACHED() << "WidgetGtk::ContainsNativeView is not implemented."; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 } | 1002 } |
| 1042 | 1003 |
| 1043 //////////////////////////////////////////////////////////////////////////////// | 1004 //////////////////////////////////////////////////////////////////////////////// |
| 1044 // WidgetGtk, protected: | 1005 // WidgetGtk, protected: |
| 1045 | 1006 |
| 1046 void WidgetGtk::OnSizeRequest(GtkWidget* widget, GtkRequisition* requisition) { | 1007 void WidgetGtk::OnSizeRequest(GtkWidget* widget, GtkRequisition* requisition) { |
| 1047 // Do only return the preferred size for child windows. GtkWindow interprets | 1008 // Do only return the preferred size for child windows. GtkWindow interprets |
| 1048 // the requisition as a minimum size for top level windows, returning a | 1009 // the requisition as a minimum size for top level windows, returning a |
| 1049 // preferred size for these would prevents us from setting smaller window | 1010 // preferred size for these would prevents us from setting smaller window |
| 1050 // sizes. | 1011 // sizes. |
| 1051 if (type_ == TYPE_CHILD) { | 1012 if (child_) { |
| 1052 gfx::Size size(GetRootView()->GetPreferredSize()); | 1013 gfx::Size size(GetRootView()->GetPreferredSize()); |
| 1053 requisition->width = size.width(); | 1014 requisition->width = size.width(); |
| 1054 requisition->height = size.height(); | 1015 requisition->height = size.height(); |
| 1055 } | 1016 } |
| 1056 } | 1017 } |
| 1057 | 1018 |
| 1058 void WidgetGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { | 1019 void WidgetGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { |
| 1059 // See comment next to size_ as to why we do this. Also note, it's tempting | 1020 // See comment next to size_ as to why we do this. Also note, it's tempting |
| 1060 // to put this in the static method so subclasses don't need to worry about | 1021 // to put this in the static method so subclasses don't need to worry about |
| 1061 // it, but if a subclasses needs to set a shape then they need to always | 1022 // it, but if a subclasses needs to set a shape then they need to always |
| 1062 // reset the shape in this method regardless of whether the size changed. | 1023 // reset the shape in this method regardless of whether the size changed. |
| 1063 gfx::Size new_size(allocation->width, allocation->height); | 1024 gfx::Size new_size(allocation->width, allocation->height); |
| 1064 if (new_size == size_) | 1025 if (new_size == size_) |
| 1065 return; | 1026 return; |
| 1066 size_ = new_size; | 1027 size_ = new_size; |
| 1067 delegate_->OnSizeChanged(size_); | 1028 delegate_->OnSizeChanged(size_); |
| 1068 } | 1029 } |
| 1069 | 1030 |
| 1070 gboolean WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) { | 1031 gboolean WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) { |
| 1071 if (transparent_ && type_ == TYPE_CHILD) { | 1032 if (transparent_ && child_) { |
| 1072 // Clear the background before drawing any view and native components. | 1033 // Clear the background before drawing any view and native components. |
| 1073 DrawTransparentBackground(widget, event); | 1034 DrawTransparentBackground(widget, event); |
| 1074 if (!CompositePainter::IsComposited(widget_) && | 1035 if (!CompositePainter::IsComposited(widget_) && |
| 1075 gdk_screen_is_composited(gdk_screen_get_default())) { | 1036 gdk_screen_is_composited(gdk_screen_get_default())) { |
| 1076 // Let the parent draw the content only after something is drawn on | 1037 // Let the parent draw the content only after something is drawn on |
| 1077 // the widget. | 1038 // the widget. |
| 1078 CompositePainter::SetComposited(widget_); | 1039 CompositePainter::SetComposited(widget_); |
| 1079 } | 1040 } |
| 1080 } | 1041 } |
| 1081 | 1042 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1094 } | 1055 } |
| 1095 | 1056 |
| 1096 gfx::CanvasSkiaPaint canvas(event); | 1057 gfx::CanvasSkiaPaint canvas(event); |
| 1097 if (!canvas.is_empty()) { | 1058 if (!canvas.is_empty()) { |
| 1098 canvas.set_composite_alpha(is_transparent()); | 1059 canvas.set_composite_alpha(is_transparent()); |
| 1099 delegate_->OnNativeWidgetPaint(&canvas); | 1060 delegate_->OnNativeWidgetPaint(&canvas); |
| 1100 } | 1061 } |
| 1101 | 1062 |
| 1102 if (!painted_) { | 1063 if (!painted_) { |
| 1103 painted_ = true; | 1064 painted_ = true; |
| 1104 if (type_ != TYPE_CHILD) | 1065 if (!child_) |
| 1105 UpdateFreezeUpdatesProperty(GTK_WINDOW(widget_), false /* remove */); | 1066 UpdateFreezeUpdatesProperty(GTK_WINDOW(widget_), false /* remove */); |
| 1106 } | 1067 } |
| 1107 return false; // False indicates other widgets should get the event as well. | 1068 return false; // False indicates other widgets should get the event as well. |
| 1108 } | 1069 } |
| 1109 | 1070 |
| 1110 void WidgetGtk::OnDragDataGet(GtkWidget* widget, | 1071 void WidgetGtk::OnDragDataGet(GtkWidget* widget, |
| 1111 GdkDragContext* context, | 1072 GdkDragContext* context, |
| 1112 GtkSelectionData* data, | 1073 GtkSelectionData* data, |
| 1113 guint info, | 1074 guint info, |
| 1114 guint time) { | 1075 guint time) { |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 return delegate_->OnMouseEvent(mouse_event); | 1216 return delegate_->OnMouseEvent(mouse_event); |
| 1256 } | 1217 } |
| 1257 | 1218 |
| 1258 gboolean WidgetGtk::OnFocusIn(GtkWidget* widget, GdkEventFocus* event) { | 1219 gboolean WidgetGtk::OnFocusIn(GtkWidget* widget, GdkEventFocus* event) { |
| 1259 if (has_focus_) | 1220 if (has_focus_) |
| 1260 return false; // This is the second focus-in event in a row, ignore it. | 1221 return false; // This is the second focus-in event in a row, ignore it. |
| 1261 has_focus_ = true; | 1222 has_focus_ = true; |
| 1262 | 1223 |
| 1263 should_handle_menu_key_release_ = false; | 1224 should_handle_menu_key_release_ = false; |
| 1264 | 1225 |
| 1265 if (type_ == TYPE_CHILD) | 1226 if (child_) |
| 1266 return false; | 1227 return false; |
| 1267 | 1228 |
| 1268 // Only top-level Widget should have an InputMethod instance. | 1229 // Only top-level Widget should have an InputMethod instance. |
| 1269 if (input_method_.get()) | 1230 if (input_method_.get()) |
| 1270 input_method_->OnFocus(); | 1231 input_method_->OnFocus(); |
| 1271 | 1232 |
| 1272 // See description of got_initial_focus_in_ for details on this. | 1233 // See description of got_initial_focus_in_ for details on this. |
| 1273 if (!got_initial_focus_in_) { | 1234 if (!got_initial_focus_in_) { |
| 1274 got_initial_focus_in_ = true; | 1235 got_initial_focus_in_ = true; |
| 1275 SetInitialFocus(); | 1236 SetInitialFocus(); |
| 1276 } | 1237 } |
| 1277 return false; | 1238 return false; |
| 1278 } | 1239 } |
| 1279 | 1240 |
| 1280 gboolean WidgetGtk::OnFocusOut(GtkWidget* widget, GdkEventFocus* event) { | 1241 gboolean WidgetGtk::OnFocusOut(GtkWidget* widget, GdkEventFocus* event) { |
| 1281 if (!has_focus_) | 1242 if (!has_focus_) |
| 1282 return false; // This is the second focus-out event in a row, ignore it. | 1243 return false; // This is the second focus-out event in a row, ignore it. |
| 1283 has_focus_ = false; | 1244 has_focus_ = false; |
| 1284 | 1245 |
| 1285 if (type_ == TYPE_CHILD) | 1246 if (child_) |
| 1286 return false; | 1247 return false; |
| 1287 | 1248 |
| 1288 // Only top-level Widget should have an InputMethod instance. | 1249 // Only top-level Widget should have an InputMethod instance. |
| 1289 if (input_method_.get()) | 1250 if (input_method_.get()) |
| 1290 input_method_->OnBlur(); | 1251 input_method_->OnBlur(); |
| 1291 return false; | 1252 return false; |
| 1292 } | 1253 } |
| 1293 | 1254 |
| 1294 gboolean WidgetGtk::OnEventKey(GtkWidget* widget, GdkEventKey* event) { | 1255 gboolean WidgetGtk::OnEventKey(GtkWidget* widget, GdkEventKey* event) { |
| 1295 KeyEvent key(reinterpret_cast<NativeEvent>(event)); | 1256 KeyEvent key(reinterpret_cast<NativeEvent>(event)); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1321 } | 1282 } |
| 1322 | 1283 |
| 1323 void WidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) { | 1284 void WidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) { |
| 1324 if (!window_contents_) | 1285 if (!window_contents_) |
| 1325 return; // Grab broke after window destroyed, don't try processing it. | 1286 return; // Grab broke after window destroyed, don't try processing it. |
| 1326 gtk_grab_remove(window_contents_); | 1287 gtk_grab_remove(window_contents_); |
| 1327 HandleGtkGrabBroke(); | 1288 HandleGtkGrabBroke(); |
| 1328 } | 1289 } |
| 1329 | 1290 |
| 1330 void WidgetGtk::OnDestroy(GtkWidget* object) { | 1291 void WidgetGtk::OnDestroy(GtkWidget* object) { |
| 1292 if (!child_) |
| 1293 ActiveWindowWatcherX::RemoveObserver(this); |
| 1331 // Note that this handler is hooked to GtkObject::destroy. | 1294 // Note that this handler is hooked to GtkObject::destroy. |
| 1332 // NULL out pointers here since we might still be in an observerer list | 1295 // NULL out pointers here since we might still be in an observerer list |
| 1333 // until delstion happens. | 1296 // until delstion happens. |
| 1334 widget_ = window_contents_ = NULL; | 1297 widget_ = window_contents_ = NULL; |
| 1335 if (delete_on_destroy_) { | 1298 if (delete_on_destroy_) { |
| 1336 // Delays the deletion of this WidgetGtk as we want its children to have | 1299 // Delays the deletion of this WidgetGtk as we want its children to have |
| 1337 // access to it when destroyed. | 1300 // access to it when destroyed. |
| 1338 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 1301 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 1339 } | 1302 } |
| 1340 } | 1303 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1407 // always consumes the key event and send it back to us later by calling | 1370 // always consumes the key event and send it back to us later by calling |
| 1408 // HandleKeyboardEvent() directly, if it's not handled by webkit. | 1371 // HandleKeyboardEvent() directly, if it's not handled by webkit. |
| 1409 if (!handled) | 1372 if (!handled) |
| 1410 handled = HandleKeyboardEvent(key); | 1373 handled = HandleKeyboardEvent(key); |
| 1411 | 1374 |
| 1412 // Dispatch the key event for bindings processing. | 1375 // Dispatch the key event for bindings processing. |
| 1413 if (!handled && event && GTK_IS_WINDOW(widget_)) | 1376 if (!handled && event && GTK_IS_WINDOW(widget_)) |
| 1414 gtk_bindings_activate_event(GTK_OBJECT(widget_), event); | 1377 gtk_bindings_activate_event(GTK_OBJECT(widget_), event); |
| 1415 } | 1378 } |
| 1416 | 1379 |
| 1380 void WidgetGtk::SetCreateParams(const CreateParams& params) { |
| 1381 DCHECK(!GetNativeView()); |
| 1382 |
| 1383 delete_on_destroy_ = params.delete_on_destroy; |
| 1384 child_ = params.child; |
| 1385 |
| 1386 if (params.transparent) |
| 1387 MakeTransparent(); |
| 1388 if (!params.accept_events && !child_) |
| 1389 ignore_events_ = true; |
| 1390 |
| 1391 if (params.type == CreateParams::TYPE_MENU) { |
| 1392 GdkEvent* event = gtk_get_current_event(); |
| 1393 if (event) { |
| 1394 is_mouse_button_pressed_ = event->type == GDK_BUTTON_PRESS || |
| 1395 event->type == GDK_2BUTTON_PRESS || |
| 1396 event->type == GDK_3BUTTON_PRESS; |
| 1397 gdk_event_free(event); |
| 1398 } |
| 1399 } |
| 1400 } |
| 1401 |
| 1417 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { | 1402 gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { |
| 1418 // Clear the background to be totally transparent. We don't need to | 1403 // Clear the background to be totally transparent. We don't need to |
| 1419 // paint the root view here as that is done by OnPaint. | 1404 // paint the root view here as that is done by OnPaint. |
| 1420 DCHECK(transparent_); | 1405 DCHECK(transparent_); |
| 1421 DrawTransparentBackground(widget, event); | 1406 DrawTransparentBackground(widget, event); |
| 1422 // The Keyboard layout view has a renderer that covers the entire | 1407 // The Keyboard layout view has a renderer that covers the entire |
| 1423 // window, which prevents OnPaint from being called on window_contents_, | 1408 // window, which prevents OnPaint from being called on window_contents_, |
| 1424 // so we need to remove the FREEZE_UPDATES property here. | 1409 // so we need to remove the FREEZE_UPDATES property here. |
| 1425 if (!painted_) { | 1410 if (!painted_) { |
| 1426 painted_ = true; | 1411 painted_ = true; |
| 1427 UpdateFreezeUpdatesProperty(GTK_WINDOW(widget_), false /* remove */); | 1412 UpdateFreezeUpdatesProperty(GTK_WINDOW(widget_), false /* remove */); |
| 1428 } | 1413 } |
| 1429 return false; | 1414 return false; |
| 1430 } | 1415 } |
| 1431 | 1416 |
| 1432 void WidgetGtk::OnChildExpose(GtkWidget* child) { | 1417 void WidgetGtk::OnChildExpose(GtkWidget* child) { |
| 1433 DCHECK(type_ != TYPE_CHILD); | 1418 DCHECK(!child_); |
| 1434 if (!painted_) { | 1419 if (!painted_) { |
| 1435 painted_ = true; | 1420 painted_ = true; |
| 1436 UpdateFreezeUpdatesProperty(GTK_WINDOW(widget_), false /* remove */); | 1421 UpdateFreezeUpdatesProperty(GTK_WINDOW(widget_), false /* remove */); |
| 1437 } | 1422 } |
| 1438 RemoveExposeHandlerIfExists(child); | 1423 RemoveExposeHandlerIfExists(child); |
| 1439 } | 1424 } |
| 1440 | 1425 |
| 1441 // static | 1426 // static |
| 1442 gboolean WidgetGtk::ChildExposeHandler(GtkWidget* widget, | 1427 gboolean WidgetGtk::ChildExposeHandler(GtkWidget* widget, |
| 1443 GdkEventExpose* event) { | 1428 GdkEventExpose* event) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1457 while (parent) { | 1442 while (parent) { |
| 1458 WidgetGtk* widget_gtk = static_cast<WidgetGtk*>( | 1443 WidgetGtk* widget_gtk = static_cast<WidgetGtk*>( |
| 1459 NativeWidget::GetNativeWidgetForNativeView(parent)); | 1444 NativeWidget::GetNativeWidgetForNativeView(parent)); |
| 1460 if (widget_gtk && widget_gtk->is_window_) | 1445 if (widget_gtk && widget_gtk->is_window_) |
| 1461 return static_cast<WindowGtk*>(widget_gtk); | 1446 return static_cast<WindowGtk*>(widget_gtk); |
| 1462 parent = gtk_widget_get_parent(parent); | 1447 parent = gtk_widget_get_parent(parent); |
| 1463 } | 1448 } |
| 1464 return NULL; | 1449 return NULL; |
| 1465 } | 1450 } |
| 1466 | 1451 |
| 1467 void WidgetGtk::CreateGtkWidget(GtkWidget* parent, const gfx::Rect& bounds) { | 1452 void WidgetGtk::CreateGtkWidget(const CreateParams& params) { |
| 1468 // We turn off double buffering for two reasons: | 1453 // We turn off double buffering for two reasons: |
| 1469 // 1. We draw to a canvas then composite to the screen, which means we're | 1454 // 1. We draw to a canvas then composite to the screen, which means we're |
| 1470 // doing our own double buffering already. | 1455 // doing our own double buffering already. |
| 1471 // 2. GTKs double buffering clips to the dirty region. RootView occasionally | 1456 // 2. GTKs double buffering clips to the dirty region. RootView occasionally |
| 1472 // needs to expand the paint region (see RootView::OnPaint). This means | 1457 // needs to expand the paint region (see RootView::OnPaint). This means |
| 1473 // that if we use GTK's double buffering and we tried to expand the dirty | 1458 // that if we use GTK's double buffering and we tried to expand the dirty |
| 1474 // region, it wouldn't get painted. | 1459 // region, it wouldn't get painted. |
| 1475 if (type_ == TYPE_CHILD) { | 1460 if (child_) { |
| 1476 window_contents_ = widget_ = gtk_views_fixed_new(); | 1461 window_contents_ = widget_ = gtk_views_fixed_new(); |
| 1477 gtk_widget_set_name(widget_, "views-gtkwidget-child-fixed"); | 1462 gtk_widget_set_name(widget_, "views-gtkwidget-child-fixed"); |
| 1478 if (!is_double_buffered_) | 1463 if (!is_double_buffered_) |
| 1479 GTK_WIDGET_UNSET_FLAGS(widget_, GTK_DOUBLE_BUFFERED); | 1464 GTK_WIDGET_UNSET_FLAGS(widget_, GTK_DOUBLE_BUFFERED); |
| 1480 gtk_fixed_set_has_window(GTK_FIXED(widget_), true); | 1465 gtk_fixed_set_has_window(GTK_FIXED(widget_), true); |
| 1481 if (!parent && !null_parent_) { | 1466 if (!params.parent && !null_parent_) { |
| 1482 GtkWidget* popup = gtk_window_new(GTK_WINDOW_POPUP); | 1467 GtkWidget* popup = gtk_window_new(GTK_WINDOW_POPUP); |
| 1483 null_parent_ = gtk_fixed_new(); | 1468 null_parent_ = gtk_fixed_new(); |
| 1484 gtk_widget_set_name(widget_, "views-gtkwidget-null-parent"); | 1469 gtk_widget_set_name(widget_, "views-gtkwidget-null-parent"); |
| 1485 gtk_container_add(GTK_CONTAINER(popup), null_parent_); | 1470 gtk_container_add(GTK_CONTAINER(popup), null_parent_); |
| 1486 gtk_widget_realize(null_parent_); | 1471 gtk_widget_realize(null_parent_); |
| 1487 } | 1472 } |
| 1488 if (transparent_) { | 1473 if (transparent_) { |
| 1489 // transparency has to be configured before widget is realized. | 1474 // transparency has to be configured before widget is realized. |
| 1490 DCHECK(parent) << "Transparent widget must have parent when initialized"; | 1475 DCHECK(params.parent) << |
| 1491 ConfigureWidgetForTransparentBackground(parent); | 1476 "Transparent widget must have parent when initialized"; |
| 1477 ConfigureWidgetForTransparentBackground(params.parent); |
| 1492 } | 1478 } |
| 1493 gtk_container_add(GTK_CONTAINER(parent ? parent : null_parent_), widget_); | 1479 gtk_container_add( |
| 1480 GTK_CONTAINER(params.parent ? params.parent : null_parent_), widget_); |
| 1494 gtk_widget_realize(widget_); | 1481 gtk_widget_realize(widget_); |
| 1495 if (transparent_) { | 1482 if (transparent_) { |
| 1496 // The widget has to be realized to set composited flag. | 1483 // The widget has to be realized to set composited flag. |
| 1497 // I tried "realize" signal to set this flag, but it did not work | 1484 // I tried "realize" signal to set this flag, but it did not work |
| 1498 // when the top level is popup. | 1485 // when the top level is popup. |
| 1499 DCHECK(GTK_WIDGET_REALIZED(widget_)); | 1486 DCHECK(GTK_WIDGET_REALIZED(widget_)); |
| 1500 gdk_window_set_composited(widget_->window, true); | 1487 gdk_window_set_composited(widget_->window, true); |
| 1501 } | 1488 } |
| 1502 if (parent && !bounds.size().IsEmpty()) { | 1489 if (params.parent && !params.bounds.size().IsEmpty()) { |
| 1503 // Make sure that an widget is given it's initial size before | 1490 // Make sure that an widget is given it's initial size before |
| 1504 // we're done initializing, to take care of some potential | 1491 // we're done initializing, to take care of some potential |
| 1505 // corner cases when programmatically arranging hierarchies as | 1492 // corner cases when programmatically arranging hierarchies as |
| 1506 // seen in | 1493 // seen in |
| 1507 // http://code.google.com/p/chromium-os/issues/detail?id=5987 | 1494 // http://code.google.com/p/chromium-os/issues/detail?id=5987 |
| 1508 | 1495 |
| 1509 // This can't be done without a parent present, or stale data | 1496 // This can't be done without a parent present, or stale data |
| 1510 // might show up on the screen as seen in | 1497 // might show up on the screen as seen in |
| 1511 // http://code.google.com/p/chromium/issues/detail?id=53870 | 1498 // http://code.google.com/p/chromium/issues/detail?id=53870 |
| 1512 GtkAllocation alloc = { 0, 0, bounds.width(), bounds.height() }; | 1499 GtkAllocation alloc = |
| 1500 { 0, 0, params.bounds.width(), params.bounds.height() }; |
| 1513 gtk_widget_size_allocate(widget_, &alloc); | 1501 gtk_widget_size_allocate(widget_, &alloc); |
| 1514 } | 1502 } |
| 1515 } else { | 1503 } else { |
| 1516 // Use our own window class to override GtkWindow's move_focus method. | 1504 // Use our own window class to override GtkWindow's move_focus method. |
| 1517 widget_ = gtk_views_window_new( | 1505 widget_ = gtk_views_window_new( |
| 1518 (type_ == TYPE_WINDOW || type_ == TYPE_DECORATED_WINDOW) ? | 1506 params.type == CreateParams::TYPE_WINDOW ? GTK_WINDOW_TOPLEVEL |
| 1519 GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP); | 1507 : GTK_WINDOW_POPUP); |
| 1520 gtk_widget_set_name(widget_, "views-gtkwidget-window"); | 1508 gtk_widget_set_name(widget_, "views-gtkwidget-window"); |
| 1521 if (transient_to_parent_) | 1509 if (transient_to_parent_) { |
| 1522 gtk_window_set_transient_for(GTK_WINDOW(widget_), GTK_WINDOW(parent)); | 1510 gtk_window_set_transient_for(GTK_WINDOW(widget_), |
| 1511 GTK_WINDOW(params.parent)); |
| 1512 } |
| 1523 GTK_WIDGET_UNSET_FLAGS(widget_, GTK_DOUBLE_BUFFERED); | 1513 GTK_WIDGET_UNSET_FLAGS(widget_, GTK_DOUBLE_BUFFERED); |
| 1524 | 1514 |
| 1525 // Gtk determines the size for windows based on the requested size of the | 1515 // Gtk determines the size for windows based on the requested size of the |
| 1526 // child. For WidgetGtk the child is a fixed. If the fixed ends up with a | 1516 // child. For WidgetGtk the child is a fixed. If the fixed ends up with a |
| 1527 // child widget it's possible the child widget will drive the requested size | 1517 // child widget it's possible the child widget will drive the requested size |
| 1528 // of the widget, which we don't want. We explicitly set a value of 1x1 here | 1518 // of the widget, which we don't want. We explicitly set a value of 1x1 here |
| 1529 // so that gtk doesn't attempt to resize the window if we end up with a | 1519 // so that gtk doesn't attempt to resize the window if we end up with a |
| 1530 // situation where the requested size of a child of the fixed is greater | 1520 // situation where the requested size of a child of the fixed is greater |
| 1531 // than the size of the window. By setting the size in this manner we're | 1521 // than the size of the window. By setting the size in this manner we're |
| 1532 // also allowing users of WidgetGtk to change the requested size at any | 1522 // also allowing users of WidgetGtk to change the requested size at any |
| 1533 // time. | 1523 // time. |
| 1534 gtk_widget_set_size_request(widget_, 1, 1); | 1524 gtk_widget_set_size_request(widget_, 1, 1); |
| 1535 | 1525 |
| 1536 if (!bounds.size().IsEmpty()) { | 1526 if (!params.bounds.size().IsEmpty()) { |
| 1537 // When we realize the window, the window manager is given a size. If we | 1527 // When we realize the window, the window manager is given a size. If we |
| 1538 // don't specify a size before then GTK defaults to 200x200. Specify | 1528 // don't specify a size before then GTK defaults to 200x200. Specify |
| 1539 // a size now so that the window manager sees the requested size. | 1529 // a size now so that the window manager sees the requested size. |
| 1540 GtkAllocation alloc = { 0, 0, bounds.width(), bounds.height() }; | 1530 GtkAllocation alloc = |
| 1531 { 0, 0, params.bounds.width(), params.bounds.height() }; |
| 1541 gtk_widget_size_allocate(widget_, &alloc); | 1532 gtk_widget_size_allocate(widget_, &alloc); |
| 1542 } | 1533 } |
| 1543 if (type_ != TYPE_DECORATED_WINDOW) { | 1534 gtk_window_set_decorated(GTK_WINDOW(widget_), false); |
| 1544 gtk_window_set_decorated(GTK_WINDOW(widget_), false); | 1535 // We'll take care of positioning our window. |
| 1545 // We'll take care of positioning our window. | 1536 gtk_window_set_position(GTK_WINDOW(widget_), GTK_WIN_POS_NONE); |
| 1546 gtk_window_set_position(GTK_WINDOW(widget_), GTK_WIN_POS_NONE); | |
| 1547 } | |
| 1548 | 1537 |
| 1549 window_contents_ = gtk_views_fixed_new(); | 1538 window_contents_ = gtk_views_fixed_new(); |
| 1550 gtk_widget_set_name(window_contents_, "views-gtkwidget-window-fixed"); | 1539 gtk_widget_set_name(window_contents_, "views-gtkwidget-window-fixed"); |
| 1551 if (!is_double_buffered_) | 1540 if (!is_double_buffered_) |
| 1552 GTK_WIDGET_UNSET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED); | 1541 GTK_WIDGET_UNSET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED); |
| 1553 gtk_fixed_set_has_window(GTK_FIXED(window_contents_), true); | 1542 gtk_fixed_set_has_window(GTK_FIXED(window_contents_), true); |
| 1554 gtk_container_add(GTK_CONTAINER(widget_), window_contents_); | 1543 gtk_container_add(GTK_CONTAINER(widget_), window_contents_); |
| 1555 gtk_widget_show(window_contents_); | 1544 gtk_widget_show(window_contents_); |
| 1556 g_object_set_data(G_OBJECT(window_contents_), kNativeWidgetKey, | 1545 g_object_set_data(G_OBJECT(window_contents_), kNativeWidgetKey, |
| 1557 static_cast<Widget*>(this)); | 1546 static_cast<Widget*>(this)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1575 GdkColormap* rgba_colormap = | 1564 GdkColormap* rgba_colormap = |
| 1576 gdk_screen_get_rgba_colormap(gtk_widget_get_screen(widget_)); | 1565 gdk_screen_get_rgba_colormap(gtk_widget_get_screen(widget_)); |
| 1577 if (!rgba_colormap) { | 1566 if (!rgba_colormap) { |
| 1578 transparent_ = false; | 1567 transparent_ = false; |
| 1579 return; | 1568 return; |
| 1580 } | 1569 } |
| 1581 // To make the background transparent we need to install the RGBA colormap | 1570 // To make the background transparent we need to install the RGBA colormap |
| 1582 // on both the window and fixed. In addition we need to make sure no | 1571 // on both the window and fixed. In addition we need to make sure no |
| 1583 // decorations are drawn. The last bit is to make sure the widget doesn't | 1572 // decorations are drawn. The last bit is to make sure the widget doesn't |
| 1584 // attempt to draw a pixmap in it's background. | 1573 // attempt to draw a pixmap in it's background. |
| 1585 if (type_ != TYPE_CHILD) { | 1574 if (!child_) { |
| 1586 DCHECK(parent == NULL); | 1575 DCHECK(parent == NULL); |
| 1587 gtk_widget_set_colormap(widget_, rgba_colormap); | 1576 gtk_widget_set_colormap(widget_, rgba_colormap); |
| 1588 gtk_widget_set_app_paintable(widget_, true); | 1577 gtk_widget_set_app_paintable(widget_, true); |
| 1589 g_signal_connect(widget_, "expose_event", | 1578 g_signal_connect(widget_, "expose_event", |
| 1590 G_CALLBACK(&OnWindowPaintThunk), this); | 1579 G_CALLBACK(&OnWindowPaintThunk), this); |
| 1591 gtk_widget_realize(widget_); | 1580 gtk_widget_realize(widget_); |
| 1592 gdk_window_set_decorations(widget_->window, | 1581 gdk_window_set_decorations(widget_->window, |
| 1593 static_cast<GdkWMDecoration>(0)); | 1582 static_cast<GdkWMDecoration>(0)); |
| 1594 } else { | 1583 } else { |
| 1595 DCHECK(parent); | 1584 DCHECK(parent); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1625 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); | 1614 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); |
| 1626 gdk_cairo_region(cr, event->region); | 1615 gdk_cairo_region(cr, event->region); |
| 1627 cairo_fill(cr); | 1616 cairo_fill(cr); |
| 1628 cairo_destroy(cr); | 1617 cairo_destroy(cr); |
| 1629 } | 1618 } |
| 1630 | 1619 |
| 1631 //////////////////////////////////////////////////////////////////////////////// | 1620 //////////////////////////////////////////////////////////////////////////////// |
| 1632 // Widget, public: | 1621 // Widget, public: |
| 1633 | 1622 |
| 1634 // static | 1623 // static |
| 1635 Widget* Widget::CreateWidget(const CreateParams& params) { | 1624 Widget* Widget::CreateWidget() { |
| 1636 // TODO(beng): coalesce with CreateParams::Type. | 1625 return new WidgetGtk(); |
| 1637 WidgetGtk::Type widget_gtk_type = WidgetGtk::TYPE_DECORATED_WINDOW; | |
| 1638 switch (params.type) { | |
| 1639 case CreateParams::TYPE_CONTROL: | |
| 1640 widget_gtk_type = WidgetGtk::TYPE_CHILD; | |
| 1641 break; | |
| 1642 case CreateParams::TYPE_MENU: | |
| 1643 widget_gtk_type = WidgetGtk::TYPE_POPUP; | |
| 1644 break; | |
| 1645 case CreateParams::TYPE_POPUP: | |
| 1646 widget_gtk_type = WidgetGtk::TYPE_POPUP; | |
| 1647 break; | |
| 1648 case CreateParams::TYPE_WINDOW: | |
| 1649 widget_gtk_type = WidgetGtk::TYPE_DECORATED_WINDOW; | |
| 1650 break; | |
| 1651 default: | |
| 1652 NOTREACHED(); | |
| 1653 break; | |
| 1654 } | |
| 1655 | |
| 1656 WidgetGtk* widget = new WidgetGtk(widget_gtk_type); | |
| 1657 widget->SetCreateParams(params); | |
| 1658 return widget; | |
| 1659 } | 1626 } |
| 1660 | 1627 |
| 1661 // static | 1628 // static |
| 1662 void Widget::NotifyLocaleChanged() { | 1629 void Widget::NotifyLocaleChanged() { |
| 1663 GList *window_list = gtk_window_list_toplevels(); | 1630 GList *window_list = gtk_window_list_toplevels(); |
| 1664 for (GList* element = window_list; element; element = g_list_next(element)) { | 1631 for (GList* element = window_list; element; element = g_list_next(element)) { |
| 1665 NativeWidget* native_widget = | 1632 NativeWidget* native_widget = |
| 1666 NativeWidget::GetNativeWidgetForNativeWindow(GTK_WINDOW(element->data)); | 1633 NativeWidget::GetNativeWidgetForNativeWindow(GTK_WINDOW(element->data)); |
| 1667 if (native_widget) | 1634 if (native_widget) |
| 1668 native_widget->GetWidget()->LocaleChanged(); | 1635 native_widget->GetWidget()->LocaleChanged(); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1745 | 1712 |
| 1746 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); | 1713 NativeWidget* native_widget = GetNativeWidgetForNativeView(native_view); |
| 1747 if (native_widget) | 1714 if (native_widget) |
| 1748 children->insert(native_widget); | 1715 children->insert(native_widget); |
| 1749 gtk_container_foreach(GTK_CONTAINER(native_view), | 1716 gtk_container_foreach(GTK_CONTAINER(native_view), |
| 1750 EnumerateChildWidgetsForNativeWidgets, | 1717 EnumerateChildWidgetsForNativeWidgets, |
| 1751 reinterpret_cast<gpointer>(children)); | 1718 reinterpret_cast<gpointer>(children)); |
| 1752 } | 1719 } |
| 1753 | 1720 |
| 1754 } // namespace views | 1721 } // namespace views |
| OLD | NEW |