def __init__(self, display): self.conn = xcffib.connect(display=display) self._connected = True self.cursors = Cursors(self) self.setup = self.conn.get_setup() extensions = self.extensions() self.screens = [Screen(self, i) for i in self.setup.roots] self.default_screen = self.screens[self.conn.pref_screen] for i in extensions: if i in self._extmap: setattr(self, i, self._extmap[i](self)) self.pseudoscreens = [] if "xinerama" in extensions: for i, s in enumerate(self.xinerama.query_screens()): scr = PseudoScreen( self, s.x_org, s.y_org, s.width, s.height, ) self.pseudoscreens.append(scr) elif "randr" in extensions: for i in self.randr.query_crtcs(self.screens[0].root.wid): scr = PseudoScreen( self, i["x"], i["y"], i["width"], i["height"], ) self.pseudoscreens.append(scr) self.atoms = AtomCache(self) self.code_to_syms = {} self.sym_to_codes = None self.refresh_keymap() self.modmap = None self.refresh_modmap()
def __init__(self, display): self.conn = xcffib.connect(display=display) self._connected = True self.cursors = Cursors(self) self.setup = self.conn.get_setup() extensions = self.extensions() self.screens = [Screen(self, i) for i in self.setup.roots] self.default_screen = self.screens[self.conn.pref_screen] for i in extensions: if i in self._extmap: setattr(self, i, self._extmap[i](self)) self.atoms = AtomCache(self) self.code_to_syms = {} self.sym_to_codes = None self.refresh_keymap() self.modmap = None self.refresh_modmap()
class Connection: _extmap = { "xinerama": Xinerama, "randr": RandR, "xfixes": XFixes, } def __init__(self, display): self.conn = xcffib.connect(display=display) self._connected = True self.cursors = Cursors(self) self.setup = self.conn.get_setup() extensions = self.extensions() self.screens = [Screen(self, i) for i in self.setup.roots] self.default_screen = self.screens[self.conn.pref_screen] for i in extensions: if i in self._extmap: setattr(self, i, self._extmap[i](self)) self.pseudoscreens = [] if "xinerama" in extensions: for i, s in enumerate(self.xinerama.query_screens()): scr = PseudoScreen( self, s.x_org, s.y_org, s.width, s.height, ) self.pseudoscreens.append(scr) elif "randr" in extensions: for i in self.randr.query_crtcs(self.screens[0].root.wid): scr = PseudoScreen( self, i["x"], i["y"], i["width"], i["height"], ) self.pseudoscreens.append(scr) self.atoms = AtomCache(self) self.code_to_syms = {} self.sym_to_codes = None self.refresh_keymap() self.modmap = None self.refresh_modmap() def finalize(self): self.cursors.finalize() self.disconnect() def refresh_keymap(self, first=None, count=None): if first is None: first = self.setup.min_keycode count = self.setup.max_keycode - self.setup.min_keycode + 1 q = self.conn.core.GetKeyboardMapping(first, count).reply() assert len(q.keysyms) % q.keysyms_per_keycode == 0 for i in range(len(q.keysyms) // q.keysyms_per_keycode): self.code_to_syms[first + i] = \ q.keysyms[i * q.keysyms_per_keycode:(i + 1) * q.keysyms_per_keycode] sym_to_codes = {} for k, s in self.code_to_syms.items(): for sym in s: if sym == 0: continue if sym not in sym_to_codes: sym_to_codes[sym] = [k] elif k not in sym_to_codes[sym]: sym_to_codes[sym].append(k) self.sym_to_codes = sym_to_codes def refresh_modmap(self): reply = self.conn.core.GetModifierMapping().reply() modmap = {} names = (repeat(name, reply.keycodes_per_modifier) for name in ModMasks) for name, keycode in zip(chain.from_iterable(names), reply.keycodes): value = modmap.setdefault(name, []) value.append(keycode) self.modmap = modmap def get_modifier(self, keycode): """Return the modifier matching keycode""" for n, l in self.modmap.items(): if keycode in l: return n return None def keysym_to_keycode(self, keysym): return self.sym_to_codes.get(keysym, [0]) def keycode_to_keysym(self, keycode, modifier): if keycode >= len(self.code_to_syms) or \ modifier >= len(self.code_to_syms[keycode]): return 0 return self.code_to_syms[keycode][modifier] def create_window(self, x, y, width, height): wid = self.conn.generate_id() self.conn.core.CreateWindow( self.default_screen.root_depth, wid, self.default_screen.root.wid, x, y, width, height, 0, WindowClass.InputOutput, self.default_screen.root_visual, CW.BackPixel | CW.EventMask, [ self.default_screen.black_pixel, EventMask.StructureNotify | EventMask.Exposure ]) return Window(self, wid) def disconnect(self): try: self.conn.disconnect() except xcffib.ConnectionException: logger.error("Failed to disconnect, connection already failed?") self._connected = False def flush(self): if self._connected: return self.conn.flush() def xsync(self): # The idea here is that pushing an innocuous request through the queue # and waiting for a response "syncs" the connection, since requests are # serviced in order. self.conn.core.GetInputFocus().reply() def get_setup(self): return self.conn.get_setup() def extensions(self): return set(i.name.to_string().lower() for i in self.conn.core.ListExtensions().reply().names) def fixup_focus(self): """ If the X11 focus is set to None, all keypress events are discarded, which makes our hotkeys not work. This fixes up the focus so it is not None. """ window = self.conn.core.GetInputFocus().reply().focus if window == xcffib.xproto.InputFocus._None: self.conn.core.SetInputFocus( xcffib.xproto.InputFocus.PointerRoot, xcffib.xproto.InputFocus.PointerRoot, xcffib.xproto.Time.CurrentTime, ) @functools.lru_cache() def color_pixel(self, name): pixel = self.screens[0].default_colormap.alloc_color(name).pixel return pixel | 0xff << 24
class Connection: _extmap = { "xinerama": Xinerama, "randr": RandR, "xfixes": XFixes, } def __init__(self, display): self.conn = xcffib.connect(display=display) self._connected = True self.cursors = Cursors(self) self.setup = self.conn.get_setup() extensions = self.extensions() self.screens = [Screen(self, i) for i in self.setup.roots] self.default_screen = self.screens[self.conn.pref_screen] for i in extensions: if i in self._extmap: setattr(self, i, self._extmap[i](self)) self.pseudoscreens = [] if "xinerama" in extensions: for i, s in enumerate(self.xinerama.query_screens()): scr = PseudoScreen( self, s.x_org, s.y_org, s.width, s.height, ) self.pseudoscreens.append(scr) elif "randr" in extensions: for i in self.randr.query_crtcs(self.screens[0].root.wid): scr = PseudoScreen( self, i["x"], i["y"], i["width"], i["height"], ) self.pseudoscreens.append(scr) self.atoms = AtomCache(self) self.code_to_syms = {} self.first_sym_to_code = None self.refresh_keymap() self.modmap = None self.refresh_modmap() def finalize(self): self.cursors.finalize() self.disconnect() def refresh_keymap(self, first=None, count=None): if first is None: first = self.setup.min_keycode count = self.setup.max_keycode - self.setup.min_keycode + 1 q = self.conn.core.GetKeyboardMapping(first, count).reply() assert len(q.keysyms) % q.keysyms_per_keycode == 0 for i in range(len(q.keysyms) // q.keysyms_per_keycode): self.code_to_syms[first + i] = \ q.keysyms[i * q.keysyms_per_keycode:(i + 1) * q.keysyms_per_keycode] first_sym_to_code = {} for k, s in self.code_to_syms.items(): if s[0] and not s[0] in first_sym_to_code: first_sym_to_code[s[0]] = k self.first_sym_to_code = first_sym_to_code def refresh_modmap(self): reply = self.conn.core.GetModifierMapping().reply() modmap = {} names = (repeat(name, reply.keycodes_per_modifier) for name in ModMasks) for name, keycode in zip(chain.from_iterable(names), reply.keycodes): value = modmap.setdefault(name, []) value.append(keycode) self.modmap = modmap def get_modifier(self, keycode): """Return the modifier matching keycode""" for n, l in self.modmap.items(): if keycode in l: return n return None def keysym_to_keycode(self, keysym): return self.first_sym_to_code.get(keysym, 0) def keycode_to_keysym(self, keycode, modifier): if keycode >= len(self.code_to_syms) or \ modifier >= len(self.code_to_syms[keycode]): return 0 return self.code_to_syms[keycode][modifier] def create_window(self, x, y, width, height): wid = self.conn.generate_id() self.conn.core.CreateWindow( self.default_screen.root_depth, wid, self.default_screen.root.wid, x, y, width, height, 0, WindowClass.InputOutput, self.default_screen.root_visual, CW.BackPixel | CW.EventMask, [ self.default_screen.black_pixel, EventMask.StructureNotify | EventMask.Exposure ]) return Window(self, wid) def disconnect(self): try: self.conn.disconnect() except xcffib.ConnectionException: logger.error("Failed to disconnect, connection already failed?") self._connected = False def flush(self): if self._connected: return self.conn.flush() def xsync(self): # The idea here is that pushing an innocuous request through the queue # and waiting for a response "syncs" the connection, since requests are # serviced in order. self.conn.core.GetInputFocus().reply() def grab_server(self): return self.conn.core.GrabServer() def get_setup(self): return self.conn.get_setup() def open_font(self, name): fid = self.conn.generate_id() self.conn.core.OpenFont(fid, len(name), name) return Font(self, fid) def extensions(self): return set(i.name.to_string().lower() for i in self.conn.core.ListExtensions().reply().names)