diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-07 23:41:29 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-07 23:41:29 +0000 |
commit | 0ae186fdc196eeb1ee8e56285a06c6fd3012ea60 (patch) | |
tree | 8ced53b52ef5dc1441bc6fa62f8f927494ca4bc5 /chrome/views/widget | |
parent | 601bffcbec8cd6222ebda98f554adba0fb9cc1f0 (diff) | |
download | chromium_src-0ae186fdc196eeb1ee8e56285a06c6fd3012ea60.zip chromium_src-0ae186fdc196eeb1ee8e56285a06c6fd3012ea60.tar.gz chromium_src-0ae186fdc196eeb1ee8e56285a06c6fd3012ea60.tar.bz2 |
Fleshes out WidgetGTK and WindowGTK a bit more. This is still vary
rough, but makes things work a bit more.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/113123
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15598 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/views/widget')
-rw-r--r-- | chrome/views/widget/root_view.h | 14 | ||||
-rw-r--r-- | chrome/views/widget/root_view_gtk.cc | 2 | ||||
-rw-r--r-- | chrome/views/widget/widget_gtk.cc | 224 | ||||
-rw-r--r-- | chrome/views/widget/widget_gtk.h | 57 |
4 files changed, 227 insertions, 70 deletions
diff --git a/chrome/views/widget/root_view.h b/chrome/views/widget/root_view.h index 1232af5..3b6a5e7 100644 --- a/chrome/views/widget/root_view.h +++ b/chrome/views/widget/root_view.h @@ -5,19 +5,17 @@ #ifndef CHROME_VIEWS_WIDGET_ROOT_VIEW_H_ #define CHROME_VIEWS_WIDGET_ROOT_VIEW_H_ -#include "build/build_config.h" - -#if defined(OS_LINUX) -#include <gtk/gtk.h> -#endif +#include <string> -#if defined(OS_WIN) #include "base/ref_counted.h" -#endif - +#include "build/build_config.h" #include "chrome/views/focus/focus_manager.h" #include "chrome/views/view.h" +#if defined(OS_LINUX) +typedef struct _GdkEventExpose GdkEventExpose; +#endif + namespace views { class PaintTask; diff --git a/chrome/views/widget/root_view_gtk.cc b/chrome/views/widget/root_view_gtk.cc index 68d0947..8ff19e4 100644 --- a/chrome/views/widget/root_view_gtk.cc +++ b/chrome/views/widget/root_view_gtk.cc @@ -4,6 +4,8 @@ #include "chrome/views/widget/root_view.h" +#include <gtk/gtk.h> + #include "app/gfx/chrome_canvas.h" #include "base/logging.h" #include "skia/include/SkColor.h" diff --git a/chrome/views/widget/widget_gtk.cc b/chrome/views/widget/widget_gtk.cc index 4fc51d9..39bbd00 100644 --- a/chrome/views/widget/widget_gtk.cc +++ b/chrome/views/widget/widget_gtk.cc @@ -6,35 +6,60 @@ #include "chrome/views/fill_layout.h" #include "chrome/views/widget/root_view.h" +#include "chrome/views/window/window_gtk.h" namespace views { -WidgetGtk::WidgetGtk() - : widget_(NULL), +// Returns the position of a widget on screen. +static void GetWidgetPositionOnScreen(GtkWidget* widget, int* x, int *y) { + GtkWidget* parent = widget; + while (parent) { + if (GTK_IS_WINDOW(widget)) { + int window_x, window_y; + gtk_window_get_position(GTK_WINDOW(widget), &window_x, &window_y); + *x += window_x; + *y += window_y; + return; + } + // Not a window. + *x += widget->allocation.x; + *y += widget->allocation.y; + parent = gtk_widget_get_parent(parent); + } +} + +WidgetGtk::WidgetGtk(Type type) + : type_(type), + widget_(NULL), + child_widget_parent_(NULL), is_mouse_down_(false), last_mouse_event_was_move_(false) { } WidgetGtk::~WidgetGtk() { - gtk_widget_unref(widget_); - + if (widget_) { + // TODO: make sure this is right. + gtk_widget_destroy(widget_); + child_widget_parent_ = widget_ = NULL; + } // MessageLoopForUI::current()->RemoveObserver(this); } void WidgetGtk::Init(const gfx::Rect& bounds, bool has_own_focus_manager) { - // Force creation of the RootView if it hasn't been created yet. GetRootView(); // Make container here. - widget_ = gtk_drawing_area_new(); - gtk_drawing_area_size(GTK_DRAWING_AREA(widget_), 100, 100); - gtk_widget_show(widget_); + CreateGtkWidget(); // Make sure we receive our motion events. - gtk_widget_set_events(widget_, - gtk_widget_get_events(widget_) | + + // 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. + gtk_widget_add_events(child_widget_parent_, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | @@ -47,36 +72,35 @@ void WidgetGtk::Init(const gfx::Rect& bounds, // TODO(port): if(has_own_focus_manager) block - SetViewForNative(widget_, this); SetRootViewForWidget(widget_, root_view_.get()); // MessageLoopForUI::current()->AddObserver(this); - g_signal_connect_after(G_OBJECT(widget_), "size_allocate", + g_signal_connect_after(G_OBJECT(child_widget_parent_), "size_allocate", G_CALLBACK(CallSizeAllocate), NULL); - g_signal_connect(G_OBJECT(widget_), "expose_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "expose_event", G_CALLBACK(CallPaint), NULL); - g_signal_connect(G_OBJECT(widget_), "enter_notify_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "enter_notify_event", G_CALLBACK(CallEnterNotify), NULL); - g_signal_connect(G_OBJECT(widget_), "leave_notify_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "leave_notify_event", G_CALLBACK(CallLeaveNotify), NULL); - g_signal_connect(G_OBJECT(widget_), "motion_notify_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "motion_notify_event", G_CALLBACK(CallMotionNotify), NULL); - g_signal_connect(G_OBJECT(widget_), "button_press_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "button_press_event", G_CALLBACK(CallButtonPress), NULL); - g_signal_connect(G_OBJECT(widget_), "button_release_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "button_release_event", G_CALLBACK(CallButtonRelease), NULL); - g_signal_connect(G_OBJECT(widget_), "focus_in_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "focus_in_event", G_CALLBACK(CallFocusIn), NULL); - g_signal_connect(G_OBJECT(widget_), "focus_out_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "focus_out_event", G_CALLBACK(CallFocusOut), NULL); - g_signal_connect(G_OBJECT(widget_), "key_press_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "key_press_event", G_CALLBACK(CallKeyPress), NULL); - g_signal_connect(G_OBJECT(widget_), "key_release_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "key_release_event", G_CALLBACK(CallKeyRelease), NULL); - g_signal_connect(G_OBJECT(widget_), "scroll_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "scroll_event", G_CALLBACK(CallScroll), NULL); - g_signal_connect(G_OBJECT(widget_), "visibility_notify_event", + g_signal_connect(G_OBJECT(child_widget_parent_), "visibility_notify_event", G_CALLBACK(CallVisibilityNotify), NULL); // TODO(erg): Ignore these signals for now because they're such a drag. @@ -91,8 +115,23 @@ void WidgetGtk::Init(const gfx::Rect& bounds, // G_CALLBACK(drag_data_received_event_cb), NULL); } +void WidgetGtk::AddChild(GtkWidget* child) { + gtk_container_add(GTK_CONTAINER(child_widget_parent_), child); +} + +void WidgetGtk::RemoveChild(GtkWidget* child) { + gtk_container_remove(GTK_CONTAINER(child_widget_parent_), child); +} + +void WidgetGtk::PositionChild(GtkWidget* child, int x, int y, int w, int h) { + GtkAllocation alloc = { x, y, w, h }; + gtk_widget_size_allocate(child, &alloc); + gtk_fixed_move(GTK_FIXED(child_widget_parent_), child, x, y); +} + void WidgetGtk::SetContentsView(View* view) { - DCHECK(view && widget_) << "Can't be called until after the HWND is created!"; + DCHECK(view && widget_) + << "Can't be called until after the HWND is created!"; // The ContentsView must be set up _after_ the window is created so that its // Widget pointer is valid. root_view_->SetLayoutManager(new FillLayout); @@ -100,26 +139,34 @@ void WidgetGtk::SetContentsView(View* view) { root_view_->RemoveAllChildViews(true); root_view_->AddChildView(view); - // TODO(erg): Terrible hack to work around lack of real sizing mechanics for - // now. - root_view_->SetBounds(0, 0, 100, 100); - root_view_->Layout(); - root_view_->SchedulePaint(); - NOTIMPLEMENTED(); + DCHECK(widget_); // Widget must have been created by now. + + OnSizeAllocate(widget_, &(widget_->allocation)); } void WidgetGtk::GetBounds(gfx::Rect* out, bool including_frame) const { + DCHECK(widget_); + + int x = 0, y = 0, w, h; + if (GTK_IS_WINDOW(widget_)) { + gtk_window_get_position(GTK_WINDOW(widget_), &x, &y); + gtk_window_get_size(GTK_WINDOW(widget_), &w, &h); + } else { + // TODO: make sure this is right. Docs indicate gtk_window_get_position + // returns a value useful to the window manager, which may not be the same + // as the actual location on the screen. + GetWidgetPositionOnScreen(widget_, &x, &y); + w = widget_->allocation.width; + h = widget_->allocation.height; + } + if (including_frame) { + // TODO: Docs indicate it isn't possible to get at this value. We may need + // to turn off all decorations so that the frame is always of a 0x0 size. NOTIMPLEMENTED(); - *out = gfx::Rect(); - return; } - // TODO(erg): Not sure how to implement this. gtk_widget_size_request() - // returns a widget's requested size--not it's actual size. The system of - // containers and such do auto sizing tricks to make everything work within - // the constraints and requested sizes... - NOTIMPLEMENTED(); + return out->SetRect(x, y, w, h); } gfx::NativeView WidgetGtk::GetNativeView() const { @@ -127,7 +174,6 @@ gfx::NativeView WidgetGtk::GetNativeView() const { } void WidgetGtk::PaintNow(const gfx::Rect& update_rect) { - // TODO(erg): This is woefully incomplete and is a straw man implementation. gtk_widget_queue_draw_area(widget_, update_rect.x(), update_rect.y(), update_rect.width(), update_rect.height()); } @@ -145,8 +191,9 @@ bool WidgetGtk::IsVisible() const { } bool WidgetGtk::IsActive() const { - NOTIMPLEMENTED(); - return false; + // If this only applies to windows, it shouldn't be in widget. + DCHECK(GTK_IS_WINDOW(widget_)); + return gtk_window_is_active(GTK_WINDOW(widget_)); } TooltipManager* WidgetGtk::GetTooltipManager() { @@ -159,6 +206,43 @@ bool WidgetGtk::GetAccelerator(int cmd_id, Accelerator* accelerator) { return false; } +Window* WidgetGtk::GetWindow() { + return GetWindowImpl(widget_); +} + +const Window* WidgetGtk::GetWindow() const { + return GetWindowImpl(widget_); +} + +void WidgetGtk::CreateGtkWidget() { + if (type_ == TYPE_CHILD) { + child_widget_parent_ = widget_ = gtk_fixed_new(); + SetViewForNative(widget_, this); + } else { + widget_ = gtk_window_new( + type_ == TYPE_WINDOW ? GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP); + gtk_window_set_decorated(GTK_WINDOW(widget_), false); + // We'll take care of positioning our window. + gtk_window_set_position(GTK_WINDOW(widget_), GTK_WIN_POS_NONE); + SetWindowForNative(widget_, static_cast<WindowGtk*>(this)); + SetViewForNative(widget_, this); + + child_widget_parent_ = gtk_fixed_new(); + gtk_fixed_set_has_window(GTK_FIXED(child_widget_parent_), true); + gtk_container_add(GTK_CONTAINER(widget_), child_widget_parent_); + gtk_widget_show(child_widget_parent_); + + SetViewForNative(child_widget_parent_, this); + } + gtk_widget_show(widget_); +} + +void WidgetGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { + root_view_->SetBounds(0, 0, allocation->width, allocation->height); + root_view_->Layout(); + root_view_->SchedulePaint(); +} + gboolean WidgetGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) { gfx::Point screen_loc(event->x_root, event->y_root); if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() && @@ -178,7 +262,8 @@ gboolean WidgetGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) { } gboolean WidgetGtk::OnButtonPress(GtkWidget* widget, GdkEventButton* event) { - return ProcessMousePressed(event); + ProcessMousePressed(event); + return true; } gboolean WidgetGtk::OnButtonRelease(GtkWidget* widget, GdkEventButton* event) { @@ -186,9 +271,8 @@ gboolean WidgetGtk::OnButtonRelease(GtkWidget* widget, GdkEventButton* event) { return true; } -gboolean WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) { +void WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) { root_view_->OnPaint(event); - return true; } gboolean WidgetGtk::OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event) { @@ -213,16 +297,42 @@ gboolean WidgetGtk::OnKeyRelease(GtkWidget* widget, GdkEventKey* event) { return root_view_->ProcessKeyEvent(key_event); } +// static +WindowGtk* WidgetGtk::GetWindowForNative(GtkWidget* widget) { + gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-window"); + return static_cast<WindowGtk*>(user_data); +} + +// static +void WidgetGtk::SetWindowForNative(GtkWidget* widget, WindowGtk* window) { + g_object_set_data(G_OBJECT(widget), "chrome-window", window); +} + RootView* WidgetGtk::CreateRootView() { return new RootView(this); } bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { last_mouse_event_was_move_ = false; + // TODO: move this code into a common place. Also need support for + // double/triple click. + int flags = Event::GetFlagsFromGdkState(event->state); + switch (event->button) { + case 1: + flags |= Event::EF_LEFT_BUTTON_DOWN; + break; + case 2: + flags |= Event::EF_MIDDLE_BUTTON_DOWN; + break; + case 3: + flags |= Event::EF_MIDDLE_BUTTON_DOWN; + break; + default: + // We only deal with 1-3. + break; + } MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, - event->x, event->y, -// (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) | - Event::GetFlagsFromGdkState(event->state)); + event->x, event->y, flags); if (root_view_->OnMousePressed(mouse_pressed)) { is_mouse_down_ = true; // TODO(port): Enable this once I figure out what capture is. @@ -288,10 +398,9 @@ void WidgetGtk::CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { gboolean WidgetGtk::CallPaint(GtkWidget* widget, GdkEventExpose* event) { WidgetGtk* widget_gtk = GetViewForNative(widget); - if (!widget_gtk) - return false; - - return widget_gtk->OnPaint(widget, event); + if (widget_gtk) + widget_gtk->OnPaint(widget, event); + return false; // False indicates other widgets should get the event as well. } gboolean WidgetGtk::CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event) { @@ -383,4 +492,17 @@ gboolean WidgetGtk::CallVisibilityNotify(GtkWidget* widget, return widget_gtk->OnVisibilityNotify(widget, event); } +// Returns the first ancestor of |widget| that is a window. +// static +Window* WidgetGtk::GetWindowImpl(GtkWidget* widget) { + GtkWidget* parent = widget; + while (parent) { + WindowGtk* window = GetWindowForNative(widget); + if (window) + return window; + parent = gtk_widget_get_parent(parent); + } + return NULL; +} + } diff --git a/chrome/views/widget/widget_gtk.h b/chrome/views/widget/widget_gtk.h index e29a869..ba3ba74 100644 --- a/chrome/views/widget/widget_gtk.h +++ b/chrome/views/widget/widget_gtk.h @@ -17,22 +17,39 @@ class Rect; namespace views { class View; +class WindowGtk; +// Widget implementation for GTK. class WidgetGtk : public Widget { public: - static WidgetGtk* Construct() { - // This isn't used, but exists to force WidgetGtk to be instantiable. - return new WidgetGtk; - } + // Type of widget. + enum Type { + // Used for popup type windows (bubbles, menus ...). + TYPE_POPUP, + + // A top level window. + TYPE_WINDOW, + + // A child widget. + TYPE_CHILD + }; - WidgetGtk(); + explicit WidgetGtk(Type type); virtual ~WidgetGtk(); - // Initializes this widget and returns the gtk drawing area for the caller to - // add to its hierarchy. (We can't pass in the parent to this method because - // there are no standard adding semantics in gtk...) + // Initializes this widget. void Init(const gfx::Rect& bounds, bool has_own_focus_manager); + void AddChild(GtkWidget* child); + void RemoveChild(GtkWidget* child); + + // Positions a child GtkWidget at the specified location and bounds. + void PositionChild(GtkWidget* child, int x, int y, int w, int h); + + // Parent GtkWidget all children are added to. This is not necessarily + // the same as returned by GetNativeView. + GtkWidget* child_widget_parent() const { return child_widget_parent_; } + virtual void SetContentsView(View* view); // Overridden from Widget: @@ -44,10 +61,12 @@ class WidgetGtk : public Widget { virtual bool IsActive() const; virtual TooltipManager* GetTooltipManager(); virtual bool GetAccelerator(int cmd_id, Accelerator* accelerator); + virtual Window* GetWindow(); + virtual const Window* GetWindow() const; protected: - virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {} - virtual gboolean OnPaint(GtkWidget* widget, GdkEventExpose* event); + virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation); + virtual void OnPaint(GtkWidget* widget, GdkEventExpose* event); virtual gboolean OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event); virtual gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event); virtual gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event); @@ -69,6 +88,10 @@ class WidgetGtk : public Widget { return false; } + // Sets and retrieves the WidgetGtk in the userdata section of the widget. + static WindowGtk* GetWindowForNative(GtkWidget* widget); + static void SetWindowForNative(GtkWidget* widget, WindowGtk* window); + private: virtual RootView* CreateRootView(); @@ -99,8 +122,18 @@ class WidgetGtk : public Widget { static gboolean CallVisibilityNotify(GtkWidget* widget, GdkEventVisibility* event); - // Our native view. + static Window* GetWindowImpl(GtkWidget* widget); + + // Creates the GtkWidget. + void CreateGtkWidget(); + + const Type type_; + + // Our native views. If we're a window/popup, then widget_ is the window and + // child_widget_parent_ is a GtkFixed. If we're not a window/popup, then + // widget_ and child_widget_parent_ are a GtkFixed. GtkWidget* widget_; + GtkWidget* child_widget_parent_; // The root of the View hierarchy attached to this window. scoped_ptr<RootView> root_view_; @@ -118,6 +151,8 @@ class WidgetGtk : public Widget { // Coordinates of the last mouse move event, in screen coordinates. int last_mouse_move_x_; int last_mouse_move_y_; + + DISALLOW_COPY_AND_ASSIGN(WidgetGtk); }; } // namespace views |