diff --git a/src/xpra/server/shadow_server_base.py b/src/xpra/server/shadow_server_base.py index 8774daf7af..0e05ef4476 100644 --- a/src/xpra/server/shadow_server_base.py +++ b/src/xpra/server/shadow_server_base.py @@ -26,6 +26,9 @@ def __init__(self, root_window): self.dynamic_property_names = [] self.internal_property_names = [] + def suspend(self): + pass + def is_managed(self): return True @@ -250,6 +253,7 @@ def _process_unmap_window(self, proto, packet): for ss in self._server_sources.values(): ss.unmap_window(wid, window) self.mapped_at = None + self.root_window_model.suspend() def _process_configure_window(self, proto, packet): wid, x, y, w, h = packet[1:6] diff --git a/src/xpra/x11/bindings/ximage.pyx b/src/xpra/x11/bindings/ximage.pyx index bd0d5a5a49..cb57d40158 100644 --- a/src/xpra/x11/bindings/ximage.pyx +++ b/src/xpra/x11/bindings/ximage.pyx @@ -507,12 +507,12 @@ cdef class XShmWrapper(object): def get_size(self): #@DuplicatedSignature return self.width, self.height - def get_image(self, Pixmap xpixmap, int x, int y, int w, int h): + def get_image(self, Drawable drawable, int x, int y, int w, int h): assert self.image!=NULL, "cannot retrieve image wrapper: XImage is NULL!" if self.closed: return None if x>=self.width or y>=self.height: - xshmlog("XShmWrapper.get_image%s position outside image dimensions %ix%i", (xpixmap, x, y, w, h), self.width, self.height) + xshmlog("XShmWrapper.get_image%s position outside image dimensions %ix%i", (drawable, x, y, w, h), self.width, self.height) return None #clamp size to image size: if x+w>self.width: @@ -520,8 +520,8 @@ cdef class XShmWrapper(object): if y+h>self.height: h = self.height-y if not self.got_image: - if not XShmGetImage(self.display, xpixmap, self.image, 0, 0, 0xFFFFFFFF): - xshmlog("XShmWrapper.get_image(%#x, %i, %i, %i, %i) XShmGetImage failed!", xpixmap, x, y, w, h) + if not XShmGetImage(self.display, drawable, self.image, 0, 0, 0xFFFFFFFF): + xshmlog("XShmWrapper.get_image(%#x, %i, %i, %i, %i) XShmGetImage failed!", drawable, x, y, w, h) return None self.got_image = True self.ref_count += 1 @@ -529,7 +529,7 @@ cdef class XShmWrapper(object): imageWrapper = XShmImageWrapper(x, y, w, h) imageWrapper.set_image(self.image) imageWrapper.set_free_callback(self.free_image_callback) - xshmdebug("XShmWrapper.get_image(%#x, %i, %i, %i, %i)=%s (ref_count=%i)", xpixmap, x, y, w, h, imageWrapper, self.ref_count) + xshmdebug("XShmWrapper.get_image(%#x, %i, %i, %i, %i)=%s (ref_count=%i)", drawable, x, y, w, h, imageWrapper, self.ref_count) return imageWrapper def discard(self): @@ -725,8 +725,8 @@ cdef class XImageBindings(X11CoreBindings): xshm.init(self.display, xwindow, attrs.visual, attrs.width, attrs.height, attrs.depth) return xshm - def get_ximage(self, xpixmap, x, y, width, height): #@DuplicatedSignature - return get_image(self.display, xpixmap, x, y, width, height) + def get_ximage(self, drawable, x, y, width, height): #@DuplicatedSignature + return get_image(self.display, drawable, x, y, width, height) def get_xcomposite_pixmap(self, xwindow): return xcomposite_name_window_pixmap(self.display, xwindow) diff --git a/src/xpra/x11/shadow_x11_server.py b/src/xpra/x11/shadow_x11_server.py index 06d85a11f0..4bf671ef0c 100644 --- a/src/xpra/x11/shadow_x11_server.py +++ b/src/xpra/x11/shadow_x11_server.py @@ -4,18 +4,67 @@ # Xpra is released under the terms of the GNU GPL v2, or, at your option, any # later version. See the file COPYING for details. +import os, time from xpra.gtk_common.gtk_util import get_xwindow, get_default_root_window from xpra.x11.x11_server_base import X11ServerBase from xpra.server.shadow_server_base import ShadowServerBase from xpra.server.gtk_root_window_model import GTKRootWindowModel +from xpra.x11.bindings.ximage import XImageBindings #@UnresolvedImport +from xpra.gtk_common.error import xsync +XImage = XImageBindings() + +from xpra.log import Logger +log = Logger("x11", "shadow") + +USE_XSHM = os.environ.get("XPRA_XSHM", "1")=="1" class GTKX11RootWindowModel(GTKRootWindowModel): + def __init__(self, root_window): + GTKRootWindowModel.__init__(self, root_window) + self.xshm = None + def __repr__(self): return "GTKX11RootWindowModel(%#x)" % get_xwindow(self.window) + def suspend(self): + #we can cleanup the current xshm area and we'll create a new one later + self.cleanup() + + def cleanup(self): + if self.xshm: + with xsync: + self.xshm.cleanup() + self.xshm = None + + + def get_image(self, x, y, width, height, logger=None): + try: + start = time.time() + with xsync: + if USE_XSHM: + log("X11 shadow get_image, xshm=%s", self.xshm) + if self.xshm is None: + self.xshm = XImage.get_XShmWrapper(get_xwindow(self.window)) + self.xshm.setup() + if self.xshm: + image = self.xshm.get_image(get_xwindow(self.window), x, y, width, height) + #discard to ensure we will call XShmGetImage next time around + self.xshm.discard() + return image + #fallback to gtk capture: + return GTKRootWindowModel.get_image(self, x, y, width, height, logger) + except Exception as e: + log.warn("Warning: failed to capture root window pixels:") + log.warn(" %s", e) + #cleanup and hope for the best! + self.cleanup() + finally: + end = time.time() + log("X11 shadow captured %s pixels at %i MPixels/s using %s", width*height, (width*height/(end-start))//1024//1024, ["GTK", "XSHM"][USE_XSHM]) + class ShadowX11Server(ShadowServerBase, X11ServerBase):