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