]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdevice-virtual.c
Fix up for newer draft of wm-spec
[~andy/gtk] / gdk / win32 / gdkdevice-virtual.c
1 /* GDK - The GIMP Drawing Kit\r
2  * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>\r
3  *\r
4  * This library is free software; you can redistribute it and/or\r
5  * modify it under the terms of the GNU Lesser General Public\r
6  * License as published by the Free Software Foundation; either\r
7  * version 2 of the License, or (at your option) any later version.\r
8  *\r
9  * This library is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
12  * Lesser General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU Lesser General Public\r
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.\r
16  */\r
17 \r
18 #include "config.h"\r
19 \r
20 #include <gdk/gdkwindow.h>\r
21 \r
22 #include <windowsx.h>\r
23 #include <objbase.h>\r
24 \r
25 #include "gdkdisplayprivate.h"\r
26 #include "gdkdevice-virtual.h"\r
27 #include "gdkwin32.h"\r
28 \r
29 static gboolean gdk_device_virtual_get_history (GdkDevice      *device,\r
30                                                 GdkWindow      *window,\r
31                                                 guint32         start,\r
32                                                 guint32         stop,\r
33                                                 GdkTimeCoord ***events,\r
34                                                 gint           *n_events);\r
35 static void gdk_device_virtual_get_state (GdkDevice       *device,\r
36                                           GdkWindow       *window,\r
37                                           gdouble         *axes,\r
38                                           GdkModifierType *mask);\r
39 static void gdk_device_virtual_set_window_cursor (GdkDevice *device,\r
40                                                   GdkWindow *window,\r
41                                                   GdkCursor *cursor);\r
42 static void gdk_device_virtual_warp (GdkDevice *device,\r
43                                      GdkScreen *screen,\r
44                                      gint       x,\r
45                                      gint       y);\r
46 static void gdk_device_virtual_query_state (GdkDevice        *device,\r
47                                             GdkWindow        *window,\r
48                                             GdkWindow       **root_window,\r
49                                             GdkWindow       **child_window,\r
50                                             gint             *root_x,\r
51                                             gint             *root_y,\r
52                                             gint             *win_x,\r
53                                             gint             *win_y,\r
54                                             GdkModifierType  *mask);\r
55 static GdkGrabStatus gdk_device_virtual_grab   (GdkDevice     *device,\r
56                                                 GdkWindow     *window,\r
57                                                 gboolean       owner_events,\r
58                                                 GdkEventMask   event_mask,\r
59                                                 GdkWindow     *confine_to,\r
60                                                 GdkCursor     *cursor,\r
61                                                 guint32        time_);\r
62 static void          gdk_device_virtual_ungrab (GdkDevice     *device,\r
63                                                 guint32        time_);\r
64 static GdkWindow * gdk_device_virtual_window_at_position (GdkDevice       *device,\r
65                                                           gint            *win_x,\r
66                                                           gint            *win_y,\r
67                                                           GdkModifierType *mask,\r
68                                                           gboolean         get_toplevel);\r
69 static void      gdk_device_virtual_select_window_events (GdkDevice       *device,\r
70                                                           GdkWindow       *window,\r
71                                                           GdkEventMask     event_mask);\r
72 \r
73 \r
74 G_DEFINE_TYPE (GdkDeviceVirtual, gdk_device_virtual, GDK_TYPE_DEVICE)\r
75 \r
76 static void\r
77 gdk_device_virtual_class_init (GdkDeviceVirtualClass *klass)\r
78 {\r
79   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);\r
80 \r
81   device_class->get_history = gdk_device_virtual_get_history;\r
82   device_class->get_state = gdk_device_virtual_get_state;\r
83   device_class->set_window_cursor = gdk_device_virtual_set_window_cursor;\r
84   device_class->warp = gdk_device_virtual_warp;\r
85   device_class->query_state = gdk_device_virtual_query_state;\r
86   device_class->grab = gdk_device_virtual_grab;\r
87   device_class->ungrab = gdk_device_virtual_ungrab;\r
88   device_class->window_at_position = gdk_device_virtual_window_at_position;\r
89   device_class->select_window_events = gdk_device_virtual_select_window_events;\r
90 }\r
91 \r
92 static void\r
93 gdk_device_virtual_init (GdkDeviceVirtual *device_virtual)\r
94 {\r
95   GdkDevice *device;\r
96 \r
97   device = GDK_DEVICE (device_virtual);\r
98 \r
99 }\r
100 \r
101 void\r
102 _gdk_device_virtual_set_active (GdkDevice *device,\r
103                                 GdkDevice *new_active)\r
104 {\r
105   GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);\r
106   int n_axes, i;\r
107   GdkAtom label_atom;\r
108   GdkAxisUse use;\r
109   gdouble min_value, max_value, resolution;\r
110 \r
111   if (virtual->active_device == new_active)\r
112     return;\r
113 \r
114   virtual->active_device = new_active;\r
115   \r
116   if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)\r
117     {\r
118       _gdk_device_reset_axes (device);\r
119       n_axes = gdk_device_get_n_axes (new_active);\r
120       for (i = 0; i < n_axes; i++)\r
121         {\r
122           _gdk_device_get_axis_info (new_active, i,\r
123                                      &label_atom, &use, \r
124                                      &min_value, &max_value, &resolution);\r
125           _gdk_device_add_axis (device,\r
126                                 label_atom, use, \r
127                                 min_value, max_value, resolution);\r
128         }\r
129     }\r
130 \r
131   g_signal_emit_by_name (G_OBJECT (device), "changed");\r
132 }\r
133 \r
134 static gboolean\r
135 gdk_device_virtual_get_history (GdkDevice      *device,\r
136                                 GdkWindow      *window,\r
137                                 guint32         start,\r
138                                 guint32         stop,\r
139                                 GdkTimeCoord ***events,\r
140                                 gint           *n_events)\r
141 {\r
142   /* History is only per slave device */\r
143   return FALSE;\r
144 }\r
145 \r
146 static void\r
147 gdk_device_virtual_get_state (GdkDevice       *device,\r
148                               GdkWindow       *window,\r
149                               gdouble         *axes,\r
150                               GdkModifierType *mask)\r
151 {\r
152   GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);\r
153   GdkDevice *active = virtual->active_device;\r
154 \r
155   GDK_DEVICE_GET_CLASS (active)->get_state (active,\r
156                                             window, axes, mask);\r
157 }\r
158 \r
159 static void\r
160 gdk_device_virtual_set_window_cursor (GdkDevice *device,\r
161                                       GdkWindow *window,\r
162                                       GdkCursor *cursor)\r
163 {\r
164   GdkWin32Cursor *cursor_private;\r
165   GdkWindow *parent_window;\r
166   GdkWindowImplWin32 *impl;\r
167   HCURSOR hcursor;\r
168   HCURSOR hprevcursor;\r
169 \r
170   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);\r
171   cursor_private = (GdkWin32Cursor*) cursor;\r
172 \r
173   hprevcursor = impl->hcursor;\r
174 \r
175   if (!cursor)\r
176     hcursor = NULL;\r
177   else\r
178     hcursor = cursor_private->hcursor;\r
179 \r
180   if (hcursor != NULL)\r
181     {\r
182       /* If the pointer is over our window, set new cursor */\r
183       GdkWindow *curr_window = gdk_window_get_pointer (window, NULL, NULL, NULL);\r
184 \r
185       if (curr_window == window ||\r
186           (curr_window && window == gdk_window_get_toplevel (curr_window)))\r
187         SetCursor (hcursor);\r
188       else\r
189         {\r
190           /* Climb up the tree and find whether our window is the\r
191            * first ancestor that has cursor defined, and if so, set\r
192            * new cursor.\r
193            */\r
194           while (curr_window && curr_window->impl &&\r
195                  !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->hcursor)\r
196             {\r
197               curr_window = curr_window->parent;\r
198               if (curr_window == GDK_WINDOW (window))\r
199                 {\r
200                   SetCursor (hcursor);\r
201                   break;\r
202                 }\r
203             }\r
204         }\r
205     }\r
206 \r
207   /* Unset the previous cursor: Need to make sure it's no longer in\r
208    * use before we destroy it, in case we're not over our window but\r
209    * the cursor is still set to our old one.\r
210    */\r
211   if (hprevcursor != NULL &&\r
212       GetCursor () == hprevcursor)\r
213     {\r
214       /* Look for a suitable cursor to use instead */\r
215       hcursor = NULL;\r
216       parent_window = GDK_WINDOW (window)->parent;\r
217 \r
218       while (hcursor == NULL)\r
219         {\r
220           if (parent_window)\r
221             {\r
222               impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);\r
223               hcursor = impl->hcursor;\r
224               parent_window = parent_window->parent;\r
225             }\r
226           else\r
227             hcursor = LoadCursor (NULL, IDC_ARROW);\r
228         }\r
229 \r
230       SetCursor (hcursor);\r
231     }\r
232 }\r
233 \r
234 static void\r
235 gdk_device_virtual_warp (GdkDevice *device,\r
236                          GdkScreen *screen,\r
237                          gint       x,\r
238                          gint       y)\r
239 {\r
240   SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);\r
241 }\r
242 \r
243 static void\r
244 gdk_device_virtual_query_state (GdkDevice        *device,\r
245                                 GdkWindow        *window,\r
246                                 GdkWindow       **root_window,\r
247                                 GdkWindow       **child_window,\r
248                                 gint             *root_x,\r
249                                 gint             *root_y,\r
250                                 gint             *win_x,\r
251                                 gint             *win_y,\r
252                                 GdkModifierType  *mask)\r
253 {\r
254   GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);\r
255 \r
256   _gdk_device_query_state (virtual->active_device,\r
257                            window, root_window, child_window,\r
258                            root_x, root_y,\r
259                            win_x, win_y,\r
260                            mask);\r
261 }\r
262 \r
263 static GdkGrabStatus\r
264 gdk_device_virtual_grab (GdkDevice    *device,\r
265                          GdkWindow    *window,\r
266                          gboolean      owner_events,\r
267                          GdkEventMask  event_mask,\r
268                          GdkWindow    *confine_to,\r
269                          GdkCursor    *cursor,\r
270                          guint32       time_)\r
271 {\r
272   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);\r
273   HCURSOR hcursor;\r
274   GdkWin32Cursor *cursor_private;\r
275 \r
276   cursor_private = (GdkWin32Cursor*) cursor;\r
277 \r
278   if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)\r
279     {\r
280       if (!cursor)\r
281         hcursor = NULL;\r
282       else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)\r
283         WIN32_API_FAILED ("CopyCursor");\r
284 \r
285       if (_gdk_win32_grab_cursor != NULL)\r
286         {\r
287           if (GetCursor () == _gdk_win32_grab_cursor)\r
288             SetCursor (NULL);\r
289           DestroyCursor (_gdk_win32_grab_cursor);\r
290         }\r
291 \r
292       _gdk_win32_grab_cursor = hcursor;\r
293 \r
294       if (_gdk_win32_grab_cursor != NULL)\r
295         SetCursor (_gdk_win32_grab_cursor);\r
296       else if (impl->hcursor != NULL)\r
297         SetCursor (impl->hcursor);\r
298       else\r
299         SetCursor (LoadCursor (NULL, IDC_ARROW));\r
300 \r
301       SetCapture (GDK_WINDOW_HWND (window));\r
302     }\r
303 \r
304   return GDK_GRAB_SUCCESS;\r
305 }\r
306 \r
307 static void\r
308 gdk_device_virtual_ungrab (GdkDevice *device,\r
309                          guint32    time_)\r
310 {\r
311   GdkDeviceGrabInfo *info;\r
312   GdkDisplay *display;\r
313 \r
314   display = gdk_device_get_display (device);\r
315   info = _gdk_display_get_last_device_grab (display, device);\r
316 \r
317   if (info)\r
318     info->serial_end = 0;\r
319 \r
320   if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)\r
321     {\r
322       if (_gdk_win32_grab_cursor != NULL)\r
323         {\r
324           if (GetCursor () == _gdk_win32_grab_cursor)\r
325             SetCursor (NULL);\r
326           DestroyCursor (_gdk_win32_grab_cursor);\r
327         }\r
328       _gdk_win32_grab_cursor = NULL;\r
329 \r
330       ReleaseCapture ();\r
331     }\r
332 \r
333   _gdk_display_device_grab_update (display, device, NULL, 0);\r
334 }\r
335 \r
336 static void\r
337 screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)\r
338 {\r
339   *client_pt = screen_pt;\r
340   ScreenToClient (hwnd, client_pt);\r
341 }\r
342 \r
343 static GdkWindow *\r
344 gdk_device_virtual_window_at_position (GdkDevice       *device,\r
345                                        gint            *win_x,\r
346                                        gint            *win_y,\r
347                                        GdkModifierType *mask,\r
348                                        gboolean         get_toplevel)\r
349 {\r
350   GdkWindow *window = NULL;\r
351   POINT screen_pt, client_pt;\r
352   HWND hwnd, hwndc;\r
353   RECT rect;\r
354 \r
355   GetCursorPos (&screen_pt);\r
356 \r
357   if (get_toplevel)\r
358     {\r
359       /* Only consider visible children of the desktop to avoid the various\r
360        * non-visible windows you often find on a running Windows box. These\r
361        * might overlap our windows and cause our walk to fail. As we assume\r
362        * WindowFromPoint() can find our windows, we follow similar logic\r
363        * here, and ignore invisible and disabled windows.\r
364        */\r
365       hwnd = GetDesktopWindow ();\r
366       do {\r
367         window = gdk_win32_handle_table_lookup (hwnd);\r
368 \r
369         if (window != NULL &&\r
370             GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&\r
371             GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)\r
372           break;\r
373 \r
374         screen_to_client (hwnd, screen_pt, &client_pt);\r
375         hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED  |\r
376                                                          CWP_SKIPINVISIBLE);\r
377 \r
378         /* Verify that we're really inside the client area of the window */\r
379         if (hwndc != hwnd)\r
380           {\r
381             GetClientRect (hwndc, &rect);\r
382             screen_to_client (hwndc, screen_pt, &client_pt);\r
383             if (!PtInRect (&rect, client_pt))\r
384               hwndc = hwnd;\r
385           }\r
386 \r
387       } while (hwndc != hwnd && (hwnd = hwndc, 1));\r
388 \r
389     }\r
390   else\r
391     {\r
392       hwnd = WindowFromPoint (screen_pt);\r
393 \r
394       /* Verify that we're really inside the client area of the window */\r
395       GetClientRect (hwnd, &rect);\r
396       screen_to_client (hwnd, screen_pt, &client_pt);\r
397       if (!PtInRect (&rect, client_pt))\r
398         hwnd = NULL;\r
399 \r
400       /* If we didn't hit any window at that point, return the desktop */\r
401       if (hwnd == NULL)\r
402         {\r
403           if (win_x)\r
404             *win_x = screen_pt.x + _gdk_offset_x;\r
405           if (win_y)\r
406             *win_y = screen_pt.y + _gdk_offset_y;\r
407           return _gdk_root;\r
408         }\r
409 \r
410       window = gdk_win32_handle_table_lookup (hwnd);\r
411     }\r
412 \r
413   if (window && (win_x || win_y))\r
414     {\r
415       if (win_x)\r
416         *win_x = client_pt.x;\r
417       if (win_y)\r
418         *win_y = client_pt.y;\r
419     }\r
420 \r
421   return window;\r
422 }\r
423 \r
424 static void\r
425 gdk_device_virtual_select_window_events (GdkDevice    *device,\r
426                                          GdkWindow    *window,\r
427                                          GdkEventMask  event_mask)\r
428 {\r
429 }\r