class WM: def __init__(self): self.display = Display() self.root = self.display.screen().root self.color_map = self.display.screen().default_colormap self.root.change_attributes(event_mask=X.SubstructureRedirectMask | X.KeyReleaseMask | X.FocusChangeMask) self.width = self.root.get_geometry().width self.height = self.root.get_geometry().height self.windows = [] self.focused_window = None self.actions = [[XK.XK_F, lambda: system("rofi -show")], [XK.XK_X, lambda: self.destroy(self.focused_window)]] self.modifier = X.Mod1Mask self.next_position = 0 self.configure() system("feh --bg-scale wallpaper.png") def getKeyCodes(self, key): codes = set(code for code, i in self.display.keysym_to_keycodes(key)) return list(codes) def configure(self): for i in self.actions: for j in self.getKeyCodes(i[0]): self.root.grab_key(j, self.modifier, True, X.GrabModeSync, X.GrabModeSync) def handleMap(self, event): event.window.map() # event.window.set_input_focus(X.RevertToParent, X.CurrentTime) width = self.width // 2 - 40 height = self.height // 2 - 40 if self.next_position == 4: self.next_position = 0 if self.next_position == 0: x = 0 y = 0 elif self.next_position == 1: x = self.width // 2 y = 0 elif self.next_position == 2: x = 0 y = self.height // 2 elif self.next_position == 3: x = self.width // 2 y = self.height // 2 event.window.configure(stack_mode=X.Above, width=width, height=height, x=x, y=y) self.next_position += 1 self.windows.append(event.window) def destroy(self, window): window.destroy() self.windows.remove(window) self.next_position -= 1 width = self.width // 2 - 40 height = self.height // 2 - 40 for i, window in enumerate(self.windows): if i == 0: x = 0 y = 0 elif i == 1: x = self.width // 2 y = 0 elif i == 2: x = 0 y = self.height // 2 elif i == 3: x = self.width // 2 y = self.height // 2 window.configure(stack_mode=X.Above, width=width, height=height, x=x, y=y) def handleKey(self, event): print("Clicked") for i in self.actions: if event.detail in self.getKeyCodes(i[0]): print("Found") i[1]() def handleEvent(self): if self.display.pending_events() > 0: event = self.display.next_event() print("Got Event:{}".format(event.type)) if event.type == X.MapRequest: self.handleMap(event) elif event.type == X.KeyRelease: self.handleKey(event) elif event.type == X.FocusIn: print("Focusing") def updateFocus(self): window = self.display.screen().root.query_pointer().child if window: self.focused_window = window else: self.focused_window = None def close(self): self.display.close() def drawBorder(self, window): if window == self.focused_window: color = FOCUS_COLOR else: color = BORDER_COLOR color = self.color_map.alloc_named_color(color).pixel window.configure(border_width=BORDER_WIDTH) window.change_attributes(None, border_pixel=color) self.display.sync() def loop(self): while True: self.handleEvent() self.updateFocus() for i in self.windows: self.drawBorder(i)
class wm(object): """Initialise WM variables and open display""" def __init__(self): self.windows = [] # List of opened windows self.display = Display() # Initialise display self.colormap = self.display.screen( ).default_colormap # Initialise colourmap self.rootWindow = self.display.screen().root # Get root window self.activeWindow = None self.currentMode = None self.activeWindowFullscreen = False self.displayWidth = self.rootWindow.get_geometry( ).width # Get width of display self.displayHeight = self.rootWindow.get_geometry( ).height # Get height of display self.rootWindow.change_attributes(event_mask=X.SubstructureRedirectMask ) # Redirect events from root window self.configureKeys() # Configure key bindings self.readConfig() self.workspaces = [] log("initialized WM and opened display") def readConfig(self): parser = configparser.ConfigParser() parser.read('config.ini') self.inactiveColour = parser.get("Theme", "inactive-window-color") self.activeColour = parser.get("Theme", "active-window-color") self.wallpaper = parser.get("Theme", "wallpaper") self.borderSize = parser.get("Theme", "border-size") self.startupScriptPath = parser.get("Options", "startup-script-path") self.startupScriptCommand = parser.get("Options", "startup-script-command") subprocess.Popen([self.startupScriptCommand, self.startupScriptPath]) self.defaultBrowser = parser.get("Defaults", "browser") self.defaultTerminal = parser.get("Defaults", "terminal") self.keymap = parser.get("Options", "keymap") subprocess.Popen(['setxkbmap', '-layout', self.keymap]) if not self.wallpaper == "None": subprocess.Popen(["feh", "--bg-scale", self.wallpaper]) log("read config file") def redraw(self): self.updateBorders() self.handleEvents() if len(self.windows) >= 1 and self.activeWindow == None: self.activeWindow = self.windows[1] def killWindow(self): try: subprocess.Popen(["killall", self.activeWindowName]) self.activeWindow.destroy() self.windows.remove(self.activeWindow) self.activeWindow = None log(f"killed window name: {self.activeWindowName}") except Exception as e: log(f"EXCEPCION on killWindow() : {e} ") def updateBorders(self): for window in self.windows: window.configure(border_width=int(self.borderSize)) window.change_attributes(None, border_pixel=int(self.borderSize)) self.display.sync() def handleEvents(self): ignoredEvents = [3, 33, 34, 23] # Blacklisted events if self.display.pending_events() > 0: event = self.display.next_event() # Get next event from display else: return if event.type == X.MapRequest: self.handleMap(event) # Send mapping events to the mapping handler elif event.type == X.KeyPress: self.handleKeyPress( event) # Send keypress event to the keypress handler """Handle a mapping request""" def handleMap(self, event): self.windows.append( event.window ) # Add the window identifier to a list of open windows self.activeWindow = event.window # Set the active window to the mapped window self.activeWindowName = event.window.get_wm_name( ) # Set the active window name to the window title event.window.map() # Map the window def grabKey(self, codes, modifier): for code in codes: # For each code self.rootWindow.grab_key( code, modifier, 1, X.GrabModeAsync, X.GrabModeAsync) # Receive events when the key is pressed def configureKeys(self): self.left = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Left) ) # Assign a list of possible keycodes to the variable self.right = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Right)) self.up = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Up)) self.down = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Down)) self.close = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_X)) self.enter = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Return)) self.d = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_D)) self.q = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Q)) self.r = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_R)) self.f = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_F)) self.esc = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_Escape)) self.h = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_H)) self.j = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_J)) self.k = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_K)) self.l = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_L)) self.g = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_G)) self.grabbedKeys = [ self.left, self.g, self.right, self.up, self.down, self.close, self.enter, self.d, self.q, self.r, self.f, self.esc, self.h, self.j, self.k, self.l ] for key in self.grabbedKeys: # For each key to grab, self.grabKey(key, X.Mod1Mask) # Grab the key with the modifer of Alt def moveWindow(self, direction): log("moved window") try: if direction == "left": windowX = self.activeWindow.get_geometry( ).x # Get the current position of the active window self.activeWindow.configure( x=windowX - 5) # Decrease the X position to move it left elif direction == "right": windowX = self.activeWindow.get_geometry().x self.activeWindow.configure(x=windowX + 5) elif direction == "up": windowY = self.activeWindow.get_geometry().y self.activeWindow.configure(y=windowY - 5) elif direction == "down": windowY = self.activeWindow.get_geometry().y self.activeWindow.configure(y=windowY + 5) except AttributeError: pass def resize(self, direction): windowGeometry = self.activeWindow.get_geometry() if direction == 0: self.activeWindow.configure(width=windowGeometry.width + 5, x=windowGeometry.x - 5) elif direction == 1: self.activeWindow.configure(width=windowGeometry.width - 5, x=windowGeometry.x + 5) elif direction == 2: self.activeWindow.configure(height=windowGeometry.height - 5, y=windowGeometry.y + 5) else: self.activeWindow.configure(height=windowGeometry.height + 5, y=windowGeometry.y - 5) def handleKeyPress(self, event): if event.detail in self.left: self.moveWindow("left") elif event.detail in self.right: self.moveWindow("right") elif event.detail in self.up: self.moveWindow("up") elif event.detail in self.down: self.moveWindow("down") if event.detail in self.enter: self.runProcess( self.defaultTerminal) # Alt+ENTER: Launch a terminal elif event.detail in self.d: self.runProcess(["rofi", "-show", "run"]) # Alt+D: Launch a program launcher elif event.detail in self.q: self.killWindow() # ALT+Q: Close a window if event.detail in self.h: self.resize(2) elif event.detail in self.j: self.resize(3) elif event.detail in self.k: self.resize(1) elif event.detail in self.l: self.resize(0) elif event.detail in self.f: self.activeWindow.configure(x=0, width=1920, y=0, height=1080) elif event.detail in self.g: self.activeWindow.configure(x=0, width=1000, y=0, height=800) if event.detail in self.h: self.resize(2) elif event.detail in self.j: self.resize(3) elif event.detail in self.k: self.resize(1) elif event.detail in self.l: self.resize(0) def runProcess(self, command): try: subprocess.Popen(command) except Exception: pass
from subprocess import check_output, CalledProcessError from Xlib.display import Display from Xlib import X, XK from Xlib.ext.xtest import fake_input kobowm_path = str(dirname(realpath(__file__))) wifi_toggle = ['/home/marek/scripts/wifi/toggle'] usb_toggle = ['/home/marek/scripts/usb/toggle'] sdcard_toggle = ['/home/marek/scripts/sdcard/toggle'] suspend_script = ['/home/marek/scripts/power/suspend'] xterm_launch = ['/usr/bin/xterm', '-e '] battery_path = '/sys/class/power_supply/mc13892_bat/' display = Display() # see kobowm.py F1 = display.keysym_to_keycodes(XK.XK_F1)[0][0] F2 = display.keysym_to_keycodes(XK.XK_F2)[0][0] F3 = display.keysym_to_keycodes(XK.XK_F3)[0][0] F4 = display.keysym_to_keycodes(XK.XK_F4)[0][0] F9 = display.keysym_to_keycodes(XK.XK_F9)[0][0] def battery_status(): # Returns percentage string and a charging boolean val, charging = 0, False if exists(battery_path): try: with open(battery_path + 'capacity', 'r') as f: val = int(f.readline().rstrip()) with open(battery_path + 'status', 'r') as f: charging = f.readline().rstrip() == 'Charging'
class WM(object): def __init__(self): self.display = Display() self.root_win = self.display.screen().root self.go_on = True # var to keep looping events (or not) self.notifs_on = False self.poweroff_time = 0 clear_log() # clear the log file once # kobo touch screen dimension: 600x800px (minus the dock) self.full_width = 600 self.full_height = 740 self.keyboard_height = 0 self.keyboard_on = False self.active_window = None # may be transient self.top_win_list = [] # list of the top window to cycle in self.top_win_pos = -1 # postition in the top win list, -1 means you have to start over self.transient_of = { } # key: win, val: set of windows transient for win # windows of wm-related apps self.wm_keyboard, self.wm_launcher, self.wm_dock, self.wm_notifs = None, None, None, None # codes for the keys to catch self.f1_codes = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_F1)) self.f2_codes = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_F2)) self.f3_codes = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_F3)) self.f4_codes = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_F4)) self.f9_codes = set( code for code, index in self.display.keysym_to_keycodes(XK.XK_F9)) XK.load_keysym_group('xf86') self.poweroff_codes = set( code for code, index in self.display.keysym_to_keycodes( XK.XK_XF86_PowerOff)) self.poweroff_codes.update( set(code for code, index in self.display.keysym_to_keycodes(XK.XK_F12))) self.launch1_codes = set( code for code, index in self.display.keysym_to_keycodes( XK.XK_XF86_Launch1)) self.launch1_codes.update( set(code for code, index in self.display.keysym_to_keycodes(XK.XK_F11))) # error catcher error_catcher = CatchError(BadAccess) self.root_win.change_attributes( event_mask=X.SubstructureRedirectMask, onerror=error_catcher, background_pixel=self.display.screen().white_pixel) self.display.sync() error = error_catcher.get_error() if error: sys.exit(1) # grab root window key events self.grab_root_key(self.poweroff_codes, X.NONE) self.grab_root_key(self.launch1_codes, X.NONE) self.grab_root_key(self.f1_codes, X.NONE) self.grab_root_key(self.f2_codes, X.NONE) self.grab_root_key(self.f3_codes, X.NONE) self.grab_root_key(self.f4_codes, X.NONE) self.grab_root_key(self.f9_codes, X.NONE) # handlers self.display.set_error_handler(self.x_error_handler) self.event_dispatch_table = { X.MapRequest: self.handle_map_request, X.ConfigureRequest: self.handle_configure_request, X.MappingNotify: self.handle_mapping_notify, X.UnmapNotify: self.handle_unmapping_notify, X.KeyPress: self.handle_key_press, X.KeyRelease: self.handle_key_release } def grab_root_key(self, codes, modifier): for code in codes: self.root_win.grab_key(code, modifier, 1, X.GrabModeAsync, X.GrabModeAsync) # top level window utility functions def win_show(self): window = self.top_win_list[self.top_win_pos] # assumes it exists # map the window window.map() # map transient window if any if window in self.transient_of: win = None for win in self.transient_of[window]: win.map() # use last transient as active window if win: self.active_window = win else: self.active_window = window else: # set the window as the active one self.active_window = window def win_hide(self): window = self.top_win_list[self.top_win_pos] # assumes it exists # unmap the window window.unmap() # un map transient window if any if window in self.transient_of: for win in self.transient_of[window]: win.unmap() # unset active window self.active_window = None def win_remove(self): window = self.top_win_list.pop(self.top_win_pos) # assumes it exists # remove entry in transient dict if any if window in self.transient_of: del self.transient_of[window] window.destroy() self.active_window = None # event handling functions def x_error_handler(self, err, request): log('X protocol error: {0}'.format(err)) def loop(self): # Load every wm app before starting the actual loop try: self.load_wmapps() except KeyboardInterrupt: raise # Loop until go_on, Ctrl+C or exceptions > MAX_EXCEPTION times. errors = 0 while self.go_on: try: self.handle_event() except KeyboardInterrupt: raise except: errors += 1 if errors > MAX_EXCEPTIONS: sys.exit(1) close_log() self.display.close() def load_wmapps(self): # launch the other apps: python_path = find_full_path('python') keyboard_path = find_full_path('matchbox-keyboard') if not keyboard_path or not python_path: raise KeyboardInterrupt system([python_path, kobowm_path + '/launcher.py']) system([python_path, kobowm_path + '/dock.py']) system([python_path, kobowm_path + '/notifzmq.py']) system([keyboard_path]) # catch the events until every wm app has a window while not all((self.wm_notifs, self.wm_keyboard, self.wm_launcher, self.wm_dock)): try: event = self.display.next_event() except ConnectionClosedError: log('Display connection closed by server') raise KeyboardInterrupt # ignore events that are not map requests if event.type == X.MapRequest: event.window.map() if str(event.window.get_wm_name()) == 'Keyboard': self.wm_keyboard = event.window self.keyboard_height = event.window.get_geometry().height event.window.configure(x=0, y=self.full_height - self.keyboard_height, width=self.full_width) # catch the keyboard events to later redirect them to the active window event.window.change_attributes(event_mask=X.KeyPressMask | X.KeyReleaseMask) event.window.unmap() elif str(event.window.get_wm_name()) == 'kobowm-dock': self.wm_dock = event.window event.window.configure(x=0, y=self.full_height, width=self.full_width, height=60) event.window.unmap() elif str(event.window.get_wm_name()) == 'kobowm-launcher': self.wm_launcher = event.window event.window.configure(x=0, y=0, height=self.full_height, width=self.full_width) event.window.unmap() elif str(event.window.get_wm_name()) == 'kobowm-notifications': self.wm_notifs = event.window event.window.configure(x=380, y=20, height=100, width=200) event.window.unmap() else: # there is an unexpexted window: stop raise KeyboardInterrupt # finally map again the dock self.wm_dock.map() def handle_event(self): try: event = self.display.next_event() except ConnectionClosedError: log('Display connection closed by server') raise KeyboardInterrupt if event.type in self.event_dispatch_table: self.event_dispatch_table[event.type](event) else: log('unhandled event: {event}'.format(event=event)) def handle_configure_request(self, event): window = event.window args = {'border_width': 1} if event.value_mask & X.CWX: args['x'] = event.x if event.value_mask & X.CWY: args['y'] = event.y if event.value_mask & X.CWWidth: args['width'] = event.width if event.value_mask & X.CWHeight: args['height'] = event.height if event.value_mask & X.CWSibling: args['sibling'] = event.above if event.value_mask & X.CWStackMode: args['stack_mode'] = event.stack_mode window.configure(**args) def handle_map_request(self, event): event.window.map() # handle transient windows transient_for = event.window.get_wm_transient_for() if transient_for: self.active_window = event.window if transient_for not in self.transient_of: self.transient_of[transient_for] = [] self.transient_of[transient_for].append(event.window) else: if self.active_window: self.active_window.unmap() self.active_window = event.window self.top_win_list.append(event.window) self.top_win_pos = len(self.top_win_list) - 1 # use all the available screen self.active_window.configure(x=-1, y=-1, width=self.full_width, height=self.full_height) # hide the keyboard if it was open if self.keyboard_on: self.wm_keyboard.unmap() self.keyboard_on = False def handle_mapping_notify(self, event): # necessary by documentation self.display.refresh_keyboard_mapping(event) def handle_unmapping_notify(self, event): # used to handle windows that get unmapped not by this wm directly transient_for = event.window.get_wm_transient_for() if transient_for: self.transient_of[transient_for].remove(event.window) if self.active_window == event.window: self.active_window = transient_for elif event.window in self.top_win_list: self.top_win_list.remove(event.window) if self.active_window == event.window: self.active_window = None self.top_win_pos = -1 def handle_key_press(self, event): if event.window == self.wm_keyboard: return # do nothing: will be sent to the active window on release if event.detail in self.poweroff_codes: self.go_on = False elif event.detail in self.launch1_codes: self.action_apps() elif event.detail in self.f1_codes: self.action_tasks() elif event.detail in self.f2_codes: self.action_keyboard() elif event.detail in self.f3_codes: system(XTERM_COMMAND) elif event.detail in self.f4_codes: self.action_close() elif event.detail in self.f9_codes: self.action_notifs() def handle_key_release(self, event): if event.window == self.wm_keyboard: # focus on the active window and emulate key press/release self.display.sync() self.display.set_input_focus(self.active_window, X.RevertToParent, X.CurrentTime) fake_input(self.display, X.KeyPress, event.detail) fake_input(self.display, X.KeyRelease, event.detail) self.display.sync() # action performer functions def action_apps(self): if not self.active_window: self.active_window = self.wm_launcher self.active_window.map() elif self.active_window == self.wm_launcher: self.active_window.unmap() self.active_window = None else: # hide the active window (and the stack if it's transient) self.win_hide() # start over with the cycling self.top_win_pos = -1 self.active_window = self.wm_launcher self.active_window.map() def action_tasks(self): if not self.top_win_list: return if self.top_win_pos != -1 and self.top_win_pos < len( self.top_win_list): self.win_hide() self.top_win_pos += 1 if self.top_win_pos >= len(self.top_win_list): self.top_win_pos = 0 self.win_show() def action_keyboard(self): if self.keyboard_on: self.wm_keyboard.unmap() self.active_window.configure(height=self.full_height) self.keyboard_on = False elif self.active_window and self.active_window != self.wm_launcher: self.wm_keyboard.map() self.active_window.configure(height=self.full_height - self.keyboard_height) self.wm_keyboard.configure(stack_mode=X.Above) self.keyboard_on = True def action_close(self): if not self.active_window: return # nothing to close here if self.active_window in self.top_win_list: self.win_remove() else: # it's a transient window transient_for = self.active_window.get_wm_transient_for() self.transient_of[transient_for].remove(self.active_window) self.active_window.destroy() self.active_window = transient_for # close the keyboard if open if self.keyboard_on: self.wm_keyboard.unmap() self.keyboard_on = False def action_notifs(self): if self.notifs_on: self.wm_notifs.unmap() log('Notification window hidden') else: self.wm_notifs.configure(stack_mode=X.Above) self.wm_notifs.map() log('Notification window visible') self.notifs_on = not self.notifs_on
class Keyboard(KeyboardMeta): """ The PyKeyboard implementation for X11 systems (mostly linux). This allows one to simulate keyboard input. """ def __init__(self, display=None): PyKeyboardMeta.__init__(self) self.display = Display(display) self.root = self.display.screen().root XK.load_keysym_group('xkb') altList = self.display.keysym_to_keycodes(XK.XK_ISO_Level3_Shift) self.__usable_modifiers = (0, 1) for code, offset in altList: if code == 108 and offset == 0: self.__usable_modifiers += (4, 5) break mapping = self.display.get_modifier_mapping() self.modmasks = {} for keyname in MODIFIERS: keysym = XK.string_to_keysym(keyname) keycodes = self.display.keysym_to_keycodes(keysym) found = False for keycode, lvl in keycodes: for index, mask in MASK_INDEXES: if keycode in mapping[index]: self.modmasks[keycode] = mask found = True if found: break self.flags = { 'Shift': X.ShiftMask, 'Lock': X.LockMask, 'Ctrl': X.ControlMask, 'Alt': 0, 'AltGr': self.modmasks[altList[0][0]], 'Hankaku': 0} self.special_key_assignment() def __findUsableKeycode(self, keycodes): for code, mask in keycodes: if mask in self.__usable_modifiers: return code, mask return None, None def press_key(self, character='', modifier=0): """ Press a given character key. Also works with character keycodes as integers, but not keysyms. """ window = self.display.get_input_focus().focus char_val, char_mask = self.lookup_character_value(character) if char_val == None or char_mask == None: return False char_mask ^= modifier print character, char_mask, modifier event = protocol.event.KeyPress( detail = char_val, time = X.CurrentTime, root = self.root, window = window, child = X.NONE, root_x = 0, root_y = 0, event_x = 0, event_y = 0, state = char_mask, same_screen = 0) window.send_event(event) self.display.sync() def release_key(self, character='', modifier=0): """ Release a given character key. Also works with character keycodes as integers, but not keysyms. """ window = self.display.get_input_focus().focus char_val, char_mask = self.lookup_character_value(character) if char_val == None or char_mask == None: return False char_mask ^= modifier event = protocol.event.KeyRelease( detail = char_val, time = X.CurrentTime, root = self.root, window = window, child = X.NONE, root_x = 0, root_y = 0, event_x = 0, event_y = 0, state = char_mask, same_screen = 0) window.send_event(event) self.display.sync() def special_key_assignment(self): """ Determines the keycodes for common special keys on the keyboard. These are integer values and can be passed to the other key methods. Generally speaking, these are non-printable codes. """ #This set of keys compiled using the X11 keysymdef.h file as reference #They comprise a relatively universal set of keys, though there may be #exceptions which may come up for other OSes and vendors. Countless #special cases exist which are not handled here, but may be extended. #TTY Function Keys self.backspace_key = self.lookup_character_value('BackSpace')[0] self.tab_key = self.lookup_character_value('Tab')[0] self.linefeed_key = self.lookup_character_value('Linefeed')[0] self.clear_key = self.lookup_character_value('Clear')[0] self.return_key = self.lookup_character_value('Return')[0] self.enter_key = self.return_key # Because many keyboards call it "Enter" self.pause_key = self.lookup_character_value('Pause')[0] self.scroll_lock_key = self.lookup_character_value('Scroll_Lock')[0] self.sys_req_key = self.lookup_character_value('Sys_Req')[0] self.escape_key = self.lookup_character_value('Escape')[0] self.delete_key = self.lookup_character_value('Delete')[0] #Modifier Keys self.shift_l_key = self.lookup_character_value('Shift_L')[0] self.shift_r_key = self.lookup_character_value('Shift_R')[0] self.shift_key = self.shift_l_key # Default Shift is left Shift self.alt_l_key = self.lookup_character_value('Alt_L')[0] self.alt_r_key = self.lookup_character_value('Alt_R')[0] self.alt_key = self.alt_l_key # Default Alt is left Alt self.alt_gr_key = self.lookup_character_value('ISO_Level3_Shift')[0] self.control_l_key = self.lookup_character_value('Control_L')[0] self.control_r_key = self.lookup_character_value('Control_R')[0] self.control_key = self.control_l_key # Default Ctrl is left Ctrl self.caps_lock_key = self.lookup_character_value('Caps_Lock')[0] self.capital_key = self.caps_lock_key # Some may know it as Capital self.shift_lock_key = self.lookup_character_value('Shift_Lock')[0] self.meta_l_key = self.lookup_character_value('Meta_L')[0] self.meta_r_key = self.lookup_character_value('Meta_R')[0] self.super_l_key = self.lookup_character_value('Super_L')[0] self.windows_l_key = self.super_l_key # Cross-support; also it's printed there self.super_r_key = self.lookup_character_value('Super_R')[0] self.windows_r_key = self.super_r_key # Cross-support; also it's printed there self.hyper_l_key = self.lookup_character_value('Hyper_L')[0] self.hyper_r_key = self.lookup_character_value('Hyper_R')[0] #Cursor Control and Motion self.home_key = self.lookup_character_value('Home')[0] self.up_key = self.lookup_character_value('Up')[0] self.down_key = self.lookup_character_value('Down')[0] self.left_key = self.lookup_character_value('Left')[0] self.right_key = self.lookup_character_value('Right')[0] self.end_key = self.lookup_character_value('End')[0] self.begin_key = self.lookup_character_value('Begin')[0] self.page_up_key = self.lookup_character_value('Page_Up')[0] self.page_down_key = self.lookup_character_value('Page_Down')[0] self.prior_key = self.lookup_character_value('Prior')[0] self.next_key = self.lookup_character_value('Next')[0] #Misc Functions self.select_key = self.lookup_character_value('Select')[0] self.print_key = self.lookup_character_value('Print')[0] self.print_screen_key = self.print_key # Seems to be the same thing self.snapshot_key = self.print_key # Another name for printscreen self.execute_key = self.lookup_character_value('Execute')[0] self.insert_key = self.lookup_character_value('Insert')[0] self.undo_key = self.lookup_character_value('Undo')[0] self.redo_key = self.lookup_character_value('Redo')[0] self.menu_key = self.lookup_character_value('Menu')[0] self.apps_key = self.menu_key # Windows... self.find_key = self.lookup_character_value('Find')[0] self.cancel_key = self.lookup_character_value('Cancel')[0] self.help_key = self.lookup_character_value('Help')[0] self.break_key = self.lookup_character_value('Break')[0] self.mode_switch_key = self.lookup_character_value('Mode_switch')[0] self.script_switch_key = self.lookup_character_value('script_switch')[0] self.num_lock_key = self.lookup_character_value('Num_Lock')[0] #Keypad Keys: Dictionary structure keypad = ['Space', 'Tab', 'Enter', 'F1', 'F2', 'F3', 'F4', 'Home', 'Left', 'Up', 'Right', 'Down', 'Prior', 'Page_Up', 'Next', 'Page_Down', 'End', 'Begin', 'Insert', 'Delete', 'Equal', 'Multiply', 'Add', 'Separator', 'Subtract', 'Decimal', 'Divide', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] self.keypad_keys = {k: self.lookup_character_value('KP_'+str(k)[0]) for k in keypad} self.numpad_keys = self.keypad_keys #Function Keys/ Auxilliary Keys #FKeys self.function_keys = [None] + [self.lookup_character_value('F'+str(i)[0]) for i in xrange(1,36)] #LKeys self.l_keys = [None] + [self.lookup_character_value('L'+str(i)[0]) for i in xrange(1,11)] #RKeys self.r_keys = [None] + [self.lookup_character_value('R'+str(i)[0]) for i in xrange(1,16)] #Unsupported keys from windows self.kana_key = None self.hangeul_key = None # old name - should be here for compatibility self.hangul_key = None self.junjua_key = None self.final_key = None self.hanja_key = None self.kanji_key = None self.convert_key = None self.nonconvert_key = None self.accept_key = None self.modechange_key = None self.sleep_key = None def lookup_character_value(self, character): """ Looks up the keysym for the character then returns the keycode mapping and modifier for that keysym. """ ch_keysym = XK.string_to_keysym(character) ch_mask = 0 if ch_keysym == 0: if character in SPECIAL_X_KEYSYMS: ch_keysym = XK.string_to_keysym(SPECIAL_X_KEYSYMS[character]) elif len(character) == 1: ch_keysym = ord(character) ch_keycodes = self.display.keysym_to_keycodes(ch_keysym) if len(ch_keycodes) == 0 and len(character) == 1: ch_keycodes = self.display.keysym_to_keycodes(ord(character.lower())) ch_mask ^= X.LockMask if len(ch_keycodes) > 0: ch_keycode, mask = self.__findUsableKeycode(ch_keycodes) if ch_keycode == None or mask == None: return None, None else: ch_mask ^= mask else: return None, None if ch_mask ^ 4 < 4: ch_mask ^= 4 ch_mask ^= self.modmasks[self.alt_gr_key] return ch_keycode, ch_mask
class wm(object): """Initialise WM variables and open display""" def __init__(self): self.windowList = [] # List of opened windows self.display = Display() # Initialise display self.colormap = self.display.screen().default_colormap # Initialise colourmap self.currentMode = None self.activeWindow = None self.rootWindow = self.display.screen().root # Get root window self.displayWidth = self.rootWindow.get_geometry().width # Get width of display self.displayHeight = self.rootWindow.get_geometry().height # Get height of display self.rootWindow.change_attributes(event_mask = X.SubstructureRedirectMask) # Redirect events from root window self.configureKeys() # Configure key bindings def mainLoop(self): self.updateFocus() self.updateBorders() self.handleEvents() log(3, "Mode:"+str(self.currentMode)) """Destroy an active window""" def destroyWindow(self, event): try: self.activeWindow.destroy() self.windowList.remove(self.activeWindow) self.activeWindow = None except: log(2, "No focused window!") def updateFocus(self): window = self.display.screen().root.query_pointer().child if window != 0: self.activeWindow = window def updateBorders(self): for window in self.windowList: #gc = self.rootWindow.create_gc() #window.fill_rectangle(gc, 0, window.get_geometry().y-5, window.get_geometry().width, 5) #window.draw_text(gc, window.get_geometry().width/2, 5, "Hello, World!", "ff0011") if window != self.activeWindow: borderColour = preferences.theme.border.inactiveColour else: borderColour = preferences.theme.border.activeColour borderColour = self.colormap.alloc_named_color(borderColour).pixel #borderColour).pixel window.configure(border_width = preferences.theme.border.borderWidth) window.change_attributes(None,border_pixel=borderColour) self.display.sync() """Handle WM events""" def handleEvents(self): ignoredEvents = [3, 33, 34, 23] # Blacklisted events if self.display.pending_events() > 0: event = self.display.next_event() # Get next event from display else: return if event.type == X.MapRequest: self.handleMap(event) # Send mapping events to the mapping handler elif event.type == X.KeyPress: self.handleKeyPress(event) # Send keypress event to the keypress handler elif event.type in ignoredEvents: log(3, "Ignoring event: "+str(event.type)) # Ignore event if it is a blacklisted event else: # Otherwise, if the event is not a currently handled event log(1, "Unhandled event: "+str(event.type)) # Warn of an unhandled event """Handle a mapping request""" def handleMap(self, event): self.windowList.append(event.window) # Add the window identifier to a list of open windows log(3, str(self.windowList)) # Show list of windows (DEBUG) self.activeWindow = event.window # Set the active window to the mapped window self.activeWindowName = event.window.get_wm_name() # Set the active window name to the window title event.window.map() # Map the window """Receive a KeyPressed event when a certain key is pressed""" def grabKey(self, codes, modifier): for code in codes: # For each code self.rootWindow.grab_key(code, modifier, 1, X.GrabModeAsync, X.GrabModeAsync) # Receive events when the key is pressed """Bind keys""" def configureKeys(self): self.left = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_Left)) # Assign a list of possible keycodes to the variable self.right = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_Right)) self.up = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_Up)) self.down = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_Down)) self.close = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_X)) self.t = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_T)) self.e = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_E)) self.x = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_X)) self.r = set(code for code, index in self.display.keysym_to_keycodes(XK.XK_X)) self.grabbedKeys = [self.left, self.right, self.up, self.down, self.close, self.t, self.e, self.x, self.r] for key in self.grabbedKeys: # For each key to grab, self.grabKey(key, X.Mod1Mask) # Grab the key with the modifer of Alt #def resizeWindow(window, direction): # windowW = window.get_geometry().width # windowH = window.get_geometry().height # if direction == 0: window.configure(width=windowW-1) # elif direction == 1: window.configure(width=windowW+1) # elif direction == 2: window.configure(height=windowH-1) # elif direction == 3: window.configure(height=windowH+1) """Change the position of an active window""" def moveWindow(self, direction): try: if direction == "left": windowX = self.activeWindow.get_geometry().x # Get the current position of the active window self.activeWindow.configure(x=windowX-5) # Decrease the X position to move it left elif direction == "right": windowX = self.activeWindow.get_geometry().x self.activeWindow.configure(x=windowX+5) elif direction == "up": windowY = self.activeWindow.get_geometry().y self.activeWindow.configure(y=windowY-5) elif direction == "down": windowY = self.activeWindow.get_geometry().y self.activeWindow.configure(y=windowY+5) else: log(1, "Invalid movement direction!") except AttributeError: log(1, "No focused window!") """Handle key presses""" def handleKeyPress(self, event): # if self.currentMode == "resize": # If resize mode is enabled: #if event.detail in self.left: self.resizeWindow(event.window, 0) # Alt+Left Arrow: resize window (x-1) # elif event.detail in self.right: self.moveWindow(event.window, 1) # Alt+Right Arrow: resize window (x+1) # elif event.detail in self.up: self.moveWindow(event.window, 2) # Alt+Up Arrow: resize window (y-1) # elif event.detail in self.down: self.moveWindow(event.window, 3) # Alt+Down Arrow: resize window (y+1) # else: # Otherwise, if event.detail in self.left: self.moveWindow("left") # Alt+Left Arrow: move a window left elif event.detail in self.right: self.moveWindow("right") # Alt+Right Arrow: move a window right elif event.detail in self.up: self.moveWindow("up") # Alt+Up Arrow: move a window up elif event.detail in self.down: self.moveWindow("down") # Alt+Down Arrow: move a window down elif event.detail in self.t: self.runProcess(preferences.applicationDefaults.terminal) # Alt+T: Launch a terminal elif event.detail in self.e: self.runProcess(preferences.applicationDefaults.launcher) # Alt+E: Launch a program launcher elif event.detail in self.x: self.destroyWindow(event) # ALT+X: Close a window elif event.detail in self.r: self.currentMode = "resize" # ALT+R: Enable resize mode else: log(1, "Unhandled key event!") """Close connection to display server""" def closeDisplay(self): log(0, "Exiting...") self.display.close() """Run an application/process""" def runProcess(self, applicationInfo): try: name = applicationInfo["name"] # Get application name command = applicationInfo["command"] # Get aplication command except: raise ValueError try: log(0, "Running: "+name) subprocess.Popen(command) # Run the command and disown the child process except BaseException as error: log(2, "Failed to launch process: "+processCommand+"!") log(3, str(error))