]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdevice-win32.c
Avoid loop in paint update cycle
[~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 void 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 }
137
138 static void
139 gdk_device_win32_warp (GdkDevice *device,
140                        GdkScreen *screen,
141                        gint       x,
142                        gint       y)
143 {
144 }
145
146 static GdkModifierType
147 get_current_mask (void)
148 {
149   GdkModifierType mask;
150   BYTE kbd[256];
151
152   GetKeyboardState (kbd);
153   mask = 0;
154   if (kbd[VK_SHIFT] & 0x80)
155     mask |= GDK_SHIFT_MASK;
156   if (kbd[VK_CAPITAL] & 0x80)
157     mask |= GDK_LOCK_MASK;
158   if (kbd[VK_CONTROL] & 0x80)
159     mask |= GDK_CONTROL_MASK;
160   if (kbd[VK_MENU] & 0x80)
161     mask |= GDK_MOD1_MASK;
162   if (kbd[VK_LBUTTON] & 0x80)
163     mask |= GDK_BUTTON1_MASK;
164   if (kbd[VK_MBUTTON] & 0x80)
165     mask |= GDK_BUTTON2_MASK;
166   if (kbd[VK_RBUTTON] & 0x80)
167     mask |= GDK_BUTTON3_MASK;
168
169   return mask;
170 }
171
172 static void
173 gdk_device_win32_query_state (GdkDevice        *device,
174                               GdkWindow        *window,
175                               GdkWindow       **root_window,
176                               GdkWindow       **child_window,
177                               gint             *root_x,
178                               gint             *root_y,
179                               gint             *win_x,
180                               gint             *win_y,
181                               GdkModifierType  *mask)
182 {
183   POINT point;
184   HWND hwnd, hwndc;
185
186   hwnd = GDK_WINDOW_HWND (window);
187   GetCursorPos (&point);
188
189   if (root_x)
190     *root_x = point.x;
191
192   if (root_y)
193     *root_y = point.y;
194
195   ScreenToClient (hwnd, &point);
196
197   if (win_x)
198     *win_x = point.x;
199
200   if (win_y)
201     *win_y = point.y;
202
203   if (window == _gdk_root)
204     {
205       if (win_x)
206         *win_x += _gdk_offset_x;
207
208       if (win_y)
209         *win_y += _gdk_offset_y;
210     }
211
212   if (child_window)
213     {
214       hwndc = ChildWindowFromPoint (hwnd, point);
215
216       if (hwndc && hwndc != hwnd)
217         *child_window = gdk_win32_handle_table_lookup (hwndc);
218       else
219         *child_window = NULL; /* Direct child unknown to gdk */
220     }
221
222   if (root_window)
223     {
224       GdkScreen *screen;
225
226       screen = gdk_window_get_screen (window);
227       *root_window = gdk_screen_get_root_window (screen);
228     }
229
230   if (mask)
231     *mask = get_current_mask ();
232 }
233
234 static GdkGrabStatus
235 gdk_device_win32_grab (GdkDevice    *device,
236                        GdkWindow    *window,
237                        gboolean      owner_events,
238                        GdkEventMask  event_mask,
239                        GdkWindow    *confine_to,
240                        GdkCursor    *cursor,
241                        guint32       time_)
242 {
243   /* No support for grabbing the slave atm */
244   return GDK_GRAB_NOT_VIEWABLE;
245 }
246
247 static void
248 gdk_device_win32_ungrab (GdkDevice *device,
249                          guint32    time_)
250 {
251 }
252
253 static void
254 screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)
255 {
256   *client_pt = screen_pt;
257   ScreenToClient (hwnd, client_pt);
258 }
259
260 static GdkWindow *
261 gdk_device_win32_window_at_position (GdkDevice       *device,
262                                      gint            *win_x,
263                                      gint            *win_y,
264                                      GdkModifierType *mask,
265                                      gboolean         get_toplevel)
266 {
267   GdkWindow *window = NULL;
268   POINT screen_pt, client_pt;
269   HWND hwnd, hwndc;
270   RECT rect;
271
272   GetCursorPos (&screen_pt);
273
274   if (get_toplevel)
275     {
276       /* Only consider visible children of the desktop to avoid the various
277        * non-visible windows you often find on a running Windows box. These
278        * might overlap our windows and cause our walk to fail. As we assume
279        * WindowFromPoint() can find our windows, we follow similar logic
280        * here, and ignore invisible and disabled windows.
281        */
282       hwnd = GetDesktopWindow ();
283       do {
284         window = gdk_win32_handle_table_lookup (hwnd);
285
286         if (window != NULL &&
287             GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&
288             GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
289           break;
290
291         screen_to_client (hwnd, screen_pt, &client_pt);
292         hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED  |
293                                                          CWP_SKIPINVISIBLE);
294
295         /* Verify that we're really inside the client area of the window */
296         if (hwndc != hwnd)
297           {
298             GetClientRect (hwndc, &rect);
299             screen_to_client (hwndc, screen_pt, &client_pt);
300             if (!PtInRect (&rect, client_pt))
301               hwndc = hwnd;
302           }
303
304       } while (hwndc != hwnd && (hwnd = hwndc, 1));
305
306     }
307   else
308     {
309       hwnd = WindowFromPoint (screen_pt);
310
311       /* Verify that we're really inside the client area of the window */
312       GetClientRect (hwnd, &rect);
313       screen_to_client (hwnd, screen_pt, &client_pt);
314       if (!PtInRect (&rect, client_pt))
315         hwnd = NULL;
316
317       /* If we didn't hit any window at that point, return the desktop */
318       if (hwnd == NULL)
319         {
320           if (win_x)
321             *win_x = screen_pt.x + _gdk_offset_x;
322           if (win_y)
323             *win_y = screen_pt.y + _gdk_offset_y;
324           return _gdk_root;
325         }
326
327       window = gdk_win32_handle_table_lookup (hwnd);
328     }
329
330   if (window && (win_x || win_y))
331     {
332       if (win_x)
333         *win_x = client_pt.x;
334       if (win_y)
335         *win_y = client_pt.y;
336     }
337
338   return window;
339 }
340
341 static void
342 gdk_device_win32_select_window_events (GdkDevice    *device,
343                                        GdkWindow    *window,
344                                        GdkEventMask  event_mask)
345 {
346 }