xpra icon
Bug tracker and wiki

Ticket #390: shadow-damage.patch

File shadow-damage.patch, 6.8 KB (added by Antoine Martin, 5 years ago)

try to use x11 damage events with the shadow server

  • xpra/x11/gtk_x11/gdk_bindings.pyx

     
    448448    return str(PyGdkAtom_New(gdk_atom))
    449449
    450450
     451def query_tree(pywindow):
     452    return _query_tree(pywindow)
     453
    451454# Children listing
    452455cdef _query_tree(pywindow):
    453456    cdef Window root = 0, parent = 0
  • xpra/x11/shadow_x11_server.py

     
    44# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
    55# later version. See the file COPYING for details.
    66
     7import gobject
    78import gtk.gdk
     9from weakref import WeakKeyDictionary
    810
     11from xpra.log import Logger
     12log = Logger("shadow")
     13
    914from xpra.x11.x11_server_base import X11ServerBase
    1015from xpra.server.shadow_server_base import ShadowServerBase
    1116from xpra.server.gtk_root_window_model import GTKRootWindowModel
    1217
     18from xpra.x11.gtk_x11.prop import prop_get
     19from xpra.x11.gtk_x11.error import trap
     20from xpra.x11.gtk_x11.gdk_bindings import (
     21                        init_x11_filter,        #@UnresolvedImport
     22                        cleanup_x11_filter,     #@UnresolvedImport
     23                        query_tree,             #@UnresolvedImport
     24                        add_event_receiver,     #@UnresolvedImport
     25                        )
     26from xpra.gtk_common.gobject_util import one_arg_signal
     27from xpra.x11.bindings.window_bindings import X11WindowBindings #@UnresolvedImport
     28X11Window = X11WindowBindings()
    1329
    14 class ShadowX11Server(ShadowServerBase, X11ServerBase):
    1530
     31class ShadowX11Server(ShadowServerBase, X11ServerBase, gobject.GObject):
     32
     33    __gsignals__ = {
     34        "xpra-configure-event"          : one_arg_signal,
     35        "xpra-unmap-event"              : one_arg_signal,
     36        "xpra-destroy-event"            : one_arg_signal,
     37        "xpra-damage-event"             : one_arg_signal,
     38        "xpra-reparent-event"           : one_arg_signal,
     39        "child-map-request-event"       : one_arg_signal,
     40        "child-configure-request-event" : one_arg_signal,
     41        }
     42
    1643    def __init__(self):
     44        gobject.GObject.__init__(self)
    1745        ShadowServerBase.__init__(self, gtk.gdk.get_default_root_window())
    1846        X11ServerBase.__init__(self)
     47        self.damage_handles = WeakKeyDictionary()
     48        self.damage_ack_pending = set()
    1949
    2050    def init(self, opts):
    2151        X11ServerBase.init(self, False, opts)
     52        init_x11_filter()
     53        #force refresh to start for now (just to test!)
     54        #self.start_refresh()
    2255
     56    def cleanup(self, *args):
     57        X11ServerBase.cleanup(self)
     58        cleanup_x11_filter()
     59        #stop listening for damage:
     60        for dh in self.damage_handles.values():
     61            trap.call_synced(X11Window.XDamageDestroy, dh)
     62
    2363    def makeRootWindowModel(self):
    24         return GTKRootWindowModel(self.root)
     64        root_model = GTKRootWindowModel(self.root)
     65        root_model.acknowledge_changes = self.acknowledge_changes
     66        return root_model
    2567
     68    def start_refresh(self):
     69        #don't use a timer, watch for window changes:
     70        log.info("start_refresh() root=%s", self.root)
     71        #listen for events on the root window and all children:
     72        self.watch_window(self.root)
     73        #also start the usual timer based refresh, but much slower:
     74        #ShadowServerBase.start_refresh(1*1000)        #every 1 second
     75
     76    def watch_window(self, win, level=0):
     77        if win in self.damage_handles:
     78            return
     79        if win.get_window_type()==gtk.gdk.WINDOW_TEMP:
     80            log.warn("ignoring temporary window %s: %#x", win, win.xid)
     81        add_event_receiver(win, self)
     82        #win.set_events(gtk.gdk.STRUCTURE_MASK | gtk.gdk.SUBSTRUCTURE_MASK | gtk.gdk.EXPOSURE_MASK)
     83        win.set_events(gtk.gdk.STRUCTURE_MASK | gtk.gdk.SUBSTRUCTURE_MASK | gtk.gdk.EXPOSURE_MASK)
     84        try:
     85            damage_handle = trap.call_synced(X11Window.XDamageCreate, win.xid)
     86        except:
     87            log.error("failed to create damage for window %s: %#x", win, win.xid)
     88            return
     89        self.damage_handles[win] = damage_handle
     90        #add children:
     91        parent, children = query_tree(win)
     92        log.info("%squery_tree(%s)=%s", " "*level, win, (parent, children))
     93        for w in children:
     94            self.watch_window(w, level+1)
     95
     96    def do_child_map_request_event(self, event):
     97        log.info("do_child_map_request_event(%s)", event)
     98
     99    def do_xpra_unmap_event(self, event):
     100        log.info("do_xpra_unmap_event(%s)", event)
     101
     102    def do_xpra_configure_event(self, event):
     103        #log.info("do_xpra_configure_event(%s)", event)
     104        win = event.window
     105        if win not in self.damage_handles:
     106            log.info("do_xpra_configure_event(..) new window: %#x", win.xid)
     107            trap.swallow(self.watch_window, win)
     108
     109    def do_child_configure_request_event(self, event):
     110        #log.info("do_child_configure_request_event(%s)", event)
     111        win = event.window
     112        if win not in self.damage_handles:
     113            log.info("do_child_configure_request_event(..) new window: %#x", win.xid)
     114            trap.swallow(self.watch_window, win)
     115       
     116    def do_xpra_reparent_event(self, event):
     117        log.info("do_xpra_reparent_event(%s)", event)
     118
     119    def do_xpra_damage_event(self, event):
     120        #log.info("do_xpra_damage_event(%s)", event)
     121        win = event.window
     122        wx, wy = win.get_geometry()[:2]
     123        absx = wx+event.x
     124        absy = wy+event.y
     125        self.damage_ack_pending.add(win.xid)
     126        log.info("do_xpra_damage_event(..) window %s: %s", self.wininfo(win), (absx, absy, event.width, event.height))
     127        self._damage(self.root_window_model, absx, absy, event.width, event.height, {})
     128
     129    def acknowledge_changes(self):
     130        log.info("acknowledge_changes() substracting X11 windows: %s", ", ".join([hex(x) for x in self.damage_ack_pending]))
     131        for xid in self.damage_ack_pending:
     132            trap.swallow_synced(X11Window.XDamageSubtract, xid)
     133        self.damage_ack_pending = set()
     134
     135    def wininfo(self, win):
     136        name = prop_get(win, "_NET_WM_NAME", "utf8", True)
     137        if name:
     138            return "%#x : %s" % (win.xid, name)
     139        return hex(win.xid)
     140        #prop_get(target, key, etype, ignore_errors=False, raise_xerrors=False):
     141
    26142    def _process_mouse_common(self, proto, wid, pointer, modifiers):
    27143        #adjust pointer position for offset in client:
    28144        x, y = pointer
     
    41157        info["features.shadow"] = True
    42158        info["server.type"] = "Python/gtk2/x11-shadow"
    43159        return info
     160
     161gobject.type_register(ShadowX11Server)