forked from AuroraMiddleware/gtk
795572710c
This commit ensures that each GdkSurface impl remembers the cursor that GDK sets for it, and that this cursor is set each time WM_SETCURSOR is called for that sufrace's HWND. This is needed because W32, unlike X, has no per-window cursors - the cursor on W32 is a global resource, and we need to keep track of which cursor should be set when pointer is over which surface ourselves (WM_SETCURSOR exists exactly for this reason). This commit also makes GDK remember the surface that has an implicit grab (since implicit grabs are gone from the upper levels of the toolkit), and ensures that crossing events are correctly synthesized and the grab is broken when surface focus changes. This fixes a bug where opening a new window (by clicking something in some other, pre-existing window) will make that new window not get any mouse input due to the fact that the mouse-button-down event from that click caused an implicit grab on the pre-existing window, and that grab was not released afterward.
220 lines
6.2 KiB
C
220 lines
6.2 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gdk/gdksurface.h>
|
|
|
|
#include <windowsx.h>
|
|
#include <objbase.h>
|
|
|
|
#include "gdkdisplayprivate.h"
|
|
#include "gdkdevice-virtual.h"
|
|
#include "gdkdevice-win32.h"
|
|
#include "gdkwin32.h"
|
|
#include "gdkdisplay-win32.h"
|
|
|
|
G_DEFINE_TYPE (GdkDeviceVirtual, gdk_device_virtual, GDK_TYPE_DEVICE)
|
|
|
|
void
|
|
_gdk_device_virtual_set_active (GdkDevice *device,
|
|
GdkDevice *new_active)
|
|
{
|
|
GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
|
|
int n_axes, i;
|
|
GdkAtom label_atom;
|
|
GdkAxisUse use;
|
|
gdouble min_value, max_value, resolution;
|
|
|
|
if (virtual->active_device == new_active)
|
|
return;
|
|
|
|
virtual->active_device = new_active;
|
|
|
|
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
|
{
|
|
_gdk_device_reset_axes (device);
|
|
n_axes = gdk_device_get_n_axes (new_active);
|
|
for (i = 0; i < n_axes; i++)
|
|
{
|
|
_gdk_device_get_axis_info (new_active, i,
|
|
&label_atom, &use,
|
|
&min_value, &max_value, &resolution);
|
|
_gdk_device_add_axis (device,
|
|
label_atom, use,
|
|
min_value, max_value, resolution);
|
|
}
|
|
}
|
|
|
|
g_signal_emit_by_name (G_OBJECT (device), "changed");
|
|
}
|
|
|
|
static gboolean
|
|
gdk_device_virtual_get_history (GdkDevice *device,
|
|
GdkSurface *window,
|
|
guint32 start,
|
|
guint32 stop,
|
|
GdkTimeCoord ***events,
|
|
gint *n_events)
|
|
{
|
|
/* History is only per slave device */
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_get_state (GdkDevice *device,
|
|
GdkSurface *window,
|
|
gdouble *axes,
|
|
GdkModifierType *mask)
|
|
{
|
|
GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
|
|
GdkDevice *active = virtual->active_device;
|
|
|
|
GDK_DEVICE_GET_CLASS (active)->get_state (active,
|
|
window, axes, mask);
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_set_surface_cursor (GdkDevice *device,
|
|
GdkSurface *window,
|
|
GdkCursor *cursor)
|
|
{
|
|
GdkDisplay *display = gdk_surface_get_display (window);
|
|
GdkWin32HCursor *win32_hcursor = NULL;
|
|
|
|
if (cursor == NULL)
|
|
cursor = gdk_cursor_new_from_name ("default", NULL);
|
|
|
|
if (display != NULL)
|
|
win32_hcursor = gdk_win32_display_get_win32hcursor (GDK_WIN32_DISPLAY (display), cursor);
|
|
|
|
/* This is correct because the code up the stack already
|
|
* checked that cursor is currently inside this window,
|
|
* and wouldn't have called this function otherwise.
|
|
*/
|
|
if (win32_hcursor != NULL)
|
|
SetCursor (gdk_win32_hcursor_get_handle (win32_hcursor));
|
|
|
|
g_set_object (&GDK_SURFACE_IMPL_WIN32 (window->impl)->cursor, win32_hcursor);
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_warp (GdkDevice *device,
|
|
gdouble x,
|
|
gdouble y)
|
|
{
|
|
SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_query_state (GdkDevice *device,
|
|
GdkSurface *window,
|
|
GdkSurface **child_window,
|
|
gdouble *root_x,
|
|
gdouble *root_y,
|
|
gdouble *win_x,
|
|
gdouble *win_y,
|
|
GdkModifierType *mask)
|
|
{
|
|
GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
|
|
|
|
_gdk_device_query_state (virtual->active_device,
|
|
window, child_window,
|
|
root_x, root_y,
|
|
win_x, win_y,
|
|
mask);
|
|
}
|
|
|
|
static GdkGrabStatus
|
|
gdk_device_virtual_grab (GdkDevice *device,
|
|
GdkSurface *window,
|
|
gboolean owner_events,
|
|
GdkEventMask event_mask,
|
|
GdkSurface *confine_to,
|
|
GdkCursor *cursor,
|
|
guint32 time_)
|
|
{
|
|
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
|
{
|
|
GdkWin32HCursor *win32_hcursor;
|
|
GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_device_get_display (device));
|
|
win32_hcursor = gdk_win32_display_get_win32hcursor (display, cursor);
|
|
g_set_object (&display->grab_cursor, win32_hcursor);
|
|
|
|
if (display->grab_cursor != NULL)
|
|
SetCursor (gdk_win32_hcursor_get_handle (display->grab_cursor));
|
|
else
|
|
SetCursor (LoadCursor (NULL, IDC_ARROW));
|
|
|
|
SetCapture (GDK_SURFACE_HWND (window));
|
|
}
|
|
|
|
return GDK_GRAB_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_ungrab (GdkDevice *device,
|
|
guint32 time_)
|
|
{
|
|
GdkDeviceGrabInfo *info;
|
|
GdkDisplay *display;
|
|
GdkWin32Display *win32_display;
|
|
|
|
display = gdk_device_get_display (device);
|
|
win32_display = GDK_WIN32_DISPLAY (display);
|
|
info = _gdk_display_get_last_device_grab (display, device);
|
|
|
|
if (info)
|
|
info->serial_end = 0;
|
|
|
|
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
|
{
|
|
g_clear_object (&win32_display->grab_cursor);
|
|
ReleaseCapture ();
|
|
}
|
|
|
|
_gdk_display_device_grab_update (display, device, device, 0);
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_select_surface_events (GdkDevice *device,
|
|
GdkSurface *window,
|
|
GdkEventMask event_mask)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_class_init (GdkDeviceVirtualClass *klass)
|
|
{
|
|
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
|
|
|
|
device_class->get_history = gdk_device_virtual_get_history;
|
|
device_class->get_state = gdk_device_virtual_get_state;
|
|
device_class->set_surface_cursor = gdk_device_virtual_set_surface_cursor;
|
|
device_class->warp = gdk_device_virtual_warp;
|
|
device_class->query_state = gdk_device_virtual_query_state;
|
|
device_class->grab = gdk_device_virtual_grab;
|
|
device_class->ungrab = gdk_device_virtual_ungrab;
|
|
device_class->surface_at_position = _gdk_device_win32_surface_at_position;
|
|
device_class->select_surface_events = gdk_device_virtual_select_surface_events;
|
|
}
|
|
|
|
static void
|
|
gdk_device_virtual_init (GdkDeviceVirtual *device_virtual)
|
|
{
|
|
}
|