[gtk+] GDK W32: Force correct mouse cursor for custom resize/move
- From: Руслан Ижбулатов <ruslanizhb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] GDK W32: Force correct mouse cursor for custom resize/move
- Date: Thu, 3 Mar 2016 07:18:56 +0000 (UTC)
commit 84ddc6aab1e0b498666c65a5283e1a0bdfa04599
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date: Sat Feb 27 00:10:12 2016 +0000
GDK W32: Force correct mouse cursor for custom resize/move
* Explicitly grab the device, setting appropriate cursor on it.
* Fix gdk_device_virtual_set_window_cursor() to just set the
cursor, without trying to check that mouse is over the given
window. Also prevent it from immediately resetting cursor.
* Alse take into account things that happen in other parts of
GDK - don't look for replacement cursor, GDK already did that,
and don't create a default arrow cursor instead of NULL,
GDK-W32 already did that up the stack as well.
Warn about inappropriate cursor == NULL argument instead.
https://bugzilla.gnome.org/show_bug.cgi?id=762711
gdk/win32/gdkdevice-virtual.c | 67 +++++++++----------------------
gdk/win32/gdkevents-win32.c | 12 +++++-
gdk/win32/gdkwindow-win32.c | 89 +++++++++++++++++++++++++++++++++++++---
gdk/win32/gdkwindow-win32.h | 12 +++++-
4 files changed, 122 insertions(+), 58 deletions(-)
---
diff --git a/gdk/win32/gdkdevice-virtual.c b/gdk/win32/gdkdevice-virtual.c
index a0f485e..64bf29c 100644
--- a/gdk/win32/gdkdevice-virtual.c
+++ b/gdk/win32/gdkdevice-virtual.c
@@ -94,7 +94,6 @@ gdk_device_virtual_set_window_cursor (GdkDevice *device,
{
GdkWindow *parent_window;
GdkWindowImplWin32 *impl;
- GdkCursor *replacement_cursor;
GdkCursor *previous_cursor;
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
@@ -103,55 +102,27 @@ gdk_device_virtual_set_window_cursor (GdkDevice *device,
if (cursor != NULL && GDK_WIN32_CURSOR (cursor)->hcursor != NULL)
{
- /* If the pointer is over our window, set new cursor */
- GdkWindow *curr_window = gdk_window_get_device_position (window, device, NULL, NULL, NULL);
-
- if (curr_window == window ||
- (curr_window && window == gdk_window_get_toplevel (curr_window)))
- SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor);
- else
- {
- /* Climb up the tree and find whether our window is the
- * first ancestor that has cursor defined, and if so, set
- * new cursor.
- */
- while (curr_window && curr_window->impl &&
- !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->cursor)
- {
- curr_window = curr_window->parent;
- if (curr_window == GDK_WINDOW (window))
- {
- SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor);
- break;
- }
- }
- }
+ SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor);
}
-
- /* Unset the previous cursor: Need to make sure it's no longer in
- * use before we destroy it, in case we're not over our window but
- * the cursor is still set to our old one.
- */
- if (previous_cursor != NULL &&
- GetCursor () == GDK_WIN32_CURSOR (previous_cursor)->hcursor)
+ else if (previous_cursor != NULL &&
+ GetCursor () == GDK_WIN32_CURSOR (previous_cursor)->hcursor)
+ {
+ /* The caller will unref previous_cursor shortly,
+ * but it holds the handle to currently-used cursor,
+ * and we can't call SetCursor(NULL).
+ */
+ g_warning (G_STRLOC ": Refusing to replace cursor %p (handle %p) with NULL. "
+ "Expect ugly results.",
+ previous_cursor, GDK_WIN32_CURSOR (previous_cursor)->hcursor);
+ }
+ else
{
- /* Look for a suitable cursor to use instead */
- replacement_cursor = NULL;
- parent_window = GDK_WINDOW (window)->parent;
-
- while (replacement_cursor == NULL)
- {
- if (parent_window)
- {
- impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
- replacement_cursor = impl->cursor;
- parent_window = parent_window->parent;
- }
- else
- replacement_cursor = _gdk_win32_display_get_cursor_for_type (gdk_device_get_display (device),
GDK_LEFT_PTR);
- }
-
- SetCursor (GDK_WIN32_CURSOR (replacement_cursor)->hcursor);
+ /* Up the stack all effors were made already to ensure that
+ * the "cursor" argument is non-NULL.
+ * If it is, calling SetCursor(NULL) is absolutely not
+ * the right decision, so we just warn and bail out.
+ */
+ g_warning (G_STRLOC ": Refusing to set NULL cursor");
}
}
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 5058545..b326b90 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -2460,6 +2460,8 @@ gdk_event_translate (MSG *msg,
/* We keep the implicit grab until no buttons at all are held down */
if ((state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (button - 1))) == 0)
{
+ GdkWindow *native_window = pointer_grab->native_window;
+
ReleaseCapture ();
new_window = NULL;
@@ -2473,8 +2475,9 @@ gdk_event_translate (MSG *msg,
if (PtInRect (&rect, client_pt))
new_window = gdk_win32_handle_table_lookup (hwnd);
}
+
synthesize_crossing_events (display,
- pointer_grab->native_window, new_window,
+ native_window, new_window,
GDK_CROSSING_UNGRAB,
&msg->pt,
0, /* TODO: Set right mask */
@@ -2488,6 +2491,13 @@ gdk_event_translate (MSG *msg,
generate_button_event (GDK_BUTTON_RELEASE, button,
window, msg);
+ impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+ /* End a drag op when the same button that started it is released */
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE &&
+ impl->drag_move_resize_context.button == button)
+ gdk_win32_window_end_move_resize_drag (window);
+
return_val = TRUE;
break;
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index cc88413..09db5d6 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -2062,17 +2062,18 @@ gdk_win32_window_set_device_cursor (GdkWindow *window,
*/
previous_cursor = impl->cursor;
- GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
-
if (cursor)
impl->cursor = g_object_ref (cursor);
else
- /* Use default cursor otherwise. Setting it to NULL will make it use
- * system-default cursor, which is not controlled by GTK cursor theming.
+ /* Use default cursor otherwise. Don't just set NULL cursor,
+ * because that will just hide the cursor, which is not
+ * what the caller probably wanted.
*/
- impl->cursor = _gdk_win32_display_get_cursor_for_type (gdk_display_get_default (),
+ impl->cursor = _gdk_win32_display_get_cursor_for_type (gdk_device_get_display (device),
GDK_LEFT_PTR);
+ GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, impl->cursor);
+
/* Destroy the previous cursor */
if (previous_cursor != NULL)
g_object_unref (previous_cursor);
@@ -2823,6 +2824,49 @@ _gdk_window_get_functions (GdkWindow *window,
return (functions_set != NULL);
}
+static const gchar *
+get_cursor_name_from_op (GdkW32WindowDragOp op,
+ GdkWindowEdge edge)
+{
+ switch (op)
+ {
+ case GDK_WIN32_DRAGOP_MOVE:
+ return "move";
+ case GDK_WIN32_DRAGOP_RESIZE:
+ switch (edge)
+ {
+ case GDK_WINDOW_EDGE_NORTH_WEST:
+ return "nw-resize";
+ case GDK_WINDOW_EDGE_NORTH:
+ return "n-resize";
+ case GDK_WINDOW_EDGE_NORTH_EAST:
+ return "ne-resize";
+ case GDK_WINDOW_EDGE_WEST:
+ return "w-resize";
+ case GDK_WINDOW_EDGE_EAST:
+ return "e-resize";
+ case GDK_WINDOW_EDGE_SOUTH_WEST:
+ return "sw-resize";
+ case GDK_WINDOW_EDGE_SOUTH:
+ return "s-resize";
+ case GDK_WINDOW_EDGE_SOUTH_EAST:
+ return "e-resize";
+ }
+ /* default: warn about unhandled enum values,
+ * fallthrough to GDK_WIN32_DRAGOP_NONE case
+ */
+ case GDK_WIN32_DRAGOP_COUNT:
+ g_assert_not_reached ();
+ case GDK_WIN32_DRAGOP_NONE:
+ return "default";
+ /* default: warn about unhandled enum values */
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
static void
setup_drag_move_resize_context (GdkWindow *window,
GdkW32DragMoveResizeContext *context,
@@ -2835,9 +2879,33 @@ setup_drag_move_resize_context (GdkWindow *window,
guint32 timestamp)
{
RECT rect;
+ const gchar *cursor_name;
+ gint x, y;
+ GdkWindow *pointer_window;
+ GdkDisplay *display = gdk_device_get_display (device);
_gdk_win32_get_window_rect (window, &rect);
+ cursor_name = get_cursor_name_from_op (op, edge);
+
+ context->cursor = _gdk_win32_display_get_cursor_for_name (display, cursor_name);
+
+ gdk_window_get_root_origin (window, &x, &y);
+ x -= root_x;
+ y -= root_y;
+ pointer_window = gdk_device_get_window_at_position (device, &x, &y);
+
+ /* Note: This triggers a WM_CAPTURECHANGED, which will trigger
+ * gdk_win32_window_end_move_resize_drag(), which will end
+ * our op before it even begins, but only if context->op is not NONE.
+ * This is why we first do the grab, *then* set the op.
+ */
+ gdk_device_grab (device, pointer_window,
+ GDK_OWNERSHIP_NONE, FALSE,
+ GDK_ALL_EVENTS_MASK,
+ context->cursor,
+ timestamp);
+
context->op = op;
context->edge = edge;
context->device = device;
@@ -2848,9 +2916,10 @@ setup_drag_move_resize_context (GdkWindow *window,
context->start_rect = rect;
GDK_NOTE (EVENTS,
- g_print ("begin drag moveresize: "
+ g_print ("begin drag moveresize: window %p, toplevel %p, "
"op %u, edge %d, device %p, "
"button %d, coord %d:%d, time %u\n",
+ window, gdk_window_get_toplevel (window),
context->op, context->edge, context->device,
context->button, context->start_root_x,
context->start_root_y, context->timestamp));
@@ -2863,10 +2932,16 @@ gdk_win32_window_end_move_resize_drag (GdkWindow *window)
GdkW32DragMoveResizeContext *context = &impl->drag_move_resize_context;
context->op = GDK_WIN32_DRAGOP_NONE;
+
+ gdk_device_ungrab (context->device, GDK_CURRENT_TIME);
+
+ g_clear_object (&context->cursor);
+
GDK_NOTE (EVENTS,
- g_print ("end drag moveresize: "
+ g_print ("end drag moveresize: window %p, toplevel %p,"
"op %u, edge %d, device %p, "
"button %d, coord %d:%d, time %u\n",
+ window, gdk_window_get_toplevel (window),
context->op, context->edge, context->device,
context->button, context->start_root_x,
context->start_root_y, context->timestamp));
diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h
index 6389f7b..24e7d18 100644
--- a/gdk/win32/gdkwindow-win32.h
+++ b/gdk/win32/gdkwindow-win32.h
@@ -64,10 +64,15 @@ struct _GdkW32DragMoveResizeContext
/* The edge that was grabbed for resizing. Not used for moving. */
GdkWindowEdge edge;
- /* Not used */
+ /* The device used to initiate the op.
+ * We grab it at the beginning and ungrab it at the end.
+ */
GdkDevice *device;
- /* Not used */
+ /* The button pressed down to initiate the op.
+ * The op will be canceled only when *this* button
+ * is released.
+ */
gint button;
/* Initial cursor position when the operation began.
@@ -89,6 +94,9 @@ struct _GdkW32DragMoveResizeContext
* the window size and poistion to the native window.
*/
gboolean native_move_resize_pending;
+
+ /* The cursor we should use while the operation is running. */
+ GdkCursor *cursor;
};
typedef struct _GdkW32DragMoveResizeContext GdkW32DragMoveResizeContext;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]