xpra icon
Bug tracker and wiki

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


Ticket #139: fix-grabs.patch

File fix-grabs.patch, 17.2 KB (added by Antoine Martin, 7 years ago)

fixes grabs but also crashes the server with X11 errors..

  • xpra/x11/gtk_x11/pointer_grab.py

     
    11# This file is part of Xpra.
    2 # Copyright (C) 2008, 2009 Nathaniel Smith <njs@pobox.com>
    3 # Copyright (C) 2012-2014 Antoine Martin <antoine@devloop.org.uk>
     2# Copyright (C) 2014 Antoine Martin <antoine@devloop.org.uk>
    43# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
    54# later version. See the file COPYING for details.
    65
    76import gobject
    87from xpra.gtk_common.gobject_util import one_arg_signal
    9 from xpra.x11.gtk_x11.gdk_bindings import (
    10             add_event_receiver,             #@UnresolvedImport
    11             remove_event_receiver,          #@UnresolvedImport
    12             get_parent)  #@UnresolvedImport
    13 from xpra.x11.gtk_x11.error import trap
     8from xpra.x11.gtk_x11.gdk_bindings import add_event_receiver,remove_event_receiver    #@UnresolvedImport
    149from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport
    15 from xpra.x11.gtk_x11.world_window import get_world_window
    1610X11Window = X11WindowBindings()
    1711
    1812from xpra.log import Logger
     
    2014
    2115
    2216StructureNotifyMask = constants["StructureNotifyMask"]
     17EnterWindowMask = constants["EnterWindowMask"]
     18LeaveWindowMask = constants["LeaveWindowMask"]
    2319
    2420NotifyNormal        = constants["NotifyNormal"]
    2521NotifyGrab          = constants["NotifyGrab"]
     
    3935          "NotifyPointerRoot", "NotifyDetailNone"):
    4036    DETAIL_CONSTANTS[constants[x]] = x
    4137
     38REVERT_CONSTANTS = {}
     39for x in ("RevertToParent", "RevertToPointerRoot", "RevertToNone"):
     40    REVERT_CONSTANTS[constants[x]] = x
     41
     42
    4243log("pointer grab constants: %s", GRAB_CONSTANTS)
    4344log("detail constants: %s", DETAIL_CONSTANTS)
    4445
    4546
    4647class PointerGrabHelper(gobject.GObject):
    47     """ Listens for StructureNotifyMask events
    48         on the window and its parents.
    49     """
     48    """ Listens for focus Grab/Ungrab events """
    5049
    5150    __gsignals__ = {
    52         "xpra-unmap-event"      : one_arg_signal,
    53         "xpra-reparent-event"   : one_arg_signal,
    54 
    5551        "xpra-focus-in-event"   : one_arg_signal,
    5652        "xpra-focus-out-event"  : one_arg_signal,
    5753
     
    5955        "ungrab"                : one_arg_signal,
    6056        }
    6157
    62     # This may raise XError.
    6358    def __init__(self, window):
    6459        super(PointerGrabHelper, self).__init__()
    65         log("PointerGrabHelper.__init__(%#x)", window.xid)
    66         self._has_grab = False
     60        log("PointerGrabHelper.__init__(%s)", window)
    6761        self._window = window
    68         self._listening = None
     62        add_event_receiver(self._window, self)
     63        #do we also need enter/leave?
     64        X11Window.addXSelectInput(self._window.xid, StructureNotifyMask | EnterWindowMask | LeaveWindowMask)
    6965
    7066    def __repr__(self):
    71         xid = 0
    72         if self._window:
    73             xid = self._window.xid
    74         return "PointerGrabHelper(%#x - %s)" % (xid, [hex(x.xid) for x in (self._listening or [])])
     67        return "PointerGrabHelper(%s)" % self._window
    7568
    76     def setup(self):
    77         self._setup_listening()
    78 
    7969    def destroy(self):
    80         if self._window is None:
     70        if self._window:
     71            remove_event_receiver(self._window, self)
     72            self._window = None
     73        else:
    8174            log.warn("pointer grab helper %s already destroyed!", self)
    82         self._window = None
    83         self.force_ungrab("destroying window")
    84         self._cleanup_listening()
    8575
    8676
    87     def _cleanup_listening(self):
    88         if self._listening:
    89             for w in self._listening:
    90                 remove_event_receiver(w, self)
    91             self._listening = None
    92 
    93     def _setup_listening(self):
    94         try:
    95             trap.call_synced(self.do_setup_listening)
    96         except Exception, e:
    97             log("PointerGrabHelper._setup_listening() failed: %s", e)
    98 
    99     def do_setup_listening(self):
    100         assert self._listening is None
    101         add_event_receiver(self._window, self, max_receivers=-1)
    102         self._listening = [self._window]
    103         #recurse parents:
    104         root = self._window.get_screen().get_root_window()
    105         world = get_world_window().window
    106         win = get_parent(self._window)
    107         while win not in (None, root, world) and win.get_parent() is not None:
    108             # We have to use a lowlevel function to manipulate the
    109             # event selection here, because SubstructureRedirectMask
    110             # does not roundtrip through the GDK event mask
    111             # functions.  So if we used them, here, we would clobber
    112             # corral window selection masks, and those don't deserve
    113             # clobbering.  They are our friends!  X is driving me
    114             # slowly mad.
    115             X11Window.addXSelectInput(win.xid, StructureNotifyMask)
    116             add_event_receiver(win, self, max_receivers=-1)
    117             self._listening.append(win)
    118             win = get_parent(win)
    119         log("grab: listening for: %s", [hex(x.xid) for x in self._listening])
    120 
    121     def do_xpra_unmap_event(self, event):
    122         log("grab: unmap %s", event)
    123         #can windows be unmapped with a grab held?
    124         self.force_ungrab(event)
    125 
    126     def do_xpra_reparent_event(self, event):
    127         log("grab: reparent %s", event)
    128         #maybe this isn't needed?
    129         self.force_ungrab(event)
    130         #setup new tree:
    131         self._cleanup_listening()
    132         self._setup_listening()
    133 
    134     def force_ungrab(self, event):
    135         log("force ungrab (has_grab=%s) %s", self._has_grab, event)
    136         if self._has_grab:
    137             self._has_grab = False
    138             self.emit("ungrab", event)
    139 
    140 
    14177    def do_xpra_focus_in_event(self, event):
    142         log("focus_in_event(%s) xid=%#x, mode=%s, detail=%s", event, self._window.xid, GRAB_CONSTANTS.get(event.mode), DETAIL_CONSTANTS.get(event.detail, event.detail))
    143         self._focus_event(event)
     78        log("focus_in_event(%s) mode=%s, detail=%s",
     79            event, GRAB_CONSTANTS.get(event.mode), DETAIL_CONSTANTS.get(event.detail, event.detail))
     80        self.may_emit_grab(event)
    14481
    14582    def do_xpra_focus_out_event(self, event):
    146         log("focus_out_event(%s) xid=%#x, mode=%s, detail=%s", event, self._window.xid, GRAB_CONSTANTS.get(event.mode), DETAIL_CONSTANTS.get(event.detail, event.detail))
    147         self._focus_event(event)
     83        log("focus_out_event(%s) mode=%s, detail=%s",
     84            event, GRAB_CONSTANTS.get(event.mode), DETAIL_CONSTANTS.get(event.detail, event.detail))
     85        self.may_emit_grab(event)
    14886
    149     def _focus_event(self, event):
    150         if event.mode==NotifyGrab and not self._has_grab:
     87    def may_emit_grab(self, event):
     88        if event.mode==NotifyGrab:
    15189            log("emitting grab on %s", self)
    152             self._has_grab = True
    15390            self.emit("grab", event)
    15491        if event.mode==NotifyUngrab:
    15592            log("emitting ungrab on %s", self)
    156             self._has_grab = False
    15793            self.emit("ungrab", event)
    15894
    15995
  • xpra/x11/gtk_x11/window.py

     
    4141from xpra.x11.gtk_x11.error import trap, XError
    4242from xpra.x11.gtk_x11.prop import prop_get, prop_set
    4343from xpra.x11.gtk_x11.composite import CompositeHelper
    44 from xpra.x11.gtk_x11.pointer_grab import PointerGrabHelper
    4544
    4645from xpra.log import Logger
    4746log = Logger("x11", "window")
     
    246245                       "Does the window use transparency", "",
    247246                       False,
    248247                       gobject.PARAM_READABLE),
    249         "has-grab": (gobject.TYPE_BOOLEAN,
    250                        "Does the window own a grab", "",
    251                        False,
    252                        gobject.PARAM_READABLE),
    253248        "fullscreen": (gobject.TYPE_BOOLEAN,
    254249                       "Fullscreen-ness of window", "",
    255250                       False,
     
    285280        "raised"                : one_arg_signal,
    286281        "unmanaged"             : one_arg_signal,
    287282
    288         "pointer-grab"          : one_arg_signal,
    289         "pointer-ungrab"        : one_arg_signal,
    290 
    291283# this signal must be defined in the subclasses to be seen by the event stuff:
    292284#        "xpra-configure-event": one_arg_signal,
    293285        }
     
    307299        self._internal_set_property("client-window", client_window)
    308300        use_xshm = USE_XSHM and (not self.is_OR() and not self.is_tray())
    309301        self._composite = CompositeHelper(self.client_window, False, use_xshm)
    310         self._pointer_grab = PointerGrabHelper(self.client_window)
    311302        self.property_names = ["pid", "transient-for", "fullscreen", "maximized", "window-type", "role", "group-leader", "xid", "has-alpha", "opacity"]
    312303
    313304    def get_property_names(self):
     
    350341            except Exception, ex:
    351342                log.error("error in cleanup handler: %s", ex)
    352343            raise Unmanageable(e)
    353         self._pointer_grab.setup()
    354         self._pointer_grab.connect("grab", self.pointer_grab_event)
    355         self._pointer_grab.connect("ungrab", self.pointer_ungrab_event)
    356344        self._setup_done = True
    357345
    358346    def setup_failed(self, e):
     
    451439                self._damage_forward_handle = None
    452440            self._composite.destroy()
    453441            self._composite = None
    454         if self._pointer_grab:
    455             self._pointer_grab.destroy()
    456             self._pointer_grab = None
    457442
    458443    def _read_initial_properties(self):
    459444        def pget(key, ptype, raise_xerrors=True):
     
    617602    def set_active(self):
    618603        prop_set(self.client_window.get_screen().get_root_window(), "_NET_ACTIVE_WINDOW", "u32", self.client_window.xid)
    619604
    620     #bits to do with grabs: just re-emit the signal
    621     def pointer_grab_event(self, gh, event):
    622         log("pointer_grab_event(%s, %s) forwarding it", gh, event)
    623         self._internal_set_property("has-grab", True)
    624         self.emit("pointer-grab", event)
    625605
    626     def pointer_ungrab_event(self, gh, event):
    627         log("pointer_ungrab_event(%s, %s) forwarding it", gh, event)
    628         self._internal_set_property("has-grab", False)
    629         self.emit("pointer-ungrab", event)
    630 
    631 
    632606gobject.type_register(BaseWindowModel)
    633607
    634608
  • xpra/x11/gtk_x11/world_window.py

     
    147147            # *will* get the focus, and thus a real FocusIn event.
    148148            send_wm_take_focus(self.window, CurrentTime)
    149149
    150     def do_focus_in_event(self, *args):
    151         focuslog("world window got focus")
     150    def do_focus_in_event(self, event):
     151        focuslog("world window got focus: %s", event)
    152152        if not self.get_property("has-toplevel-focus"):
    153153            #super(WorldWindow, self).do_focus_in_event(*args)
    154             gtk.Window.do_focus_in_event(self, *args)
     154            gtk.Window.do_focus_in_event(self, event)
    155155            self.reset_x_focus()
    156156
    157     def do_focus_out_event(self, *args):
    158         focuslog("world window lost focus")
     157    def do_focus_out_event(self, event):
     158        focuslog("world window lost focus: %s", event)
    159159        # Do nothing -- harder:
    160160        self.stop_emission("focus-out-event")
    161161        return False
  • xpra/x11/server.py

     
    1818from xpra.gtk_common.gobject_util import one_arg_signal
    1919from xpra.x11.xsettings import XSettingsManager, XSettingsHelper
    2020from xpra.x11.gtk_x11.wm import Wm
     21from xpra.x11.gtk_x11.pointer_grab import PointerGrabHelper
    2122from xpra.x11.gtk_x11.tray import get_tray_window, SystemTray
    2223from xpra.x11.gtk_x11.prop import prop_set
    2324from xpra.x11.gtk_x11.gdk_bindings import (
     
    2728                               cleanup_x11_filter,          #@UnresolvedImport
    2829                               cleanup_all_event_receivers  #@UnresolvedImport
    2930                               )
     31from xpra.x11.gtk_x11.world_window import get_world_window
    3032from xpra.x11.bindings.window_bindings import X11WindowBindings #@UnresolvedImport
    3133X11Window = X11WindowBindings()
    3234from xpra.x11.bindings.keyboard_bindings import X11KeyboardBindings #@UnresolvedImport
     
    197199        self._wm.connect("bell", self._bell_signaled)
    198200        self._wm.connect("quit", lambda _: self.quit(True))
    199201
     202        #manage pointer grabs:
     203        self._has_grab = None
     204        self._grab_helper = PointerGrabHelper(get_world_window().window)
     205        self._grab_helper.connect("grab", self._pointer_grab)
     206        self._grab_helper.connect("ungrab", self._pointer_ungrab)
     207
    200208        #save default xsettings:
    201209        self.default_xsettings = XSettingsHelper().get_settings()
    202210        settingslog("default_xsettings=%s", self.default_xsettings)
     
    256264
    257265    def get_window_info(self, window):
    258266        info = X11ServerBase.get_window_info(self, window)
    259         info["focused"] = self._window_to_id.get(window, -1)==self._has_focus
     267        info["focused"] = self._has_focus and self._window_to_id.get(window, -1)==self._has_focus
     268        info["grabbed"] = self._has_grab and self._window_to_id.get(window, -1)==self._has_grab
    260269        return info
    261270
    262271
     
    283292        X11ServerBase.cleanup(self)
    284293        cleanup_x11_filter()
    285294        cleanup_all_event_receivers()
     295        if self._grab_helper:
     296            self._grab_helper.destroy()
     297            self._grab_helper = None
     298        if self._wm:
     299            self._wm.cleanup()
     300            self._wm = None
    286301
    287302
    288303    def cleanup_source(self, protocol):
     
    374389        window.managed_connect("client-contents-changed", self._contents_changed)
    375390        window.managed_connect("unmanaged", self._lost_window)
    376391        window.managed_connect("raised", self._raised_window)
    377         window.managed_connect("pointer-grab", self._pointer_grab)
    378         window.managed_connect("pointer-ungrab", self._pointer_ungrab)
    379392        return wid
    380393
    381394    _window_export_properties = ("title", "size-hints", "fullscreen", "maximized", "opacity")
     
    425438            #but for now it is just easier to create a new one:
    426439            self._lost_window(window)
    427440        tray_window = get_tray_window(raw_window)
    428         windowlog("Discovered new override-redirect window: %#x (tray=%s)", xid, tray_window)
     441        windowlog("Discovered new override-redirect window: %#x with geometry=%s (tray=%s)", xid, raw_window.get_geometry(), tray_window)
    429442        try:
    430443            if tray_window is not None:
    431444                assert self._tray
     
    443456                self._send_new_or_window_packet(window)
    444457        except Unmanageable, e:
    445458            if window:
     459                windowlog("window %s is not manageable", window)
    446460                #if window is set, we failed after instantiating it,
    447461                #so we need to fail it manually:
    448462                window.setup_failed(e)
     
    523537            return
    524538        had_focus = self._id_to_window.get(self._has_focus)
    525539        def reset_focus():
    526             focuslog("reset_focus() %s / %s had focus", self._has_focus, had_focus)
     540            toplevel = None
     541            if self._wm:
     542                toplevel = self._wm.get_property("toplevel")
     543            focuslog("reset_focus() %s / %s had focus (toplevel=%s)", self._has_focus, had_focus, toplevel)
    527544            self._clear_keys_pressed()
    528545            # FIXME: kind of a hack:
    529546            self._has_focus = 0
    530             self._wm.get_property("toplevel").reset_x_focus()
     547            #toplevel may be None during cleanup!
     548            if toplevel:
     549                toplevel.reset_x_focus()
    531550
    532551        if wid == 0:
    533552            #wid==0 means root window
     
    595614
    596615
    597616    def _pointer_grab(self, window, event):
    598         log("pointer_grab(%s, %s)", window, event)
    599         wid = self._window_to_id[window]
     617        log("pointer_grab(%s, %s) has_grab=%s, has focus=%s", window, event, self._has_grab, self._has_focus)
     618        if self._has_focus is None or self._has_grab==self._has_focus:
     619            return
     620        self._has_grab = self._has_focus
    600621        for ss in self._server_sources.values():
    601             ss.pointer_grab(wid)
     622            ss.pointer_grab(self._has_grab)
    602623
    603624    def _pointer_ungrab(self, window, event):
    604         log("pointer_ungrab(%s, %s)", window, event)
    605         wid = self._window_to_id[window]
     625        log("pointer_ungrab(%s, %s) has_grab=%s, has focus=%s", window, event, self._has_grab, self._has_focus)
     626        if self._has_grab is None:
     627            return
     628        had_grab = self._has_grab
     629        self._has_grab = None
    606630        for ss in self._server_sources.values():
    607             ss.pointer_ungrab(wid)
     631            ss.pointer_ungrab(had_grab)
    608632
    609633
    610634    def _raised_window(self, window, event):
  • xpra/x11/x11_server_base.py

     
    173173
    174174    def get_window_info(self, window):
    175175        info = GTKServerBase.get_window_info(self, window)
    176         if "has-grab" in window.get_property_names():
    177             info["has-grab"] = window.get_property("has-grab")
    178176        info["XShm"] = window.uses_XShm()
    179177        return info
    180178