handle the client having a shape mask, fixes #101806

2003-01-05  Havoc Pennington  <hp@pobox.com>

	* src/frames.c (meta_frames_apply_shapes): handle
	the client having a shape mask, fixes #101806

	* src/core.c (meta_core_get_client_xwindow): new function

	* src/frame.c, src/frame.h: keep a flag for whether we need to
	update the frame shape

	* src/window.c (meta_window_new): select for ShapeNotify

	* src/display.h, src/display.c: actually query the shape
	extension, instead of just using it all over the place.

	* src/prefs.c (update_application_based): don't let people turn on
	application_based, as it just causes funky bugs. We can reenable
	the pref when/if it ever does something useful.
This commit is contained in:
Havoc Pennington 2003-01-05 07:51:02 +00:00 committed by Havoc Pennington
parent f8b2f6ca5c
commit 6cfcc01334
16 changed files with 369 additions and 51 deletions

View File

@ -1,3 +1,22 @@
2003-01-05 Havoc Pennington <hp@pobox.com>
* src/frames.c (meta_frames_apply_shapes): handle
the client having a shape mask, fixes #101806
* src/core.c (meta_core_get_client_xwindow): new function
* src/frame.c, src/frame.h: keep a flag for whether we need to
update the frame shape
* src/window.c (meta_window_new): select for ShapeNotify
* src/display.h, src/display.c: actually query the shape
extension, instead of just using it all over the place.
* src/prefs.c (update_application_based): don't let people turn on
application_based, as it just causes funky bugs. We can reenable
the pref when/if it ever does something useful.
2003-01-03 Havoc Pennington <hp@redhat.com>
* src/display.c: include the Xrandr header file

View File

@ -46,6 +46,22 @@ meta_core_get_client_size (Display *xdisplay,
*height = window->rect.height;
}
Window
meta_core_get_client_xwindow (Display *xdisplay,
Window frame_xwindow)
{
MetaDisplay *display;
MetaWindow *window;
display = meta_display_for_x_display (xdisplay);
window = meta_display_lookup_x_window (display, frame_xwindow);
if (window == NULL || window->frame == NULL)
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
return window->xwindow;
}
MetaFrameFlags
meta_core_get_frame_flags (Display *xdisplay,
Window frame_xwindow)

View File

