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" | |
10 #include "ui/gfx/path.h" | 9 #include "ui/gfx/path.h" |
11 #include "ui/gfx/rect.h" | 10 #include "ui/gfx/rect.h" |
12 #include "views/events/event.h" | 11 #include "views/events/event.h" |
13 #include "views/window/hit_test.h" | 12 #include "views/window/hit_test.h" |
14 #include "views/window/native_window_delegate.h" | 13 #include "views/window/native_window_delegate.h" |
15 #include "views/window/non_client_view.h" | 14 #include "views/window/non_client_view.h" |
16 #include "views/window/window_delegate.h" | 15 #include "views/window/window_delegate.h" |
17 | 16 |
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 { | 17 namespace views { |
78 | 18 |
79 NativeWindowGtk::NativeWindowGtk(internal::NativeWindowDelegate* delegate) | 19 NativeWindowGtk::NativeWindowGtk(internal::NativeWindowDelegate* delegate) |
80 : NativeWidgetGtk(delegate->AsNativeWidgetDelegate()), | 20 : NativeWidgetGtk(delegate->AsNativeWidgetDelegate()), |
81 delegate_(delegate), | 21 delegate_(delegate) { |
82 window_closed_(false) { | |
83 is_window_ = true; | 22 is_window_ = true; |
84 } | 23 } |
85 | 24 |
86 NativeWindowGtk::~NativeWindowGtk() { | 25 NativeWindowGtk::~NativeWindowGtk() { |
87 } | 26 } |
88 | 27 |
89 //////////////////////////////////////////////////////////////////////////////// | 28 //////////////////////////////////////////////////////////////////////////////// |
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: | 29 // NativeWindowGtk, NativeWindow implementation: |
199 | 30 |
200 NativeWidget* NativeWindowGtk::AsNativeWidget() { | 31 NativeWidget* NativeWindowGtk::AsNativeWidget() { |
201 return this; | 32 return this; |
202 } | 33 } |
203 | 34 |
204 const NativeWidget* NativeWindowGtk::AsNativeWidget() const { | 35 const NativeWidget* NativeWindowGtk::AsNativeWidget() const { |
205 return this; | 36 return this; |
206 } | 37 } |
207 | 38 |
208 void NativeWindowGtk::BecomeModal() { | |
209 gtk_window_set_modal(GetNativeWindow(), true); | |
210 } | |
211 | |
212 Window* NativeWindowGtk::GetWindow() { | 39 Window* NativeWindowGtk::GetWindow() { |
213 return delegate_->AsWindow(); | 40 return delegate_->AsWindow(); |
214 } | 41 } |
215 | 42 |
216 const Window* NativeWindowGtk::GetWindow() const { | 43 const Window* NativeWindowGtk::GetWindow() const { |
217 return delegate_->AsWindow(); | 44 return delegate_->AsWindow(); |
218 } | 45 } |
219 | 46 |
220 //////////////////////////////////////////////////////////////////////////////// | 47 //////////////////////////////////////////////////////////////////////////////// |
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: | 48 // NativeWindowGtk, private: |
232 | 49 |
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 //////////////////////////////////////////////////////////////////////////////// | 50 //////////////////////////////////////////////////////////////////////////////// |
252 // NativeWindow, public: | 51 // NativeWindow, public: |
253 | 52 |
254 // static | 53 // static |
255 NativeWindow* NativeWindow::CreateNativeWindow( | 54 NativeWindow* NativeWindow::CreateNativeWindow( |
256 internal::NativeWindowDelegate* delegate) { | 55 internal::NativeWindowDelegate* delegate) { |
257 return new NativeWindowGtk(delegate); | 56 return new NativeWindowGtk(delegate); |
258 } | 57 } |
259 | 58 |
260 } // namespace views | 59 } // namespace views |
OLD | NEW |