def __init__(self, id, windows=None, name=None): self.id = id if not name: name = "(desktop %s)" % id(self) self.log = Log("desktop %s" % name) if not windows: windows = [] self.windows = windows self.name = name self.cur_focus = None self.prev_focus = None self.were_mapped = [] self.hidden = True # TODO: rename to active
def __init__(self, wm, wid, atoms, mapped=True): from wm import WM # TODO: dirtyhack to avoid circular imports assert isinstance(wm, WM), "wm must be an instance of WM" assert isinstance(wid, int), "wid must be int" self.wid = wid self.wm = wm self._conn = self.wm._conn self.prev_geometry = None self.props = Props(conn=self._conn, window=self, atoms=atoms) self.update_name() # TODO: this is not updated self.update_window_type() # do it after self.name is set (so repr works) self.log = Log(self) self.mapped = mapped self.hints = {} self.update_wm_hints() # subscribe for notifications self._conn.core.ChangeWindowAttributesChecked(wid, CW.EventMask, [EventMask.EnterWindow])
def __init__(self, xcb_setup, conn): self._conn = conn self.code_to_syms = {} self.first_sym_to_code = {} self.log = Log("keyboard") first = xcb_setup.min_keycode count = xcb_setup.max_keycode - xcb_setup.min_keycode + 1 q = self._conn.core.GetKeyboardMapping(first, count).reply() assert len(q.keysyms) % q.keysyms_per_keycode == 0, \ "Wrong keyboard mapping from X server??" 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] for k, s in self.code_to_syms.items(): if s[0] and not s[0] in self.first_sym_to_code: self.first_sym_to_code[s[0]] = k
from useful.log import Log from defs import ModMasks from subprocess import Popen from itertools import chain import shlex import os log = Log("utils") def run(cmd): if isinstance(cmd, str): cmd = shlex.split(cmd) # os.setpgrp supressses signal forwarding to children # TODO: test this return Popen(cmd, preexec_fn=os.setpgrp) def run_(cmd): try: return run(cmd) except Exception as err: log.run_.error("failed to exec %s: %s" % (cmd, err)) def get_modmask(modifiers): result = 0 for m in modifiers: assert m in ModMasks, "unknown modifier %s" % m result |= ModMasks[m] return result
def __init__(self, display=None, desktops=None, loop=None): self.log = Log("WM") # INIT SOME BASIC STUFF self.hook = Hook() self.windows = {} # mapping between window id and Window self.win2desk = {} if not display: display = os.environ.get("DISPLAY") try: self._conn = xcffib.connect(display=display) except xcffib.ConnectionException: sys.exit("cannot connect to %s" % display) self.atoms = AtomVault(self._conn) self.desktops = desktops or [Desktop()] self.cur_desktop = self.desktops[0] self.cur_desktop.show() # CREATE ROOT WINDOW xcb_setup = self._conn.get_setup() xcb_screens = [i for i in xcb_setup.roots] self.xcb_default_screen = xcb_screens[self._conn.pref_screen] root_wid = self.xcb_default_screen.root self.root = Window(self, wid=root_wid, atoms=self.atoms, mapped=True) self.windows[root_wid] = self.root # for desktop in self.desktops: # desktop.windows.append(self.root) self.root.set_attr( eventmask=( EventMask.StructureNotify | EventMask.SubstructureNotify | EventMask.FocusChange # | EventMask.SubstructureRedirect | EventMask.EnterWindow # | EventMask.LeaveWindow # | EventMask.PropertyChange | EventMask.OwnerGrabButton ) ) # INFORM X WHICH FEATURES WE SUPPORT self.root.props[self.atoms._NET_SUPPORTED] = [self.atoms[a] for a in SUPPORTED_ATOMS] # PRETEND TO BE A WINDOW MANAGER supporting_wm_check_window = self.create_window(-1, -1, 1, 1) supporting_wm_check_window.props['_NET_WM_NAME'] = "SWM" self.root.props['_NET_SUPPORTING_WM_CHECK'] = supporting_wm_check_window.wid self.root.props['_NET_NUMBER_OF_DESKTOPS'] = len(self.desktops) self.root.props['_NET_CURRENT_DESKTOP'] = 0 # TODO: set cursor # EVENTS THAT HAVE LITTLE USE FOR US... self.ignoreEvents = { "KeyRelease", "ReparentNotify", # "CreateNotify", # DWM handles this to help "broken focusing windows". # "MapNotify", "ConfigureNotify", "LeaveNotify", "FocusOut", "FocusIn", "NoExposure", } # KEYBOARD self.kbd = Keyboard(xcb_setup, self._conn) self.mouse = Mouse(conn=self._conn, root=self.root) # FLUSH XCB BUFFER self.xsync() # apply settings # the event loop is not yet there, but we might have some pending # events... self._xpoll() # TODO: self.grabMouse # NOW IT'S TIME TO GET PHYSICAL SCREEN CONFIGURATION self.xrandr = Xrandr(root=self.root, conn=self._conn) # TODO: self.update_net_desktops() # SETUP EVENT LOOP if not loop: loop = asyncio.new_event_loop() self._eventloop = loop self._eventloop.add_signal_handler(signal.SIGINT, self.stop) self._eventloop.add_signal_handler(signal.SIGTERM, self.stop) self._eventloop.add_signal_handler(signal.SIGCHLD, self.on_sigchld) self._eventloop.set_exception_handler( lambda loop, ctx: self.log.error( "Got an exception in {}: {}".format(loop, ctx)) ) fd = self._conn.get_file_descriptor() self._eventloop.add_reader(fd, self._xpoll) # HANDLE STANDARD EVENTS self.hook.register("MapRequest", self.on_map_request) self.hook.register("MapNotify", self.on_map_notify) self.hook.register("UnmapNotify", self.on_window_unmap) self.hook.register("KeyPress", self.on_key_press) # self.hook.register("KeyRelease", self.on_key_release) # self.hook.register("CreateNotify", self.on_window_create) self.hook.register("PropertyNotify", self.on_property_notify) self.hook.register("ClientMessage", self.on_client_message) self.hook.register("DestroyNotify", self.on_window_destroy) self.hook.register("EnterNotify", self.on_window_enter) self.hook.register("ConfigureRequest", self.on_configure_window) self.hook.register("MotionNotify", self.on_mouse_event) self.hook.register("ButtonPress", self.on_mouse_event) self.hook.register("ButtonRelease", self.on_mouse_event)
from useful.prettybt import prettybt sys.excepthook = prettybt # USEFUL ALIASES up, down, left, right = 'Up', 'Down', 'Left', 'Right' win = fail = 'mod4' ctrl = control = 'control' shift = 'shift' caps = 'Caps_Lock' alt = 'mod1' tab = 'Tab' MouseL = 1 MouseC = 2 MouseR = 3 log = Log("USER HOOKS") osd = OSD() mod = win # PRE-INIT # switch to english just in case run_("setxkbmap -layout en") # create event loop and setup text GUI loop = asyncio.new_event_loop() # logwidget = gui(loop=loop) # Log.file = logwidget # INIT num_desktops = 4
def __init__(self): self.cb_map = defaultdict(list) self.log = Log("hook") self.suppressed = set()