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 | |
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')
-rw-r--r-- | chrome/chrome.gyp | 12 | ||||
-rw-r--r-- | chrome/common/temp_scaffolding_stubs.cc | 6 | ||||
-rw-r--r-- | chrome/common/temp_scaffolding_stubs.h | 5 | ||||
-rw-r--r-- | chrome/views/controls/button/native_button.cc | 18 | ||||
-rw-r--r-- | chrome/views/controls/button/native_button_wrapper.h | 1 | ||||
-rw-r--r-- | chrome/views/event.h | 10 | ||||
-rw-r--r-- | chrome/views/event_gtk.cc | 2 | ||||
-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 | ||||
-rw-r--r-- | chrome/views/window/client_view.cc | 3 | ||||
-rw-r--r-- | chrome/views/window/custom_frame_view.cc | 10 | ||||
-rw-r--r-- | chrome/views/window/hit_test.h | 41 | ||||
-rw-r--r-- | chrome/views/window/non_client_view.cc | 9 | ||||
-rw-r--r-- | chrome/views/window/window_delegate.h | 1 | ||||
-rw-r--r-- | chrome/views/window/window_gtk.cc | 199 | ||||
-rw-r--r-- | chrome/views/window/window_gtk.h | 92 |
18 files changed, 611 insertions, 95 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index e635d89..334162e 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2984,6 +2984,7 @@ 'views/window/dialog_client_view.h', 'views/window/dialog_delegate.cc', 'views/window/dialog_delegate.h', + 'views/window/hit_test.h', 'views/window/native_frame_view.cc', 'views/window/native_frame_view.h', 'views/window/non_client_view.cc', @@ -2991,6 +2992,8 @@ 'views/window/window.h', 'views/window/window_delegate.cc', 'views/window/window_delegate.h', + 'views/window/window_gtk.cc', + 'views/window/window_gtk.h', 'views/window/window_resources.h', 'views/window/window_win.cc', 'views/window/window_win.h', @@ -3035,13 +3038,10 @@ 'views/widget/aero_tooltip_manager.cc', 'views/widget/root_view_drop_target.cc', 'views/widget/tooltip_manager.cc', - 'views/window/client_view.cc', - 'views/window/custom_frame_view.cc', 'views/window/dialog_delegate.cc', 'views/window/dialog_client_view.cc', + 'views/window/hit_test.cc', 'views/window/native_frame_view.cc', - 'views/window/non_client_view.cc', - 'views/window/window_delegate.cc', ], }], ['OS=="win"', { @@ -3089,13 +3089,9 @@ 'views/widget/root_view_drop_target.cc', 'views/widget/tooltip_manager.cc', 'views/widget/widget_win.cc', - 'views/window/client_view.cc', - 'views/window/custom_frame_view.cc', 'views/window/dialog_delegate.cc', 'views/window/dialog_client_view.cc', 'views/window/native_frame_view.cc', - 'views/window/non_client_view.cc', - 'views/window/window_delegate.cc', 'views/window/window_win.cc', ], }], diff --git a/chrome/common/temp_scaffolding_stubs.cc b/chrome/common/temp_scaffolding_stubs.cc index 9706e26..a9b6e52 100644 --- a/chrome/common/temp_scaffolding_stubs.cc +++ b/chrome/common/temp_scaffolding_stubs.cc @@ -269,12 +269,6 @@ DownloadRequestDialogDelegate* DownloadRequestDialogDelegate::Create( return NULL; } -views::Window* CreateInputWindow(gfx::NativeWindow parent_hwnd, - InputWindowDelegate* delegate) { - NOTIMPLEMENTED(); - return new views::Window(); -} - namespace download_util { void DragDownload(const DownloadItem* download, SkBitmap* icon) { diff --git a/chrome/common/temp_scaffolding_stubs.h b/chrome/common/temp_scaffolding_stubs.h index 0dcf436..b2c3055 100644 --- a/chrome/common/temp_scaffolding_stubs.h +++ b/chrome/common/temp_scaffolding_stubs.h @@ -234,11 +234,13 @@ class MenuItemView { class MenuDelegate { }; +#if !defined(OS_LINUX) class Window { public: void Show() { NOTIMPLEMENTED(); } virtual void Close() { NOTIMPLEMENTED(); } }; +#endif } // namespace views @@ -277,9 +279,6 @@ class Menu { void AppendDelegateMenuItem(int item_id) { NOTIMPLEMENTED(); } }; -views::Window* CreateInputWindow(gfx::NativeWindow parent_hwnd, - InputWindowDelegate* delegate); - class BookmarkManagerView { public: static BookmarkManagerView* current() { diff --git a/chrome/views/controls/button/native_button.cc b/chrome/views/controls/button/native_button.cc index 0e6646f..07de95c 100644 --- a/chrome/views/controls/button/native_button.cc +++ b/chrome/views/controls/button/native_button.cc @@ -4,6 +4,10 @@ #include "chrome/views/controls/button/native_button.h" +#if defined(OS_LINUX) +#include <gdk/gdkkeysyms.h> +#endif + #include "app/l10n_util.h" #include "base/logging.h" @@ -69,10 +73,15 @@ void NativeButton::SetLabel(const std::wstring& label) { void NativeButton::SetIsDefault(bool is_default) { if (is_default == is_default_) return; +#if defined(OS_WIN) + int return_code = VK_RETURN; +#else + int return_code = GDK_Return; +#endif 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); } @@ -106,6 +115,7 @@ gfx::Size NativeButton::GetPreferredSize() { // Clamp the size returned to at least the minimum size. if (!ignore_minimum_size_) { +#if defined(OS_WIN) if (minimum_size_.width()) { int min_width = font_.horizontal_dlus_to_pixels(minimum_size_.width()); sz.set_width(std::max(static_cast<int>(sz.width()), min_width)); @@ -114,6 +124,10 @@ gfx::Size NativeButton::GetPreferredSize() { int min_height = font_.vertical_dlus_to_pixels(minimum_size_.height()); 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/chrome/views/controls/button/native_button_wrapper.h b/chrome/views/controls/button/native_button_wrapper.h index 475166e..2d7fc25 100644 --- a/chrome/views/controls/button/native_button_wrapper.h +++ b/chrome/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/chrome/views/event.h b/chrome/views/event.h index d3dbb61..40aca37 100644 --- a/chrome/views/event.h +++ b/chrome/views/event.h @@ -6,13 +6,11 @@ #define CHROME_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 +216,7 @@ class MouseEvent : public LocatedEvent { } private: - DISALLOW_EVIL_CONSTRUCTORS(MouseEvent); + DISALLOW_COPY_AND_ASSIGN(MouseEvent); }; //////////////////////////////////////////////////////////////////////////////// @@ -235,7 +233,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 { diff --git a/chrome/views/event_gtk.cc b/chrome/views/event_gtk.cc index dfe89d2..6a6482a 100644 --- a/chrome/views/event_gtk.cc +++ b/chrome/views/event_gtk.cc @@ -4,6 +4,8 @@ #include "chrome/views/event.h" +#include <gdk/gdk.h> + namespace views { KeyEvent::KeyEvent(GdkEventKey* event) 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 diff --git a/chrome/views/window/client_view.cc b/chrome/views/window/client_view.cc index 37ae937..9b1e578 100644 --- a/chrome/views/window/client_view.cc +++ b/chrome/views/window/client_view.cc @@ -4,6 +4,9 @@ #include "base/logging.h" #include "chrome/views/window/client_view.h" +#if defined(OS_LINUX) +#include "chrome/views/window/hit_test.h" +#endif #include "chrome/views/window/window.h" #include "chrome/views/window/window_delegate.h" diff --git a/chrome/views/window/custom_frame_view.cc b/chrome/views/window/custom_frame_view.cc index 4c824af..c8a33fd 100644 --- a/chrome/views/window/custom_frame_view.cc +++ b/chrome/views/window/custom_frame_view.cc @@ -8,9 +8,14 @@ #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 "chrome/views/window/client_view.h" +#if defined(OS_LINUX) +#include "chrome/views/window/hit_test.h" +#endif #include "chrome/views/window/window_delegate.h" #include "grit/theme_resources.h" @@ -686,7 +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/chrome/views/window/hit_test.h b/chrome/views/window/hit_test.h new file mode 100644 index 0000000..8b8caba --- /dev/null +++ b/chrome/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 CHROME_VIEWS_WINDOW_HIT_TEST_H_ +#define CHROME_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 // CHROME_VIEWS_WINDOW_HIT_TEST_H_ diff --git a/chrome/views/window/non_client_view.cc b/chrome/views/window/non_client_view.cc index 95b97e9..8a8fb71 100644 --- a/chrome/views/window/non_client_view.cc +++ b/chrome/views/window/non_client_view.cc @@ -4,9 +4,14 @@ #include "chrome/views/window/non_client_view.h" +#if defined(OS_WIN) #include "chrome/common/win_util.h" +#endif #include "chrome/views/widget/root_view.h" #include "chrome/views/widget/widget.h" +#if defined(OS_LINUX) +#include "chrome/views/window/hit_test.h" +#endif #include "chrome/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/chrome/views/window/window_delegate.h b/chrome/views/window/window_delegate.h index 52dd86a8..8e9a556 100644 --- a/chrome/views/window/window_delegate.h +++ b/chrome/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/chrome/views/window/window_gtk.cc b/chrome/views/window/window_gtk.cc new file mode 100644 index 0000000..612a416 --- /dev/null +++ b/chrome/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 "chrome/views/window/window_gtk.h" + +#include "app/l10n_util.h" +#include "base/gfx/rect.h" +#include "chrome/views/window/custom_frame_view.h" +#include "chrome/views/window/non_client_view.h" +#include "chrome/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/chrome/views/window/window_gtk.h b/chrome/views/window/window_gtk.h new file mode 100644 index 0000000..3a4ef26 --- /dev/null +++ b/chrome/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 CHROME_VIEWS_WINDOW_WINDOW_GTK_H_ +#define CHROME_VIEWS_WINDOW_WINDOW_GTK_H_ + +#include "base/basictypes.h" +#include "chrome/views/widget/widget_gtk.h" +#include "chrome/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 // CHROME_VIEWS_WINDOW_WINDOW_GTK_H_ |