[gtk+] Make DND work better with shaped windows
- From: Matthias Clasen <matthiasc src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gtk+] Make DND work better with shaped windows
- Date: Fri, 5 Feb 2010 00:20:16 +0000 (UTC)
commit 69aa7a6392f2ed5d20483b01c0183a3b0fece0be
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Feb 4 19:15:54 2010 -0500
Make DND work better with shaped windows
If mouse clicks go through, drag-and-drop should too...
Fixes bug 608615.
gdk/x11/gdkdisplay-x11.c | 4 +-
gdk/x11/gdkdisplay-x11.h | 1 +
gdk/x11/gdkdnd-x11.c | 148 +++++++++++++++++++++++++++++++++++++++++-----
gdk/x11/gdkprivate-x11.h | 4 +
gdk/x11/gdkwindow-x11.c | 14 ++--
5 files changed, 146 insertions(+), 25 deletions(-)
---
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 2b10a93..c0cbc99 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -280,10 +280,10 @@ gdk_display_open (const gchar *display_name)
display_x11->have_shapes = FALSE;
display_x11->have_input_shapes = FALSE;
- if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &ignore, &ignore))
+ if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &display_x11->shape_event_base, &ignore))
{
display_x11->have_shapes = TRUE;
-#ifdef ShapeInput
+#ifdef ShapeInput
if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
display_x11->have_input_shapes = (maj == 1 && min >= 1);
#endif
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index 2873c2d..f8a55d0 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -147,6 +147,7 @@ struct _GdkDisplayX11
guint have_shapes : 1;
guint have_input_shapes : 1;
+ gint shape_event_base;
/* Alpha mask picture format */
XRenderPictFormat *mask_format;
diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c
index 938e7e1..2da9567 100644
--- a/gdk/x11/gdkdnd-x11.c
+++ b/gdk/x11/gdkdnd-x11.c
@@ -27,6 +27,8 @@
#include "config.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+
#include <string.h>
#include "gdk.h" /* For gdk_flush() */
@@ -53,6 +55,9 @@ typedef struct {
guint32 xid;
gint x, y, width, height;
gboolean mapped;
+ gboolean shape_selected;
+ gboolean shape_valid;
+ GdkRegion *shape;
} GdkCacheChild;
typedef struct {
@@ -309,6 +314,23 @@ precache_target_list (GdkDragContext *context)
/* Utility functions */
static void
+free_cache_child (GdkCacheChild *child,
+ GdkDisplay *display)
+{
+ if (child->shape)
+ gdk_region_destroy (child->shape);
+
+ if (child->shape_selected && display)
+ {
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+ XShapeSelectInput (display_x11->xdisplay, child->xid, 0);
+ }
+
+ g_free (child);
+}
+
+static void
gdk_window_cache_add (GdkWindowCache *cache,
guint32 xid,
gint x, gint y, gint width, gint height,
@@ -322,6 +344,9 @@ gdk_window_cache_add (GdkWindowCache *cache,
child->width = width;
child->height = height;
child->mapped = mapped;
+ child->shape_selected = FALSE;
+ child->shape_valid = FALSE;
+ child->shape = NULL;
cache->children = g_list_prepend (cache->children, child);
g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid),
@@ -329,6 +354,41 @@ gdk_window_cache_add (GdkWindowCache *cache,
}
static GdkFilterReturn
+gdk_window_cache_shape_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xevent = (XEvent *)xev;
+ GdkWindowCache *cache = data;
+
+ GdkDisplayX11 *display = GDK_DISPLAY_X11 (gdk_screen_get_display (cache->screen));
+
+ if (display->have_shapes &&
+ xevent->type == display->shape_event_base + ShapeNotify)
+ {
+ XShapeEvent *xse = (XShapeEvent*)xevent;
+ GList *node;
+
+ node = g_hash_table_lookup (cache->child_hash,
+ GUINT_TO_POINTER (xse->window));
+ if (node)
+ {
+ GdkCacheChild *child = node->data;
+ child->shape_valid = FALSE;
+ if (child->shape)
+ {
+ gdk_region_destroy (child->shape);
+ child->shape = NULL;
+ }
+ }
+
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static GdkFilterReturn
gdk_window_cache_filter (GdkXEvent *xev,
GdkEvent *event,
gpointer data)
@@ -403,10 +463,13 @@ gdk_window_cache_filter (GdkXEvent *xev,
GUINT_TO_POINTER (xdwe->window));
if (node)
{
+ GdkCacheChild *child = node->data;
+
g_hash_table_remove (cache->child_hash,
GUINT_TO_POINTER (xdwe->window));
cache->children = g_list_remove_link (cache->children, node);
- g_free (node->data);
+ /* window is destroyed, no need to disable ShapeNotify */
+ free_cache_child (child, NULL);
g_list_free_1 (node);
}
break;
@@ -434,7 +497,7 @@ gdk_window_cache_filter (GdkXEvent *xev,
node = g_hash_table_lookup (cache->child_hash,
GUINT_TO_POINTER (xume->window));
- if (node)
+ if (node)
{
GdkCacheChild *child = node->data;
child->mapped = FALSE;
@@ -486,6 +549,7 @@ gdk_window_cache_new (GdkScreen *screen)
XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
result->old_event_mask | SubstructureNotifyMask);
gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
+ gdk_window_add_filter (NULL, gdk_window_cache_shape_filter, result);
if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
GDK_WINDOW_XWINDOW (root_window),
@@ -514,14 +578,57 @@ gdk_window_cache_destroy (GdkWindowCache *cache)
GDK_WINDOW_XWINDOW (root_window),
cache->old_event_mask);
gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
+ gdk_window_remove_filter (NULL, gdk_window_cache_shape_filter, cache);
- g_list_foreach (cache->children, (GFunc)g_free, NULL);
+ g_list_foreach (cache->children, (GFunc)free_cache_child,
+ gdk_screen_get_display (cache->screen));
g_list_free (cache->children);
g_hash_table_destroy (cache->child_hash);
g_free (cache);
}
+static gboolean
+is_pointer_within_shape (GdkDisplay *display,
+ GdkCacheChild *child,
+ gint x_pos,
+ gint y_pos)
+{
+ if (!child->shape_selected)
+ {
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+ XShapeSelectInput (display_x11->xdisplay, child->xid, ShapeNotifyMask);
+ child->shape_selected = TRUE;
+ }
+ if (!child->shape_valid)
+ {
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+ GdkRegion *input_shape;
+
+ child->shape = _xwindow_get_shape (display_x11->xdisplay,
+ child->xid, ShapeBounding);
+#ifdef ShapeInput
+ input_shape = _xwindow_get_shape (display_x11->xdisplay,
+ child->xid, ShapeInput);
+ if (child->shape && input_shape)
+ {
+ gdk_region_intersect (child->shape, input_shape);
+ gdk_region_destroy (input_shape);
+ }
+ else if (input_shape)
+ {
+ child->shape = input_shape;
+ }
+#endif
+
+ child->shape_valid = TRUE;
+ }
+
+ return child->shape == NULL ||
+ gdk_region_point_in (child->shape, x_pos, y_pos);
+}
+
static Window
get_client_window_at_coords_recurse (GdkDisplay *display,
Window win,
@@ -594,19 +701,28 @@ get_client_window_at_coords (GdkWindowCache *cache,
GdkCacheChild *child = tmp_list->data;
if ((child->xid != ignore) && (child->mapped))
- {
- if ((x_root >= child->x) && (x_root < child->x + child->width) &&
- (y_root >= child->y) && (y_root < child->y + child->height))
- {
- retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen),
- child->xid, TRUE,
- x_root - child->x,
- y_root - child->y);
- if (!retval)
- retval = child->xid;
- }
-
- }
+ {
+ if ((x_root >= child->x) && (x_root < child->x + child->width) &&
+ (y_root >= child->y) && (y_root < child->y + child->height))
+ {
+ GdkDisplay *display = gdk_screen_get_display (cache->screen);
+
+ if (!is_pointer_within_shape (display, child,
+ x_root - child->x,
+ y_root - child->y))
+ {
+ tmp_list = tmp_list->next;
+ continue;
+ }
+
+ retval = get_client_window_at_coords_recurse (display,
+ child->xid, TRUE,
+ x_root - child->x,
+ y_root - child->y);
+ if (!retval)
+ retval = child->xid;
+ }
+ }
tmp_list = tmp_list->next;
}
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index bfbf3d9..5eaf188 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -138,6 +138,10 @@ void _gdk_x11_window_queue_translation (GdkWindow *window,
void _gdk_selection_window_destroyed (GdkWindow *window);
gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event);
+GdkRegion* _xwindow_get_shape (Display *xdisplay,
+ Window window,
+ gint shape_type);
+
void _gdk_region_get_xrectangles (const GdkRegion *region,
gint x_offset,
gint y_offset,
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 9c46716..c6d608c 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -4593,10 +4593,10 @@ gdk_window_set_functions (GdkWindow *window,
gdk_window_set_mwm_hints (window, &hints);
}
-static GdkRegion *
-xwindow_get_shape (Display *xdisplay,
- Window window,
- gint shape_type)
+GdkRegion *
+_xwindow_get_shape (Display *xdisplay,
+ Window window,
+ gint shape_type)
{
GdkRegion *shape;
GdkRectangle *rl;
@@ -4658,7 +4658,7 @@ _gdk_windowing_get_shape_for_mask (GdkBitmap *mask)
GDK_PIXMAP_XID (mask),
ShapeSet);
- region = xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display),
+ region = _xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display),
window, ShapeBounding);
XDestroyWindow (GDK_DISPLAY_XDISPLAY (display),
@@ -4672,7 +4672,7 @@ _gdk_windowing_window_get_shape (GdkWindow *window)
{
if (!GDK_WINDOW_DESTROYED (window) &&
gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
- return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
+ return _xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window), ShapeBounding);
return NULL;
@@ -4684,7 +4684,7 @@ _gdk_windowing_window_get_input_shape (GdkWindow *window)
#if defined(ShapeInput)
if (!GDK_WINDOW_DESTROYED (window) &&
gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
- return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
+ return _xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
ShapeInput);
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]