xpra icon
Bug tracker and wiki

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


Ticket #170: xpra-saveworkspace2.patch

File xpra-saveworkspace2.patch, 11.8 KB (added by Antoine Martin, 9 years ago)

this patch preserves workspace, and potentially other properties that clients can set

  • wimpiggy/window.py

     
    266266            trap.call(setup)
    267267        except XError, e:
    268268            raise Unmanageable(e)
     269        #so clients can store persistent attributes on windows:
     270        self.client_properties = {}
    269271
     272    def update_client_properties(self, props):
     273        for k,v in props.items():
     274            log.info("update_client_properties setting %s=%s", k, v)
     275            self.client_properties[k] = v
     276
    270277    def _forward_contents_changed(self, obj, event):
    271278        self.emit("client-contents-changed", event)
    272279
  • xpra/client_window.py

     
    128128log = Logger()
    129129
    130130from xpra.window_backing import new_backing
     131try:
     132    from wimpiggy.prop import prop_set, prop_get
     133    has_wimpiggy_prop = True
     134except ImportError, e:
     135    has_wimpiggy_prop = False
    131136
    132137if sys.version < '3':
    133138    import codecs
     
    140145
    141146
    142147class ClientWindow(gtk.Window):
    143     def __init__(self, client, wid, x, y, w, h, metadata, override_redirect):
     148    def __init__(self, client, wid, x, y, w, h, metadata, override_redirect, client_properties):
    144149        if override_redirect:
    145150            init_window(self, WINDOW_POPUP)
    146151        else:
     
    153158        self.new_backing(w, h)
    154159        self._metadata = {}
    155160        self._override_redirect = override_redirect
     161        self._client_properties = client_properties
    156162        self._refresh_timer = None
    157163        self._refresh_ignore_sequence = -1
    158164        # used for only sending focus events *after* the window is mapped:
     
    175181                transient_for._override_redirect_windows.append(self)
    176182        self.connect("notify::has-toplevel-focus", self._focus_change)
    177183
     184    def do_realize(self):
     185        ndesktops = 0
     186        try:
     187            root = gtk.gdk.screen_get_default().get_root_window()
     188            ndesktops = root.property_get("_NET_NUMBER_OF_DESKTOPS")[2][0]
     189        except Exception, e:
     190            log.error("failed to get workspace count: %s", e)
     191        workspace = self._client_properties.get("workspace", -1)
     192        log.info("do_realize() ndesktops=%s, workspace=%s", ndesktops, workspace)
     193
     194        if not has_wimpiggy_prop or ndesktops<2 or workspace<0:
     195            gtk.Window.do_realize(self)
     196            return
     197        #below we duplicate gtk.Widget.do_realize() code
     198        #just so we can insert the property code at the right place:
     199        #after the gdk.Window is created, but before it gets positionned.
     200
     201        self.set_flags(gtk.REALIZED)
     202
     203        # Create a new gdk.Window which we can draw on.
     204        # Also say that we want to receive exposure events by setting
     205        # the event_mask
     206        self.window = gdk.Window(
     207            self.get_parent_window(),
     208            width=self.allocation.width,
     209            height=self.allocation.height,
     210            window_type=gdk.WINDOW_CHILD,
     211            wclass=gdk.INPUT_OUTPUT,
     212            event_mask=self.get_events() | gdk.EXPOSURE_MASK)
     213
     214        try:
     215            prop_set(self.get_window(), "_NET_WM_DESKTOP", "u32", workspace)
     216        except Exception, e:
     217            log.error("failed to set workspace: %s", e)
     218
     219        # Associate the gdk.Window with ourselves, Gtk+ needs a reference
     220        # between the widget and the gdk window
     221        self.window.set_user_data(self)
     222
     223        # Attach the style to the gdk.Window, a style contains colors and
     224        # GC contextes used for drawing
     225        self.style.attach(self.window)
     226
     227        # The default color of the background should be what
     228        # the style (theme engine) tells us.
     229        self.style.set_background(self.window, gtk.STATE_NORMAL)
     230        self.window.move_resize(*self.allocation)       
     231
     232    def get_workspace(self):
     233        try:
     234            if not has_wimpiggy_prop:
     235                prop = self.window.get_screen().get_root_window().property_get("_NET_CURRENT_DESKTOP")
     236                if not prop or len(prop)!=3 or len(prop[2])!=1:
     237                    return  -1
     238                return prop[2][0]
     239            v = prop_get(self.get_window(), "_NET_WM_DESKTOP", "u32", ignore_errors=True)
     240            if type(v)==int:
     241                return  v
     242            return  -1
     243        except Exception, e:
     244            log.error("failed to detect workspace: %s", e)
     245
     246
    178247    def new_backing(self, w, h):
    179248        self._backing = new_backing(self._id, w, h, self._backing, self._client.supports_mmap, self._client.mmap)
    180249
     
    311380        self._backing.cairo_draw(context, x, y)
    312381
    313382    def do_map_event(self, event):
    314         log("Got map event")
     383        log.info("Got map event")
    315384        gtk.Window.do_map_event(self, event)
    316385        if not self._override_redirect:
    317386            x, y, w, h = get_window_geometry(self)
    318             self._client.send(["map-window", self._id, x, y, w, h])
     387            client_properties = {"workspace" : self.get_workspace()}
     388            self._client.send(["map-window", self._id, x, y, w, h, client_properties])
    319389            self._pos = (x, y)
    320390            self._size = (w, h)
    321391        self._been_mapped = True
    322392        gobject.idle_add(self._focus_change)
    323393
    324394    def do_configure_event(self, event):
    325         log("Got configure event: %s", event)
     395        log.info("Got configure event: %s", event)
    326396        gtk.Window.do_configure_event(self, event)
    327397        if self._override_redirect:
    328398            return
  • xpra/server_source.py

     
    342342    def window_metadata(self, wid, metadata):
    343343        self.send(["window-metadata", wid, metadata])
    344344
    345     def new_window(self, ptype, wid, x, y, w, h, metadata):
    346         self.send([ptype, wid, x, y, w, h, metadata])
     345    def new_window(self, ptype, wid, x, y, w, h, metadata, client_properties):
     346        self.send([ptype, wid, x, y, w, h, metadata, client_properties])
    347347
    348348    def lost_window(self, wid):
    349349        self.send(["lost-window", wid])
  • xpra/client.py

     
    101101        self.server_platform = ""
    102102        self.server_actual_desktop_size = None
    103103        self.server_randr = False
     104        self.server_window_properties = False
    104105        self.pixel_counter = maxdeque(maxlen=100)
    105106        self.server_latency = maxdeque(maxlen=100)
    106107        self.server_load = None
     
    629630        if e and e!=self.encoding:
    630631            log.debug("server is using %s encoding" % e)
    631632            self.encoding = e
     633        self.server_window_properties = capabilities.get("client_window_properties", False)
    632634        self.window_configure = capabilities.get("window_configure", False)
    633635        self.server_supports_notifications = capabilities.get("notifications", False)
    634636        self.notifications_enabled = self.server_supports_notifications and self.client_supports_notifications
     
    726728        return screen_sizes
    727729
    728730    def _process_new_common(self, packet, override_redirect):
    729         (wid, x, y, w, h, metadata) = packet[1:7]
     731        log.info("new-common: %s", packet)
     732        wid, x, y, w, h, metadata = packet[1:7]
    730733        assert wid not in self._id_to_window, "we already have a window %s" % wid
    731734        if w<=0 or h<=0:
    732735            log.error("window dimensions are wrong: %sx%s", w, h)
    733736            w = 10
    734737            h = 5
    735         window = ClientWindowClass(self, wid, x, y, w, h, metadata, override_redirect)
     738        client_properties = {}
     739        if len(packet)>=8:
     740            client_properties = packet[7]
     741        window = ClientWindowClass(self, wid, x, y, w, h, metadata, override_redirect, client_properties)
    736742        self._id_to_window[wid] = window
    737743        self._window_to_id[window] = wid
    738744        window.show_all()
  • xpra/server.py

     
    817817
    818818    def _do_send_new_window_packet(self, ptype, window, geometry, properties):
    819819        wid = self._window_to_id[window]
    820         (x, y, w, h) = geometry
     820        x, y, w, h = geometry
    821821        for ss in self._server_sources.values():
    822822            metadata = {}
    823823            for propname in properties:
    824824                metadata.update(self._make_metadata(window, propname, ss.png_window_icons))
    825             ss.new_window(ptype, wid, x, y, w, h, metadata)
     825            ss.new_window(ptype, wid, x, y, w, h, metadata, window.client_properties)
    826826
    827827    def _update_metadata(self, window, pspec):
    828828        wid = self._window_to_id[window]
     
    11411141                metadata = {}
    11421142                for propname in self._all_metadata:
    11431143                    metadata.update(self._make_metadata(window, propname, ss.png_window_icons))
    1144                 ss.new_window("new-window", wid, x, y, w, h, metadata)
     1144                ss.new_window("new-window", wid, x, y, w, h, metadata, window.client_properties)
    11451145        ss.send_cursor(self.cursor_data)
    11461146
    11471147    def send_hello(self, client_capabilities, server_source):
     
    11691169        capabilities["rencode"] = has_rencode
    11701170        capabilities["window_configure"] = True
    11711171        capabilities["xsettings-tuple"] = True
     1172        capabilities["client_window_properties"] = True
    11721173        add_version_info(capabilities)
    11731174        add_gtk_version_info(capabilities, gtk)
    11741175        #_get_desktop_size_capability may cause an asynchronous root window resize event
     
    13531354        self._desktop_manager.configure_window(window, x, y, width, height)
    13541355        self._desktop_manager.show_window(window)
    13551356        self._damage(window, 0, 0, width, height)
     1357        log.info("map_window: %s, window=%s", packet, window)
     1358        if len(packet)>=7:
     1359            client_properties = packet[6]
     1360            window.update_client_properties(client_properties)
    13561361
    13571362    def _process_unmap_window(self, proto, packet):
    13581363        wid = packet[1]
     
    13651370        self._desktop_manager.hide_window(window)
    13661371
    13671372    def _process_configure_window(self, proto, packet):
    1368         (wid, x, y, w, h) = packet[1:6]
     1373        wid, x, y, w, h = packet[1:6]
    13691374        window = self._id_to_window.get(wid)
    13701375        if not window:
    13711376            log("cannot map window %s: already removed!", wid)
    13721377            return
    13731378        assert not isinstance(window, OverrideRedirectWindowModel)
    1374         (owx, owy, oww, owh) = self._desktop_manager.window_geometry(window)
     1379        owx, owy, oww, owh = self._desktop_manager.window_geometry(window)
    13751380        log("_process_configure_window(%s) old window geometry: %s", packet[1:], (owx, owy, oww, owh))
    13761381        self._desktop_manager.configure_window(window, x, y, w, h)
    13771382        if self._desktop_manager.visible(window) and (oww!=w or owh!=h):
  • xpra/gl_client_window.py

     
    6464    MODE_RGB = 1
    6565    MODE_YUV = 2
    6666
    67     def __init__(self, client, wid, x, y, w, h, metadata, override_redirect):
    68         ClientWindow.__init__(self, client, wid, x, y, w, h, metadata, override_redirect)
     67    def __init__(self, client, wid, x, y, w, h, metadata, override_redirect, client_properties):
     68        ClientWindow.__init__(self, client, wid, x, y, w, h, metadata, override_redirect, client_properties)
    6969        display_mode = (gtk.gdkgl.MODE_RGB | gtk.gdkgl.MODE_SINGLE)
    7070        self.glconfig = gtk.gdkgl.Config(mode=display_mode)
    7171        self.glarea = gtk.gtkgl.DrawingArea(self.glconfig)