diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-20 20:56:11 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-20 20:56:11 +0000 |
commit | 893160d54cb5b2c1c68d3b69ec8ebc9b25b68b82 (patch) | |
tree | 0f29c1776a2f34f06ba60ba53a20691d261b6366 /views | |
parent | 22332192088e1e897d02a4bc7a2983e3864ab3b6 (diff) | |
download | chromium_src-893160d54cb5b2c1c68d3b69ec8ebc9b25b68b82.zip chromium_src-893160d54cb5b2c1c68d3b69ec8ebc9b25b68b82.tar.gz chromium_src-893160d54cb5b2c1c68d3b69ec8ebc9b25b68b82.tar.bz2 |
Minor gtk-views cleanup:
. Makes closing widget work.
. Makes clicking button send action.
. Fixes ownership of native controls.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/113657
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16532 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/button/native_button_gtk.cc | 13 | ||||
-rw-r--r-- | views/controls/button/native_button_gtk.h | 5 | ||||
-rw-r--r-- | views/controls/native_control_gtk.cc | 8 | ||||
-rw-r--r-- | views/controls/native_view_host_gtk.cc | 36 | ||||
-rw-r--r-- | views/controls/native_view_host_gtk.h | 13 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 78 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 19 | ||||
-rw-r--r-- | views/window/window_gtk.cc | 22 | ||||
-rw-r--r-- | views/window/window_gtk.h | 6 |
9 files changed, 177 insertions, 23 deletions
diff --git a/views/controls/button/native_button_gtk.cc b/views/controls/button/native_button_gtk.cc index 858fdcd..3f10897 100644 --- a/views/controls/button/native_button_gtk.cc +++ b/views/controls/button/native_button_gtk.cc @@ -75,6 +75,8 @@ gfx::Size NativeButtonGtk::GetPreferredSize() { void NativeButtonGtk::CreateNativeControl() { GtkWidget* widget = gtk_button_new(); + g_signal_connect(G_OBJECT(widget), "clicked", + G_CALLBACK(CallClicked), NULL); NativeControlCreated(widget); } @@ -86,6 +88,17 @@ void NativeButtonGtk::NativeControlCreated(GtkWidget* widget) { UpdateDefault(); } +// static +void NativeButtonGtk::CallClicked(GtkButton* widget) { + View* view = GetViewForNative(GTK_WIDGET(widget)); + if (view) + static_cast<NativeButtonGtk*>(view)->OnClicked(); +} + +void NativeButtonGtk::OnClicked() { + native_button_->ButtonPressed(); +} + NativeCheckboxGtk::NativeCheckboxGtk(Checkbox* checkbox) : NativeButtonGtk(checkbox) { } diff --git a/views/controls/button/native_button_gtk.h b/views/controls/button/native_button_gtk.h index d526dcd..96a8f53 100644 --- a/views/controls/button/native_button_gtk.h +++ b/views/controls/button/native_button_gtk.h @@ -35,6 +35,11 @@ class NativeButtonGtk : public NativeControlGtk, public NativeButtonWrapper { virtual bool IsCheckbox() const { return false; } private: + static void CallClicked(GtkButton* widget); + + // Invoked when the user clicks on the button. + void OnClicked(); + // The NativeButton we are bound to. NativeButton* native_button_; diff --git a/views/controls/native_control_gtk.cc b/views/controls/native_control_gtk.cc index 3cf6438..ad7382f 100644 --- a/views/controls/native_control_gtk.cc +++ b/views/controls/native_control_gtk.cc @@ -10,13 +10,12 @@ namespace views { -static const char* kNativeControlGtkKey = "__NATIVE_CONTROL_GTK__"; - NativeControlGtk::NativeControlGtk() { } NativeControlGtk::~NativeControlGtk() { - DCHECK(!native_view()); + if (native_view()) + gtk_widget_destroy(native_view()); } //////////////////////////////////////////////////////////////////////////////// @@ -58,9 +57,6 @@ void NativeControlGtk::Focus() { } void NativeControlGtk::NativeControlCreated(GtkWidget* native_control) { - // Adds a mapping between the GtkWidget and us. - g_object_set_data(G_OBJECT(native_control), kNativeControlGtkKey, this); - Attach(native_control); // Update the newly created GtkWdigetwith any resident enabled state. diff --git a/views/controls/native_view_host_gtk.cc b/views/controls/native_view_host_gtk.cc index 5f6b8a3..a6f125e 100644 --- a/views/controls/native_view_host_gtk.cc +++ b/views/controls/native_view_host_gtk.cc @@ -11,16 +11,33 @@ namespace views { -NativeViewHostGtk::NativeViewHostGtk() { +NativeViewHostGtk::NativeViewHostGtk() : destroy_signal_id_(0) { } NativeViewHostGtk::~NativeViewHostGtk() { } +// static +View* NativeViewHostGtk::GetViewForNative(GtkWidget* widget) { + gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-view"); + return static_cast<View*>(user_data); +} + +// static +void NativeViewHostGtk::SetViewForNative(GtkWidget* widget, View* view) { + g_object_set_data(G_OBJECT(widget), "chrome-view", view); +} + void NativeViewHostGtk::Attach(GtkWidget* widget) { DCHECK(native_view() == NULL); DCHECK(widget); + // Adds a mapping between the GtkWidget and us. + SetViewForNative(widget, this); + + destroy_signal_id_ = g_signal_connect(G_OBJECT(widget), "destroy", + G_CALLBACK(CallDestroy), NULL); + set_native_view(widget); // First hide the new window. We don't want anything to draw (like sub-hwnd @@ -38,6 +55,10 @@ void NativeViewHostGtk::Attach(GtkWidget* widget) { void NativeViewHostGtk::Detach() { DCHECK(native_view()); + + g_signal_handler_disconnect(G_OBJECT(native_view()), destroy_signal_id_); + destroy_signal_id_ = 0; + // TODO: focus. // FocusManager::UninstallFocusSubclass(native_view()); set_native_view(NULL); @@ -118,4 +139,17 @@ void NativeViewHostGtk::HideWidget() { gtk_widget_hide(native_view()); } +void NativeViewHostGtk::OnDestroy() { + set_native_view(NULL); +} + +// static +void NativeViewHostGtk::CallDestroy(GtkObject* object) { + View* view = GetViewForNative(GTK_WIDGET(object)); + if (!view) + return; + + return static_cast<NativeViewHostGtk*>(view)->OnDestroy(); +} + } // namespace views diff --git a/views/controls/native_view_host_gtk.h b/views/controls/native_view_host_gtk.h index d8a134d..1b383af 100644 --- a/views/controls/native_view_host_gtk.h +++ b/views/controls/native_view_host_gtk.h @@ -5,6 +5,7 @@ #ifndef VIEWS_CONTROLS_NATIVE_HOST_VIEW_GTK_H_ #define VIEWS_CONTROLS_NATIVE_HOST_VIEW_GTK_H_ +#include <gtk/gtk.h> #include <string> #include "views/controls/native_view_host.h" @@ -16,6 +17,10 @@ class NativeViewHostGtk : public NativeViewHost { NativeViewHostGtk(); virtual ~NativeViewHostGtk(); + // Sets and retrieves the View associated with a particular widget. + static View* GetViewForNative(GtkWidget* widget); + static void SetViewForNative(GtkWidget* widget, View* view); + // Attach a widget to this View, making the window it represents // subject to sizing according to this View's parent container's Layout // Manager's sizing heuristics. @@ -41,6 +46,14 @@ class NativeViewHostGtk : public NativeViewHost { virtual void HideWidget(); private: + // Signal handle id for 'destroy' signal. + gulong destroy_signal_id_; + + // Invoked from the 'destroy' signal. + void OnDestroy(); + + static void CallDestroy(GtkObject* object); + DISALLOW_COPY_AND_ASSIGN(NativeViewHostGtk); }; diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index 0b24657..1f8790e 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -4,6 +4,7 @@ #include "views/widget/widget_gtk.h" +#include "base/compiler_specific.h" #include "views/fill_layout.h" #include "views/widget/root_view.h" #include "views/window/window_gtk.h" @@ -57,15 +58,12 @@ WidgetGtk::WidgetGtk(Type type) child_widget_parent_(NULL), is_mouse_down_(false), has_capture_(false), - last_mouse_event_was_move_(false) { + last_mouse_event_was_move_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)), + delete_on_destroy_(true) { } WidgetGtk::~WidgetGtk() { - if (widget_) { - // TODO: make sure this is right. - gtk_widget_destroy(widget_); - child_widget_parent_ = widget_ = NULL; - } MessageLoopForUI::current()->RemoveObserver(this); } @@ -79,10 +77,10 @@ void WidgetGtk::Init(const gfx::Rect& bounds, // Make sure we receive our motion events. - // We register everything on the parent of all widgets. At a minimum we need - // painting to happen on the parent (otherwise painting doesn't work at all), - // and similarly we need mouse release events on the parent as windows don't - // get mouse releases. + // In general we register most events on the parent of all widgets. At a + // minimum we need painting to happen on the parent (otherwise painting + // doesn't work at all), and similarly we need mouse release events on the + // parent as windows don't get mouse releases. gtk_widget_add_events(child_widget_parent_, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | @@ -114,10 +112,6 @@ void WidgetGtk::Init(const gfx::Rect& bounds, G_CALLBACK(CallButtonPress), NULL); g_signal_connect(G_OBJECT(child_widget_parent_), "button_release_event", G_CALLBACK(CallButtonRelease), NULL); - g_signal_connect(G_OBJECT(child_widget_parent_), "focus_in_event", - G_CALLBACK(CallFocusIn), NULL); - g_signal_connect(G_OBJECT(child_widget_parent_), "focus_out_event", - G_CALLBACK(CallFocusOut), NULL); g_signal_connect(G_OBJECT(child_widget_parent_), "grab_broke_event", G_CALLBACK(CallGrabBrokeEvent), NULL); g_signal_connect(G_OBJECT(child_widget_parent_), "grab_notify", @@ -133,6 +127,17 @@ void WidgetGtk::Init(const gfx::Rect& bounds, g_signal_connect(G_OBJECT(child_widget_parent_), "visibility_notify_event", G_CALLBACK(CallVisibilityNotify), NULL); + // In order to receive notification when the window is no longer the front + // window, we need to install these on the widget. + // NOTE: this doesn't work with focus follows mouse. + g_signal_connect(G_OBJECT(widget_), "focus_in_event", + G_CALLBACK(CallFocusIn), NULL); + g_signal_connect(G_OBJECT(widget_), "focus_out_event", + G_CALLBACK(CallFocusOut), NULL); + + g_signal_connect(G_OBJECT(widget_), "destroy", + G_CALLBACK(CallDestroy), NULL); + // TODO(erg): Ignore these signals for now because they're such a drag. // // g_signal_connect(G_OBJECT(widget_), "drag_motion", @@ -174,6 +179,35 @@ void WidgetGtk::SetContentsView(View* view) { OnSizeAllocate(widget_, &(widget_->allocation)); } +void WidgetGtk::Close() { + if (!widget_) + return; // No need to do anything. + + // Hide first. + Hide(); + if (close_widget_factory_.empty()) { + // And we delay the close just in case we're on the stack. + MessageLoop::current()->PostTask(FROM_HERE, + close_widget_factory_.NewRunnableMethod( + &WidgetGtk::CloseNow)); + } +} + +void WidgetGtk::CloseNow() { + if (widget_) + gtk_widget_destroy(widget_); +} + +void WidgetGtk::Show() { + if (widget_) + gtk_widget_show(widget_); +} + +void WidgetGtk::Hide() { + if (widget_) + gtk_widget_hide(widget_); +} + void WidgetGtk::GetBounds(gfx::Rect* out, bool including_frame) const { DCHECK(widget_); @@ -368,6 +402,13 @@ void WidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) { HandleGrabBroke(); } +void WidgetGtk::OnDestroy(GtkWidget* widget) { + widget_ = child_widget_parent_ = NULL; + root_view_->OnWidgetDestroyed(); + if (delete_on_destroy_) + delete this; +} + // static WindowGtk* WidgetGtk::GetWindowForNative(GtkWidget* widget) { gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-window"); @@ -572,6 +613,15 @@ void WidgetGtk::CallGrabNotify(GtkWidget* widget, gboolean was_grabbed) { } // static +void WidgetGtk::CallDestroy(GtkObject* object) { + WidgetGtk* widget_gtk = GetViewForNative(GTK_WIDGET(object)); + if (!widget_gtk) + return; + + return widget_gtk->OnDestroy(GTK_WIDGET(object)); +} + +// static Window* WidgetGtk::GetWindowImpl(GtkWidget* widget) { GtkWidget* parent = widget; while (parent) { diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h index cebc686..e1a7468 100644 --- a/views/widget/widget_gtk.h +++ b/views/widget/widget_gtk.h @@ -39,6 +39,12 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { // Initializes this widget. void Init(const gfx::Rect& bounds, bool has_own_focus_manager); + // Sets whether or not we are deleted when the widget is destroyed. The + // default is true. + void set_delete_on_destroy(bool delete_on_destroy) { + delete_on_destroy_ = delete_on_destroy; + } + void AddChild(GtkWidget* child); void RemoveChild(GtkWidget* child); @@ -51,6 +57,11 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { virtual void SetContentsView(View* view); + virtual void Close(); + void CloseNow(); + virtual void Show(); + virtual void Hide(); + // Overridden from Widget: virtual void GetBounds(gfx::Rect* out, bool including_frame) const; virtual gfx::NativeView GetNativeView() const; @@ -93,6 +104,7 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { } virtual gboolean OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event); virtual void OnGrabNotify(GtkWidget* widget, gboolean was_grabbed); + virtual void OnDestroy(GtkWidget* widget); // Returns whether capture should be released on mouse release. The default // is true. @@ -136,6 +148,7 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { GdkEventVisibility* event); static gboolean CallGrabBrokeEvent(GtkWidget* widget, GdkEvent* event); static void CallGrabNotify(GtkWidget* widget, gboolean was_grabbed); + static void CallDestroy(GtkObject* object); // Returns the first ancestor of |widget| that is a window. static Window* GetWindowImpl(GtkWidget* widget); @@ -173,6 +186,12 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { int last_mouse_move_x_; int last_mouse_move_y_; + // The following factory is used to delay destruction. + ScopedRunnableMethodFactory<WidgetGtk> close_widget_factory_; + + // See description above setter. + bool delete_on_destroy_; + DISALLOW_COPY_AND_ASSIGN(WidgetGtk); }; diff --git a/views/window/window_gtk.cc b/views/window/window_gtk.cc index 2a74706..087bf11 100644 --- a/views/window/window_gtk.cc +++ b/views/window/window_gtk.cc @@ -72,7 +72,16 @@ void WindowGtk::Activate() { } void WindowGtk::Close() { - NOTIMPLEMENTED(); + if (window_closed_) { + // Don't do anything if we've already been closed. + return; + } + + if (non_client_view_->CanClose()) { + SaveWindowPosition(); + WidgetGtk::Close(); + window_closed_ = true; + } } void WindowGtk::Maximize() { @@ -175,7 +184,8 @@ WindowGtk::WindowGtk(WindowDelegate* window_delegate) : WidgetGtk(TYPE_WINDOW), is_modal_(false), window_delegate_(window_delegate), - non_client_view_(new NonClientView(this)) { + non_client_view_(new NonClientView(this)), + window_closed_(false) { is_window_ = true; window_delegate_->window_.reset(this); } @@ -210,4 +220,12 @@ void WindowGtk::Init(const gfx::Rect& bounds) { // ResetWindowRegion(false); } +void WindowGtk::SaveWindowPosition() { + // The delegate may have gone away on us. + if (!window_delegate_) + return; + + NOTIMPLEMENTED(); +} + } // namespace views diff --git a/views/window/window_gtk.h b/views/window/window_gtk.h index 4391c19..d38ce62 100644 --- a/views/window/window_gtk.h +++ b/views/window/window_gtk.h @@ -71,6 +71,9 @@ class WindowGtk : public WidgetGtk, public Window { void Init(const gfx::Rect& bounds); private: + // Asks the delegate if any to save the window's location and size. + void SaveWindowPosition(); + // Whether or not the window is modal. This comes from the delegate and is // cached at Init time to avoid calling back to the delegate from the // destructor. @@ -85,6 +88,9 @@ class WindowGtk : public WidgetGtk, public Window { // desired implementation before calling |Init|. NonClientView* non_client_view_; + // Set to true if the window is in the process of closing. + bool window_closed_; + DISALLOW_COPY_AND_ASSIGN(WindowGtk); }; |