| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "views/window/native_window_gtk.h" | 5 #include "views/window/native_window_gtk.h" |
| 6 | 6 |
| 7 #include "base/i18n/rtl.h" | 7 #include "base/i18n/rtl.h" |
| 8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
| 9 #include "ui/gfx/gtk_util.h" | 9 #include "ui/gfx/gtk_util.h" |
| 10 #include "ui/gfx/path.h" | 10 #include "ui/gfx/path.h" |
| 11 #include "ui/gfx/rect.h" | 11 #include "ui/gfx/rect.h" |
| 12 #include "views/events/event.h" | 12 #include "views/events/event.h" |
| 13 #include "views/window/hit_test.h" | 13 #include "views/window/hit_test.h" |
| 14 #include "views/window/native_window_delegate.h" | 14 #include "views/window/native_window_delegate.h" |
| 15 #include "views/window/non_client_view.h" | 15 #include "views/window/non_client_view.h" |
| 16 #include "views/window/window_delegate.h" | 16 #include "views/window/window_delegate.h" |
| 17 | 17 |
| 18 namespace { | |
| 19 | |
| 20 // Converts a Windows-style hit test result code into a GDK window edge. | |
| 21 GdkWindowEdge HitTestCodeToGDKWindowEdge(int hittest_code) { | |
| 22 switch (hittest_code) { | |
| 23 case HTBOTTOM: | |
| 24 return GDK_WINDOW_EDGE_SOUTH; | |
| 25 case HTBOTTOMLEFT: | |
| 26 return GDK_WINDOW_EDGE_SOUTH_WEST; | |
| 27 case HTBOTTOMRIGHT: | |
| 28 case HTGROWBOX: | |
| 29 return GDK_WINDOW_EDGE_SOUTH_EAST; | |
| 30 case HTLEFT: | |
| 31 return GDK_WINDOW_EDGE_WEST; | |
| 32 case HTRIGHT: | |
| 33 return GDK_WINDOW_EDGE_EAST; | |
| 34 case HTTOP: | |
| 35 return GDK_WINDOW_EDGE_NORTH; | |
| 36 case HTTOPLEFT: | |
| 37 return GDK_WINDOW_EDGE_NORTH_WEST; | |
| 38 case HTTOPRIGHT: | |
| 39 return GDK_WINDOW_EDGE_NORTH_EAST; | |
| 40 default: | |
| 41 NOTREACHED(); | |
| 42 break; | |
| 43 } | |
| 44 // Default to something defaultish. | |
| 45 return HitTestCodeToGDKWindowEdge(HTGROWBOX); | |
| 46 } | |
| 47 | |
| 48 // Converts a Windows-style hit test result code into a GDK cursor type. | |
| 49 GdkCursorType HitTestCodeToGdkCursorType(int hittest_code) { | |
| 50 switch (hittest_code) { | |
| 51 case HTBOTTOM: | |
| 52 return GDK_BOTTOM_SIDE; | |
| 53 case HTBOTTOMLEFT: | |
| 54 return GDK_BOTTOM_LEFT_CORNER; | |
| 55 case HTBOTTOMRIGHT: | |
| 56 case HTGROWBOX: | |
| 57 return GDK_BOTTOM_RIGHT_CORNER; | |
| 58 case HTLEFT: | |
| 59 return GDK_LEFT_SIDE; | |
| 60 case HTRIGHT: | |
| 61 return GDK_RIGHT_SIDE; | |
| 62 case HTTOP: | |
| 63 return GDK_TOP_SIDE; | |
| 64 case HTTOPLEFT: | |
| 65 return GDK_TOP_LEFT_CORNER; | |
| 66 case HTTOPRIGHT: | |
| 67 return GDK_TOP_RIGHT_CORNER; | |
| 68 default: | |
| 69 break; | |
| 70 } | |
| 71 // Default to something defaultish. | |
| 72 return GDK_LEFT_PTR; | |
| 73 } | |
| 74 | |
| 75 } // namespace | |
| 76 | |
| 77 namespace views { | 18 namespace views { |
| 78 | 19 |
| 79 NativeWindowGtk::NativeWindowGtk(internal::NativeWindowDelegate* delegate) | 20 NativeWindowGtk::NativeWindowGtk(internal::NativeWindowDelegate* delegate) |
| 80 : NativeWidgetGtk(delegate->AsNativeWidgetDelegate()), | 21 : NativeWidgetGtk(delegate->AsNativeWidgetDelegate()), |
| 81 delegate_(delegate), | 22 delegate_(delegate) { |
| 82 window_closed_(false) { | |
| 83 is_window_ = true; | 23 is_window_ = true; |
| 84 } | 24 } |
| 85 | 25 |
| 86 NativeWindowGtk::~NativeWindowGtk() { | 26 NativeWindowGtk::~NativeWindowGtk() { |
| 87 } | 27 } |
| 88 | 28 |
| 89 //////////////////////////////////////////////////////////////////////////////// | 29 //////////////////////////////////////////////////////////////////////////////// |
| 90 // NativeWindowGtk, NativeWidgetGtk overrides: | |
| 91 | |
| 92 gboolean NativeWindowGtk::OnButtonPress(GtkWidget* widget, | |
| 93 GdkEventButton* event) { | |
| 94 GdkEventButton transformed_event = *event; | |
| 95 MouseEvent mouse_event(TransformEvent(&transformed_event)); | |
| 96 | |
| 97 int hittest_code = | |
| 98 GetWindow()->non_client_view()->NonClientHitTest(mouse_event.location()); | |
| 99 switch (hittest_code) { | |
| 100 case HTCAPTION: { | |
| 101 // Start dragging if the mouse event is a single click and *not* a right | |
| 102 // click. If it is a right click, then pass it through to | |
| 103 // NativeWidgetGtk::OnButtonPress so that View class can show ContextMenu | |
| 104 // upon a mouse release event. We only start drag on single clicks as we | |
| 105 // get a crash in Gtk on double/triple clicks. | |
| 106 if (event->type == GDK_BUTTON_PRESS && | |
| 107 !mouse_event.IsOnlyRightMouseButton()) { | |
| 108 gfx::Point screen_point(event->x, event->y); | |
| 109 View::ConvertPointToScreen(GetWindow()->GetRootView(), &screen_point); | |
| 110 gtk_window_begin_move_drag(GetNativeWindow(), event->button, | |
| 111 screen_point.x(), screen_point.y(), | |
| 112 event->time); | |
| 113 return TRUE; | |
| 114 } | |
| 115 break; | |
| 116 } | |
| 117 case HTBOTTOM: | |
| 118 case HTBOTTOMLEFT: | |
| 119 case HTBOTTOMRIGHT: | |
| 120 case HTGROWBOX: | |
| 121 case HTLEFT: | |
| 122 case HTRIGHT: | |
| 123 case HTTOP: | |
| 124 case HTTOPLEFT: | |
| 125 case HTTOPRIGHT: { | |
| 126 gfx::Point screen_point(event->x, event->y); | |
| 127 View::ConvertPointToScreen(GetWindow()->GetRootView(), &screen_point); | |
| 128 // TODO(beng): figure out how to get a good minimum size. | |
| 129 gtk_widget_set_size_request(GetNativeView(), 100, 100); | |
| 130 gtk_window_begin_resize_drag(GetNativeWindow(), | |
| 131 HitTestCodeToGDKWindowEdge(hittest_code), | |
| 132 event->button, screen_point.x(), | |
| 133 screen_point.y(), event->time); | |
| 134 return TRUE; | |
| 135 } | |
| 136 default: | |
| 137 // Everything else falls into standard client event handling... | |
| 138 break; | |
| 139 } | |
| 140 return NativeWidgetGtk::OnButtonPress(widget, event); | |
| 141 } | |
| 142 | |
| 143 gboolean NativeWindowGtk::OnConfigureEvent(GtkWidget* widget, | |
| 144 GdkEventConfigure* event) { | |
| 145 SaveWindowPosition(); | |
| 146 return FALSE; | |
| 147 } | |
| 148 | |
| 149 gboolean NativeWindowGtk::OnMotionNotify(GtkWidget* widget, | |
| 150 GdkEventMotion* event) { | |
| 151 GdkEventMotion transformed_event = *event; | |
| 152 TransformEvent(&transformed_event); | |
| 153 gfx::Point translated_location(transformed_event.x, transformed_event.y); | |
| 154 | |
| 155 // Update the cursor for the screen edge. | |
| 156 int hittest_code = | |
| 157 GetWindow()->non_client_view()->NonClientHitTest(translated_location); | |
| 158 if (hittest_code != HTCLIENT) { | |
| 159 GdkCursorType cursor_type = HitTestCodeToGdkCursorType(hittest_code); | |
| 160 gdk_window_set_cursor(widget->window, gfx::GetCursor(cursor_type)); | |
| 161 } | |
| 162 | |
| 163 return NativeWidgetGtk::OnMotionNotify(widget, event); | |
| 164 } | |
| 165 | |
| 166 void NativeWindowGtk::OnSizeAllocate(GtkWidget* widget, | |
| 167 GtkAllocation* allocation) { | |
| 168 NativeWidgetGtk::OnSizeAllocate(widget, allocation); | |
| 169 | |
| 170 // The Window's NonClientView may provide a custom shape for the Window. | |
| 171 gfx::Path window_mask; | |
| 172 GetWindow()->non_client_view()->GetWindowMask(gfx::Size(allocation->width, | |
| 173 allocation->height), | |
| 174 &window_mask); | |
| 175 GdkRegion* mask_region = window_mask.CreateNativeRegion(); | |
| 176 gdk_window_shape_combine_region(GetNativeView()->window, mask_region, 0, 0); | |
| 177 if (mask_region) | |
| 178 gdk_region_destroy(mask_region); | |
| 179 | |
| 180 SaveWindowPosition(); | |
| 181 } | |
| 182 | |
| 183 gboolean NativeWindowGtk::OnLeaveNotify(GtkWidget* widget, | |
| 184 GdkEventCrossing* event) { | |
| 185 gdk_window_set_cursor(widget->window, gfx::GetCursor(GDK_LEFT_PTR)); | |
| 186 | |
| 187 return NativeWidgetGtk::OnLeaveNotify(widget, event); | |
| 188 } | |
| 189 | |
| 190 void NativeWindowGtk::InitNativeWidget(const Widget::InitParams& params) { | |
| 191 NativeWidgetGtk::InitNativeWidget(params); | |
| 192 | |
| 193 g_signal_connect(G_OBJECT(GetNativeWindow()), "configure-event", | |
| 194 G_CALLBACK(CallConfigureEvent), this); | |
| 195 } | |
| 196 | |
| 197 //////////////////////////////////////////////////////////////////////////////// | |
| 198 // NativeWindowGtk, NativeWindow implementation: | 30 // NativeWindowGtk, NativeWindow implementation: |
| 199 | 31 |
| 200 NativeWidget* NativeWindowGtk::AsNativeWidget() { | 32 NativeWidget* NativeWindowGtk::AsNativeWidget() { |
| 201 return this; | 33 return this; |
| 202 } | 34 } |
| 203 | 35 |
| 204 const NativeWidget* NativeWindowGtk::AsNativeWidget() const { | 36 const NativeWidget* NativeWindowGtk::AsNativeWidget() const { |
| 205 return this; | 37 return this; |
| 206 } | 38 } |
| 207 | 39 |
| 208 void NativeWindowGtk::BecomeModal() { | |
| 209 gtk_window_set_modal(GetNativeWindow(), true); | |
| 210 } | |
| 211 | |
| 212 Window* NativeWindowGtk::GetWindow() { | 40 Window* NativeWindowGtk::GetWindow() { |
| 213 return delegate_->AsWindow(); | 41 return delegate_->AsWindow(); |
| 214 } | 42 } |
| 215 | 43 |
| 216 const Window* NativeWindowGtk::GetWindow() const { | 44 const Window* NativeWindowGtk::GetWindow() const { |
| 217 return delegate_->AsWindow(); | 45 return delegate_->AsWindow(); |
| 218 } | 46 } |
| 219 | 47 |
| 220 //////////////////////////////////////////////////////////////////////////////// | 48 //////////////////////////////////////////////////////////////////////////////// |
| 221 // NativeWindowGtk, NativeWidgetGtk overrides: | |
| 222 | |
| 223 gboolean NativeWindowGtk::OnWindowStateEvent(GtkWidget* widget, | |
| 224 GdkEventWindowState* event) { | |
| 225 if (!(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) | |
| 226 SaveWindowPosition(); | |
| 227 return NativeWidgetGtk::OnWindowStateEvent(widget, event); | |
| 228 } | |
| 229 | |
| 230 //////////////////////////////////////////////////////////////////////////////// | |
| 231 // NativeWindowGtk, private: | 49 // NativeWindowGtk, private: |
| 232 | 50 |
| 233 // static | |
| 234 gboolean NativeWindowGtk::CallConfigureEvent(GtkWidget* widget, | |
| 235 GdkEventConfigure* event, | |
| 236 NativeWindowGtk* window_gtk) { | |
| 237 return window_gtk->OnConfigureEvent(widget, event); | |
| 238 } | |
| 239 | |
| 240 void NativeWindowGtk::SaveWindowPosition() { | |
| 241 // The delegate may have gone away on us. | |
| 242 if (!GetWindow()->window_delegate()) | |
| 243 return; | |
| 244 | |
| 245 bool maximized = window_state_ & GDK_WINDOW_STATE_MAXIMIZED; | |
| 246 GetWindow()->window_delegate()->SaveWindowPlacement( | |
| 247 GetWidget()->GetWindowScreenBounds(), | |
| 248 maximized); | |
| 249 } | |
| 250 | |
| 251 //////////////////////////////////////////////////////////////////////////////// | 51 //////////////////////////////////////////////////////////////////////////////// |
| 252 // NativeWindow, public: | 52 // NativeWindow, public: |
| 253 | 53 |
| 254 // static | 54 // static |
| 255 NativeWindow* NativeWindow::CreateNativeWindow( | 55 NativeWindow* NativeWindow::CreateNativeWindow( |
| 256 internal::NativeWindowDelegate* delegate) { | 56 internal::NativeWindowDelegate* delegate) { |
| 257 return new NativeWindowGtk(delegate); | 57 return new NativeWindowGtk(delegate); |
| 258 } | 58 } |
| 259 | 59 |
| 260 } // namespace views | 60 } // namespace views |
| OLD | NEW |