summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-11-23 18:16:01 +0000
committerHavoc Pennington <hp@src.gnome.org>2003-11-23 18:16:01 +0000
commit927a6def1bc621516927fae981845e08c35d02e3 (patch)
tree2dd32c7232d8a5b0b513200ad704eb77a9b3360b /src
parentd538690bd497ad86fdeeb61154402a3aa0ef9e9b (diff)
downloadmetacity-927a6def1bc621516927fae981845e08c35d02e3.tar.gz
move xcompmgr code in here (minus drop shadows), untested since Keith's
2003-11-23 Havoc Pennington <hp@redhat.com> * src/compositor.c: move xcompmgr code in here (minus drop shadows), untested since Keith's server just crashes at the moment. "It compiles"
Diffstat (limited to 'src')
-rw-r--r--src/compositor.c558
-rw-r--r--src/display.c7
-rw-r--r--src/screen.c3
-rw-r--r--src/screen.h5
4 files changed, 559 insertions, 14 deletions
diff --git a/src/compositor.c b/src/compositor.c
index e9aef849..05323b97 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2003 Red Hat, Inc.
+ * Copyright (C) 2003 Keith Packard
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -21,13 +22,14 @@
#include <config.h>
#include "compositor.h"
+#include "screen.h"
+#include "errors.h"
#ifdef HAVE_COMPOSITE_EXTENSIONS
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h>
-
#endif /* HAVE_COMPOSITE_EXTENSIONS */
/* Unlike MetaWindow, there's one of these for _all_ toplevel windows,
@@ -40,16 +42,29 @@
typedef struct
{
Window xwindow;
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+ MetaCompositor *compositor;
+ int x;
+ int y;
+ int width;
+ int height;
+ int border_width;
+ Damage damage;
+ XserverRegion last_painted_extents;
-} MetaCompositorWindow;
-
-typedef struct
-{
- GList *windows;
+ Picture picture;
+ XserverRegion border_size;
+
+ unsigned int managed : 1;
+ unsigned int damaged : 1;
-} MetaCompositorScreen;
+ unsigned int screen_index : 8;
+
+#endif
+} MetaCompositorWindow;
struct MetaCompositor
{
@@ -62,13 +77,36 @@ struct MetaCompositor
int fixes_error_base;
int fixes_event_base;
int render_error_base;
- int render_event_base;
+ int render_event_base;
+
+ GHashTable *window_hash;
- GSList *screens;
+ guint repair_idle;
guint enabled : 1;
};
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+meta_compositor_window_free (MetaCompositorWindow *cwindow)
+{
+ XDamageDestroy (cwindow->compositor->display->xdisplay,
+ cwindow->damage);
+
+ g_free (cwindow);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+free_window_hash_value (void *v)
+{
+ MetaCompositorWindow *cwindow = v;
+
+ meta_compositor_window_free (cwindow);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
MetaCompositor*
meta_compositor_new (MetaDisplay *display)
{
@@ -137,6 +175,11 @@ meta_compositor_new (MetaDisplay *display)
return compositor;
}
+ compositor->window_hash = g_hash_table_new_full (meta_unsigned_long_hash,
+ meta_unsigned_long_equal,
+ NULL,
+ free_window_hash_value);
+
compositor->enabled = TRUE;
return compositor;
@@ -145,6 +188,18 @@ meta_compositor_new (MetaDisplay *display)
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+remove_repair_idle (MetaCompositor *compositor)
+{
+ if (compositor->repair_idle != 0)
+ {
+ g_source_remove (compositor->repair_idle);
+ compositor->repair_idle = 0;
+ }
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
void
meta_compositor_unref (MetaCompositor *compositor)
{
@@ -152,27 +207,385 @@ meta_compositor_unref (MetaCompositor *compositor)
/* There isn't really a refcount at the moment since
* there's no ref()
*/
+ remove_repair_idle (compositor);
+
+ g_hash_table_destroy (compositor->window_hash);
g_free (compositor);
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static XserverRegion
+window_extents (MetaCompositorWindow *cwindow)
+{
+ XRectangle r;
+
+ r.x = cwindow->x;
+ r.y = cwindow->y;
+ r.width = cwindow->width;
+ r.height = cwindow->height;
+
+ return XFixesCreateRegion (cwindow->compositor->display->xdisplay, &r, 1);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+paint_screen (MetaCompositor *compositor,
+ MetaScreen *screen,
+ XserverRegion damage_region)
+{
+ XserverRegion region;
+ Picture buffer_picture;
+ Pixmap buffer_pixmap;
+ Display *xdisplay;
+ XRenderPictFormat *format;
+ GList *tmp;
+
+ xdisplay = screen->display->xdisplay;
+
+ if (damage_region == None)
+ {
+ XRectangle r;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = screen->width;
+ r.height = screen->height;
+
+ region = XFixesCreateRegion (xdisplay, &r, 1);
+ }
+ else
+ {
+ region = XFixesCreateRegion (xdisplay, NULL, 0);
+
+ XFixesCopyRegion (compositor->display->xdisplay,
+ region,
+ damage_region);
+ }
+
+ buffer_pixmap = XCreatePixmap (xdisplay, None,
+ screen->width,
+ screen->height,
+ DefaultDepth (xdisplay,
+ screen->number));
+
+ format = XRenderFindVisualFormat (xdisplay,
+ DefaultVisual (xdisplay,
+ screen->number));
+
+ buffer_picture = XRenderCreatePicture (xdisplay,
+ buffer_pixmap,
+ format,
+ 0, 0);
+
+ /* set clip on the root window */
+ XFixesSetPictureClipRegion (xdisplay,
+ screen->root_picture, 0, 0, region);
+
+ /* draw windows from bottom to top */
+ meta_error_trap_push (compositor->display);
+ tmp = g_list_last (screen->compositor_windows);
+ while (tmp != NULL)
+ {
+ MetaCompositorWindow *cwindow = tmp->data;
+
+ if (cwindow->picture == None) /* InputOnly */
+ goto next;
+
+ if (cwindow->last_painted_extents)
+ XFixesDestroyRegion (xdisplay,
+ cwindow->last_painted_extents);
+
+ cwindow->last_painted_extents = window_extents (cwindow);
+
+ XFixesSetPictureClipRegion (xdisplay,
+ buffer_picture, 0, 0,
+ region);
+
+ /* XFixesSubtractRegion (dpy, region, region, 0, 0, w->borderSize, 0, 0); */
+
+ XRenderComposite (xdisplay,
+ PictOpSrc, /* PictOpOver for alpha */
+ cwindow->picture,
+ None, buffer_picture,
+ 0, 0, 0, 0,
+ cwindow->x + cwindow->border_width,
+ cwindow->y + cwindow->border_width,
+ cwindow->width,
+ cwindow->height);
+
+ next:
+ tmp = tmp->prev;
+ }
+ meta_error_trap_pop (compositor->display, FALSE);
+
+ /* Copy buffer to root window */
+
+ XFixesSetPictureClipRegion (xdisplay, buffer_picture, 0, 0, None);
+ XRenderComposite (xdisplay, PictOpSrc, buffer_picture, None,
+ screen->root_picture,
+ 0, 0, 0, 0, 0, 0,
+ screen->width, screen->height);
+
+ XFixesDestroyRegion (xdisplay, region);
+ XFreePixmap (xdisplay, buffer_pixmap);
+ XRenderFreePicture (xdisplay, buffer_picture);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static gboolean
+repair_idle_func (void *data)
+{
+ GSList *tmp;
+
+ MetaCompositor *compositor = data;
+
+ tmp = compositor->display->screens;
+ while (tmp != NULL)
+ {
+ MetaScreen *s = tmp->data;
+
+ if (s->damage_region != None)
+ {
+ paint_screen (compositor, s,
+ s->damage_region);
+ XFixesDestroyRegion (s->display->xdisplay,
+ s->damage_region);
+ s->damage_region = None;
+ }
+
+ tmp = tmp->next;
+ }
+
+ compositor->repair_idle = 0;
+
+ return FALSE;
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static MetaScreen*
+meta_compositor_window_get_screen (MetaCompositorWindow *cwindow)
+{
+ MetaScreen *screen;
+ GSList *tmp;
+
+ screen = NULL;
+ tmp = cwindow->compositor->display->screens;
+ while (tmp != NULL)
+ {
+ MetaScreen *s = tmp->data;
+
+ if (s->number == cwindow->screen_index)
+ {
+ screen = s;
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+ g_assert (screen != NULL);
+
+ return screen;
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+ensure_repair_idle (MetaCompositor *compositor)
+{
+ if (compositor->repair_idle != 0)
+ return;
+
+ compositor->repair_idle = g_idle_add (repair_idle_func, compositor);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+merge_and_destroy_damage_region (MetaCompositor *compositor,
+ MetaScreen *screen,
+ XserverRegion region)
+{
+ if (screen->damage_region != None)
+ {
+ XFixesCopyRegion (compositor->display->xdisplay,
+ screen->damage_region,
+ region);
+ XFixesDestroyRegion (compositor->display->xdisplay,
+ region);
+ }
+ else
+ {
+ screen->damage_region = region;
+ }
+
+ ensure_repair_idle (compositor);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+merge_damage_region (MetaCompositor *compositor,
+ MetaScreen *screen,
+ XserverRegion region)
+{
+ if (screen->damage_region == None)
+ screen->damage_region =
+ XFixesCreateRegion (compositor->display->xdisplay, NULL, 0);
+
+ XFixesCopyRegion (compositor->display->xdisplay,
+ screen->damage_region,
+ region);
+
+ ensure_repair_idle (compositor);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+process_damage_notify (MetaCompositor *compositor,
+ XDamageNotifyEvent *event)
+{
+ MetaCompositorWindow *cwindow;
+ XserverRegion region;
+ MetaScreen *screen;
+
+ cwindow = g_hash_table_lookup (compositor->window_hash,
+ &event->drawable);
+ if (cwindow == NULL)
+ return;
+
+ region = XFixesCreateRegion (compositor->display->xdisplay, NULL, 0);
+
+ /* translate region to screen */
+ XDamageSubtract (compositor->display->xdisplay,
+ cwindow->damage, None, region);
+
+ XFixesTranslateRegion (compositor->display->xdisplay,
+ region,
+ cwindow->x,
+ cwindow->y);
+
+ screen = meta_compositor_window_get_screen (cwindow);
+
+ merge_and_destroy_damage_region (compositor, screen, region);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
+#ifdef HAVE_COMPOSITE_EXTENSIONS
+static void
+process_configure_notify (MetaCompositor *compositor,
+ XConfigureEvent *event)
+{
+ MetaCompositorWindow *cwindow;
+ MetaScreen *screen;
+ GList *link;
+ Window above;
+ XserverRegion region;
+
+ cwindow = g_hash_table_lookup (compositor->window_hash,
+ &event->window);
+ if (cwindow == NULL)
+ return;
+
+ screen = meta_compositor_window_get_screen (cwindow);
+
+ if (cwindow->last_painted_extents)
+ {
+ merge_damage_region (compositor,
+ screen,
+ cwindow->last_painted_extents);
+ }
+
+ cwindow->x = event->x;
+ cwindow->y = event->y;
+ cwindow->width = event->width;
+ cwindow->height = event->height;
+ cwindow->border_width = event->border_width;
+
+ link = g_list_find (screen->compositor_windows,
+ cwindow);
+
+ g_assert (link != NULL);
+
+ if (link->next)
+ above = ((MetaCompositorWindow*) link->next)->xwindow;
+ else
+ above = None;
+
+ if (above != event->above)
+ {
+ GList *tmp;
+
+ screen->compositor_windows =
+ g_list_delete_link (screen->compositor_windows,
+ link);
+ link = NULL;
+
+ /* Note that event->above is None if our window is on the bottom */
+ tmp = screen->compositor_windows;
+ while (tmp != NULL)
+ {
+ MetaCompositorWindow *t = tmp->data;
+
+ if (t->xwindow == event->above)
+ {
+ /* We are above this window, i.e. earlier in list */
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+
+ if (tmp != NULL)
+ {
+ screen->compositor_windows =
+ g_list_insert_before (screen->compositor_windows,
+ tmp,
+ cwindow);
+ }
+ else
+ screen->compositor_windows =
+ g_list_prepend (screen->compositor_windows,
+ cwindow);
+ }
+
+ region = window_extents (cwindow);
+ merge_damage_region (compositor,
+ screen,
+ region);
+ XFixesDestroyRegion (compositor->display->xdisplay, region);
+}
+#endif /* HAVE_COMPOSITE_EXTENSIONS */
+
void
meta_compositor_process_event (MetaCompositor *compositor,
- XEvent *xevent,
+ XEvent *event,
MetaWindow *window)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
if (!compositor->enabled)
return; /* no extension */
-
-
+ if (event->type == (compositor->damage_event_base + XDamageNotify))
+ {
+ process_damage_notify (compositor,
+ (XDamageNotifyEvent*) event);
+ }
+ else if (event->type == ConfigureNotify)
+ {
+ process_configure_notify (compositor,
+ (XConfigureEvent*) event);
+ }
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
/* This is called when metacity does its XQueryTree() on startup
- * and when a new window is created.
+ * and when a new window is mapped.
*/
void
meta_compositor_add_window (MetaCompositor *compositor,
@@ -180,11 +593,71 @@ meta_compositor_add_window (MetaCompositor *compositor,
XWindowAttributes *attrs)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
+ MetaCompositorWindow *cwindow;
+ MetaScreen *screen;
+ Damage damage;
+ XRenderPictFormat *format;
+ XRenderPictureAttributes pa;
+
g_print ("compositor adding window 0x%lx\n", xwindow);
if (!compositor->enabled)
return; /* no extension */
+ screen = meta_screen_for_x_screen (attrs->screen);
+ g_assert (screen != NULL);
+
+ cwindow = g_hash_table_lookup (compositor->window_hash,
+ &xwindow);
+
+ if (cwindow != NULL)
+ return;
+
+ /* Create Damage object to monitor window damage */
+ meta_error_trap_push (compositor->display);
+ damage = XDamageCreate (compositor->display->xdisplay,
+ xwindow, XDamageReportNonEmpty);
+ meta_error_trap_pop (compositor->display, FALSE);
+
+ if (damage == None)
+ return;
+
+ cwindow = g_new0 (MetaCompositorWindow, 1);
+
+ cwindow->compositor = compositor;
+ cwindow->xwindow = xwindow;
+ cwindow->screen_index = screen->number;
+ cwindow->damage = damage;
+ cwindow->x = attrs->x;
+ cwindow->y = attrs->y;
+ cwindow->width = attrs->width;
+ cwindow->height = attrs->height;
+ cwindow->border_width = attrs->border_width;
+
+ pa.subwindow_mode = IncludeInferiors;
+
+ if (attrs->class != InputOnly)
+ {
+ format = XRenderFindVisualFormat (compositor->display->xdisplay,
+ attrs->visual);
+ cwindow->picture = XRenderCreatePicture (compositor->display->xdisplay,
+ xwindow,
+ format,
+ CPSubwindowMode,
+ &pa);
+ }
+ else
+ {
+ cwindow->picture = None;
+ }
+
+ g_hash_table_insert (compositor->window_hash,
+ &cwindow->xwindow, cwindow);
+
+ /* assume cwindow is at the top of the stack */
+ screen->compositor_windows = g_list_prepend (screen->compositor_windows,
+ cwindow);
+
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
@@ -193,11 +666,37 @@ meta_compositor_remove_window (MetaCompositor *compositor,
Window xwindow)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
+ MetaCompositorWindow *cwindow;
+ MetaScreen *screen;
+
g_print ("compositor removing window 0x%lx\n", xwindow);
if (!compositor->enabled)
return; /* no extension */
+ cwindow = g_hash_table_lookup (compositor->window_hash,
+ &xwindow);
+
+ if (cwindow == NULL)
+ return;
+
+ screen = meta_compositor_window_get_screen (cwindow);
+
+ if (cwindow->last_painted_extents)
+ {
+ merge_and_destroy_damage_region (compositor,
+ screen,
+ cwindow->last_painted_extents);
+ cwindow->last_painted_extents = None;
+ }
+
+ screen->compositor_windows = g_list_remove (screen->compositor_windows,
+ cwindow);
+
+ /* Frees cwindow as side effect */
+ g_hash_table_remove (compositor->window_hash,
+ &xwindow);
+
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
@@ -206,9 +705,30 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
MetaScreen *screen)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
+ XRenderPictureAttributes pa;
+
if (!compositor->enabled)
return; /* no extension */
+ /* FIXME we need to handle root window resize by recreating the
+ * root_picture
+ */
+
+ g_assert (screen->root_picture == None);
+
+ pa.subwindow_mode = IncludeInferiors;
+
+ screen->root_picture =
+ XRenderCreatePicture (compositor->display->xdisplay,
+ screen->xroot,
+ XRenderFindVisualFormat (compositor->display->xdisplay,
+ DefaultVisual (compositor->display->xdisplay,
+ screen->number)),
+ CPSubwindowMode,
+ &pa);
+
+ g_assert (screen->root_picture != None);
+
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
@@ -216,10 +736,20 @@ void
meta_compositor_unmanage_screen (MetaCompositor *compositor,
MetaScreen *screen)
{
-#ifdef HAVE_COMPOSITE_EXTENSIONS
+#ifdef HAVE_COMPOSITE_EXTENSIONS
if (!compositor->enabled)
return; /* no extension */
+ XRenderFreePicture (screen->display->xdisplay,
+ screen->root_picture);
+ screen->root_picture = None;
+
+ while (screen->compositor_windows != NULL)
+ {
+ MetaCompositorWindow *cwindow = screen->compositor_windows->data;
+
+ meta_compositor_remove_window (compositor, cwindow->xwindow);
+ }
#endif /* HAVE_COMPOSITE_EXTENSIONS */
}
diff --git a/src/display.c b/src/display.c
index aa36bfe6..e807d04c 100644
--- a/src/display.c
+++ b/src/display.c
@@ -1298,6 +1298,10 @@ event_callback (XEvent *event,
}
}
#endif /* HAVE_SHAPE */
+
+ meta_compositor_process_event (display->compositor,
+ event,
+ window);
switch (event->type)
{
@@ -1636,6 +1640,9 @@ event_callback (XEvent *event,
case CreateNotify:
break;
case DestroyNotify:
+ meta_compositor_remove_window (display->compositor,
+ modified);
+
if (window)
{
if (display->grab_op != META_GRAB_OP_NONE &&
diff --git a/src/screen.c b/src/screen.c
index d8d5defd..35168158 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -559,6 +559,9 @@ meta_screen_new (MetaDisplay *display,
screen->showing_desktop = FALSE;
+ screen->compositor_windows = NULL;
+ screen->damage_region = None;
+
{
XGCValues gc_values;
diff --git a/src/screen.h b/src/screen.h
index 24b29ab7..93a2cb4f 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -113,6 +113,11 @@ struct _MetaScreen
/* gc for XOR on root window */
GC root_xor_gc;
+
+ /* Managed by compositor.c; top of stack is first in list */
+ GList *compositor_windows;
+ XID root_picture;
+ XID damage_region;
};
MetaScreen* meta_screen_new (MetaDisplay *display,