1 /* GDK - The GIMP Drawing Kit
\r
2 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
\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
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
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
20 #include <gdk/gdkwindow.h>
\r
22 #include <windowsx.h>
\r
23 #include <objbase.h>
\r
25 #include "gdkdisplayprivate.h"
\r
26 #include "gdkdevice-virtual.h"
\r
27 #include "gdkwin32.h"
\r
29 static gboolean gdk_device_virtual_get_history (GdkDevice *device,
\r
33 GdkTimeCoord ***events,
\r
35 static void gdk_device_virtual_get_state (GdkDevice *device,
\r
38 GdkModifierType *mask);
\r
39 static void gdk_device_virtual_set_window_cursor (GdkDevice *device,
\r
42 static void gdk_device_virtual_warp (GdkDevice *device,
\r
46 static void gdk_device_virtual_query_state (GdkDevice *device,
\r
48 GdkWindow **root_window,
\r
49 GdkWindow **child_window,
\r
54 GdkModifierType *mask);
\r
55 static GdkGrabStatus gdk_device_virtual_grab (GdkDevice *device,
\r
57 gboolean owner_events,
\r
58 GdkEventMask event_mask,
\r
59 GdkWindow *confine_to,
\r
62 static void gdk_device_virtual_ungrab (GdkDevice *device,
\r
64 static GdkWindow * gdk_device_virtual_window_at_position (GdkDevice *device,
\r
67 GdkModifierType *mask,
\r
68 gboolean get_toplevel);
\r
69 static void gdk_device_virtual_select_window_events (GdkDevice *device,
\r
71 GdkEventMask event_mask);
\r
74 G_DEFINE_TYPE (GdkDeviceVirtual, gdk_device_virtual, GDK_TYPE_DEVICE)
\r
77 gdk_device_virtual_class_init (GdkDeviceVirtualClass *klass)
\r
79 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
\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
93 gdk_device_virtual_init (GdkDeviceVirtual *device_virtual)
\r
97 device = GDK_DEVICE (device_virtual);
\r
102 _gdk_device_virtual_set_active (GdkDevice *device,
\r
103 GdkDevice *new_active)
\r
105 GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
\r
107 GdkAtom label_atom;
\r
109 gdouble min_value, max_value, resolution;
\r
111 if (virtual->active_device == new_active)
\r
114 virtual->active_device = new_active;
\r
116 if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
\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
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
127 min_value, max_value, resolution);
\r
131 g_signal_emit_by_name (G_OBJECT (device), "changed");
\r
135 gdk_device_virtual_get_history (GdkDevice *device,
\r
139 GdkTimeCoord ***events,
\r
142 /* History is only per slave device */
\r
147 gdk_device_virtual_get_state (GdkDevice *device,
\r
150 GdkModifierType *mask)
\r
152 GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
\r
153 GdkDevice *active = virtual->active_device;
\r
155 GDK_DEVICE_GET_CLASS (active)->get_state (active,
\r
156 window, axes, mask);
\r
160 gdk_device_virtual_set_window_cursor (GdkDevice *device,
\r
164 GdkWin32Cursor *cursor_private;
\r
165 GdkWindow *parent_window;
\r
166 GdkWindowImplWin32 *impl;
\r
168 HCURSOR hprevcursor;
\r
170 impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
\r
171 cursor_private = (GdkWin32Cursor*) cursor;
\r
173 hprevcursor = impl->hcursor;
\r
178 hcursor = cursor_private->hcursor;
\r
180 if (hcursor != NULL)
\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
185 if (curr_window == window ||
\r
186 (curr_window && window == gdk_window_get_toplevel (curr_window)))
\r
187 SetCursor (hcursor);
\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
194 while (curr_window && curr_window->impl &&
\r
195 !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->hcursor)
\r
197 curr_window = curr_window->parent;
\r
198 if (curr_window == GDK_WINDOW (window))
\r
200 SetCursor (hcursor);
\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
211 if (hprevcursor != NULL &&
\r
212 GetCursor () == hprevcursor)
\r
214 /* Look for a suitable cursor to use instead */
\r
216 parent_window = GDK_WINDOW (window)->parent;
\r
218 while (hcursor == NULL)
\r
222 impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
\r
223 hcursor = impl->hcursor;
\r
224 parent_window = parent_window->parent;
\r
227 hcursor = LoadCursor (NULL, IDC_ARROW);
\r
230 SetCursor (hcursor);
\r
235 gdk_device_virtual_warp (GdkDevice *device,
\r
240 SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
\r
244 gdk_device_virtual_query_state (GdkDevice *device,
\r
246 GdkWindow **root_window,
\r
247 GdkWindow **child_window,
\r
252 GdkModifierType *mask)
\r
254 GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
\r
256 _gdk_device_query_state (virtual->active_device,
\r
257 window, root_window, child_window,
\r
263 static GdkGrabStatus
\r
264 gdk_device_virtual_grab (GdkDevice *device,
\r
266 gboolean owner_events,
\r
267 GdkEventMask event_mask,
\r
268 GdkWindow *confine_to,
\r
272 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
\r
274 GdkWin32Cursor *cursor_private;
\r
276 cursor_private = (GdkWin32Cursor*) cursor;
\r
278 if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
\r
282 else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
\r
283 WIN32_API_FAILED ("CopyCursor");
\r
285 if (_gdk_win32_grab_cursor != NULL)
\r
287 if (GetCursor () == _gdk_win32_grab_cursor)
\r
289 DestroyCursor (_gdk_win32_grab_cursor);
\r
292 _gdk_win32_grab_cursor = hcursor;
\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
299 SetCursor (LoadCursor (NULL, IDC_ARROW));
\r
301 SetCapture (GDK_WINDOW_HWND (window));
\r
304 return GDK_GRAB_SUCCESS;
\r
308 gdk_device_virtual_ungrab (GdkDevice *device,
\r
311 GdkDeviceGrabInfo *info;
\r
312 GdkDisplay *display;
\r
314 display = gdk_device_get_display (device);
\r
315 info = _gdk_display_get_last_device_grab (display, device);
\r
318 info->serial_end = 0;
\r
320 if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
\r
322 if (_gdk_win32_grab_cursor != NULL)
\r
324 if (GetCursor () == _gdk_win32_grab_cursor)
\r
326 DestroyCursor (_gdk_win32_grab_cursor);
\r
328 _gdk_win32_grab_cursor = NULL;
\r
333 _gdk_display_device_grab_update (display, device, NULL, 0);
\r
337 screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)
\r
339 *client_pt = screen_pt;
\r
340 ScreenToClient (hwnd, client_pt);
\r
344 gdk_device_virtual_window_at_position (GdkDevice *device,
\r
347 GdkModifierType *mask,
\r
348 gboolean get_toplevel)
\r
350 GdkWindow *window = NULL;
\r
351 POINT screen_pt, client_pt;
\r
355 GetCursorPos (&screen_pt);
\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
365 hwnd = GetDesktopWindow ();
\r
367 window = gdk_win32_handle_table_lookup (hwnd);
\r
369 if (window != NULL &&
\r
370 GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&
\r
371 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
\r
374 screen_to_client (hwnd, screen_pt, &client_pt);
\r
375 hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED |
\r
376 CWP_SKIPINVISIBLE);
\r
378 /* Verify that we're really inside the client area of the window */
\r
381 GetClientRect (hwndc, &rect);
\r
382 screen_to_client (hwndc, screen_pt, &client_pt);
\r
383 if (!PtInRect (&rect, client_pt))
\r
387 } while (hwndc != hwnd && (hwnd = hwndc, 1));
\r
392 hwnd = WindowFromPoint (screen_pt);
\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
400 /* If we didn't hit any window at that point, return the desktop */
\r
404 *win_x = screen_pt.x + _gdk_offset_x;
\r
406 *win_y = screen_pt.y + _gdk_offset_y;
\r
410 window = gdk_win32_handle_table_lookup (hwnd);
\r
413 if (window && (win_x || win_y))
\r
416 *win_x = client_pt.x;
\r
418 *win_y = client_pt.y;
\r
425 gdk_device_virtual_select_window_events (GdkDevice *device,
\r
427 GdkEventMask event_mask)
\r