summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-20 20:56:11 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-20 20:56:11 +0000
commit893160d54cb5b2c1c68d3b69ec8ebc9b25b68b82 (patch)
tree0f29c1776a2f34f06ba60ba53a20691d261b6366 /views
parent22332192088e1e897d02a4bc7a2983e3864ab3b6 (diff)
downloadchromium_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.cc13
-rw-r--r--views/controls/button/native_button_gtk.h5
-rw-r--r--views/controls/native_control_gtk.cc8
-rw-r--r--views/controls/native_view_host_gtk.cc36
-rw-r--r--views/controls/native_view_host_gtk.h13
-rw-r--r--views/widget/widget_gtk.cc78
-rw-r--r--views/widget/widget_gtk.h19
-rw-r--r--views/window/window_gtk.cc22
-rw-r--r--views/window/window_gtk.h6
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);
};