Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/x11/xsettings.py : 62%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of Xpra.
2# Copyright (C) 2010-2019 Antoine Martin <antoine@xpra.org>
3# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7from gi.repository import GObject, Gdk, Gtk
9from xpra.gtk_common.gobject_util import no_arg_signal, one_arg_signal
10from xpra.gtk_common.error import xlog, XError
11from xpra.x11.gtk_x11.prop import prop_set, prop_get
12from xpra.x11.gtk_x11.selection import ManagerSelection
13from xpra.x11.gtk_x11.gdk_bindings import (
14 add_event_receiver, #@UnresolvedImport
15 remove_event_receiver, #@UnresolvedImport
16 get_pywindow, #@UnresolvedImport
17 get_xatom, #@UnresolvedImport
18 )
19from xpra.log import Logger
21log = Logger("x11", "xsettings")
23#the X11 atom name for the XSETTINGS property:
24XSETTINGS = "_XSETTINGS_SETTINGS"
25#constant type in prop.py:
26XSETTINGS_TYPE = "xsettings-settings"
28XNone = 0
31class XSettingsManager:
32 def __init__(self, screen_number=0):
33 selection = "_XSETTINGS_S%i" % screen_number
34 self._manager = ManagerSelection(selection)
35 # Technically I suppose ICCCM says we should use FORCE, but it's not
36 # like a window manager where you have to wait for the old wm to clean
37 # things up before you can do anything... as soon as the selection is
38 # gone, the settings are gone. (Also, if we're stealing from
39 # ourselves, we probably don't clean up the window properly.)
40 self._manager.acquire(self._manager.FORCE_AND_RETURN)
41 self._window = self._manager.window()
43 def set_settings(self, settings):
44 if isinstance(settings, list):
45 settings = tuple(settings)
46 elif not isinstance(settings, tuple):
47 log.warn("Warning: discarding xsettings because of incompatible format: %s", type(settings))
48 return
49 try:
50 prop_set(self._window, XSETTINGS, XSETTINGS_TYPE, settings)
51 except XError as e:
52 log("set_settings(%s)", settings, exc_info=True)
53 log.error("Error: XSettings not applied")
54 log.error(" %s", e)
57class XSettingsHelper:
58 """
59 Convenience class for accessing XSETTINGS,
60 without all the code from the watcher.
61 """
62 def __init__(self, screen_number=0):
63 self._selection = "_XSETTINGS_S%s" % screen_number
64 atom = Gdk.Atom.intern(self._selection, False)
65 self._clipboard = Gtk.Clipboard.get(atom)
67 def xsettings_owner(self):
68 with xlog:
69 from xpra.x11.bindings.window_bindings import X11WindowBindings #@UnresolvedImport
70 X11Window = X11WindowBindings()
71 owner_x = X11Window.XGetSelectionOwner(self._selection)
72 log("XGetSelectionOwner(%s)=%#x", self._selection, owner_x)
73 if owner_x == XNone:
74 return None
75 return get_pywindow(self._clipboard, owner_x)
77 def get_settings(self):
78 owner = self.xsettings_owner()
79 log("Fetching current XSettings data, owner=%s", owner)
80 if owner is None:
81 return None
82 try:
83 return prop_get(owner, XSETTINGS, XSETTINGS_TYPE)
84 except XError:
85 log("X error while fetching XSettings data; ignored", exc_info=True)
86 return None
89class XSettingsWatcher(XSettingsHelper, GObject.GObject):
90 __gsignals__ = {
91 "xsettings-changed": no_arg_signal,
93 "xpra-property-notify-event": one_arg_signal,
94 "xpra-client-message-event": one_arg_signal,
95 }
96 def __init__(self, screen_number=0):
97 GObject.GObject.__init__(self)
98 XSettingsHelper.__init__(self, screen_number)
99 self._root = self._clipboard.get_display().get_default_screen().get_root_window()
100 add_event_receiver(self._root, self)
101 self._add_watch()
103 def cleanup(self):
104 remove_event_receiver(self._root, self)
106 def _add_watch(self):
107 owner = self.xsettings_owner()
108 if owner is not None:
109 add_event_receiver(owner, self)
111 def do_xpra_client_message_event(self, event):
112 if (event.window is self._root
113 and event.message_type == "MANAGER"
114 and event.data[1] == get_xatom(self._selection)):
115 log("XSettings manager changed")
116 self._add_watch()
117 self.emit("xsettings-changed")
119 def do_xpra_property_notify_event(self, event):
120 if str(event.atom) == XSETTINGS:
121 log("XSettings property value changed")
122 self.emit("xsettings-changed")
124GObject.type_register(XSettingsWatcher)
127def main():
128 from xpra.x11.xsettings_prop import XSettingsNames
129 from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source
130 init_gdk_display_source()
131 s = XSettingsHelper().get_settings()
132 assert s
133 seq, data = s
134 print("XSettings: (sequence %i)" % seq)
135 for vtype, prop, value, serial in data:
136 if isinstance(value, bytes):
137 vstr = value.decode()
138 else:
139 vstr = str(value)
140 if serial>0:
141 vstr += " (serial=%#x)" % serial
142 print("%8s: %32s = %-32s" % (XSettingsNames.get(vtype, "?"), prop.decode(), vstr))
145if __name__ == "__main__":
146 main()