@ -31,6 +31,9 @@ void meta_core_get_client_size (Display *xdisplay,
int *width,
int *height);
Window meta_core_get_client_xwindow (Display *xdisplay,
Window frame_xwindow);
MetaFrameFlags meta_core_get_frame_flags (Display *xdisplay,
Window frame_xwindow);
MetaFrameType meta_core_get_frame_type (Display *xdisplay,

View File

@ -45,6 +45,9 @@
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
#endif
#include <string.h>
#define USE_GDK_DISPLAY
@ -490,6 +493,27 @@ meta_display_open (const char *name)
meta_verbose ("Not compiled with Xsync support\n");
#endif /* !HAVE_XSYNC */
#ifdef HAVE_SHAPE
{
display->shape_error_base = 0;
display->shape_event_base = 0;
if (!XShapeQueryExtension (display->xdisplay,
&display->shape_event_base,
&display->shape_error_base))
{
display->shape_error_base = 0;
display->shape_event_base = 0;
}
meta_verbose ("Attempted to init Shape, found error base %d event base %d\n",
display->shape_error_base,
display->shape_event_base);
}
#else /* HAVE_SHAPE */
meta_verbose ("Not compiled with Shape support\n");
#endif /* !HAVE_SHAPE */
screens = NULL;
#ifdef HAVE_GTK_MULTIHEAD
@ -1190,6 +1214,56 @@ event_callback (XEvent *event,
}
#endif /* HAVE_XSYNC */
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (display) &&
event->type == (display->shape_event_base + ShapeNotify))
{
filter_out_event = TRUE; /* GTK doesn't want to see this really */
if (window && !frame_was_receiver)
{
XShapeEvent *sev = (XShapeEvent*) event;
if (sev->kind == ShapeBounding)
{
if (sev->shaped && !window->has_shape)
{
window->has_shape = TRUE;
meta_topic (META_DEBUG_SHAPES,
"Window %s now has a shape\n",
window->desc);
}
else if (!sev->shaped && window->has_shape)
{
window->has_shape = FALSE;
meta_topic (META_DEBUG_SHAPES,
"Window %s no longer has a shape\n",
window->desc);
}
else
{
meta_topic (META_DEBUG_SHAPES,
"Window %s shape changed\n",
window->desc);
}
if (window->frame)
{
window->frame->need_reapply_frame_shape = TRUE;
meta_window_queue_move_resize (window);
}
}
}
else
{
meta_topic (META_DEBUG_SHAPES,
"ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n",
window ? window->desc : "(none)",
frame_was_receiver);
}
}
#endif /* HAVE_SHAPE */
switch (event->type)
{
case KeyPress:
@ -1902,6 +1976,15 @@ event_get_modified_window (MetaDisplay *display,
return None;
default:
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (display) &&
event->type == (display->shape_event_base + ShapeNotify))
{
XShapeEvent *sev = (XShapeEvent*) event;
return sev->window;
}
#endif
return None;
}
}
@ -2360,6 +2443,27 @@ meta_spew_event (MetaDisplay *display,
}
else
#endif /* HAVE_XSYNC */
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (display) &&
event->type == (display->shape_event_base + ShapeNotify))
{
XShapeEvent *sev = (XShapeEvent*) event;
name = "ShapeNotify";
extra =
g_strdup_printf ("kind: %s "
"x: %d y: %d w: %d h: %d "
"shaped: %d",
sev->kind == ShapeBounding ?
"ShapeBounding" :
(sev->kind == ShapeClip ?
"ShapeClip" : "(unknown)"),
sev->x, sev->y, sev->width, sev->height,
sev->shaped);
}
else
#endif /* HAVE_SHAPE */
{
name = "(Unknown event)";
extra = g_strdup_printf ("type: %d", event->xany.type);
@ -3046,19 +3150,9 @@ meta_display_queue_retheme_all_windows (MetaDisplay *display)
meta_window_queue_move_resize (window);
if (window->frame)
{
window->frame->need_reapply_frame_shape = TRUE;
meta_frame_queue_draw (window->frame);
/* FIXME this sucks and is slooooooooow. Do it in the idle with the
* redraw or the window resize.
*/
#if 0
/* in case the theme doesn't affect the frame size */
meta_ui_apply_frame_shape (window->screen->ui,
window->frame->xwindow,
window->frame->rect.width,
window->frame->rect.height);
#endif
}
tmp = tmp->next;

View File

@ -296,6 +296,13 @@ struct _MetaDisplay
#else
#define META_DISPLAY_HAS_XSYNC(display) FALSE
#endif
#ifdef HAVE_SHAPE
int shape_event_base;
int shape_error_base;
#define META_DISPLAY_HAS_SHAPE(display) ((display)->shape_event_base != 0)
#else
#define META_DISPLAY_HAS_SHAPE(display) FALSE
#endif
};
gboolean meta_display_open (const char *name);

View File

