def do_child_configure_request_event(self, event): # The point of this method is to handle configure requests on # withdrawn windows. We simply allow them to move/resize any way they # want. This is harmless because the window isn't visible anyway (and # apps can create unmapped windows with whatever coordinates they want # anyway, no harm in letting them move existing ones around), and it # means that when the window actually gets mapped, we have more # accurate info on what the app is actually requesting. log("do_child_configure_request_event(%s)", event) if event.window in self._windows: return log("Reconfigure on withdrawn window") def configure(): xid = event.window.xid x, y, w, h = X11Window.getGeometry(xid)[:4] if event.value_mask & CWX: x = event.x if event.value_mask & CWY: y = event.y if event.value_mask & CWWidth: w = event.width if event.value_mask & CWHeight: h = event.height if event.value_mask & (CWX | CWY | CWWidth | CWHeight): log("updated window geometry for window %#x from %s to %s", xid, X11Window.getGeometry(xid)[:4], (x, y, w, h)) X11Window.configureAndNotify(xid, x, y, w, h, event.value_mask) trap.swallow_synced(configure)
def reset_x_focus(self): focuslog("reset_x_focus: widget with focus: %s", self.get_focus()) def do_reset_x_focus(): self._take_focus() root_set("_NET_ACTIVE_WINDOW", "u32", XNone) trap.swallow_synced(do_reset_x_focus)
def get_contents_handle(self): if not self.client_window: #shortcut out return None if self._contents_handle is None: log("refreshing named pixmap") trap.swallow_synced(self._set_pixmap) return self._contents_handle
def _process_mouse_common(self, proto, wid, pointer, modifiers): ss = self._server_sources.get(proto) if ss is None: return pos = gtk.gdk.get_default_root_window().get_pointer()[:2] if pos == pointer: return trap.swallow_synced(self._move_pointer, wid, pointer) ss.make_keymask_match(modifiers)
def _process_mouse_common(self, proto, wid, pointer, modifiers): ss = self._server_sources.get(proto) if ss is None: return pos = gtk.gdk.get_default_root_window().get_pointer()[:2] if pos==pointer: return trap.swallow_synced(self._move_pointer, wid, pointer) ss.make_keymask_match(modifiers)
def do_get_property_contents_handle(self, name): if self._window is None: #shortcut out return None if self._contents_handle is None: log("refreshing named pixmap") assert self._listening_to is None def set_pixmap(): # The tricky part here is that the pixmap returned by # NameWindowPixmap gets invalidated every time the window's # viewable state changes. ("viewable" here is the X term that # means "mapped, and all ancestors are also mapped".) But # there is no X event that will tell you when a window's # viewability changes! Instead we have to find all ancestors, # and watch all of them for unmap and reparent events. But # what about races? I hear you cry. By doing things in the # exact order: # 1) select for StructureNotify # 2) QueryTree to get parent # 3) repeat 1 & 2 up to the root # 4) call NameWindowPixmap # we are safe. (I think.) listening = [] e = None try: root = self._window.get_screen().get_root_window() world = get_world_window().window win = get_parent(self._window) while win not in (None, root, world) and win.get_parent() is not None: # We have to use a lowlevel function to manipulate the # event selection here, because SubstructureRedirectMask # does not roundtrip through the GDK event mask # functions. So if we used them, here, we would clobber # corral window selection masks, and those don't deserve # clobbering. They are our friends! X is driving me # slowly mad. X11Window.addXSelectInput(win.xid, StructureNotifyMask) add_event_receiver(win, self, max_receivers=-1) listening.append(win) win = get_parent(win) handle = XImage.get_xcomposite_pixmap(self._window.xid) except Exception, e: try: self._cleanup_listening(listening) except: pass raise if handle is None: log("failed to name a window pixmap for %s: %s", self._window.xid, e) self._cleanup_listening(listening) else: self._contents_handle = handle # Don't save the listening set until after # NameWindowPixmap has succeeded, to maintain our # invariant: self._listening_to = listening trap.swallow_synced(set_pixmap)
def init_cursor(self): #cursor: self.default_cursor_data = None self.last_cursor_serial = None self.last_cursor_data = None self.send_cursor_pending = False def get_default_cursor(): self.default_cursor_data = X11Keyboard.get_cursor_image() cursorlog("get_default_cursor=%s", self.default_cursor_data) trap.swallow_synced(get_default_cursor) X11Keyboard.selectCursorChange(True)
def _update_window_list(self, *args): # Ignore errors because not all the windows may still exist; if so, # then it's okay to leave the lists out of date for a moment, because # in a moment we'll get a signal telling us about the window that # doesn't exist anymore, will remove it from the list, and then call # _update_window_list again. trap.swallow_synced(self.root_set, "_NET_CLIENT_LIST", ["window"], self._windows_in_order) # This is a lie, but we don't maintain a stacking order, so... trap.swallow_synced(self.root_set, "_NET_CLIENT_LIST_STACKING", ["window"], self._windows_in_order)
def init_cursor(self): #cursor: self.default_cursor_image = None self.last_cursor_serial = None self.last_cursor_image = None self.send_cursor_pending = False def get_default_cursor(): self.default_cursor_image = X11Keyboard.get_cursor_image() cursorlog("get_default_cursor=%s", self.default_cursor_image) trap.swallow_synced(get_default_cursor) X11Keyboard.selectCursorChange(True)
def do_child_configure_request_event(self, event): # The point of this method is to handle configure requests on # withdrawn windows. We simply allow them to move/resize any way they # want. This is harmless because the window isn't visible anyway (and # apps can create unmapped windows with whatever coordinates they want # anyway, no harm in letting them move existing ones around), and it # means that when the window actually gets mapped, we have more # accurate info on what the app is actually requesting. log("do_child_configure_request_event(%s)", event) if event.window in self._windows: return log("Reconfigure on withdrawn window") trap.swallow_synced(X11Window.configureAndNotify, event.window.xid, event.x, event.y, event.width, event.height, event.value_mask)
def destroy_damage_handle(self): log("close_damage_handle()") self.invalidate_pixmap() dh = self._damage_handle if dh: self._damage_handle = None trap.swallow_synced(X11Window.XDamageDestroy, dh) sh = self._xshm_handle if sh: self._xshm_handle = None sh.cleanup() #note: this should be redundant since we cleared the #reference to self.client_window and shortcut out in do_get_property_contents_handle #but it's cheap anyway self.invalidate_pixmap()
def acknowledge_changes(self): if self._shm_handle: self._shm_handle.discard() if self._damage_handle is not None and self._window is not None: #"Synchronously modifies the regions..." so unsynced? if not trap.swallow_synced(X11Window.XDamageSubtract, self._damage_handle): self.invalidate_pixmap()
def x11_init(self): X11ServerBase.x11_init(self) assert init_x11_filter() is True self._has_grab = 0 self._has_focus = 0 # Do this before creating the Wm object, to avoid clobbering its # selecting SubstructureRedirect. root = gtk.gdk.get_default_root_window() root.set_events(root.get_events() | gtk.gdk.SUBSTRUCTURE_MASK) root.property_change(gtk.gdk.atom_intern("XPRA_SERVER", False), gtk.gdk.atom_intern("STRING", False), 8, gtk.gdk.PROP_MODE_REPLACE, xpra.__version__) add_event_receiver(root, self) ### Create the WM object self._wm = Wm(self.clobber, self.wm_name) self._wm.connect("new-window", self._new_window_signaled) self._wm.connect("bell", self._bell_signaled) self._wm.connect("quit", lambda _: self.clean_quit(True)) self._wm.connect("show-desktop", self._show_desktop) #save default xsettings: self.default_xsettings = XSettingsHelper().get_settings() settingslog("default_xsettings=%s", self.default_xsettings) self._settings = {} self._xsettings_manager = None #for handling resize synchronization between client and server (this is not xsync!): self.last_client_configure_event = 0 self.snc_timer = 0 #cursor: self.default_cursor_data = None self.last_cursor_serial = None self.last_cursor_data = None self.send_cursor_pending = False def get_default_cursor(): self.default_cursor_data = X11Keyboard.get_cursor_image() cursorlog("get_default_cursor=%s", self.default_cursor_data) trap.swallow_synced(get_default_cursor) self._wm.enableCursors(True)
def cleanup(self): log("SystemTray.cleanup()") root = gtk.gdk.get_default_root_window() owner = X11Window.XGetSelectionOwner(SELECTION) if owner==self.tray_window.xid: X11Window.XSetSelectionOwner(0, SELECTION) else: log.warn("SystemTray.cleanup() we were no longer the selection owner") remove_event_receiver(self.tray_window, self) def undock(window): log("undocking %s", window) X11Window.Unmap(window.xid) X11Window.Reparent(window.xid, root.xid, 0, 0) for window, tray_window in self.tray_windows.items(): trap.swallow_synced(undock, window) tray_window.destroy() self.tray_window.destroy() self.tray_window = None log("SystemTray.cleanup() done")
def acknowledge_changes(self): sh = self._xshm_handle dh = self._damage_handle log("acknowledge_changes() xshm handle=%s, damage handle=%s", sh, dh) if sh: sh.discard() if dh and self.client_window: #"Synchronously modifies the regions..." so unsynced? if not trap.swallow_synced(X11Window.XDamageSubtract, dh): self.invalidate_pixmap()
def cleanup(self): log("SystemTray.cleanup()") root = gtk.gdk.get_default_root_window() owner = X11Window.XGetSelectionOwner(SELECTION) if owner==self.tray_window.xid: X11Window.XSetSelectionOwner(0, SELECTION) log("SystemTray.cleanup() reset %s selection owner to %#x", SELECTION, X11Window.XGetSelectionOwner(SELECTION)) else: log.warn("SystemTray.cleanup() we were no longer the selection owner") remove_event_receiver(self.tray_window, self) def undock(window): log("undocking %s", window) X11Window.Unmap(window.xid) X11Window.Reparent(window.xid, root.xid, 0, 0) for window, tray_window in self.tray_windows.items(): trap.swallow_synced(undock, window) tray_window.destroy() self.tray_window.destroy() self.tray_window = None log("SystemTray.cleanup() done")
def destroy(self): if self._window is None: log.warn("composite window %s already destroyed!", self) return #clear the reference to the window early: win = self._window xwin = self._window.xid #Note: invalidate_pixmap()/_cleanup_listening() use self._window, but won't care if it's None self._window = None remove_event_receiver(win, self) self.invalidate_pixmap() if not self._already_composited: trap.swallow_synced(X11Window.XCompositeUnredirectWindow, xwin) if self._damage_handle: trap.swallow_synced(X11Window.XDamageDestroy, self._damage_handle) self._damage_handle = None if self._shm_handle: self._shm_handle.cleanup() self._shm_handle = None #note: this should be redundant since we cleared the #reference to self._window and shortcut out in do_get_property_contents_handle #but it's cheap anyway self.invalidate_pixmap()
def do_destroy(self, window): trap.swallow_synced(X11Window.XCompositeUnredirectWindow, self.xid) WindowDamageHandler.do_destroy(self, window)
def do_destroy(self, window): trap.swallow_synced(X11Window.XCompositeUnredirectWindow, window.xid) WindowDamageHandler.do_destroy(self, window)