summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIain Holmes <iain@src.gnome.org>2007-11-26 00:55:26 +0000
committerIain Holmes <iain@src.gnome.org>2007-11-26 00:55:26 +0000
commitded388770eca5514c6ad4cd6a570e694045076a1 (patch)
treeeb7ffdbc24501b89592096661a3214c3a4c1e014
parent94f5bbd000ad74103157fa8c12fea69ff7f3794f (diff)
downloadmetacity-ded388770eca5514c6ad4cd6a570e694045076a1.tar.gz
Only draw dock shadows on the desktop.
Add long explanations on how compositing works svn path=/branches/iains-blingtastic-bucket-o-bling/; revision=3438
-rw-r--r--src/compositor.c106
1 files changed, 101 insertions, 5 deletions
diff --git a/src/compositor.c b/src/compositor.c
index 87001808..f0354c36 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -96,6 +96,8 @@ typedef struct _MetaCompScreen
guint overlays;
gboolean compositor_active;
gboolean clip_changed;
+
+ GList *dock_windows;
} MetaCompScreen;
typedef struct _MetaCompWindow
@@ -853,6 +855,72 @@ get_window_picture (MetaCompWindow *cw)
return None;
}
+/* Dock shadows are only drawn on the desktop...
+ Here's how that all works. When a window is added in add_win, if it is
+ a Dock window, it gets added to a list. In phase 2 of the compositing
+ function, this list is walked before the main list. The shadows are then
+ drawn on the same clip region as the root window was drawn. This means
+ that in the compositing function, when we come to the dock windows in
+ phase 3, we do not need to redraw their shadows. The end goal of all this
+ is that all(*) windows are drawn over the dock shadows.
+
+ (*) There is one caveat: Desktop windows. These are pretending to be the
+ root window, so we draw over them as well. This is done by copying the
+ overall region before subtracting the desktop area and then using this
+ copy to base where we draw the dock shadows on */
+static void
+paint_dock_shadows (MetaScreen *screen,
+ Picture root_buffer,
+ XserverRegion region)
+{
+ MetaDisplay *display = screen->display;
+ Display *xdisplay = display->xdisplay;
+ MetaCompScreen *info = screen->compositor_data;
+ GList *d;
+
+ for (d = info->dock_windows; d; d = d->next)
+ {
+ MetaCompWindow *cw = d->data;
+ XserverRegion shadow_clip;
+
+ if (cw->shadow)
+ {
+ shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0);
+ XFixesIntersectRegion (xdisplay, shadow_clip,
+ cw->border_clip, region);
+
+ XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0,
+ shadow_clip);
+
+ XRenderComposite (xdisplay, PictOpOver, info->black_picture,
+ cw->shadow, root_buffer,
+ 0, 0, 0, 0,
+ cw->attrs.x + cw->shadow_dx,
+ cw->attrs.y + cw->shadow_dy,
+ cw->shadow_width, cw->shadow_height);
+ XFixesDestroyRegion (xdisplay, shadow_clip);
+ }
+ }
+}
+
+/* How compositing works:
+ The desktop is drawn in 3 phases, with some subphases.
+ Phase 1: The window list is walked from depthwise (so top windows first)
+ drawing all the opaque windows.
+ 1.1: Once a window is drawn its region is removed from the overall region
+ This new region is recorded for drawing the shadows on later.
+ Phase 2: Once the window list has been walked, the root window is drawn
+ Because all the opaque windows regions have been removed from the
+ overall region, the root window is only drawn on the bits in between
+ windows
+ Phase 3: The window list is walked from the bottom to the top
+ 3.1: The window's shadow is drawn, clipped to the region saved in
+ phase 1.1
+ 3.2: The translucent windows are then drawn as well.
+
+ This is the general idea. However there are a few tweaks and tricks in it.
+ See comments above and below about the dock shadow
+*/
static void
paint_windows (MetaScreen *screen,
GList *windows,
@@ -866,7 +934,7 @@ paint_windows (MetaScreen *screen,
int screen_width, screen_height, screen_number;
Window xroot;
MetaCompWindow *cw;
- XserverRegion paint_region;
+ XserverRegion paint_region, desktop_region;
screen_width = screen->rect.width;
screen_height = screen->rect.height;
@@ -888,6 +956,8 @@ paint_windows (MetaScreen *screen,
XFixesCopyRegion (xdisplay, paint_region, region);
}
+ desktop_region = None;
+
/*
* Painting from top to bottom, reducing the clipping area at
* each iteration. Only the opaque windows are painted 1st.
@@ -956,6 +1026,16 @@ paint_windows (MetaScreen *screen,
XRenderComposite (xdisplay, PictOpSrc, cw->picture,
None, root_buffer, 0, 0, 0, 0,
x, y, wid, hei);
+
+ /* Here we copy paint_region before we subtract the desktop
+ border_size region so we can draw the dock shadows over the
+ same area that we drew the desktop window */
+ if (cw->type == META_COMP_WINDOW_DESKTOP)
+ {
+ desktop_region = XFixesCreateRegion (xdisplay, 0, 0);
+ XFixesCopyRegion (xdisplay, desktop_region, paint_region);
+ }
+
XFixesSubtractRegion (xdisplay, paint_region,
paint_region, cw->border_size);
}
@@ -970,16 +1050,25 @@ paint_windows (MetaScreen *screen,
XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, paint_region);
paint_root (screen, root_buffer);
+ /* We draw the dock shadows on the same region that we drew the
+ desktop. If there was no desktop window then desktop_region will still
+ be None, and so we use the paint_region as that was where we drew
+ the root window. We cannot use paint_region if there was a desktop window
+ because the desktop window covers the root window and so paint_region
+ will be empty */
+ paint_dock_shadows (screen, root_buffer,
+ desktop_region == None ? paint_region : desktop_region);
+
/*
* Painting from bottom to top, translucent windows and shadows are painted
*/
for (index = g_list_last (windows); index; index = index->prev)
{
cw = (MetaCompWindow *) index->data;
-
+
if (cw->picture)
{
- if (cw->shadow)
+ if (cw->shadow && cw->type != META_COMP_WINDOW_DOCK)
{
XserverRegion shadow_clip;
@@ -1085,7 +1174,8 @@ static void
repair_display (MetaDisplay *display)
{
GSList *screens;
-
+
+ meta_error_trap_push (display);
#ifdef USE_IDLE_REPAINT
if (display->compositor->repaint_id > 0)
{
@@ -1096,6 +1186,8 @@ repair_display (MetaDisplay *display)
for (screens = display->screens; screens; screens = screens->next)
repair_screen ((MetaScreen *) screens->data);
+
+ meta_error_trap_pop (display, FALSE);
}
#ifdef USE_IDLE_REPAINT
@@ -1458,6 +1550,9 @@ add_win (MetaScreen *screen,
}
get_window_type (display, cw);
+ if (cw->type == META_COMP_WINDOW_DOCK)
+ info->dock_windows = g_list_append (info->dock_windows, cw);
+
/* If Metacity has decided not to manage this window then the input events
won't have been set on the window */
event_mask = cw->attrs.your_event_mask | PropertyChangeMask;
@@ -2040,7 +2135,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
info = g_new0 (MetaCompScreen, 1);
info->screen = screen;
-
+ info->dock_windows = NULL;
+
visual_format = XRenderFindVisualFormat (display->xdisplay,
DefaultVisual (display->xdisplay,
screen->number));