Index: ChangeLog =================================================================== RCS file: /cvs/gnome/vino/ChangeLog,v retrieving revision 1.7 diff -u -r1.7 ChangeLog --- ChangeLog 16 Apr 2004 11:36:41 -0000 1.7 +++ ChangeLog 21 May 2004 01:13:56 -0000 @@ -1,3 +1,27 @@ +2004-05-20 Federico Mena Quintero + + * configure.in: Test for the DAMAGE extension. + + * server/Makefile.am (vino_server_LDADD): Add the XDAMAGE_LIBS. + + * server/vino-fb.c (struct _VinoFBPrivate): Added these fields: + xdamage, xdamage_event_base, xdamage_error_base, use_xdamage. + (vino_fb_init_polling): New function; moved the polling + initialization code over from vino_fb_init_from_screen(). + (vino_fb_init_from_screen): Call vino_fb_init_xdamage(), or + vino_fb_init_polling() if the former fails. + (vino_fb_finalize_polling): New function, code moved over from + vino_fb_finalize_screen_data(). Also, destroy the timeout here. + (vino_fb_finalize_xdamage): New function to get rid of the Damage + object. + (vino_fb_finalize_screen_data): Call vino_fb_finalize_xdamage() or + vino_fb_finalize_polling() as appropriate. + (vino_fb_finalize): Don't destroy the timeout here. + (copy_image_to_fb_image): New helper function, code moved over + from vino_fb_copy_tile(). + (vino_fb_copy_tile): Use copy_image_to_fb_image(). Removed the + bytes_per_pixel argument. + 2004-04-16 Mark McLoughlin * configure.in: don't rebuild the jar file by default even when Index: configure.in =================================================================== RCS file: /cvs/gnome/vino/configure.in,v retrieving revision 1.4 diff -u -r1.4 configure.in --- configure.in 16 Apr 2004 11:36:41 -0000 1.4 +++ configure.in 21 May 2004 01:13:56 -0000 @@ -148,6 +148,17 @@ ]) AC_SUBST(XTEST_LIBS) +# +# Check for MIT-SHM extension +# +XDAMAGE_LIBS= +AC_CHECK_HEADER(X11/extensions/Xdamage.h, [ + AC_CHECK_LIB(Xdamage, XDamageQueryExtension, [ + AC_DEFINE(HAVE_DAMAGE) + XDAMAGE_LIBS="-lXdamage"],, $X_LIBS) + ],, [#include ]) +AC_SUBST(XDAMAGE_LIBS) + dnl dnl From libvncserver Index: server/Makefile.am =================================================================== RCS file: /cvs/gnome/vino/server/Makefile.am,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 Makefile.am --- server/Makefile.am 5 Feb 2004 08:54:54 -0000 1.1.1.1 +++ server/Makefile.am 21 May 2004 01:13:56 -0000 @@ -21,7 +21,7 @@ $(VINO_SERVER_LIBS) \ $(LIBGNUTLS_LIBS) \ $(LIBGCRYPT_LIBS) \ - $(X_LIBS) $(XTEST_LIBS) $(XSHM_LIBS) \ + $(X_LIBS) $(XTEST_LIBS) $(XSHM_LIBS) $(XDAMAGE_LIBS) \ $(top_builddir)/server/libvncserver/libvncserver.la \ $(NULL) Index: server/vino-fb.c =================================================================== RCS file: /cvs/gnome/vino/server/vino-fb.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 vino-fb.c --- server/vino-fb.c 5 Feb 2004 08:54:56 -0000 1.1.1.1 +++ server/vino-fb.c 21 May 2004 01:13:56 -0000 @@ -40,6 +40,9 @@ #ifdef HAVE_XSHM #include #endif +#ifdef HAVE_DAMAGE +#include +#endif #include "vino-util.h" @@ -67,9 +70,17 @@ guint update_timeout; +#ifdef HAVE_DAMAGE + Damage *xdamage; + int xdamage_event_base; + int xdamage_error_base; +#endif + guint use_x_shm : 1; guint scanline_is_x_shm_segment : 1; guint tile_is_x_shm_segment : 1; + + guint use_xdamage : 1; }; @@ -277,16 +288,40 @@ } } +/* Copies a whole image to a region of our fb_image. The rectangle specifies + * the area that the image is supposed to occupy within the fb_image. + */ +static void +copy_image_to_fb_image (VinoFB *vfb, XImage *image, int x, int y, int width, int height) +{ + VinoFBPrivate *priv; + char *src, *dest; + int bytes_per_pixel; + int src_bytes_per_line, dest_bytes_per_line; + int i; + + priv = vfb->priv; + + src_bytes_per_line = image->bytes_per_line; + dest_bytes_per_line = priv->fb_image->bytes_per_line; + bytes_per_pixel = priv->fb_image->bits_per_pixel >> 3; + + src = image->data; + dest = priv->fb_image->data + y * dest_bytes_per_line + x * bytes_per_pixel; + + for (i = 0; i < height; i++) + { + memcpy (dest, src, width * bytes_per_pixel); + + src += src_bytes_per_line; + dest += dest_bytes_per_line; + } +} static gboolean vino_fb_copy_tile (VinoFB *vfb, - GdkRectangle *rect, - int bytes_per_pixel) + GdkRectangle *rect) { - char *dest; - int bytes_per_line; - int i; - if (!vino_fb_get_image (vfb, vfb->priv->root_window, vfb->priv->tile, @@ -298,18 +333,7 @@ rect->height)) return FALSE; - bytes_per_line = vfb->priv->fb_image->bytes_per_line; - - dest = vfb->priv->fb_image->data + (rect->y * bytes_per_line) + (rect->x * bytes_per_pixel); - - for (i = 0; i < rect->height; i++) - { - memcpy (dest, - vfb->priv->tile->data + i * bytes_per_pixel * rect->width, - rect->width * bytes_per_pixel); - - dest += bytes_per_line; - } + copy_image_to_fb_image (vfb, vfb->priv->tile, rect->x, rect->y, rect->width, rect->height); return TRUE; } @@ -359,7 +383,7 @@ dprintf (POLLING, "damage: (%d, %d) (%d x %d)\n", rect.x, rect.y, rect.width, rect.height); - if (vino_fb_copy_tile (vfb, &rect, bytes_per_pixel)) + if (vino_fb_copy_tile (vfb, &rect)) { if (!vfb->priv->damage_region) vfb->priv->damage_region = gdk_region_rectangle (&rect); @@ -412,16 +436,29 @@ return TRUE; } +/* Frees the Damage object */ static void -vino_fb_finalize_screen_data (VinoFB *vfb) +vino_fb_finalize_xdamage (VinoFB *vfb) { - if (vfb->priv->damage_region) - gdk_region_destroy (vfb->priv->damage_region); - vfb->priv->damage_region = NULL; +#ifdef HAVE_DAMAGE + VinoFBPrivate *priv; + Display *xdisplay; - if (vfb->priv->fb_image) - XDestroyImage (vfb->priv->fb_image); - vfb->priv->fb_image = NULL; + priv = vfb->priv; + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (priv->screen)); + XDamageDestroy (xdisplay, priv->xdamage); + priv->xdamage = None; +#endif +} + +/* Frees the scanline and tile data */ +static void +vino_fb_finalize_polling (VinoFB *vfb) +{ + if (vfb->priv->update_timeout) + g_source_remove (vfb->priv->update_timeout); + vfb->priv->update_timeout = 0; if (vfb->priv->scanline) vino_fb_destroy_image (vfb, @@ -429,7 +466,7 @@ &vfb->priv->scanline_x_shm_info, vfb->priv->scanline_is_x_shm_segment); vfb->priv->scanline = NULL; - + if (vfb->priv->tile) vino_fb_destroy_image (vfb, vfb->priv->tile, @@ -439,6 +476,23 @@ } static void +vino_fb_finalize_screen_data (VinoFB *vfb) +{ + if (vfb->priv->damage_region) + gdk_region_destroy (vfb->priv->damage_region); + vfb->priv->damage_region = NULL; + + if (vfb->priv->fb_image) + XDestroyImage (vfb->priv->fb_image); + vfb->priv->fb_image = NULL; + + if (vfb->priv->use_xdamage) + vino_fb_finalize_xdamage (vfb); + else + vino_fb_finalize_polling (vfb); +} + +static void vino_fb_screen_size_changed (VinoFB *vfb, GdkScreen *screen) { @@ -450,43 +504,155 @@ emit_size_changed (vfb); } +#ifdef HAVE_DAMAGE + +/* Fetches a rectangle of the screen to update our fb_image buffer */ static void -vino_fb_init_from_screen (VinoFB *vfb, - GdkScreen *screen) +update_xrectangle (VinoFB *vfb, XRectangle *xrect) +{ + VinoFBPrivate *priv; + gboolean use_shm; + XShmSegmentInfo shm_info; + XImage *image; + + priv = vfb->priv; + + use_shm = vino_fb_create_image (vfb, &image, &shm_info, + xrect->width, xrect->height, + priv->fb_image->bits_per_pixel); + if (!image) + { + g_warning (G_STRLOC ": Could not create XImage; buffer will be out of sync"); + return; + } + + if (vino_fb_get_image (vfb, priv->root_window, image, &shm_info, use_shm, + xrect->x, xrect->y, xrect->width, xrect->height)) + copy_image_to_fb_image (vfb, image, xrect->x, xrect->y, xrect->width, xrect->height); + else + g_warning (G_STRLOC ": Could not fetch the XImage; buffer will be out of sync"); + + vino_fb_destroy_image (vfb, image, &shm_info, use_shm); +} + +/* Adds an XRectangle to our damage_region */ +static void +add_xrectangle_to_damage_region (VinoFB *vfb, XRectangle *xrect) { + VinoFBPrivate *priv; + GdkRectangle rect; + + rect.x = xrect->x; + rect.y = xrect->y; + rect.width = xrect->width; + rect.height = xrect->height; + + if (priv->damage_region) + gdk_region_union_with_rect (priv->damage_region, &rect); + else + priv->damage_region = gdk_region_rectangle (&rect); +} + +/* Subtracts an XRectangle from the Damage region */ +static void +subtract_xrectangle_from_damage (VinoFB *vfb, XRectangle *xrect) +{ + VinoFBPrivate *priv; Display *xdisplay; + XserverRegion region; - g_return_if_fail (screen != NULL); + priv = vfb->priv; - xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (priv->screen)); - vfb->priv->screen = screen; - vfb->priv->root_window = gdk_screen_get_root_window (screen); + region = XFixesCreateRegion (xdisplay, &event->area, 1); + XDamageSubtract (xdisplay, priv->xdamage, region, None); + XFixesDestroyRegion (xdisplay, region); +} - g_signal_connect_swapped (vfb->priv->screen, "size-changed", - G_CALLBACK (vino_fb_screen_size_changed), - vfb); +/* Handles an XDamageNotify event by updating our image buffer and damage + * region. + */ +static void +handle_damage_notify_event (VinoFB *vfb, XDamageNotifyEvent *event) +{ + g_assert (event->type == XDamageNotify); - vfb->priv->fb_image = - XGetImage (xdisplay, - GDK_WINDOW_XWINDOW (vfb->priv->root_window), - 0, 0, - gdk_screen_get_width (screen), - gdk_screen_get_height (screen), - AllPlanes, - ZPixmap); - if (!vfb->priv->fb_image) + update_xrectangle (vfb, &event->area); + add_xrectangle_to_damage_region (vfb, &event->area); + subtract_xrectangle_from_damage (vfb, &event->area); + emit_damage_notify (vfb); +} + +static GdkFilterReturn +root_window_filter_cb (GdkXEvent *xevent, GdkEvent *event, gpointer data) +{ + VinoFB *vfb; + VinoFBPrivate *priv; + XEvent *xev; + + vfb = VINO_FB (data); + priv = vfb->priv; + + xev = (XEvent *) xevent; + + if (xev->type == priv->xdamage_event_base + XDamageNotify) { - g_warning (G_STRLOC ": failed to copy frame buffer contents with XGetImage"); - return; + XDamageNotifyEvent *notify; + + notify = (XDamageNotifyEvent *) xev; + handle_damage_notify_event (vfb, notify); + + return GDK_FILTER_REMOVE; } - dprintf (POLLING, "Initialized framebuffer contents (%p) for screen %d: %dx%d %dbpp\n", - vfb->priv->fb_image, - gdk_screen_get_number (vfb->priv->screen), - vfb->priv->fb_image->width, - vfb->priv->fb_image->height, - vfb->priv->fb_image->bits_per_pixel); + return GDK_FILTER_CONTINUE; +} + +#endif + +static void +vino_fb_init_xdamage (VinoFB *vfb) +{ +#ifdef HAVE_DAMAGE + Display *xdisplay; + int major, minor; +#endif + VinoFBPrivate *priv; + + priv = vfb->priv; + + priv->use_xdamage = FALSE; + +#ifdef HAVE_DAMAGE + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (priv->screen)); + + if (!XDamageQueryExtension (xdisplay, + &priv->xdamage_event_base, + &priv->xdamage_error_base)) + return; + + if (XDamageQueryVersion (xdisplay, &major, &minor) != Success + || major != 1) + return; + + priv->xdamage = XDamageCreate (xdisplay, + GDK_WINDOW_XWINDOW (priv->root_window), + XDamageReportDeltaRectangles); + if (priv->xdamage == None) + return; + + gdk_window_add_filter (priv->root_window, root_window_filter_cb, vfb); + + priv->use_xdamage = TRUE; +#endif +} + +/* Initializes a VinoFB for polling mode. */ +static void +vino_fb_init_polling (VinoFB *vfb) +{ + g_assert (!vfb->priv->use_xdamage); #ifdef HAVE_XSHM vfb->priv->use_x_shm = XShmQueryExtension (xdisplay) != False; @@ -537,16 +703,56 @@ g_timeout_add (20, (GSourceFunc) vino_fb_poll_screen, vfb); } +static void +vino_fb_init_from_screen (VinoFB *vfb, + GdkScreen *screen) +{ + Display *xdisplay; + + g_return_if_fail (screen != NULL); + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); + + vfb->priv->screen = screen; + vfb->priv->root_window = gdk_screen_get_root_window (screen); + + g_signal_connect_swapped (vfb->priv->screen, "size-changed", + G_CALLBACK (vino_fb_screen_size_changed), + vfb); + + vfb->priv->fb_image = + XGetImage (xdisplay, + GDK_WINDOW_XWINDOW (vfb->priv->root_window), + 0, 0, + gdk_screen_get_width (screen), + gdk_screen_get_height (screen), + AllPlanes, + ZPixmap); + if (!vfb->priv->fb_image) + { + g_warning (G_STRLOC ": failed to copy frame buffer contents with XGetImage"); + return; + } + + dprintf (POLLING, "Initialized framebuffer contents (%p) for screen %d: %dx%d %dbpp\n", + vfb->priv->fb_image, + gdk_screen_get_number (vfb->priv->screen), + vfb->priv->fb_image->width, + vfb->priv->fb_image->height, + vfb->priv->fb_image->bits_per_pixel); + + vino_fb_init_xdamage (vfb); + + if (!vfb->priv->use_xdamage) + vino_fb_init_polling (vfb); +} + static void vino_fb_finalize (GObject *object) { VinoFB *vfb = VINO_FB (object); - if (vfb->priv->update_timeout) - g_source_remove (vfb->priv->update_timeout); - vfb->priv->update_timeout = 0; - vino_fb_finalize_screen_data (vfb); g_free (vfb->priv);