xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #345: xshm-v3.patch

File xshm-v3.patch, 14.3 KB (added by Antoine Martin, 8 years ago)

updated patch on top of r3512

  • xpra/x11/gtk_x11/composite.py

     
    77import gobject
    88from xpra.gtk_common.gobject_util import one_arg_signal, AutoPropGObjectMixin
    99from xpra.x11.gtk_x11.gdk_bindings import (
     10            XShmWrapper,                    #@UnresolvedImport
    1011            add_event_receiver,             #@UnresolvedImport
    1112            remove_event_receiver,          #@UnresolvedImport
    1213            get_xwindow,                    #@UnresolvedImport
     
    3435    __gproperties__ = {
    3536        "contents-handle": (gobject.TYPE_PYOBJECT,
    3637                            "", "", gobject.PARAM_READABLE),
     38        "shm-handle": (gobject.TYPE_PYOBJECT,
     39                            "", "", gobject.PARAM_READABLE),
    3740        }
    3841
    3942    # This may raise XError.
    40     def __init__(self, window, already_composited):
     43    def __init__(self, window, already_composited, use_shm=False):
    4144        super(CompositeHelper, self).__init__()
    4245        log("CompositeHelper.__init__(%s,%s)", window, already_composited)
    4346        self._window = window
    4447        self._already_composited = already_composited
    4548        self._listening_to = None
    4649        self._damage_handle = None
     50        self._use_shm = use_shm
     51        self._shm_handle = None
    4752
    4853    def setup(self):
    4954        xwin = get_xwindow(self._window)
     
    7176        if self._damage_handle:
    7277            trap.swallow_synced(X11Window.XDamageDestroy, self._damage_handle)
    7378            self._damage_handle = None
     79        if self._shm_handle:
     80            self._shm_handle.cleanup()
     81            self._shm_handle = None
    7482        #note: this should be redundant since we cleared the
    7583        #reference to self._window and shortcut out in do_get_property_contents_handle
    7684        #but it's cheap anyway
     
    96104            for w in listening:
    97105                remove_event_receiver(w, self)
    98106
     107    def do_get_property_shm_handle(self, name):
     108        if not self._use_shm:
     109            return None
     110        if self._shm_handle is None:
     111            self._shm_handle = XShmWrapper()
     112            if not self._shm_handle.init(self._window):
     113                self._shm_handle = None
     114        return self._shm_handle
     115
    99116    def do_get_property_contents_handle(self, name):
    100117        if self._window is None:
    101118            #shortcut out
     
    153170            trap.swallow_synced(set_pixmap)
    154171        return self._contents_handle
    155172
    156     def do_get_property_contents(self, name):
    157         return self.get_property("contents-handle")
    158 
    159173    def do_xpra_unmap_event(self, *args):
    160174        self.invalidate_pixmap()
    161175
  • xpra/x11/gtk_x11/gdk_bindings.pyx

     
    4242    int PyObject_AsReadBuffer(object obj, void ** buffer, Py_ssize_t * buffer_len) except -1
    4343
    4444cdef extern from "string.h":
    45     void * memcpy ( void * destination, void * source, size_t num )
     45    void * memcpy( void * destination, void * source, size_t num )
    4646
     47cdef extern from "sys/ipc.h":
     48    ctypedef struct key_t:
     49        pass
     50    key_t IPC_PRIVATE
     51    int IPC_CREAT
     52
     53cdef extern from "sys/shm.h":
     54    int shmget(key_t __key, size_t __size, int __shmflg)
     55    void *shmat(int __shmid, const void *__shmaddr, int __shmflg)
     56    int shmdt (const void *__shmaddr)
     57
    4758cdef extern from "stdlib.h":
    4859    void* malloc(size_t __size)
    4960    void free(void* mem)
     
    240251        XDestroyWindowEvent xdestroywindow
    241252        XPropertyEvent xproperty
    242253
     254    Bool XQueryExtension(Display * display, char *name,
     255                         int *major_opcode_return, int *first_event_return, int *first_error_return)
    243256
    244257    Status XQueryTree(Display * display, Window w,
    245258                      Window * root, Window * parent,
     
    365378        Window      window
    366379        Bool        event_only
    367380
     381cdef extern from "X11/extensions/XShm.h":
     382    unsigned int ShmCompletion
     383    ctypedef struct ShmSeg:
     384        pass
     385    ctypedef struct XShmSegmentInfo:
     386        ShmSeg shmseg   # resource id
     387        int shmid       # kernel id
     388        char *shmaddr   # address in client
     389        Bool readOnly   # how the server should attach it
    368390
     391    XShmQueryExtension(Display *display)
     392    Bool XShmQueryVersion(Display *display, int *major, int *minor, Bool *pixmaps)
    369393
     394    Bool XShmAttach(Display *display, XShmSegmentInfo *shminfo)
     395    Bool XShmDetach(Display *display, XShmSegmentInfo *shminfo)
    370396
     397    XImage *XShmCreateImage(Display *display, Visual *visual,
     398                            unsigned int depth, int format, char *data,
     399                            XShmSegmentInfo *shminfo,
     400                            unsigned int width, unsigned int height)
     401
     402    Bool XShmGetImage(Display *display, Drawable d, XImage *image,
     403                      int x, int y,
     404                      unsigned long plane_mask)
     405
     406    int XShmGetEventBase(Display *display)
     407
     408
    371409######
    372410# GDK primitives, and wrappers for Xlib
    373411######
     
    425463
    426464def get_xvisual(pyvisual):
    427465    cdef Visual * xvisual
    428     xvisual = GDK_VISUAL_XVISUAL(<cGdkVisual*>unwrap(pyvisual, gtk.gdk.Visual))
     466    xvisual = _get_xvisual(pyvisual)
    429467    if xvisual==NULL:
    430468        return  -1
    431469    return xvisual.visualid
    432470
     471cdef Visual *_get_xvisual(pyvisual):
     472    return GDK_VISUAL_XVISUAL(<cGdkVisual*>unwrap(pyvisual, gtk.gdk.Visual))
    433473
     474
    434475cdef cGdkDisplay * get_raw_display_for(obj) except? NULL:
    435476    return <cGdkDisplay*> unwrap(get_display_for(obj), gtk.gdk.Display)
    436477
     
    566607    return (new_width, new_height, vis_width, vis_height)
    567608
    568609
     610cdef class XShmWrapper(object):
     611    cdef Display *display                              #@DuplicatedSignature
     612    cdef XShmSegmentInfo shminfo
     613    cdef XImage *image
     614    cdef int width
     615    cdef int height
     616    cdef XImageWrapper imageWrapper
     617    cdef Bool closed
     618
     619    def __init__(self):
     620        self.imageWrapper = None
     621
     622    def init(self, window):
     623        cdef Visual *visual
     624        cdef int depth
     625        cdef size_t size
     626        self.closed = False
     627        self.shminfo.shmaddr = <char *> -1
     628
     629        self.display = get_xdisplay_for(window)
     630        visual = _get_xvisual(window.get_visual())
     631        depth = window.get_depth()
     632        self.width, self.height = window.get_size()
     633        self.image = XShmCreateImage(self.display, visual, depth,
     634                          ZPixmap, NULL, &self.shminfo,
     635                          self.width, self.height)
     636        log.info("XShmWrapper.XShmCreateImage(..) %s", self.image!=NULL)
     637        if self.image==NULL:
     638            log.info("XShmWrapper.XShmCreateImage(..) failed!")
     639            self.free()
     640            return False
     641        # Get the shared memory:
     642        size = self.image.bytes_per_line*self.image.height
     643        self.shminfo.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777)
     644        log.info("XShmWrapper.shmget(..) %s", self.shminfo.shmid >= 0)
     645        if self.shminfo.shmid < 0:
     646            log.info("XShmWrapper.shmget(..) failed!")
     647            self.free()
     648            return False
     649        # Attach:
     650        self.image.data = <char *> shmat(self.shminfo.shmid, NULL, 0)
     651        self.shminfo.shmaddr = self.image.data
     652        log.info("XShmWrapper.shmat(..) %s", self.shminfo.shmaddr != <char *> -1)
     653        if self.shminfo.shmaddr == <char *> -1:
     654            log.info("XShmWrapper.shmat(..) failed!")
     655            self.free()
     656            return False
     657
     658        # set as read/write, and attach to the display:
     659        self.shminfo.readOnly = False
     660        a = XShmAttach(self.display, &self.shminfo)
     661        log.info("XShmWrapper.shmat(..) %s", bool(a))
     662        if not a:
     663            log.info("XShmWrapper.shmat(..) failed!")
     664            self.free()
     665            return False
     666        return True
     667
     668    def get_image(self, xpixmap):
     669        assert self.image!=NULL
     670        if self.closed:
     671            return None
     672        if not XShmGetImage(self.display, xpixmap, self.image, 0, 0, 0xFFFFFFFF):
     673            log.warn("get_image(%s) XShmGetImage failed!", xpixmap)
     674            return None
     675        if self.imageWrapper is None:
     676            self.imageWrapper = XImageWrapper(0, 0, self.width, self.height)
     677            self.imageWrapper.set_image(self.image)
     678        return self.imageWrapper
     679
     680    def cleanup(self):
     681        #ok, we want to free resources... problem is,
     682        #we may have handed out an imageWrapper!
     683        #and it will point to our Image xshm area.
     684        #so we have to wait until *that* is freed,
     685        #and rely on it telling us it's done.
     686        #(by setting the callback, we also prevent __dealloc__
     687        #from firing, since our class is still referenced there)
     688        log.info("XShmWrapper.cleanup()")
     689        self.closed = True
     690        if self.imageWrapper:
     691            self.imageWrapper.set_del_callback(self.free)
     692            self.imageWrapper = None
     693
     694    def __dealloc__(self):
     695        log.info("XShmWrapper.__dealloc__() self=%s", self)
     696        self.free()
     697
     698    def free(self):
     699        has_shm = self.shminfo.shmaddr!=<char *> -1
     700        log.info("XShmWrapper.free() has_shm=%s, imageWrapper=%s", has_shm, self.imageWrapper)
     701        if has_shm:
     702            XShmDetach(self.display, &self.shminfo)
     703        #this should take care of freeing the XImage via garbage collection:
     704        #see: XImageWrapper.__dealloc__(), but see also cleanup() above...
     705        self.imageWrapper = None
     706        if has_shm:
     707            shmdt(self.shminfo.shmaddr)
     708            self.shminfo.shmaddr = <char *> -1
     709
    569710class PixmapWrapper(object):
    570711    "Reference count an X Pixmap that needs explicit cleanup."
    571     def __init__(self, display, xpixmap, width, height):
     712    def __init__(self, display, xpixmap, width, height):     #@DuplicatedSignature
    572713        self.display = display
    573714        self.xpixmap = xpixmap
    574715        self.width = width
    575716        self.height = height
    576717
    577     def get_image(self, x, y, width, height):
     718    def get_image(self, x, y, width, height):               #@DuplicatedSignature
    578719        if self.xpixmap is None:
    579720            log.warn("PixmapWrapper.get_pixels() xpixmap=%s", self.xpixmap)
    580721            return  None
     
    607748RGB_FORMATS[5] = NULL
    608749
    609750cdef class XImageWrapper:
    610     cdef XImage *image
     751    cdef XImage *image                              #@DuplicatedSignature
    611752    cdef int x
    612753    cdef int y
    613     cdef int width
    614     cdef int height
    615     cdef int depth
     754    cdef int width                                  #@DuplicatedSignature
     755    cdef int height                                 #@DuplicatedSignature
     756    cdef int depth                                  #@DuplicatedSignature
    616757    cdef int rowstride
    617758    cdef char *rgb_format
    618759    cdef char *pixels
     760    cdef object del_callback
    619761
     762    def __init__(self, *args):                      #@DuplicatedSignature
     763        self.del_callback = None
     764
    620765    def __cinit__(self, int x, int y, int width, int height):
    621766        self.image = NULL
    622767        self.pixels = NULL
     
    694839    def set_pixels(self, pixels):
    695840        cdef const unsigned char * buf = NULL
    696841        cdef Py_ssize_t buf_len = 0
    697         #since we replace the pixels,
    698         #we no longer need the XImage or the previous pixels:
    699         self.free()
     842        if self.pixels!=NULL:
     843            free(self.pixels)
     844            self.pixels = NULL
     845        #Note: we can't free the XImage, because it may
     846        #still be used somewhere else (see XShmWrapper)
    700847        assert PyObject_AsReadBuffer(pixels, <const_void_pp> &buf, &buf_len)==0
    701848        self.pixels = <char *> malloc(buf_len)
    702849        assert self.pixels!=NULL
    703850        memcpy(self.pixels, buf, buf_len)
    704851
    705     def __dealloc__(self):
     852    def set_del_callback(self, callback):
     853        self.del_callback = callback
     854
     855    def __dealloc__(self):                              #@DuplicatedSignature
     856        log.info("XImageWrapper.__dealloc__() self=%s, del_callback=%s", self, self.del_callback)
     857        if self.del_callback:
     858            cb = self.del_callback
     859            self.del_callback = None
     860            cb()
    706861        self.free()
    707862
    708     def free(self):
     863    def free(self):                                     #@DuplicatedSignature
     864        log.info("XImageWrapper.free()")
    709865        if self.image!=NULL:
    710866            XDestroyImage(self.image)
    711867            self.image = NULL
  • xpra/x11/gtk_x11/window.py

     
    5555#will then misbehave (they use signed shorts instead of signed ints..)
    5656MAX_WINDOW_SIZE = 2**15-1
    5757MAX_ASPECT = 2*15-1
     58USE_XSHM = os.environ.get("XPRA_XSHM", "1")=="1"
    5859
    5960
    6061# Todo:
     
    231232        self._geometry = None
    232233        self._damage_forward_handle = None
    233234        self._internal_set_property("client-window", client_window)
    234         self._composite = CompositeHelper(self.client_window, False)
     235        use_xshm = USE_XSHM and (not self.is_OR() and not self.is_tray())
     236        self._composite = CompositeHelper(self.client_window, False, use_xshm)
    235237
    236238    def managed_connect(self, detailed_signal, handler, *args):
    237239        """ connects a signal handler and makes sure we will clean it up on unmanage() """
     
    380382
    381383    def get_rgb_rawdata(self, x, y, width, height, logger=log.debug):
    382384        handle = self._composite.get_property("contents-handle")
    383         logger("get_rgb_rawdata(%s, %s, %s, %s) handle=%s", x, y, width, height, handle)
    384385        if handle is None:
    385386            logger("get_rgb_rawdata(..) pixmap is None for window %s", hex(get_xwindow(self.client_window)))
    386387            return  None
    387388
    388389        try:
     390            #try XShm:
     391            w, h = self._geometry[2:4]
     392            logger("get_rgb_rawdata(%s, %s, %s, %s) geometry=%s", x, y, width, height, self._geometry[:4])
     393            if x==0 and y==0 and w==width and h==height:
     394                shm = self._composite.get_property("shm-handle")
     395                logger("get_rgb_rawdata(..) XShm image: %s", shm)
     396                if shm is not None:
     397                    return trap.call_synced(shm.get_image, handle.xpixmap)
     398
    389399            w = min(handle.width, width)
    390400            h = min(handle.height, height)
    391401            if w!=width or h!=height: