xpra icon
Bug tracker and wiki

Ticket #1934: window-filters.patch

File window-filters.patch, 10.2 KB (added by Antoine Martin, 2 years ago)

work in progress: control commands, inject x11 filters, etc

  • xpra/server/mixins/server_base_controlcommands.py

     
    9898            ArgsControlCommand("reset-video-region",    "reset video region heuristics",    min_args=1, max_args=1, validation=[int]),
    9999            ArgsControlCommand("lock-batch-delay",      "set a specific batch delay for a window",       min_args=2, max_args=2, validation=[int, int]),
    100100            ArgsControlCommand("unlock-batch-delay",    "let the heuristics calculate the batch delay again for a window (following a 'lock-batch-delay')",  min_args=1, max_args=1, validation=[int]),
     101            ArgsControlCommand("remove-window-filters", "remove all window filters",        min_args=0, max_args=1),
     102            ArgsControlCommand("add-window-filter",     "add a window filter",              min_args=4, max_args=5),
    101103            ):
    102104            cmd.do_run = getattr(self, "control_command_%s" % cmd.name.replace("-", "_"))
    103105            self.control_commands[cmd.name] = cmd
     
    281283        return "%s of '%s' to %s initiated" % (command_type, filename, client_uuids)
    282284
    283285
     286    def control_command_remove_window_filters(self, client_uuids=""):
     287        #modify the existing list object,
     288        #which is referenced by all the sources
     289        l = len(self.window_filters)
     290        self.window_filters[:] = []
     291        return "removed %i window-filters" % l
     292
     293    def control_command_add_window_filter(self, object_name, property_name, operator, value, client_uuids=""):
     294        from xpra.server.window import filters
     295        window_filter = filters.get_window_filter(object_name, property_name, operator, value)
     296        #log("%s%s=%s", filters.get_window_filter, (object_name, property_name, operator, value), window_filter)
     297        if client_uuids=="*":
     298            #applies to all sources:
     299            self.window_filters.append(("*", window_filter))
     300        else:
     301            sources = tuple(self._control_get_sources(client_uuids))
     302            for ss in sources:
     303                ss.do_add_window_filter(window_filter)
     304        return "added window-filter: %s" % window_filter
     305
     306
    284307    def control_command_compression(self, compression):
    285308        c = compression.lower()
    286309        from xpra.net import compression
  • xpra/server/server_base.py

     
    314314
    315315        def drop_client(reason="unknown", *args):
    316316            self.disconnect_client(proto, reason, *args)
    317         ClientConnectionClass = self.get_server_source_class()
    318         ss = ClientConnectionClass(proto, drop_client,
     317        from xpra.server.source.client_connection import ClientConnection
     318        ss = ClientConnection(proto, drop_client,
    319319                          self.session_name, self,
    320320                          self.idle_add, self.timeout_add, self.source_remove,
    321321                          self.setting_changed,
     
    335335        self.idle_add(self.parse_hello_ui, ss, c, auth_caps, send_ui, share_count)
    336336
    337337
    338     def get_server_source_class(self):
    339         from xpra.server.source.client_connection import ClientConnection
    340         return ClientConnection
    341 
    342338    def reset_window_filters(self):
    343339        self.window_filters = []
    344340
  • xpra/server/source/windows_mixin.py

     
    303303    def get_all_window_filters(self):
    304304        return [f for uuid, f in self.window_filters if uuid==self.uuid]
    305305
    306     def get_window_filter(self, object_name, property_name, operator, value):
    307         if object_name!="window":
    308             raise ValueError("invalid object name")
    309         from xpra.server.window.filters import WindowPropertyIn, WindowPropertyNotIn
    310         if operator=="=":
    311             return WindowPropertyIn(property_name, [value])
    312         elif operator=="!=":
    313             return WindowPropertyNotIn(property_name, [value])
    314         raise ValueError("unknown filter operator: %s" % operator)
    315 
    316306    def add_window_filter(self, object_name, property_name, operator, value):
    317         window_filter = self.get_window_filter(object_name, property_name, operator, value)
     307        from xpra.server.window.filters import get_window_filter
     308        window_filter = get_window_filter(object_name, property_name, operator, value)
    318309        assert window_filter
    319         self.window_filters.append((self.uuid, window_filter.show))
     310        self.do_add_window_filter(window_filter)
    320311
     312    def do_add_window_filter(self, window_filter):
     313        #(reminder: filters are shared between all sources)
     314        self.window_filters.append((self.uuid, window_filter))
     315
    321316    def can_send_window(self, window):
    322317        if not self.hello_sent:
    323318            return False
    324         for uuid,x in self.window_filters:
    325             v = x(window)
     319        for uuid, window_filter in self.window_filters:
     320            v = window_filter.can_show(window)
     321            isuuidmatch = uuid==self.uuid or uuid=="*"
    326322            if v is True:
    327                 return uuid==self.uuid
     323                return isuuidmatch
     324            elif v is False:
     325                return not(isuuidmatch)
    328326        if self.send_windows and self.system_tray:
    329327            #common case shortcut
    330328            return True
  • xpra/server/window/filters.py

     
    66
    77from xpra.log import Logger
    88log = Logger("window")
     9log.enable_debug()
    910
    1011
    1112class WindowPropertyFilter(object):
    12     def __init__(self, property_name, value):
     13    def __init__(self, property_name, value, recurse=False):
    1314        self.property_name = property_name
    1415        self.value = value
     16        self.recurse = recurse
    1517
     18    def get_window(self, window):
     19        return window.get_property("client-window")
     20
    1621    def get_window_value(self, window):
     22        assert window
    1723        return window.get_property(self.property_name)
    1824
    19     def show(self, window):
     25    def can_show(self, window):
    2026        try:
    21             v = self.get_window_value(window)
    22             log("%s.show(%s) %s(..)=%s", type(self).__name__, window, self.get_window_value, v)
     27            w = self.get_window(window)
     28            log("get_window(%s)=%s", window, w)
     29            v = self.get_window_value(w)
     30            log("%s.can_show(%s) %s(..)=%s", self, w, self.get_window_value, v)
    2331        except Exception:
    24             log("%s.show(%s) %s(..) error:", type(self).__name__, window, self.get_window_value, exc_info=True)
     32            log("%s.can_show(%s) %s(..) error:", self, w, self.get_window_value, exc_info=True)
    2533            v = None
    2634        e = self.evaluate(v)
     35        log("%s.evaluate(%s)=%s", self, v, e)
    2736        return e
    2837
    2938    def evaluate(self, window_value):
     
    3544    def evaluate(self, window_value):
    3645        return window_value in self.value
    3746
     47    def __repr__(self):
     48        return "WindowPropertyIn(%s=%s, recurse=%s)" % (self.property_name, self.value, self.recurse)
    3849
     50
    3951class WindowPropertyNotIn(WindowPropertyIn):
    4052
    4153    def evaluate(self, window_value):
    42         return not(WindowPropertyIn.evaluate(window_value))
     54        return not(WindowPropertyIn.evaluate(self, window_value))
     55
     56    def __repr__(self):
     57        return "WindowPropertyNotIn(%s=%s, recurse=%s)" % (self.property_name, self.value, self.recurse)
     58
     59
     60def get_window_filter(object_name, property_name, operator, value):
     61    oname = object_name.lower()
     62    if oname not in ("window", "window-parent"):
     63        raise ValueError("invalid object name '%s'" % object_name)
     64    recurse = oname=="window-parent"
     65    if operator=="=":
     66        window_filter = WindowPropertyIn(property_name, [value], recurse)
     67    elif operator=="!=":
     68        window_filter = WindowPropertyNotIn(property_name, [value], recurse)
     69    else:
     70        raise ValueError("invalid window filter operator: %s" % operator)
     71    log("get_window_filter%s=%s", (object_name, property_name, operator, value), window_filter)
     72    return window_filter
  • xpra/x11/bindings/window_bindings.pyx

     
    984984                                     xreq_type, &xactual_type,
    985985                                     &actual_format, &nitems, &bytes_after, &prop)
    986986        if status != Success:
    987             raise None
     987            raise XError("XGetWindowProperty status: %s" % status)
    988988        if xactual_type == XNone:
    989             raise None
     989            raise BadPropertyType("None type")
    990990        # This should only occur for bad property types:
    991991        assert not (bytes_after and not nitems)
    992992        if bytes_after:
    993             raise None
     993            raise BadPropertyType("incomplete data: %i bytes after" % bytes_after)
    994994        assert actual_format in (8, 16, 32)
    995995        XFree(prop)
    996996        return self.XGetAtomName(xactual_type)
  • xpra/x11/x11_server_core.py

     
    103103        self.current_keyboard_group = None
    104104        with xsync:
    105105            self.x11_init()
     106        from xpra.server import server_features
     107        if server_features.windows:
     108            from xpra.x11.x11_window_filters import init_x11_window_filters
     109            init_x11_window_filters()
    106110
     111
    107112    def x11_init(self):
    108113        clean_keyboard_state()
    109114        if self.fake_xinerama:
     
    275280        self.input_devices = "xtest"
    276281
    277282
    278     def get_server_source_class(self):
    279         from xpra.x11.x11_source import X11ServerSource
    280         return X11ServerSource
    281 
    282 
    283283    def get_child_env(self):
    284284        #adds fakeXinerama:
    285285        env = super(X11ServerCore, self).get_child_env()