def __init__(self, props): gobject.GObject.__init__(self) self._props = props self._root = gtk.gdk.get_default_root_window() self._saved_event_mask = self._root.get_events() self._root.set_events(self._saved_event_mask | gtk.gdk.PROPERTY_CHANGE_MASK) self._own_x11_filter = init_x11_filter() add_event_receiver(self._root, self)
def setup(self): xwin = self._window.xid if not self._already_composited: X11Window.XCompositeRedirectWindow(xwin) self._border_width = X11Window.geometry_with_border(xwin)[-1] self.invalidate_pixmap() self._damage_handle = X11Window.XDamageCreate(xwin) log("CompositeHelper.setup() damage handle(%#x)=%#x", xwin, self._damage_handle) add_event_receiver(self._window, self)
def setup(self): self.invalidate_pixmap() xid = self.client_window.xid geom = X11Window.geometry_with_border(xid) if geom is None: raise Unmanageable("window %#x disappeared already" % xid) self._border_width = geom[-1] self.create_damage_handle() add_event_receiver(self.client_window, self)
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 as e: try: self._cleanup_listening(listening) except: pass raise if handle is None: #avoid race during signal exit, which will clear self._window: win = self._window xid = 0 if win: xid = win.xid log("failed to name a window pixmap for %#x: %s", 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
def x11_init(self): X11ServerBase.x11_init(self) assert init_x11_filter() is True display = gtk.gdk.display_get_default() screens = display.get_n_screens() for n in range(screens): screen = display.get_screen(n) root = screen.get_root_window() add_event_receiver(root, self) add_catchall_receiver("xpra-motion-event", self) add_catchall_receiver("xpra-xkb-event", self) X11Keyboard.selectBellNotification(True)
def call_setup(self): """ Call this method to prepare the window: * makes sure it still exists (by querying its geometry which may raise an XError) * setup composite redirection * calls setup The difficulty comes from X11 errors and synchronization: we want to catch errors and undo what we've done. The mix of GTK and pure-X11 calls is not helping. """ try: with xsync: geom = X11Window.geometry_with_border(self.xid) if geom is None: raise Unmanageable("window %#x disappeared already" % self.xid) self._internal_set_property("geometry", geom[:4]) self._read_initial_X11_properties() except XError as e: raise Unmanageable(e) add_event_receiver(self.client_window, self) # Keith Packard says that composite state is undefined following a # reparent, so I'm not sure doing this here in the superclass, # before we reparent, actually works... let's wait and see. try: self._composite = CompositeHelper(self.client_window) with xsync: self._composite.setup() if X11Window.displayHasXShape(): X11Window.XShapeSelectInput(self.xid) except Exception as e: remove_event_receiver(self.client_window, self) log("%s %#x does not support compositing: %s", self._MODELTYPE, self.xid, e) with xswallow: self._composite.destroy() self._composite = None if isinstance(e, Unmanageable): raise raise Unmanageable(e) #compositing is now enabled, #from now on we must call setup_failed to clean things up self._managed = True try: with xsync: self.setup() except XError as e: try: with xsync: self.setup_failed(e) except Exception as ex: log.error("error in cleanup handler: %s", ex) raise Unmanageable(e) self._setup_done = True
def setup(self): super(WindowModel, self).setup() x, y, w, h, _ = self.client_window.get_geometry() # We enable PROPERTY_CHANGE_MASK so that we can call # x11_get_server_time on this window. self.corral_window = gtk.gdk.Window(self.parking_window, x = x, y = y, width =w, height= h, window_type=gtk.gdk.WINDOW_CHILD, wclass=gtk.gdk.INPUT_OUTPUT, event_mask=gtk.gdk.PROPERTY_CHANGE_MASK, title = "CorralWindow-%#x" % self.xid) log("setup() corral_window=%#x", self.corral_window.xid) prop_set(self.corral_window, "_NET_WM_NAME", "utf8", u"Xpra-CorralWindow-%#x" % self.xid) X11Window.substructureRedirect(self.corral_window.xid) add_event_receiver(self.corral_window, self) # The child might already be mapped, in case we inherited it from # a previous window manager. If so, we unmap it now, and save the # serial number of the request -- this way, when we get an # UnmapNotify later, we'll know that it's just from us unmapping # the window, not from the client withdrawing the window. if X11Window.is_mapped(self.xid): log("hiding inherited window") self.last_unmap_serial = X11Window.Unmap(self.xid) log("setup() adding to save set") X11Window.XAddToSaveSet(self.xid) self.in_save_set = True log("setup() reparenting") X11Window.Reparent(self.xid, self.corral_window.xid, 0, 0) self.client_reparented = True log("setup() geometry") w, h = X11Window.geometry_with_border(self.xid)[2:4] hints = self.get_property("size-hints") log("setup() hints=%s size=%ix%i", hints, w, h) nw, nh = calc_constrained_size(w, h, hints) if nw>=MAX_WINDOW_SIZE or nh>=MAX_WINDOW_SIZE: #we can't handle windows that big! raise Unmanageable("window constrained size is too large: %sx%s (from client geometry: %s,%s with size hints=%s)" % (nw, nh, w, h, hints)) self._updateprop("geometry", (x, y, nw, nh)) log("setup() resizing windows to %sx%s", nw, nh) self.corral_window.resize(nw, nh) self.client_window.resize(nw, nh) self.client_window.show_unraised() #this is here to trigger X11 errors if any are pending #or if the window is deleted already: self.client_window.get_geometry()
def dock_tray(self, xid): root = gtk.gdk.get_default_root_window() window = gtk.gdk.window_foreign_new(xid) if window is None: log.warn("could not find gdk window for tray window %#x", xid) return w, h = window.get_geometry()[2:4] event_mask = gtk.gdk.STRUCTURE_MASK | gtk.gdk.EXPOSURE_MASK | gtk.gdk.PROPERTY_CHANGE_MASK window.set_events(event_mask=event_mask) add_event_receiver(window, self) w = max(1, min(64, w)) h = max(1, min(64, h)) title = prop_get(window, "_NET_WM_NAME", "utf8", ignore_errors=True) if title is None: title = prop_get(window, "WM_NAME", "latin1", ignore_errors=True) if title is None: title = "" log("dock_tray(%#x) gdk window=%#x, geometry=%s, title=%s, visual.depth=%s", xid, window.xid, window.get_geometry(), title, window.get_visual().depth) event_mask = gtk.gdk.STRUCTURE_MASK | gtk.gdk.EXPOSURE_MASK | gtk.gdk.PROPERTY_CHANGE_MASK tray_window = gtk.gdk.Window(root, width=w, height=h, window_type=gtk.gdk.WINDOW_TOPLEVEL, event_mask = event_mask, wclass=gtk.gdk.INPUT_OUTPUT, title=title, x=-200, y=-200, override_redirect=True, visual=window.get_visual(), colormap=window.get_colormap()) log("dock_tray(%#x) setting tray properties", xid) set_tray_window(tray_window, window) tray_window.show() self.tray_windows[window] = tray_window self.window_trays[tray_window] = window log("dock_tray(%#x) resizing and reparenting", xid) window.resize(w, h) xwin = window.xid xtray = tray_window.xid X11Window.Withdraw(xwin) X11Window.Reparent(xwin, xtray, 0, 0) X11Window.MapRaised(xwin) log("dock_tray(%#x) new tray container window %#x", xid, xtray) tray_window.invalidate_rect(gtk.gdk.Rectangle(width=w, height=h), True) X11Window.send_xembed_message(xwin, XEMBED_EMBEDDED_NOTIFY, 0, xtray, XEMBED_VERSION)
def setup_tray_window(self): display = gtk.gdk.display_get_default() root = gtk.gdk.get_default_root_window() screen = root.get_screen() if TRANSPARENCY: colormap, visual = screen.get_rgba_colormap(), screen.get_rgba_visual() if colormap is None or visual is None: log.warn("setup tray: using rgb visual fallback") colormap, visual = screen.get_rgb_colormap(), screen.get_rgb_visual() assert colormap is not None and visual is not None, "failed to obtain visual or colormap" owner = X11Window.XGetSelectionOwner(SELECTION) log("setup tray: current selection owner=%#x", owner) if owner!=XNone: raise Exception("%s already owned by %s" % (SELECTION, owner)) self.tray_window = gtk.gdk.Window(root, width=1, height=1, window_type=gtk.gdk.WINDOW_TOPLEVEL, event_mask = 0, wclass=gtk.gdk.INPUT_OUTPUT, title="Xpra-SystemTray", visual=visual, colormap=colormap) xtray = self.tray_window.xid set_tray_visual(self.tray_window, visual) set_tray_orientation(self.tray_window, TRAY_ORIENTATION_HORZ) log("setup tray: tray window %#x", xtray) display.request_selection_notification(SELECTION) try: with xsync: setsel = X11Window.XSetSelectionOwner(xtray, SELECTION) log("setup tray: set selection owner returned %s, owner=%#x", setsel, X11Window.XGetSelectionOwner(SELECTION)) event_mask = StructureNotifyMask log("setup tray: sending client message") X11Window.sendClientMessage(root.xid, root.xid, False, event_mask, "MANAGER", CurrentTime, SELECTION, xtray) owner = X11Window.XGetSelectionOwner(SELECTION) assert owner==xtray, "we failed to get ownership of the tray selection" add_event_receiver(self.tray_window, self) log("setup tray: done") except Exception: log("setup_tray failure", exc_info=True) self.cleanup() raise
def __init__(self, replace_other_wm, wm_name, display=None): gobject.GObject.__init__(self) if display is None: display = gtk.gdk.display_manager_get().get_default_display() self._display = display self._root = self._display.get_default_screen().get_root_window() self._wm_name = wm_name self._ewmh_window = None self._windows = {} # EWMH says we have to know the order of our windows oldest to # youngest... self._windows_in_order = [] # Become the Official Window Manager of this year's display: self._wm_selection = ManagerSelection(self._display, "WM_S0") self._cm_wm_selection = ManagerSelection(self._display, "_NET_WM_CM_S0") self._wm_selection.connect("selection-lost", self._lost_wm_selection) self._cm_wm_selection.connect("selection-lost", self._lost_wm_selection) # May throw AlreadyOwned: if replace_other_wm: mode = self._wm_selection.FORCE else: mode = self._wm_selection.IF_UNOWNED self._wm_selection.acquire(mode) self._cm_wm_selection.acquire(mode) # Set up the necessary EWMH properties on the root window. self._setup_ewmh_window() # Start with just one desktop: self.set_desktop_list([u"Main"]) self.set_current_desktop(0) # Start with the full display as workarea: root_w, root_h = gtk.gdk.get_default_root_window().get_size() self.root_set("_NET_SUPPORTED", ["atom"], NET_SUPPORTED) self.set_workarea(0, 0, root_w, root_h) self.set_desktop_geometry(root_w, root_h) self.root_set("_NET_DESKTOP_VIEWPORT", ["u32"], [0, 0]) # Load up our full-screen widget self._world_window = WorldWindow(self._display.get_default_screen()) self.notify("toplevel") self._world_window.show_all() # Okay, ready to select for SubstructureRedirect and then load in all # the existing clients. add_event_receiver(self._root, self) add_fallback_receiver("xpra-client-message-event", self) X11Window.substructureRedirect(self._root.xid) for w in get_children(self._root): # Checking for FOREIGN here filters out anything that we've # created ourselves (like, say, the world window), and checking # for mapped filters out any withdrawn windows. if (w.get_window_type() == gtk.gdk.WINDOW_FOREIGN and not X11Window.is_override_redirect(w.xid) and X11Window.is_mapped(w.xid)): log("Wm managing pre-existing child window %#x", w.xid) self._manage_client(w) # Also watch for focus change events on the root window X11Window.selectFocusChange(self._root.xid) X11Keyboard.selectBellNotification(True)
def acquire(self, when): old_owner = self._owner() if when is self.IF_UNOWNED and old_owner != XNone: raise AlreadyOwned self.clipboard.set_with_data([("VERSION", 0, 0)], self._get, self._clear, None) # Having acquired the selection, we have to announce our existence # (ICCCM 2.8, still). The details here probably don't matter too # much; I've never heard of an app that cares about these messages, # and metacity actually gets the format wrong in several ways (no # MANAGER or owner_window atoms). But might as well get it as right # as possible. # To announce our existence, we need: # -- the timestamp we arrived at # -- the manager selection atom # -- the window that registered the selection # Of course, because Gtk is doing so much magic for us, we have to do # some weird tricks to get at these. # Ask ourselves when we acquired the selection: ts_data = self.clipboard.wait_for_contents("TIMESTAMP").data #data is a timestamp, X11 datatype is Time which is CARD32, #(which is 64 bits on 64-bit systems!) Lsize = calcsize("@L") if len(ts_data)==Lsize: ts_num = unpack("@L", ts_data[:Lsize])[0] else: ts_num = 0 #CurrentTime log.warn("invalid data for 'TIMESTAMP': %s", ([hex(ord(x)) for x in ts_data])) # Calculate the X atom for this selection: selection_xatom = get_xatom(self.atom) # Ask X what window we used: self._xwindow = X11Window.XGetSelectionOwner(self.atom) root = self.clipboard.get_display().get_default_screen().get_root_window() X11Window.sendClientMessage(root.xid, root.xid, False, StructureNotifyMask, "MANAGER", ts_num, selection_xatom, self._xwindow) if old_owner != XNone and when is self.FORCE: # Block in a recursive mainloop until the previous owner has # cleared out. try: with xsync: window = get_pywindow(self.clipboard, old_owner) window.set_events(window.get_events() | gtk.gdk.STRUCTURE_MASK) log("got window") except XError: log("Previous owner is already gone, not blocking") else: log("Waiting for previous owner to exit...") add_event_receiver(window, self) gtk.main() log("...they did.") window = get_pywindow(self.clipboard, self._xwindow) window.set_title("Xpra-ManagerSelection")
def __init__(self, screen_number=0): gobject.GObject.__init__(self) XSettingsHelper.__init__(self, screen_number) self._root = self._clipboard.get_display().get_default_screen().get_root_window() add_event_receiver(self._root, self) self._add_watch()
def _add_watch(self): owner = self.xsettings_owner() if owner is not None: add_event_receiver(owner, self)