@ -58,6 +58,7 @@ meta_window_ensure_frame (MetaWindow *window)
frame->current_cursor = 0;
frame->mapped = FALSE;
frame->need_reapply_frame_shape = TRUE;
attrs.event_mask = EVENT_MASK;
@ -144,7 +145,9 @@ meta_window_ensure_frame (MetaWindow *window)
meta_ui_apply_frame_shape (frame->window->screen->ui,
frame->xwindow,
frame->rect.width,
frame->rect.height);
frame->rect.height,
frame->window->has_shape);
frame->need_reapply_frame_shape = FALSE;
meta_display_ungrab (window->display);
}
@ -277,6 +280,20 @@ meta_frame_calc_geometry (MetaFrame *frame,
*geomp = geom;
}
static void
update_shape (MetaFrame *frame)
{
if (frame->need_reapply_frame_shape)
{
meta_ui_apply_frame_shape (frame->window->screen->ui,
frame->xwindow,
frame->rect.width,
frame->rect.height,
frame->window->has_shape);
frame->need_reapply_frame_shape = FALSE;
}
}
void
meta_frame_sync_to_window (MetaFrame *frame,
int resize_gravity,
@ -284,7 +301,10 @@ meta_frame_sync_to_window (MetaFrame *frame,
gboolean need_resize)
{
if (!(need_move || need_resize))
return;
{
update_shape (frame);
return;
}
meta_topic (META_DEBUG_GEOMETRY,
"Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n",
@ -301,19 +321,18 @@ meta_frame_sync_to_window (MetaFrame *frame,
frame->rect.width,
frame->rect.height);
/* Done before the window resize, because doing it before means
* part of the window being resized becomes unshaped, which may
* be sort of hard to see with bg = None. If we did it after
* window resize, part of the window being resized would become
* shaped, which might be more visible.
*/
meta_ui_apply_frame_shape (frame->window->screen->ui,
frame->xwindow,
frame->rect.width,
frame->rect.height);
/* we need new shape if we're resized */
frame->need_reapply_frame_shape = TRUE;
}
/* Done before the window resize, because doing it before means
* part of the window being resized becomes unshaped, which may
* be sort of hard to see with bg = None. If we did it after
* window resize, part of the window being resized would become
* shaped, which might be more visible.
*/
update_shape (frame);
if (need_move && need_resize)
XMoveResizeWindow (frame->window->display->xdisplay,
frame->xwindow,

View File

@ -57,6 +57,7 @@ struct _MetaFrame
int bottom_height;
guint mapped : 1;
guint need_reapply_frame_shape : 1;
};
void meta_window_ensure_frame (MetaWindow *window);

View File

@ -495,6 +495,7 @@ meta_frames_manage_window (MetaFrames *frames,
frame->text_height = -1;
frame->title = NULL;
frame->expose_delayed = FALSE;
frame->shape_applied = FALSE;
frame->prelit_control = META_FRAME_CONTROL_NONE;
meta_core_grab_buttons (gdk_display, frame->xwindow);
@ -664,7 +665,8 @@ void
meta_frames_apply_shapes (MetaFrames *frames,
Window xwindow,
int new_window_width,
int new_window_height)
int new_window_height,
gboolean window_has_shape)
{
#ifdef HAVE_SHAPE
/* Apply shapes as if window had new_window_width, new_window_height */
@ -685,10 +687,25 @@ meta_frames_apply_shapes (MetaFrames *frames,
if (!(fgeom.top_left_corner_rounded ||
fgeom.top_right_corner_rounded ||
fgeom.bottom_left_corner_rounded ||
fgeom.bottom_right_corner_rounded))
fgeom.bottom_right_corner_rounded ||
window_has_shape))
{
XShapeCombineMask (gdk_display, frame->xwindow,
ShapeBounding, 0, 0, None, ShapeSet);
if (frame->shape_applied)
{
meta_topic (META_DEBUG_SHAPES,
"Unsetting shape mask on frame 0x%lx\n",
frame->xwindow);
XShapeCombineMask (gdk_display, frame->xwindow,
ShapeBounding, 0, 0, None, ShapeSet);
frame->shape_applied = FALSE;
}
else
{
meta_topic (META_DEBUG_SHAPES,
"Frame 0x%lx still doesn't need a shape mask\n",
frame->xwindow);
}
return; /* nothing to do */
}
@ -804,11 +821,98 @@ meta_frames_apply_shapes (MetaFrames *frames,
XSubtractRegion (window_xregion, corners_xregion, window_xregion);
XShapeCombineRegion (gdk_display, frame->xwindow,
ShapeBounding, 0, 0, window_xregion, ShapeSet);
XDestroyRegion (corners_xregion);
if (window_has_shape)
{
/* The client window is oclock or something and has a shape
* mask. To avoid a round trip to get its shape region, we
* create a fake window that's never mapped, build up our shape
* on that, then combine. Wasting the window is assumed cheaper
* than a round trip, but who really knows for sure.
*/
XSetWindowAttributes attrs;
Window shape_window;
Window client_window;
Region client_xregion;
GdkScreen *screen;
int screen_number;
meta_topic (META_DEBUG_SHAPES,
"Frame 0x%lx needs to incorporate client shape\n",
frame->xwindow);
screen = gtk_widget_get_screen (GTK_WIDGET (frames));
screen_number = gdk_x11_screen_get_screen_number (screen);
attrs.override_redirect = True;
shape_window = XCreateWindow (gdk_display,
RootWindow (gdk_display, screen_number),
-5000, -5000,
new_window_width,
new_window_height,
0,
CopyFromParent,
CopyFromParent,
CopyFromParent,
CWOverrideRedirect,
&attrs);
/* Copy the client's shape to the temporary shape_window */
client_window = meta_core_get_client_xwindow (gdk_display,
frame->xwindow);
XShapeCombineShape (gdk_display, shape_window, ShapeBounding,
fgeom.left_width,
fgeom.top_height,
client_window,
ShapeBounding,
ShapeSet);
/* Punch the client area out of the normal frame shape,
* then union it with the shape_window's existing shape
*/
client_xregion = XCreateRegion ();
xrect.x = fgeom.left_width;
xrect.y = fgeom.top_height;
xrect.width = new_window_width - fgeom.right_width - xrect.x;
xrect.height = new_window_height - fgeom.bottom_height - xrect.y;
XUnionRectWithRegion (&xrect, client_xregion, client_xregion);
XSubtractRegion (window_xregion, client_xregion, window_xregion);
XDestroyRegion (client_xregion);
XShapeCombineRegion (gdk_display, shape_window,
ShapeBounding, 0, 0, window_xregion, ShapeUnion);
/* Now copy shape_window shape to the real frame */
XShapeCombineShape (gdk_display, frame->xwindow, ShapeBounding,
0, 0,
shape_window,
ShapeBounding,
ShapeSet);
XDestroyWindow (gdk_display, shape_window);
}
else
{
/* No shape on the client, so just do simple stuff */
meta_topic (META_DEBUG_SHAPES,
"Frame 0x%lx has shaped corners\n",
frame->xwindow);
XShapeCombineRegion (gdk_display, frame->xwindow,
ShapeBounding, 0, 0, window_xregion, ShapeSet);
}
frame->shape_applied = TRUE;
XDestroyRegion (window_xregion);
XDestroyRegion (corners_xregion);
#endif
}

View File

@ -72,6 +72,7 @@ struct _MetaUIFrame
int text_height;
char *title; /* NULL once we have a layout */
guint expose_delayed : 1;
guint shape_applied : 1;
/* FIXME get rid of this, it can just be in the MetaFrames struct */
MetaFrameControl prelit_control;
@ -127,7 +128,8 @@ void meta_frames_unflicker_bg (MetaFrames *frames,
void meta_frames_apply_shapes (MetaFrames *frames,
Window xwindow,
int new_window_width,
int new_window_height);
int new_window_height,
gboolean window_has_shape);
void meta_frames_queue_draw (MetaFrames *frames,
Window xwindow);

View File

@ -1028,7 +1028,12 @@ update_application_based (gboolean value)
{
gboolean old = application_based;
/* DISABLE application_based feature for now */
#if 0
application_based = value;
#else
application_based = FALSE;
#endif
return old != application_based;
}

View File

@ -238,12 +238,15 @@ meta_ui_reset_frame_bg (MetaUI *ui,
}
void
meta_ui_apply_frame_shape (MetaUI *ui,
Window xwindow,
int new_window_width,
int new_window_height)
meta_ui_apply_frame_shape (MetaUI *ui,
Window xwindow,
int new_window_width,
int new_window_height,
gboolean window_has_shape)
{
meta_frames_apply_shapes (ui->frames, xwindow, new_window_width, new_window_height);
meta_frames_apply_shapes (ui->frames, xwindow,
new_window_width, new_window_height,
window_has_shape);
}
void

View File

@ -73,10 +73,11 @@ void meta_ui_unflicker_frame_bg (MetaUI *ui,
void meta_ui_reset_frame_bg (MetaUI *ui,
Window xwindow);
void meta_ui_apply_frame_shape (MetaUI *ui,
Window xwindow,
int new_window_width,
int new_window_height);
void meta_ui_apply_frame_shape (MetaUI *ui,
Window xwindow,
int new_window_width,
int new_window_height,
gboolean window_has_shape);
void meta_ui_queue_frame_draw (MetaUI *ui,
Window xwindow);

View File

@ -282,6 +282,8 @@ topic_name (MetaDebugTopic topic)
return "GROUPS";
case META_DEBUG_RESIZING:
return "RESIZING";
case META_DEBUG_SHAPES:
return "SHAPES";
}
return "Window manager";

View File

@ -65,7 +65,8 @@ typedef enum
META_DEBUG_STARTUP = 1 << 15,
META_DEBUG_PREFS = 1 << 16,
META_DEBUG_GROUPS = 1 << 17,
META_DEBUG_RESIZING = 1 << 18
META_DEBUG_RESIZING = 1 << 18,
META_DEBUG_SHAPES = 1 << 19
} MetaDebugTopic;

View File

@ -41,6 +41,10 @@
#include <X11/Xatom.h>
#include <string.h>
#ifdef HAVE_SHAPE
#include <X11/extensions/shape.h>
#endif
typedef enum
{
META_IS_CONFIGURE_REQUEST = 1 << 0,
@ -159,9 +163,11 @@ meta_window_new (MetaDisplay *display,
GSList *tmp;
MetaWorkspace *space;
gulong existing_wm_state;
gulong event_mask;
#define N_INITIAL_PROPS 10
Atom initial_props[N_INITIAL_PROPS];
int i;
gboolean has_shape;
g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props));
@ -241,11 +247,36 @@ meta_window_new (MetaDisplay *display,
XAddToSaveSet (display->xdisplay, xwindow);
XSelectInput (display->xdisplay, xwindow,
PropertyChangeMask |
EnterWindowMask | LeaveWindowMask |
FocusChangeMask |
ColormapChangeMask);
event_mask =
PropertyChangeMask | EnterWindowMask | LeaveWindowMask |
FocusChangeMask | ColormapChangeMask;
XSelectInput (display->xdisplay, xwindow, event_mask);
has_shape = FALSE;
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (display))
{
int x_bounding, y_bounding, x_clip, y_clip;
unsigned w_bounding, h_bounding, w_clip, h_clip;
int bounding_shaped, clip_shaped;
XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
XShapeQueryExtents (display->xdisplay, xwindow,
&bounding_shaped, &x_bounding, &y_bounding,
&w_bounding, &h_bounding,
&clip_shaped, &x_clip, &y_clip,
&w_clip, &h_clip);
has_shape = bounding_shaped != FALSE;
meta_topic (META_DEBUG_SHAPES,
"Window has_shape = %d extents %d,%d %d x %d\n",
has_shape, x_bounding, y_bounding,
w_bounding, h_bounding);
}
#endif
/* Get rid of any borders */
if (attrs.border_width != 0)
@ -312,6 +343,8 @@ meta_window_new (MetaDisplay *display,
/* avoid tons of stack updates */
meta_stack_freeze (window->screen->stack);
window->has_shape = has_shape;
/* Remember this rect is the actual window size */
window->rect.x = attrs.x;
window->rect.y = attrs.y;
@ -978,6 +1011,11 @@ meta_window_free (MetaWindow *window)
window->xwindow,
NoEventMask);
#ifdef HAVE_SHAPE
if (META_DISPLAY_HAS_SHAPE (window->display))
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
#endif
meta_error_trap_pop (window->display, FALSE);
if (window->icon)

View File

@ -219,6 +219,9 @@ struct _MetaWindow
guint using_net_wm_name : 1; /* vs. plain wm_name */
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
/* has a shape mask */
guint has_shape : 1;
#ifdef HAVE_XSYNC
/* XSync update counter */
XSyncCounter update_counter;