diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 21:04:17 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 21:04:17 +0000 |
commit | efc6544b43973ee7dfed1f7e56986982e42ebee0 (patch) | |
tree | bfc655f45240b2d7da4148983123e073dff04ebe | |
parent | c3bb07a6e81588caaf2d5efced692b2166a30161 (diff) | |
download | chromium_src-efc6544b43973ee7dfed1f7e56986982e42ebee0.zip chromium_src-efc6544b43973ee7dfed1f7e56986982e42ebee0.tar.gz chromium_src-efc6544b43973ee7dfed1f7e56986982e42ebee0.tar.bz2 |
Resurrect Scott's WindowGtk changes.
http://crbug.com/11387
Review URL: http://codereview.chromium.org/115143
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15678 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome.gyp | 13 | ||||
-rw-r--r-- | views/DEPS | 74 | ||||
-rw-r--r-- | views/controls/button/native_button.cc | 18 | ||||
-rw-r--r-- | views/controls/button/native_button_wrapper.h | 1 | ||||
-rw-r--r-- | views/event.h | 15 | ||||
-rw-r--r-- | views/event_gtk.cc | 2 | ||||
-rw-r--r-- | views/widget/root_view.h | 13 | ||||
-rw-r--r-- | views/widget/root_view_gtk.cc | 2 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 220 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 58 | ||||
-rw-r--r-- | views/window/client_view.cc | 3 | ||||
-rw-r--r-- | views/window/custom_frame_view.cc | 11 | ||||
-rw-r--r-- | views/window/hit_test.h | 41 | ||||
-rw-r--r-- | views/window/non_client_view.cc | 9 | ||||
-rw-r--r-- | views/window/window_delegate.h | 1 | ||||
-rw-r--r-- | views/window/window_gtk.cc | 199 | ||||
-rw-r--r-- | views/window/window_gtk.h | 92 |
17 files changed, 645 insertions, 127 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index c0cbfa22..06ade17 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -3116,6 +3116,8 @@ '../views/window/window.h', '../views/window/window_delegate.h', '../views/window/window_resources.h', + '../views/window/window_gtk.cc', + '../views/window/window_gtk.h', '../views/window/window_win.cc', '../views/window/window_win.h', ], @@ -3167,11 +3169,6 @@ '../views/window/custom_frame_view.h', '../views/window/hit_test.cc', '../views/window/native_frame_view.cc', - '../views/window/non_client_view.cc', - '../views/window/non_client_view.h', - '../views/window/client_view.cc', - '../views/window/client_view.h', - '../views/window/window_delegate.cc', ], }], ['OS=="win"', { @@ -3224,12 +3221,6 @@ '../views/window/dialog_delegate.cc', '../views/window/dialog_client_view.cc', '../views/window/native_frame_view.cc', - '../views/window/client_view.cc', - '../views/window/client_view.h', - '../views/window/non_client_view.cc', - '../views/window/non_client_view.h', - '../views/window/window_win.cc', - '../views/window/window_delegate.cc', ], }], ], @@ -1,37 +1,37 @@ -include_rules = [ - "+app", - "+skia/ext", - "+skia/include", - - # TODO(beng): sever these dependencies into chrome by either refactoring or - # moving code into app/ - - # view.h - "+chrome/common/accessibility_types.h", - - # view_unittest.cc - "+chrome/browser/browser_process.h", - - # label.cc - "+chrome/common/gfx/text_elider.h", - - # message_box_view.cc - "+chrome/browser/views/standard_layout.h", - - # text_field.cc - "+chrome/common/win_util.h", - - # widget_win.cc - "+chrome/app/chrome_dll_resource.h", - - # window_delegate.cc - "+chrome/common/pref_service.h", - - # chrome_menu.cc - "+chrome/browser/drag_utils.h", - "+chrome/common/gfx/color_utils.h", - - # TODO(beng): swap these with app/views specific generated resources. - "+grit/generated_resources.h", - "+grit/theme_resources.h", -] +include_rules = [
+ "+app",
+ "+skia/ext",
+ "+skia/include",
+
+ # TODO(beng): sever these dependencies into chrome by either refactoring or
+ # moving code into app/
+
+ # view.h
+ "+chrome/common/accessibility_types.h",
+
+ # view_unittest.cc
+ "+chrome/browser/browser_process.h",
+
+ # label.cc
+ "+chrome/common/gfx/text_elider.h",
+
+ # message_box_view.cc
+ "+chrome/browser/views/standard_layout.h",
+
+ # text_field.cc
+ "+chrome/common/win_util.h",
+
+ # widget_win.cc
+ "+chrome/app/chrome_dll_resource.h",
+
+ # window_delegate.cc
+ "+chrome/common/pref_service.h",
+
+ # chrome_menu.cc
+ "+chrome/browser/drag_utils.h",
+ "+chrome/common/gfx/color_utils.h",
+
+ # TODO(beng): swap these with app/views specific generated resources.
+ "+grit/generated_resources.h",
+ "+grit/theme_resources.h",
+]
diff --git a/views/controls/button/native_button.cc b/views/controls/button/native_button.cc index 0af6f88..ccb600a 100644 --- a/views/controls/button/native_button.cc +++ b/views/controls/button/native_button.cc @@ -4,6 +4,10 @@ #include "views/controls/button/native_button.h" +#if defined(OS_LINUX) +#include <gdk/gdkkeysyms.h> +#endif + #include "app/l10n_util.h" #include "base/logging.h" @@ -67,12 +71,17 @@ void NativeButton::SetLabel(const std::wstring& label) { } void NativeButton::SetIsDefault(bool is_default) { +#if defined(OS_WIN) + int return_code = VK_RETURN; +#else + int return_code = GDK_Return; +#endif if (is_default == is_default_) return; if (is_default) - AddAccelerator(Accelerator(VK_RETURN, false, false, false)); + AddAccelerator(Accelerator(return_code, false, false, false)); else - RemoveAccelerator(Accelerator(VK_RETURN, false, false, false)); + RemoveAccelerator(Accelerator(return_code, false, false, false)); SetAppearsAsDefault(is_default); } @@ -105,6 +114,7 @@ gfx::Size NativeButton::GetPreferredSize() { sz.set_height(sz.height() + border.top() + border.bottom()); // Clamp the size returned to at least the minimum size. +#if defined(OS_WIN) if (!ignore_minimum_size_) { if (minimum_size_.width()) { int min_width = font_.horizontal_dlus_to_pixels(minimum_size_.width()); @@ -115,6 +125,10 @@ gfx::Size NativeButton::GetPreferredSize() { sz.set_height(std::max(static_cast<int>(sz.height()), min_height)); } } +#else + if (minimum_size_.width() || minimum_size_.height()) + NOTIMPLEMENTED(); +#endif return sz; } diff --git a/views/controls/button/native_button_wrapper.h b/views/controls/button/native_button_wrapper.h index 5535ed4..a4cbbc8 100644 --- a/views/controls/button/native_button_wrapper.h +++ b/views/controls/button/native_button_wrapper.h @@ -12,6 +12,7 @@ namespace views { class Checkbox; class NativeButton; class RadioButton; +class View; // A specialization of NativeControlWrapper that hosts a platform-native button. class NativeButtonWrapper { diff --git a/views/event.h b/views/event.h index f0ab24a..70d0abc 100644 --- a/views/event.h +++ b/views/event.h @@ -6,13 +6,12 @@ #define VIEWS_EVENT_H_ #include "base/basictypes.h" +#include "base/gfx/point.h" #if defined(OS_LINUX) -#include <gdk/gdk.h> +typedef struct _GdkEventKey GdkEventKey; #endif -#include "base/gfx/point.h" - class OSExchangeData; namespace views { @@ -218,7 +217,7 @@ class MouseEvent : public LocatedEvent { } private: - DISALLOW_EVIL_CONSTRUCTORS(MouseEvent); + DISALLOW_COPY_AND_ASSIGN(MouseEvent); }; //////////////////////////////////////////////////////////////////////////////// @@ -235,7 +234,7 @@ class KeyEvent : public Event { // Create a new key event KeyEvent(EventType type, int ch, int repeat_count, int message_flags); #elif defined(OS_LINUX) - KeyEvent(GdkEventKey* event); + explicit KeyEvent(GdkEventKey* event); #endif int GetCharacter() const { @@ -259,7 +258,7 @@ class KeyEvent : public Event { int repeat_count_; int message_flags_; - DISALLOW_EVIL_CONSTRUCTORS(KeyEvent); + DISALLOW_COPY_AND_ASSIGN(KeyEvent); }; //////////////////////////////////////////////////////////////////////////////// @@ -284,7 +283,7 @@ class MouseWheelEvent : public LocatedEvent { private: int offset_; - DISALLOW_EVIL_CONSTRUCTORS(MouseWheelEvent); + DISALLOW_COPY_AND_ASSIGN(MouseWheelEvent); }; //////////////////////////////////////////////////////////////////////////////// @@ -316,7 +315,7 @@ class DropTargetEvent : public LocatedEvent { const OSExchangeData& data_; int source_operations_; - DISALLOW_EVIL_CONSTRUCTORS(DropTargetEvent); + DISALLOW_COPY_AND_ASSIGN(DropTargetEvent); }; } // namespace views diff --git a/views/event_gtk.cc b/views/event_gtk.cc index ac5a2ce..ed55628 100644 --- a/views/event_gtk.cc +++ b/views/event_gtk.cc @@ -4,6 +4,8 @@ #include "views/event.h" +#include <gdk/gdk.h> + namespace views { KeyEvent::KeyEvent(GdkEventKey* event) diff --git a/views/widget/root_view.h b/views/widget/root_view.h index d775ac1..1ebb3e1 100644 --- a/views/widget/root_view.h +++ b/views/widget/root_view.h @@ -5,19 +5,16 @@ #ifndef VIEWS_WIDGET_ROOT_VIEW_H_ #define VIEWS_WIDGET_ROOT_VIEW_H_ -#include "build/build_config.h" +#include <string> -#if defined(OS_LINUX) -#include <gtk/gtk.h> -#endif - -#if defined(OS_WIN) #include "base/ref_counted.h" -#endif - #include "views/focus/focus_manager.h" #include "views/view.h" +#if defined(OS_LINUX) +typedef struct _GdkEventExpose GdkEventExpose; +#endif + namespace views { class PaintTask; diff --git a/views/widget/root_view_gtk.cc b/views/widget/root_view_gtk.cc index 428c695..231beca 100644 --- a/views/widget/root_view_gtk.cc +++ b/views/widget/root_view_gtk.cc @@ -4,6 +4,8 @@ #include "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/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index 25869f6..5f1ff31 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -6,24 +6,47 @@ #include "views/fill_layout.h" #include "views/widget/root_view.h" +#include "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(); @@ -33,8 +56,12 @@ void WidgetGtk::Init(const gfx::Rect& bounds, gtk_widget_show(widget_); // 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 +74,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 +117,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 +141,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 +176,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 +193,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 +208,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 +264,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 +273,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 +299,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 +400,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 +494,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; } + +} // namespace views diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h index 4bbc0dd..3abc18b 100644 --- a/views/widget/widget_gtk.h +++ b/views/widget/widget_gtk.h @@ -17,22 +17,38 @@ 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; - } - - 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 + }; + + 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 +60,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 +87,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 +121,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 +150,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 diff --git a/views/window/client_view.cc b/views/window/client_view.cc index 5b5afb1..e5bfe32 100644 --- a/views/window/client_view.cc +++ b/views/window/client_view.cc @@ -4,6 +4,9 @@ #include "base/logging.h" #include "views/window/client_view.h" +#if defined(OS_LINUX) +#include "chrome/views/window/hit_test.h" +#endif #include "views/window/window.h" #include "views/window/window_delegate.h" diff --git a/views/window/custom_frame_view.cc b/views/window/custom_frame_view.cc index cf8173f..8639340 100644 --- a/views/window/custom_frame_view.cc +++ b/views/window/custom_frame_view.cc @@ -8,10 +8,15 @@ #include "app/gfx/chrome_font.h" #include "app/gfx/path.h" #include "app/resource_bundle.h" +#if defined(OS_WIN) #include "base/win_util.h" #include "chrome/common/win_util.h" +#endif #include "grit/theme_resources.h" #include "views/window/client_view.h" +#if defined(OS_LINUX) +#include "views/window/hit_test.h" +#endif #include "views/window/window_delegate.h" namespace views { @@ -686,8 +691,12 @@ void CustomFrameView::InitClass() { active_resources_ = new ActiveWindowResources; inactive_resources_ = new InactiveWindowResources; +#if defined(OS_WIN) title_font_ = new ChromeFont(win_util::GetWindowTitleFont()); - +#elif defined(OS_LINUX) + // TODO: need to resolve what font this is. + title_font_ = new ChromeFont(); +#endif initialized = true; } } diff --git a/views/window/hit_test.h b/views/window/hit_test.h new file mode 100644 index 0000000..35e88ae --- /dev/null +++ b/views/window/hit_test.h @@ -0,0 +1,41 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VIEWS_WINDOW_HIT_TEST_H_ +#define VIEWS_WINDOW_HIT_TEST_H_ + +// Defines the same symbolic names used by the WM_NCHITTEST Notification under +// win32 (the integer values are not guaranteed to be equivalent). We do this +// because we have a whole bunch of code that deals with window resizing and +// such that requires these values. +enum HitTestCompat { + HTBORDER = 1, + HTBOTTOM, + HTBOTTOMLEFT, + HTBOTTOMRIGHT, + HTCAPTION, + HTCLIENT, + HTCLOSE, + HTERROR, + HTGROWBOX, + HTHELP, + HTHSCROLL, + HTLEFT, + HTMENU, + HTMAXBUTTON, + HTMINBUTTON, + HTNOWHERE, + HTREDUCE, + HTRIGHT, + HTSIZE, + HTSYSMENU, + HTTOP, + HTTOPLEFT, + HTTOPRIGHT, + HTTRANSPARENT, + HTVSCROLL, + HTZOOM +}; + +#endif // VIEWS_WINDOW_HIT_TEST_H_ diff --git a/views/window/non_client_view.cc b/views/window/non_client_view.cc index 9a06cfc..6135a7b 100644 --- a/views/window/non_client_view.cc +++ b/views/window/non_client_view.cc @@ -4,9 +4,14 @@ #include "views/window/non_client_view.h" +#if defined(OS_WIN) #include "chrome/common/win_util.h" +#endif #include "views/widget/root_view.h" #include "views/widget/widget.h" +#if defined(OS_LINUX) +#include "views/window/hit_test.h" +#endif #include "views/window/window.h" namespace views { @@ -27,7 +32,11 @@ static const int kClientViewIndex = 1; NonClientView::NonClientView(Window* frame) : frame_(frame), client_view_(NULL), +#if defined(OS_WIN) use_native_frame_(win_util::ShouldUseVistaFrame()) { +#else + use_native_frame_(false) { +#endif } NonClientView::~NonClientView() { diff --git a/views/window/window_delegate.h b/views/window/window_delegate.h index af8285c..992e94a 100644 --- a/views/window/window_delegate.h +++ b/views/window/window_delegate.h @@ -148,6 +148,7 @@ class WindowDelegate { void ReleaseWindow(); private: + friend class WindowGtk; friend class WindowWin; // This is a little unusual. We use a scoped_ptr here because it's // initialized to NULL automatically. We do this because we want to allow diff --git a/views/window/window_gtk.cc b/views/window/window_gtk.cc new file mode 100644 index 0000000..a8c710c --- /dev/null +++ b/views/window/window_gtk.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "views/window/window_gtk.h" + +#include "app/l10n_util.h" +#include "base/gfx/rect.h" +#include "views/window/custom_frame_view.h" +#include "views/window/non_client_view.h" +#include "views/window/window_delegate.h" + +namespace views { + +WindowGtk::~WindowGtk() { +} + +// static +Window* Window::CreateChromeWindow(gfx::NativeWindow parent, + const gfx::Rect& bounds, + WindowDelegate* window_delegate) { + WindowGtk* window = new WindowGtk(window_delegate); + window->GetNonClientView()->SetFrameView(window->CreateFrameViewForWindow()); + window->Init(bounds); + return window; +} + +gfx::Rect WindowGtk::GetBounds() const { + gfx::Rect bounds; + WidgetGtk::GetBounds(&bounds, true); + return bounds; +} + +gfx::Rect WindowGtk::GetNormalBounds() const { + NOTIMPLEMENTED(); + return GetBounds(); +} + +void WindowGtk::SetBounds(const gfx::Rect& bounds) { + // TODO: this may need to set an initial size if not showing. + // TODO: need to constrain based on screen size. + gtk_window_resize(GTK_WINDOW(GetNativeView()), bounds.width(), + bounds.height()); + + gtk_window_move(GTK_WINDOW(GetNativeView()), bounds.x(), bounds.y()); +} + +void WindowGtk::SetBounds(const gfx::Rect& bounds, + gfx::NativeWindow other_window) { + // TODO: need to deal with other_window. + SetBounds(bounds); +} + +void WindowGtk::Show() { + gtk_widget_show_all(GetNativeView()); +} + +void WindowGtk::Activate() { + NOTIMPLEMENTED(); +} + +void WindowGtk::Close() { + NOTIMPLEMENTED(); +} + +void WindowGtk::Maximize() { + gtk_window_maximize(GetNativeWindow()); +} + +void WindowGtk::Minimize() { + gtk_window_iconify(GetNativeWindow()); +} + +void WindowGtk::Restore() { + NOTIMPLEMENTED(); +} + +bool WindowGtk::IsActive() const { + return gtk_window_is_active(GetNativeWindow()); +} + +bool WindowGtk::IsVisible() const { + return GTK_WIDGET_VISIBLE(GetNativeView()); +} + +bool WindowGtk::IsMaximized() const { + NOTIMPLEMENTED(); + return false; +} + +bool WindowGtk::IsMinimized() const { + NOTIMPLEMENTED(); + return false; +} + +void WindowGtk::SetFullscreen(bool fullscreen) { + NOTIMPLEMENTED(); +} + +bool WindowGtk::IsFullscreen() const { + NOTIMPLEMENTED(); + return false; +} + +void WindowGtk::EnableClose(bool enable) { + gtk_window_set_deletable(GetNativeWindow(), enable); +} + +void WindowGtk::DisableInactiveRendering() { + NOTIMPLEMENTED(); +} + +void WindowGtk::UpdateWindowTitle() { + // If the non-client view is rendering its own title, it'll need to relayout + // now. + non_client_view_->Layout(); + + // Update the native frame's text. We do this regardless of whether or not + // the native frame is being used, since this also updates the taskbar, etc. + std::wstring window_title = window_delegate_->GetWindowTitle(); + std::wstring localized_text; + if (l10n_util::AdjustStringForLocaleDirection(window_title, &localized_text)) + window_title.assign(localized_text); + + gtk_window_set_title(GetNativeWindow(), WideToUTF8(window_title).c_str()); +} + +void WindowGtk::UpdateWindowIcon() { + NOTIMPLEMENTED(); +} + +NonClientFrameView* WindowGtk::CreateFrameViewForWindow() { + // TODO(erg): Always use a custom frame view? Are there cases where we let + // the window manager deal with the X11 equivalent of the "non-client" area? + return new CustomFrameView(this); +} + +void WindowGtk::UpdateFrameAfterFrameChange() { + NOTIMPLEMENTED(); +} + +WindowDelegate* WindowGtk::GetDelegate() const { + return window_delegate_; +} + +NonClientView* WindowGtk::GetNonClientView() const { + return non_client_view_; +} + +ClientView* WindowGtk::GetClientView() const { + return non_client_view_->client_view(); +} + +gfx::NativeWindow WindowGtk::GetNativeWindow() const { + return GTK_WINDOW(GetNativeView()); +} + +WindowGtk::WindowGtk(WindowDelegate* window_delegate) + : WidgetGtk(TYPE_WINDOW), + is_modal_(false), + is_always_on_top_(false), + window_delegate_(window_delegate), + non_client_view_(new NonClientView(this)) { + window_delegate_->window_.reset(this); +} + +void WindowGtk::Init(const gfx::Rect& bounds) { + // We call this after initializing our members since our implementations of + // assorted WidgetWin functions may be called during initialization. + is_modal_ = window_delegate_->IsModal(); + if (is_modal_) { + // TODO(erg): Fix once modality works. + // BecomeModal(); + } + is_always_on_top_ = window_delegate_->IsAlwaysOnTop(); + + WidgetGtk::Init(bounds, true); + + // Create the ClientView, add it to the NonClientView and add the + // NonClientView to the RootView. This will cause everything to be parented. + non_client_view_->set_client_view(window_delegate_->CreateClientView(this)); + WidgetGtk::SetContentsView(non_client_view_); + + UpdateWindowTitle(); + + // SetInitialBounds(bounds); + // InitAlwaysOnTopState(); + + // if (!IsAppWindow()) { + // notification_registrar_.Add( + // this, + // NotificationType::ALL_APPWINDOWS_CLOSED, + // NotificationService::AllSources()); + // } + + // ResetWindowRegion(false); +} + +} // namespace views diff --git a/views/window/window_gtk.h b/views/window/window_gtk.h new file mode 100644 index 0000000..224c85a5 --- /dev/null +++ b/views/window/window_gtk.h @@ -0,0 +1,92 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VIEWS_WINDOW_WINDOW_GTK_H_ +#define VIEWS_WINDOW_WINDOW_GTK_H_ + +#include "base/basictypes.h" +#include "views/widget/widget_gtk.h" +#include "views/window/window.h" + +namespace gfx { +class Point; +class Size; +}; + +namespace views { + +class Client; +class WindowDelegate; + +// Window implementation for GTK. +class WindowGtk : public WidgetGtk, public Window { + public: + virtual ~WindowGtk(); + + // Window overrides: + virtual gfx::Rect GetBounds() const; + virtual gfx::Rect GetNormalBounds() const; + virtual void SetBounds(const gfx::Rect& bounds); + virtual void SetBounds(const gfx::Rect& bounds, + gfx::NativeWindow other_window); + virtual void Show(); + virtual void Activate(); + virtual void Close(); + virtual void Maximize(); + virtual void Minimize(); + virtual void Restore(); + virtual bool IsActive() const; + virtual bool IsVisible() const; + virtual bool IsMaximized() const; + virtual bool IsMinimized() const; + virtual void SetFullscreen(bool fullscreen); + virtual bool IsFullscreen() const; + virtual void EnableClose(bool enable); + virtual void DisableInactiveRendering(); + virtual void UpdateWindowTitle(); + virtual void UpdateWindowIcon(); + virtual NonClientFrameView* CreateFrameViewForWindow(); + virtual void UpdateFrameAfterFrameChange(); + virtual WindowDelegate* GetDelegate() const; + virtual NonClientView* GetNonClientView() const; + virtual ClientView* GetClientView() const; + virtual gfx::NativeWindow GetNativeWindow() const; + + virtual Window* AsWindow() { return this; } + virtual const Window* AsWindow() const { return this; } + + protected: + // For the constructor. + friend class Window; + + // Constructs the WindowGtk. |window_delegate| cannot be NULL. + explicit WindowGtk(WindowDelegate* window_delegate); + + // Initializes the window to the passed in bounds. + void Init(const gfx::Rect& bounds); + + private: + // 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. + bool is_modal_; + + // Whether the window is currently always on top. + bool is_always_on_top_; + + // Our window delegate. + WindowDelegate* window_delegate_; + + // The View that provides the non-client area of the window (title bar, + // window controls, sizing borders etc). To use an implementation other than + // the default, this class must be subclassed and this value set to the + // desired implementation before calling |Init|. + NonClientView* non_client_view_; + + DISALLOW_COPY_AND_ASSIGN(WindowGtk); +}; + +} // namespace views + +#endif // VIEWS_WINDOW_WINDOW_GTK_H_ |