def main(): root.change_attributes(event_mask=X.PropertyChangeMask) is_bad_window = False while True: win, changed = get_active_window() if not is_bad_window or changed: try: # TODO: Application/window -specific detection configuration is_bad_window = False win.map() width = win.get_geometry().width height = 1 raw = win.get_image(0, 1, width, height, X.ZPixmap, 0xffffffff) image = Image.frombytes('RGB', (width, height), raw.data, 'raw', 'BGRX') colors = image.getcolors() if colors is None: target_color = (0, 0, 0) else: target_color = sorted(colors, key=lambda k: k[0])[-1][1] wm_class = ' '.join(win.get_wm_class()) name = '_'.join(win.get_wm_class()) set_window_config(wm_class, name, ','.join(map(str, target_color))) except Exception as e: print(e) is_bad_window = True while display.pending_events(): event = display.next_event() time.sleep(1 / 60)
def main() -> None: for cmd in CMDS: assert shutil.which(cmd) is not None, "'%s' not found in PATH." % cmd signal.signal(signal.SIGCHLD, signal.SIG_IGN) display: Xlib.display.Display = Xlib.display.Display() window_manager: WindowManager = WindowManager(display) while window_manager.is_running(): window_manager.on_event(display.next_event()) display.close()
def on_event(): nonlocal bound while display.pending_events(): evt = display.next_event() if evt.type == X.KeyPress: k = (evt.detail, evt.state & modmask) if k in bound: asyncio.ensure_future(bound[k]()) if evt.type == X.MappingNotify and evt.request == X.MappingKeyboard: display.refresh_keyboard_mapping(evt) regrab_keys()
def __update_focus_cb(self, command, sync=False): # Check FocusIn/FocusOut events if self.focus: focus_in = None focus_out = None for i in range(display.pending_events()): event = display.next_event() if event.type == Xlib.X.FocusIn: focus_in = event.window elif event.type == Xlib.X.FocusOut: focus_out = event.window if focus_in == self.focus: if focus_out != self.focus: # This is ugly workaround, but necessary to avoid a # problem that the language bar doesn't appear after # moving to other workspace in Ubuntu Unity desktop. # If old version of ibus.el which doesn't define # `ibus-redo-focus-in-cb' is running on Emacs, the # following message will just be ignored and take no effect. print_command('ibus_redo_focus_in_cb') if sync: print_command(command, focus_in.id) return True # Main part focus = self.display.get_input_focus().focus try: # get_input_focus() may return an integer 0 that query_tree() # causes AttributeError when X session is going to logout. tree = focus.query_tree() # In Ubuntu's Unity desktop, get_input_focus() often returns root # window incorrectly after changing workspace. if focus != tree.root: if not (focus.get_wm_class() or focus.get_wm_name()): focus = tree.parent if focus != self.focus or sync: print_command(command, focus.id) focus.change_attributes(event_mask=Xlib.X.FocusChangeMask) self.focus = focus return True except AttributeError: if sync: print_command(command, 0) return True # Fallback atom = display.get_atom("_NET_ACTIVE_WINDOW", True) focus_id = tree.root.get_property(atom, Xlib.Xatom.WINDOW, 0, 1).value[0] focus = display.create_resource_object("window", focus_id) if focus != self.focus or sync: print_command(command, focus_id) focus.change_attributes(event_mask=Xlib.X.FocusChangeMask) self.focus = focus return True
def update(): global current_window_id, current_window window_id = _check_current_window_id() if current_window_id is None or not window_id == current_window_id: window = display.create_resource_object('window', window_id) window.change_attributes(event_mask=Xlib.X.PropertyChangeMask) current_window = window current_window_id = window_id print("Current window: {0}".format(get_focused_window_name())) event = display.next_event()
def main(argv): bg_size = 16 # Default corner size corners = ['nw', 'ne', 'se', 'sw'] # Default corners to draw try: opts, args = getopt.getopt(argv, "h", ["help", "corners=", "size="]) except: return usage() sys.exit(2) for opt, arg in opts: if opt in ("-h", "--help"): return usage() elif opt in ("--corners"): corners = ''.join(str(arg)).lower() if not any(sz in corners for sz in ["nw", "ne", "sw", "se"]): return usage() elif opt in ("--size"): try: bg_size = int(arg) except: return usage() for arg in sys.argv: print(arg) window = create_window( bg_size, corners) # Make the window using specified size / corners window.map() # Make the window appear while True: e = display.next_event() set_wm_state(window, "_NET_WM_DESKTOP", data=[0xFFFFFFFF, 1, 0, 0, 0]) # Keeps window on all workspaces set_wm_state(window, "_NET_WM_STATE", data=[1, "_NET_WM_STATE_SKIP_TASKBAR", 0, 1, 0]) # Removes window from task list set_wm_state(window, "_NET_WM_STATE", data=[1, "_NET_WM_STATE_ABOVE", 0, 1, 0]) # Keeps window above (almost all) other windows # TODO: How to keep above fullscreened windows (F11 sublime / chrome / etc.) ? This doesn't work: # set_wm_state(window, "_NET_WM_STATE", data=[1, "_NET_WM_STATE_FULLSCREEN", 0, 1, 0]) display.flush() # Is this really needed? Seems to work fine without
def xtype(keysyms, keycode=KEYCODE): keysyms = list(enumerate(keysyms, keycode)) print(keysyms) import Xlib.display from Xlib import X display = Xlib.display.Display() display.change_keyboard_mapping(keycode, [(sym,) * 8 for code, sym in keysyms]) while 1: e = display.next_event() if e.type == X.MappingNotify: for code, sym in keysyms: display.xtest_fake_input(X.KeyPress, code) display.xtest_fake_input(X.KeyRelease, code) break display.sync()
def main(): args = parse_args() ckb = CKBPipe(args.ckb_pipe) display = Xlib.display.Display() atom = display.intern_atom('_NET_CURRENT_DESKTOP', True) window = display.screen().root highlight_current_workspace(ckb, window, atom) window.change_attributes(event_mask=X.PropertyChangeMask) while True: ev = display.next_event() if ev.type == X.PropertyNotify and ev.state == X.PropertyNewValue and ev.window == window and ev.atom == atom: highlight_current_workspace(ckb, window, atom)
def get_selection(): display = Xlib.display.Display() xsel_data_atom = display.intern_atom("XSEL_DATA") screen = display.screen() w = screen.root.create_window(0, 0, 2, 2, 0, screen.root_depth) w.convert_selection(Xlib.Xatom.PRIMARY, Xlib.Xatom.STRING, xsel_data_atom, Xlib.X.CurrentTime) while True: e = display.next_event() if e.type == Xlib.X.SelectionNotify: break assert e.property == xsel_data_atom assert e.target == Xlib.Xatom.STRING reply = w.get_full_property(xsel_data_atom, Xlib.X.AnyPropertyType) return reply.value
def __init__(self, display): self.display = display self.screen = display.screen() self.colormap = self.screen.default_colormap bg = self.colormap.alloc_named_color("gray10").pixel self.window = self.screen.root.create_window( 50, 50, 600, 400, 0, self.screen.root_depth, X.InputOutput, X.CopyFromParent, # special attribute values background_pixel = bg, event_mask = (#X.ExposureMask | X.StructureNotifyMask), colormap = self.colormap ) self.window.set_wm_name('Pyxine') self.window.set_wm_icon_name('Pyxine') self.window.set_wm_class('pyxine', 'PyXine') self.window.set_wm_protocols([display.WM_DELETE_WINDOW]) self.window.set_wm_hints(flags = Xutil.StateHint, initial_state = Xutil.NormalState) self.window.set_wm_normal_hints(flags = (Xutil.PPosition | Xutil.PSize | Xutil.PMinSize), min_width = 20, min_height = 20) # Map the window, making it visible self.window.map() # Wait for window to map. # FIXME: is this right? while 1: e = display.next_event() if e.type == X.MapNotify: break self.xine_visual = pyxine.XlibDrawable(self.window)
def get_x_selection(): import Xlib.display # from the python X library, http://python-xlib.sf.net/ import Xlib.X import Xlib.Xatom display = Xlib.display.Display() xsel_data_atom = display.intern_atom("XSEL_DATA") screen = display.screen() w = screen.root.create_window(0, 0, 2, 2, 0, screen.root_depth) w.convert_selection(Xlib.Xatom.PRIMARY, # selection Xlib.Xatom.STRING, # target xsel_data_atom, # property Xlib.X.CurrentTime) # time while True: e = display.next_event() if e.type == Xlib.X.SelectionNotify: break assert e.property == xsel_data_atom assert e.target == Xlib.Xatom.STRING reply = w.get_full_property(xsel_data_atom, Xlib.X.AnyPropertyType) return reply.value
def events(display): """Returns an generator which yields incoming x11 events""" return (display.next_event() for _ in itertools.count())
def on_event(): while display.pending_events(): display.next_event()
def main(argv): try: s = serial.Serial(port = SERIAL_PATH) except: print 'exception opening serial port' exit(0) # for audio control m = alsaaudio.Mixer() while True: try: cmd = long(s.readline()) & 0x0000FFFF if cmd == 254: try: print '[254] volume increase' m.setvolume(int(m.getvolume()[0] + 5)) except: pass elif cmd == 8414: try: print '[8414] volume decrease' m.setvolume(int(m.getvolume()[0] - 5)) except: pass elif cmd == 24734: print '[24734] netflix continue' d = display.Display() screen = d.screen() root_screen = screen.root root_screen.warp_pointer(831, 460) d.sync() fake_input(d, X.ButtonPress, 1) d.sync() fake_input(d, X.ButtonRelease, 1) d.sync() fake_input(d, X.ButtonPress, 1) d.sync() fake_input(d, X.ButtonRelease, 1) d.sync() # netflix pause button elif cmd == 24990: print '[24990] netflix pause/resume' d = display.Display() screen = d.screen() # move cursor to position of pause/resume button root_screen = screen.root root_screen.warp_pointer(199, 896) d.sync() # click twice, once for focus and once for actual pause/resume fake_input(d, X.ButtonPress, 1) d.sync() fake_input(d, X.ButtonRelease, 1) d.sync() root_screen.warp_pointer(0, 0) d.sync() # move cursor off screen root_screen.warp_pointer(9999, 0) d.sync() fake_input(d, X.ButtonPress, 1) d.sync() fake_input(d, X.ButtonRelease, 1) d.sync() elif cmd == 510: print '[510] sleep displays' subprocess.call('xset dpms force off'.split()) p = subprocess.Popen('gnome-screensaver-command -i'.split()) time.sleep(1) print display.next_event() p.terminate() except Exception, e: print 'exception while reading data from serial port'
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import Xlib from Xlib import display, X # X is also needed display = Xlib.display.Display() screen = display.screen() root = screen.root #print(root.get_attributes()) root.change_attributes(event_mask=X.ExposureMask) # "adds" this event mask #print(root.get_attributes()) # see the difference gc = root.create_gc(foreground = screen.white_pixel, background = screen.black_pixel) def draw_it(): root.draw_text(gc, 100, 100, b"Hello, world!") display.flush() draw_it() while 1: if display.pending_events() != 0: # check to safely apply next_event event = display.next_event() if event.type == X.Expose and event.count == 0: draw_it()
def sendViaClipboard(blobs, record = None, txtselections = defSelections, ui=ui_null()): """ Send a list of blobs via the clipboard (using X selections, cut buffers are not yet supported) in sequence. Typically the PRIMARY and/or SECONDARY selections are used for middle click and shift+insert pasting, while the CLIPBOARD selection is often used by Ctrl+V pasting. Raises an XFailConnection exception if connecting to the X DISPLAY failed. """ global Xlib, X, Xatom, Xerror if Xlib is None: ui.status('Initialising python-Xlib, stand by...') ui.mainloop.draw_screen() try: from Xlib import X, Xatom, error as Xerror import Xlib.display except ImportError: ui.status('Error importing python-Xlib, X clipboard integration unavailable') return # Can't do this in the function definition - it seems that a .remove() # affects the default. That would be expected if it were assigned as a # reference to the default list, but even happens when the [:] syntax is # used to copy the list. I guess that must be an unexpected side effect of # the function definition only excuting once when the file is loaded? txtselections = txtselections[:] selections = txtselections[:] def findClientWindow(window, ui): """ walk up the tree looking for a client window """ def get_wm_client_leader(window): d = window.get_full_property(Xatom.WM_CLIENT_LEADER, Xatom.WINDOW) if d is None or d.format != 32 or len(d.value) < 1: return None else: cls = window.display.get_resource_class('window', type(window)) return cls(window.display, d.value[0]) host = window.get_wm_client_machine() while True: comm = window.get_full_property(Xatom.WM_COMMAND, Xatom.STRING) name = window.get_wm_name() # Nokia N900 uses _NET_WM_NAME instead of WM_NAME: netname = window.get_full_property(Xatom._NET_WM_NAME, Xatom.UTF8_STRING) leadercomm = None # Only one top-level window for a given client has WM_COMMAND. Find the # leader top-level window (if we are looking at a top-level window) and # check it's WM_COMMAND property. # # I don't see a requirement in the ICCCM that the client leader # necessarily be the window with the WM_COMMAND property, it may end up # being necessary to iterate all the windows with the same # WM_CLIENT_LEADER to find the one window that has the WM_COMMAND. leader = get_wm_client_leader(window) if leader is not None and leader != window: leadercomm = leader.get_full_property(Xatom.WM_COMMAND, Xatom.STRING) requestor = name or netname or comm or leadercomm if hasattr(requestor, 'value'): requestor = requestor.value if requestor: break resp = window.query_tree() root = resp.root; parent = resp.parent if parent == root: return ('<unknown>', host) window = parent return (requestor, host) def handleSelectionRequest(e, field, record, ui): global _prev_requestor if ((e.time != X.CurrentTime and e.time < timestamp) or # Timestamp out of bounds (e.selection not in selections) or # Requesting a different selection (e.owner.id != win.id)): # We aren't the owner return _refuseSelectionRequest(e) if (e.target in (Xatom.STRING, Xatom.TEXT)): (requestor, host) = findClientWindow(e.requestor, ui) if requestor.lower() in blacklist or any([ pattern.match(requestor) for pattern in blacklist_re ]): if requestor != _prev_requestor: ui.status("Ignoring request from %s@%s"%(requestor, host), append=True) _prev_requestor = requestor return _refuseSelectionRequest(e) ui.status("Sent %s for '%s' via %s to %s@%s"%(field.upper(), record, display.get_atom_name(e.selection), requestor, host), append=True) oldmask = e.requestor.get_attributes().your_event_mask e.requestor.change_attributes(event_mask = oldmask | X.PropertyChangeMask) _sendSelection(blob, Xatom.STRING, 8, e, ui) return True elif (e.target == Xatom.TIMESTAMP): _sendSelection([timestamp], Xatom.TIMESTAMP, 32, e, ui) elif (e.target == Xatom.TARGETS): _sendSelection([Xatom.TARGETS, Xatom.TIMESTAMP, Xatom.TEXT, Xatom.STRING], Xatom.ATOM, 32, e, ui) else: return _refuseSelectionRequest(e) return False # Opening the display prints 'Xlib.protocol.request.QueryExtension' to # stdout, so temporarily redirect it: ui.status('Connecting to display, stand by...') ui.mainloop.draw_screen() import sys, StringIO saved_stdout = sys.stdout sys.stdout = StringIO.StringIO() try: display = Xlib.display.Display() except Xerror.DisplayError: raise XFailConnection() finally: sys.stdout = saved_stdout screen = display.screen() win = screen.root.create_window(0,0,1,1,0,0) Xatom.TEXT = display.intern_atom('TEXT', True) Xatom.TARGETS = display.intern_atom('TARGETS', True) Xatom.TIMESTAMP = display.intern_atom('TIMESTAMP', True) Xatom.WM_CLIENT_LEADER = display.intern_atom('WM_CLIENT_LEADER', True) Xatom._NET_WM_NAME = display.intern_atom('_NET_WM_NAME', True) Xatom.UTF8_STRING = display.intern_atom('UTF8_STRING', True) ui_fds = ui.mainloop.screen.get_input_descriptors() if ui_fds is None: ui_fds = [] select_fds = set([display] + ui_fds) try: old = ui_tty.set_cbreak() # Set unbuffered IO (if not already) ui.status('') for (field, blob) in blobs: ui.status("Ready to send %s for '%s' via %s... (enter skips, escape cancels)"%(field.upper(),record,str(txtselections)), append=True) ui.mainloop.draw_screen() awaitingCompletion = [] timestamp = _ownSelections(display, win, selections) timeout = None skip = False while 1: if skip and awaitingCompletion == []: break while True: try: (readable, ign, ign) = select.select(select_fds, [], [], timeout) except select.error as e: if e.args[0] == 4: continue # Interrupted system call raise break if not readable and awaitingCompletion == []: break for fd in readable: if fd == sys.stdin.fileno(): char = sys.stdin.read(1) if char == '\n': skip = True elif char == '\x1b': return elif fd in ui_fds: # This is a hack to redraw the screen - we really should # restructure all this so as not to block instead: ui.mainloop.event_loop._loop() if fd == display: while display.pending_events(): e = display.next_event() if e.type == X.SelectionRequest: if handleSelectionRequest(e, field, record, ui): # Don't break immediately, transfer will not have finished. # Wait until the property has been deleted by the requestor awaitingCompletion.append((e.requestor, e.property)) elif e.type == X.PropertyNotify: if (e.window, e.atom) in awaitingCompletion \ and e.state == 1: # Deleted awaitingCompletion.remove((e.window, e.atom)) # Some programs, such as firefox (when pasting with # shift+insert), don't expect the selection to change suddenly # and behave badly if it does, so wait a moment before ending: timeout = 0.01 elif e.type == X.SelectionClear: if e.time == X.CurrentTime or e.time >= timestamp: # If we lost CLIPBOARD (explicit copy) or no longer control any selection, abort: name = display.get_atom_name(e.atom) selections.remove(e.atom) txtselections.remove(name) if name == 'CLIPBOARD' or not selections: # If transfer is in progress it should be allowed to complete: if awaitingCompletion == []: return timeout = 0.01 else: ui.status("Lost control of %s, still ready to send %s via %s..."%(name, field.upper() ,str(txtselections)), append=True) ui.mainloop.draw_screen() ui.mainloop.draw_screen() finally: ui_tty.restore_cbreak(old) win.destroy() display.close() # I may have introduced a bug while adding the urwid loop # stuff here - the clipboard selection remained grabbed # after destroying the window. This worked around it since # I can't see what is wrong. ui.status('Clipboard Cleared', append=True)
code = compile(code, config_file, 'exec') g, l = globals(), dict(locals()) for key in l: g[key] = l[key] exec(code, g) else: print('No configuration file found') sys.exit(1) open_x() display = get_display() outputs = get_monitors() start() while True: try: e = display.next_event() if e.type == Xlib.X.DestroyNotify: break else: unhandled_event(e) except KeyboardInterrupt: break redraw() display.flush() stop() close_x()
def _monitor(self): def _reset(): LOGGER.debug('Resetting screensaver.') self._reset_timer() self.SetActive(False) def _input_monitor(dev): LOGGER.info(f'Monitoring "{dev.name}"') for event in dev.read_loop(): if self.GetSessionIdleTime() < self.input_reset_delay: continue _reset() # Xlib for monitoring windows display = Xlib.display.Display(None) root = display.screen().root win_attr_mask = (Xlib.X.PropertyChangeMask | Xlib.X.SubstructureNotifyMask) root.change_attributes(event_mask=win_attr_mask) # evdev for monitoring input devices devices = [] for dev in [evdev.InputDevice(path) for path in evdev.list_devices()]: for k, caps in dev.capabilities(absinfo=False).items(): if (ecodes['BTN_TOUCH'] in caps or ecodes['BTN_MOUSE'] in caps or ecodes['KEY_ENTER'] in caps): devices.append(dev) for dev in devices: t = threading.Thread(target=_input_monitor, args=(dev, )) t.daemon = True t.start() _reset() while True: event = display.next_event() # Test for new windows try: if event.type == Xlib.X.CreateNotify: LOGGER.debug('Registering new window') event.window.change_attributes(event_mask=win_attr_mask) elif event.type == Xlib.X.MapNotify: wm_class = event.window.get_wm_class() wm_name = event.window.get_wm_name() LOGGER.debug('New window: class: {}, name: {}'.format( wm_class, wm_name)) if self._should_ignore(self._idle_reset_ignore, wm_class, wm_name): LOGGER.debug('Window is in ignore list. ' 'Not resetting ScreenSaver.') continue _reset() elif event.type == Xlib.X.PropertyNotify: self._handle_fullscreen(display) except Xlib.error.XError: continue