Make DND work better with shaped windows
If mouse clicks go through, drag-and-drop should too... Fixes bug 608615.
This commit is contained in:
parent
0d94617935
commit
69aa7a6392
@ -280,10 +280,10 @@ gdk_display_open (const gchar *display_name)
|
|||||||
display_x11->have_shapes = FALSE;
|
display_x11->have_shapes = FALSE;
|
||||||
display_x11->have_input_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;
|
display_x11->have_shapes = TRUE;
|
||||||
#ifdef ShapeInput
|
#ifdef ShapeInput
|
||||||
if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
|
if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
|
||||||
display_x11->have_input_shapes = (maj == 1 && min >= 1);
|
display_x11->have_input_shapes = (maj == 1 && min >= 1);
|
||||||
#endif
|
#endif
|
||||||
|
@ -147,6 +147,7 @@ struct _GdkDisplayX11
|
|||||||
|
|
||||||
guint have_shapes : 1;
|
guint have_shapes : 1;
|
||||||
guint have_input_shapes : 1;
|
guint have_input_shapes : 1;
|
||||||
|
gint shape_event_base;
|
||||||
|
|
||||||
/* Alpha mask picture format */
|
/* Alpha mask picture format */
|
||||||
XRenderPictFormat *mask_format;
|
XRenderPictFormat *mask_format;
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/extensions/shape.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "gdk.h" /* For gdk_flush() */
|
#include "gdk.h" /* For gdk_flush() */
|
||||||
@ -53,6 +55,9 @@ typedef struct {
|
|||||||
guint32 xid;
|
guint32 xid;
|
||||||
gint x, y, width, height;
|
gint x, y, width, height;
|
||||||
gboolean mapped;
|
gboolean mapped;
|
||||||
|
gboolean shape_selected;
|
||||||
|
gboolean shape_valid;
|
||||||
|
GdkRegion *shape;
|
||||||
} GdkCacheChild;
|
} GdkCacheChild;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -308,6 +313,23 @@ precache_target_list (GdkDragContext *context)
|
|||||||
|
|
||||||
/* Utility functions */
|
/* 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
|
static void
|
||||||
gdk_window_cache_add (GdkWindowCache *cache,
|
gdk_window_cache_add (GdkWindowCache *cache,
|
||||||
guint32 xid,
|
guint32 xid,
|
||||||
@ -322,12 +344,50 @@ gdk_window_cache_add (GdkWindowCache *cache,
|
|||||||
child->width = width;
|
child->width = width;
|
||||||
child->height = height;
|
child->height = height;
|
||||||
child->mapped = mapped;
|
child->mapped = mapped;
|
||||||
|
child->shape_selected = FALSE;
|
||||||
|
child->shape_valid = FALSE;
|
||||||
|
child->shape = NULL;
|
||||||
|
|
||||||
cache->children = g_list_prepend (cache->children, child);
|
cache->children = g_list_prepend (cache->children, child);
|
||||||
g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid),
|
g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid),
|
||||||
cache->children);
|
cache->children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static GdkFilterReturn
|
||||||
gdk_window_cache_filter (GdkXEvent *xev,
|
gdk_window_cache_filter (GdkXEvent *xev,
|
||||||
GdkEvent *event,
|
GdkEvent *event,
|
||||||
@ -403,10 +463,13 @@ gdk_window_cache_filter (GdkXEvent *xev,
|
|||||||
GUINT_TO_POINTER (xdwe->window));
|
GUINT_TO_POINTER (xdwe->window));
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
|
GdkCacheChild *child = node->data;
|
||||||
|
|
||||||
g_hash_table_remove (cache->child_hash,
|
g_hash_table_remove (cache->child_hash,
|
||||||
GUINT_TO_POINTER (xdwe->window));
|
GUINT_TO_POINTER (xdwe->window));
|
||||||
cache->children = g_list_remove_link (cache->children, node);
|
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);
|
g_list_free_1 (node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -434,7 +497,7 @@ gdk_window_cache_filter (GdkXEvent *xev,
|
|||||||
|
|
||||||
node = g_hash_table_lookup (cache->child_hash,
|
node = g_hash_table_lookup (cache->child_hash,
|
||||||
GUINT_TO_POINTER (xume->window));
|
GUINT_TO_POINTER (xume->window));
|
||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
GdkCacheChild *child = node->data;
|
GdkCacheChild *child = node->data;
|
||||||
child->mapped = FALSE;
|
child->mapped = FALSE;
|
||||||
@ -486,6 +549,7 @@ gdk_window_cache_new (GdkScreen *screen)
|
|||||||
XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
|
XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
|
||||||
result->old_event_mask | SubstructureNotifyMask);
|
result->old_event_mask | SubstructureNotifyMask);
|
||||||
gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
|
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),
|
if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
|
||||||
GDK_WINDOW_XWINDOW (root_window),
|
GDK_WINDOW_XWINDOW (root_window),
|
||||||
@ -514,14 +578,57 @@ gdk_window_cache_destroy (GdkWindowCache *cache)
|
|||||||
GDK_WINDOW_XWINDOW (root_window),
|
GDK_WINDOW_XWINDOW (root_window),
|
||||||
cache->old_event_mask);
|
cache->old_event_mask);
|
||||||
gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
|
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_list_free (cache->children);
|
||||||
g_hash_table_destroy (cache->child_hash);
|
g_hash_table_destroy (cache->child_hash);
|
||||||
|
|
||||||
g_free (cache);
|
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
|
static Window
|
||||||
get_client_window_at_coords_recurse (GdkDisplay *display,
|
get_client_window_at_coords_recurse (GdkDisplay *display,
|
||||||
Window win,
|
Window win,
|
||||||
@ -594,19 +701,28 @@ get_client_window_at_coords (GdkWindowCache *cache,
|
|||||||
GdkCacheChild *child = tmp_list->data;
|
GdkCacheChild *child = tmp_list->data;
|
||||||
|
|
||||||
if ((child->xid != ignore) && (child->mapped))
|
if ((child->xid != ignore) && (child->mapped))
|
||||||
{
|
{
|
||||||
if ((x_root >= child->x) && (x_root < child->x + child->width) &&
|
if ((x_root >= child->x) && (x_root < child->x + child->width) &&
|
||||||
(y_root >= child->y) && (y_root < child->y + child->height))
|
(y_root >= child->y) && (y_root < child->y + child->height))
|
||||||
{
|
{
|
||||||
retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen),
|
GdkDisplay *display = gdk_screen_get_display (cache->screen);
|
||||||
child->xid, TRUE,
|
|
||||||
x_root - child->x,
|
if (!is_pointer_within_shape (display, child,
|
||||||
y_root - child->y);
|
x_root - child->x,
|
||||||
if (!retval)
|
y_root - child->y))
|
||||||
retval = child->xid;
|
{
|
||||||
}
|
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;
|
tmp_list = tmp_list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +138,10 @@ void _gdk_x11_window_queue_translation (GdkWindow *window,
|
|||||||
void _gdk_selection_window_destroyed (GdkWindow *window);
|
void _gdk_selection_window_destroyed (GdkWindow *window);
|
||||||
gboolean _gdk_selection_filter_clear_event (XSelectionClearEvent *event);
|
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,
|
void _gdk_region_get_xrectangles (const GdkRegion *region,
|
||||||
gint x_offset,
|
gint x_offset,
|
||||||
gint y_offset,
|
gint y_offset,
|
||||||
|
@ -4593,10 +4593,10 @@ gdk_window_set_functions (GdkWindow *window,
|
|||||||
gdk_window_set_mwm_hints (window, &hints);
|
gdk_window_set_mwm_hints (window, &hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkRegion *
|
GdkRegion *
|
||||||
xwindow_get_shape (Display *xdisplay,
|
_xwindow_get_shape (Display *xdisplay,
|
||||||
Window window,
|
Window window,
|
||||||
gint shape_type)
|
gint shape_type)
|
||||||
{
|
{
|
||||||
GdkRegion *shape;
|
GdkRegion *shape;
|
||||||
GdkRectangle *rl;
|
GdkRectangle *rl;
|
||||||
@ -4658,7 +4658,7 @@ _gdk_windowing_get_shape_for_mask (GdkBitmap *mask)
|
|||||||
GDK_PIXMAP_XID (mask),
|
GDK_PIXMAP_XID (mask),
|
||||||
ShapeSet);
|
ShapeSet);
|
||||||
|
|
||||||
region = xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display),
|
region = _xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display),
|
||||||
window, ShapeBounding);
|
window, ShapeBounding);
|
||||||
|
|
||||||
XDestroyWindow (GDK_DISPLAY_XDISPLAY (display),
|
XDestroyWindow (GDK_DISPLAY_XDISPLAY (display),
|
||||||
@ -4672,7 +4672,7 @@ _gdk_windowing_window_get_shape (GdkWindow *window)
|
|||||||
{
|
{
|
||||||
if (!GDK_WINDOW_DESTROYED (window) &&
|
if (!GDK_WINDOW_DESTROYED (window) &&
|
||||||
gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (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);
|
GDK_WINDOW_XID (window), ShapeBounding);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -4684,7 +4684,7 @@ _gdk_windowing_window_get_input_shape (GdkWindow *window)
|
|||||||
#if defined(ShapeInput)
|
#if defined(ShapeInput)
|
||||||
if (!GDK_WINDOW_DESTROYED (window) &&
|
if (!GDK_WINDOW_DESTROYED (window) &&
|
||||||
gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (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),
|
GDK_WINDOW_XID (window),
|
||||||
ShapeInput);
|
ShapeInput);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user