Esempio n. 1
0
def get_primary_selection():
    """Get the word selected in the primary selection."""
    display = Display()
    xsel_data_atom = display.intern_atom("XSEL_DATA")
    UTF8_STRING = display.intern_atom("UTF8_STRING")
    screen = display.screen()
    w = screen.root.create_window(0, 0, 2, 2, 0, screen.root_depth)
    w.convert_selection(
        Xlib.Xatom.PRIMARY,  # selection
        UTF8_STRING,  # target
        xsel_data_atom,  # property
        Xlib.X.CurrentTime)  # time

    while True:
        e = display.next_event()
        if e.type == X.SelectionNotify:
            break

    if e.property != xsel_data_atom or \
       e.target != UTF8_STRING:
        return ''

    reply = w.get_full_property(xsel_data_atom, X.AnyPropertyType)
    reply = reply.value.strip()
    return reply
Esempio n. 2
0
class Window(object):

    """
        Abstract object representing the X Window of an application
        obtained with the window ID.
    """

    def __init__(self, windowID):

        self._display = Display()
        self._root = self._display.screen().root
        self._window = self._display.create_resource_object('window', windowID)


    def reserve_space(self, left=0, right=0, top=0, bottom=0):

        """ Reserves screen-space for toplevel window. """

        LEFT    = left
        RIGHT   = right
        TOP     = top
        BOTTOM  = bottom

        self._window.change_property(self._display.intern_atom('_NET_WM_STRUT'),
                                    self._display.intern_atom('CARDINAL'),
                                    32, [LEFT, RIGHT, TOP, BOTTOM])
        self._display.sync()


    def set_wm_state_skip_taskbar(self):

        """ Change state of the window. """

        self._window.set_wm_state(Display().intern_atom('_NET_WM_STATE_SKIP_TASKBAR'))
Esempio n. 3
0
    def start(self):
        mod = self.MOD_MASK
        dpy = Display()

        keys = {}
        for key, name in self.KEY_MAP.items():
            keys[key] = dpy.keysym_to_keycode(XK.string_to_keysym(key))

        root = dpy.screen().root
        for key, code in keys.items():
            root.grab_key(code, mod, 1, X.GrabModeAsync, X.GrabModeAsync)

        root.grab_button(
            1, mod, 1,
            X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask,
            X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE)
        root.grab_button(
            3, mod, 1,
            X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask,
            X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE)

        self.dpy = dpy
        self.keys = keys
        self.root = root

        self.WM_PROTOCOLS = dpy.intern_atom("WM_PROTOCOLS")
        self.WM_DELETE_WINDOW = dpy.intern_atom("WM_DELETE_WINDOW")

        self._loop()
Esempio n. 4
0
class BarWindow:
    def __init__(self, window_id):
        self._display = Display()
        self._window = self._display.create_resource_object('window', window_id)

    def reserve_space(self, left=0, right=0, top=0, bottom=0):
        self._window.change_property(
            self._display.intern_atom('_NET_WM_STRUT'),
            self._display.intern_atom('CARDINAL'),
            32,
            [left, right, top, bottom])
        self._display.sync()
Esempio n. 5
0
def init():
    global display
    display = Display()
    global root
    root = display.screen().root
    global NET_WM_NAME
    NET_WM_NAME = display.intern_atom('_NET_WM_NAME')  # UTF-8
    global WM_NAME
    WM_NAME = display.intern_atom('WM_NAME')
    global NET_ACTIVE_WINDOW
    NET_ACTIVE_WINDOW = display.intern_atom('_NET_ACTIVE_WINDOW')
    root.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
Esempio n. 6
0
def repositionize(title=str, x=int, y=int, width=int, height=int):
    HEIGHT = height
    WIDTH = width
    y=1080-y-height
    display = Display()
    root = display.screen().root
    windowIDs = root.get_full_property(display.intern_atom('_NET_CLIENT_LIST'),X.AnyPropertyType).value
    for windowID in windowIDs:
        window = display.create_resource_object('window', windowID)
        titles = window.get_wm_name()
        pid = window.get_full_property(display.intern_atom('_NET_WM_PID'), X.AnyPropertyType)
        if title in titles:
            window.configure(x = x, y = y, width=WIDTH, height=HEIGHT)
            display.sync()
Esempio n. 7
0
def from_python_xlib():
    """Get the I3 socket path using python-xlib.

    """
    try:
        from Xlib.display import Display
    except ImportError:
        return None

    display = Display(os.environ.get('DISPLAY', ':0.0'))
    screen = display.screen()
    atom = display.intern_atom(I3_SOCK_X_ATOM, True)
    utf8_string = display.intern_atom('UTF8_STRING', True)
    response = screen.root.get_full_property(atom, utf8_string)
    return response.value
Esempio n. 8
0
    def run(self):

        self.disable_keyboard_interrupt()

        display = Display()

        while True:
            try:
                time.sleep(self._interval)
                window = display.get_input_focus().focus

                if window.get_wm_class() is None and window.get_wm_name() is None:
                    window = window.query_tree().parent
                if window:
                    pid_value = window.get_full_property(display.intern_atom('_NET_WM_PID'),0)
                    if pid_value:
                        try:
                            pid = int(pid_value.value[0])
                            process = psutil.Process(pid)
                            name,exe,title = process.name,process.exe,window.get_wm_name()
                            value = {'exe':exe,'title':title.decode('latin-1'),'time':time.time()-self._last_time}
                            self.send_event(value)
                            self._last_time = time.time()
                        except:
                            pass
            except AttributeError:
                pass
Esempio n. 9
0
def resize(title=str, height=int, width=int):
    TITLE = title
    HEIGHT = height
    WIDTH = width

    display = Display()
    root = display.screen().root
    windowIDs = root.get_full_property(display.intern_atom('_NET_CLIENT_LIST'),
                                       X.AnyPropertyType).value
    for windowID in windowIDs:
        window = display.create_resource_object('window', windowID)
        title = window.get_wm_name()
        pid = window.get_full_property(display.intern_atom('_NET_WM_PID'),
                                       X.AnyPropertyType)
        if TITLE in title:
            window.configure(width=WIDTH, height=HEIGHT)
            display.sync()
Esempio n. 10
0
 def run(self, window, screen):
     opacity = max(0.0, min(1.0, self.arg))
     xdisplay = XDisplay()
     xwindow = xdisplay.create_resource_object("window", window.get_xid())
     atom = xdisplay.intern_atom("_NET_WM_WINDOW_OPACITY")
     data = struct.pack("L", int(4294967295 * opacity))
     xwindow.change_property(atom, Xatom.CARDINAL, 32, data)
     xdisplay.sync()
Esempio n. 11
0
class Window(object):
    def __init__(self, window_ID):
        self._display = Display()
        self._window = self._display.create_resource_object(
            'window', window_ID)

    def reserve_space(self, left=0, right=0, top=0, bottom=0):
        LEFT = int(left)
        RIGHT = int(right)
        TOP = int(top)
        BOTTOM = int(bottom)
        print([LEFT, RIGHT, TOP, BOTTOM])
        self._window.change_property(
            self._display.intern_atom('_NET_WM_STRUT'),
            self._display.intern_atom('CARDINAL'), 32,
            [LEFT, RIGHT, TOP, BOTTOM])
        self._display.sync()
Esempio n. 12
0
def resize(title=str, height=int, width=int):
    TITLE = title
    HEIGHT = height
    WIDTH = width

    display = Display()
    root = display.screen().root
    windowIDs = root.get_full_property(display.intern_atom('_NET_CLIENT_LIST'),
        X.AnyPropertyType).value
    for windowID in windowIDs:
        window = display.create_resource_object('window', windowID)
        title = window.get_wm_name()
        pid = window.get_full_property(display.intern_atom('_NET_WM_PID'),
        X.AnyPropertyType)
        if TITLE in title:
            window.configure(width = WIDTH, height = HEIGHT)
            display.sync()
Esempio n. 13
0
def main(argv):
    display = Display()
    root = display.screen().root
    root.change_attributes(event_mask=X.PropertyChangeMask
                           | X.SubstructureNotifyMask)
    skip_windows = [
        'tk.TkN/Awindowswitcher',
        'xfce4-appfinder.Xfce4-appfinderxavierApplicationFinder'
    ]

    NET_ACTIVE_WINDOW = display.intern_atom('_NET_ACTIVE_WINDOW')

    try:
        while True:
            event = display.next_event()
            if event.type != X.PropertyNotify:
                continue

            response = root.get_full_property(NET_ACTIVE_WINDOW,
                                              X.AnyPropertyType)
            win_id = hex(response.value[0]).rstrip('L').lstrip('0x')

            if len(win_id) == 0:
                continue

            wmctrl_out = os.popen(
                'sleep 0.1; wmctrl -dliGux | grep -i {win_id}'.format(
                    win_id=win_id)).read()
            wmctrl_out = wmctrl_out.split('\n')
            wmctrl_out.pop()

            if len(wmctrl_out) != 1:
                continue

            window = WmctrlWindow(wmctrl_out[0])
            # ignore window switcher
            if window.name in skip_windows:
                continue

            str_json = open("/home/danilo/scripts/flip360_wids.json",
                            "r").read()
            jjson = json.loads(str_json)

            key_json = 'm{m}{w}'.format(m=window.monitor, w=window.workspace)
            if jjson.get(key_json, None) == None:
                continue

            window_previous = WmctrlWindow(jjson[key_json])
            if window.id == window_previous.id:
                continue

            jjson[key_json] = window.str_win
            flip360_wids = open("/home/danilo/scripts/flip360_wids.json", "w")
            flip360_wids.write(json.dumps(jjson))
            flip360_wids.close()

    finally:
        display.close()
Esempio n. 14
0
class Window(object):
    def __init__(self):
        self.display = Display()
        self.root = self.display.screen().root
        self.title = 'Pointer active'

    def active_window(self):
        window_id = self.root.get_full_property(self.display.intern_atom('_NET_ACTIVE_WINDOW'), X.AnyPropertyType).value[0]
        window = self.display.create_resource_object('window', window_id)
        return window

    def find_window(self, title):
        window_ids = self.root.get_full_property(self.display.intern_atom('_NET_CLIENT_LIST'), X.AnyPropertyType).value
        for window_id in window_ids:
            window = self.display.create_resource_object('window', window_id)
            if title == window.get_wm_name():
                return window
        return None

    def resize(self, window, dim):
        window.configure(width = dim[0], height = dim[1])
        self.display.sync()

    def move(self, window, pos):
        window.configure(x = pos[0], y = pos[1])
        self.display.sync()

    def destroy(self, window):
        window.destroy()
        self.display.sync()

    def shape(self, window):
        geo = window.get_geometry()
        return (geo.width, geo.height)

    def position(self, window):
        p = window.query_pointer()
        return (p.root_x - p.win_x, p.root_y - p.win_y - 28) # The 28 seems to be the taskbar

    def rename(self, window):
        print 'renaming', window.get_wm_name()
        window.set_wm_icon_name('poo')
        window.set_wm_name('poo')
        self.display.sync()
Esempio n. 15
0
def generate_message(args):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('localhost', args.port))
    flag = False
    disp = Display()
    root = disp.screen().root
    NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')

    if args.add == 0:
        response = root.get_full_property(NET_ACTIVE_WINDOW, X.AnyPropertyType)

        if not response:
            print("Couldn't find the active window", file=sys.stderr)

        send(s, "add " + str(response.value[0]))
    elif args.add is None:
        pass
    else:
        send(s, "add " + str(args.add))
        flag = True

    if args.rm == 0:
        response = root.get_full_property(NET_ACTIVE_WINDOW, X.AnyPropertyType)

        if not response:
            print("Couldn't find the active window", file=sys.stderr)

        send(s, "rm " + str(response.value[0]))
    if args.rm is None:
        pass
    else:
        send(s, "rm " + str(args.rm))
        flag = True

    if args.clear is True:
        send(s, "clear")
        flag = True

    if args.active is True:
        send(s, "active")
        flag = True

    if args.deactive is True:
        send(s, "deactive")
        flag = True

    if args.toggle is True:
        send(s, "toggle")
        flag = True

    if args.kill is True:
        send(s, "stop")
        flag = True

    return flag
Esempio n. 16
0
def x11_setup():
    global _x11, xdisplay, modifier_keycodes, NET_ACTIVE_WINDOW, NET_WM_PID, WM_CLASS, xtest_available
    if _x11 is not None:
        return _x11
    try:
        from Xlib.display import Display
        xdisplay = Display()
        modifier_keycodes = xdisplay.get_modifier_mapping(
        )  # there should be a way to do this in Gdk
        NET_ACTIVE_WINDOW = xdisplay.intern_atom('_NET_ACTIVE_WINDOW')
        NET_WM_PID = xdisplay.intern_atom('_NET_WM_PID')
        WM_CLASS = xdisplay.intern_atom('WM_CLASS')
        _x11 = True  # X11 available
        if _log.isEnabledFor(_INFO):
            _log.info('X11 library loaded and display set up')
    except Exception:
        _log.warn('X11 not available - some rule capabilities inoperable: %s',
                  exc_info=_sys.exc_info())
        _x11 = False
        xtest_available = False
    return _x11
Esempio n. 17
0
def get_primary_selection():
    """Get the word selected in the primary selection."""
    display = Display()
    xsel_data_atom = display.intern_atom("XSEL_DATA")
    UTF8_STRING = display.intern_atom("UTF8_STRING")
    screen = display.screen()
    w = screen.root.create_window(0, 0, 2, 2, 0, screen.root_depth)
    w.convert_selection(Xlib.Xatom.PRIMARY,  # selection
                        UTF8_STRING,         # target
                        xsel_data_atom,      # property
                        Xlib.X.CurrentTime)  # time

    while True:
        e = display.next_event()
        if e.type == X.SelectionNotify:
            break

    if e.property != xsel_data_atom or \
       e.target != UTF8_STRING:
        return ''

    reply = w.get_full_property(xsel_data_atom, X.AnyPropertyType)
    reply = reply.value.strip()
    return reply
Esempio n. 18
0
	def xstuff(self):
		screen = self.window.get_screen()
		s = Gdk.Screen.get_default()
		disp = screen.get_display()
		width = s.get_width()
		height = s.get_height()
		bar_size = 40
		x,y = 0,0
		self.window.move(x,y)
		self.window.resize(width,bar_size)
		self.window.show_all()

		display = Display()
		topw = display.create_resource_object('window',
                                       self.window.get_toplevel().get_window().get_xid())
		topw.change_property(display.intern_atom('_NET_WM_STRUT'),
                       display.intern_atom('CARDINAL'), 32,
                       [0, 0, bar_size, 0 ],
                       X.PropModeReplace)

		topw.change_property(display.intern_atom('_NET_WM_STRUT_PARTIAL'),
		display.intern_atom('CARDINAL'), 32,
		[0, 0, bar_size, 0, 0, 0, 0, 0, x, x+width-1, 0, 0],
		X.PropModeReplace)
Esempio n. 19
0
def main(argv):
    display = Display()

    thread = EventThread(display)
    thread.start()
    time.sleep(1)

    screen = display.screen()

    # The get_property call should not deadlock, despite the blocking next_event
    # call in the thread.
    atom = display.intern_atom('_XROOTPMAP_ID', True)
    response = screen.root.get_property(atom, Xatom.PIXMAP, 0, 1)
    print('get_property response: %r' % response)

    display.close()
Esempio n. 20
0
 def set_wm_class(self):
     """
     Set the X11 WM_CLASS. This is used to link the window to the X11
     application (menu entry from the .desktop file). Gnome-shell won't
     display the application icon correctly in the dash with the default
     value of `python3, python3`.
     """
     display = Display()
     root = display.screen().root
     windowIDs = root.get_full_property(
         display.intern_atom('_NET_CLIENT_LIST'), X.AnyPropertyType).value
     for windowID in windowIDs:
         window = display.create_resource_object('window', windowID)
         title = window.get_wm_name()
         if title == self.title:
             window.set_wm_class("MyKivyTestApp", "python3")
             display.sync()
Esempio n. 21
0
    def __init__(self,
                 notification: int,
                 summary: str,
                 body: str,
                 application: str,
                 icon_path: Optional[str] = None,
                 timeout: Optional[int] = -1,
                 actions: Optional[List[List]] = None,
                 dismiss: bool = False):
        # Set up empty window and add style
        Gtk.Window.__init__(self)

        # No need to provide a mainloop, as we are only sending

        # Version information
        print("Gtk %d.%d.%d" %
              (Gtk.get_major_version(), Gtk.get_minor_version(),
               Gtk.get_micro_version()))
        self.notification = notification
        self.body = body
        self.summary = summary
        self.application = application
        self.icon_path = icon_path
        self.timeout = timeout
        self.actions = actions
        self.dismiss = dismiss

        self.set_name("bar")
        self.set_type_hint(Gdk.WindowTypeHint.DOCK)
        self.set_decorated(False)
        self.connect("delete-event", Gtk.main_quit)

        # style_provider = Gtk.CssProvider()
        # style_provider.from_data(stylesheet)
        # Gtk.StyleContext.add_provider_for_screen(
        #     Gdk.Screen.get_default(),
        #     style_provider,
        #     Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

        # Layout container
        self.hbox = Gtk.Box(spacing=5)
        self.hbox.set_homogeneous(False)

        message_str = "<big>{}</big>".format(self.application)

        if icon_path is not None:
            if self._try_init_icon():
                message_str = ""  # Application displayed with icon

        self.message = Gtk.Label()

        if self.body is None:
            message_str += "<b>{}</b>".format(self.summary)
        else:
            message_str += "<b>{}</b>\n{}".format(self.summary, self.body)
        self.message.set_markup(message_str)
        self.hbox.pack_start(self.message, False, True, 0)

        self._init_action_buttons()
        button = Gtk.Button.new_with_mnemonic("_OK")
        button.connect("clicked", self.done)
        self.hbox.pack_end(button, False, False, 0)

        self.add(self.hbox)

        # the screen contains all monitors
        screen = self.get_screen()
        width = screen.width()  # width = Gdk.Screen.width()
        print("width: %d" % width)

        # (c) collect data about each monitor
        monitors = []
        nmons = screen.get_display().get_n_monitors()
        print("there are %d monitors" % nmons)
        for m in range(nmons):
            mg = screen.get_monitor_geometry(m)
            print("monitor %d: %d x %d" % (m, mg.width, mg.height))
            monitors.append(mg)

        # current monitor
        curmon = screen.get_monitor_at_window(screen.get_active_window())
        x = monitors[curmon].x
        y = monitors[curmon].y
        width = monitors[curmon].width
        height = monitors[curmon].height
        print("monitor %d: %d x %d (current, offset %d)" %
              (curmon, width, height, x))
        print("bar: start=%d end=%d" % (x, x + width - 1))

        # display bar along the top of the current monitor
        self.move(x, y)
        self.resize(width, bar_size)

        # it must be shown before changing properties
        self.show_all()
        print(f"Window shown. Size {self.get_size()}")
        print(f"Window shown. Size {self.get_size()}")
        # (d) reserve space (a "strut") for the bar so it does not become obscured
        #     when other windows are maximized, etc
        # http://stackoverflow.com/questions/33719686  property_change not in gtk3.0
        # https://sourceforge.net/p/python-xlib/mailman/message/27574603
        display = Display()
        topw = display.create_resource_object(
            'window',
            self.get_toplevel().get_window().get_xid())

        # http://python-xlib.sourceforge.net/doc/html/python-xlib_21.html#SEC20
        topw.change_property(display.intern_atom('_NET_WM_STRUT'),
                             display.intern_atom('CARDINAL'), 32,
                             [0, 0, bar_size, 0], X.PropModeReplace)
        topw.change_property(
            display.intern_atom('_NET_WM_STRUT_PARTIAL'),
            display.intern_atom('CARDINAL'), 32,
            [0, 0, bar_size, 0, 0, 0, 0, 0, x, x + width - 1, 0, 0],
            X.PropModeReplace)

        # we set _NET_WM_STRUT, the older mechanism as well as _NET_WM_STRUT_PARTIAL
        # but window managers ignore the former if they support the latter.
        #
        # the numbers in the array are as follows:
        #
        # 0, 0, bar_size, 0 are the number of pixels to reserve along each edge of the
        # screen given in the order left, right, top, bottom. Here the size of the bar
        # is reserved at the top of the screen and the other edges are left alone.
        #
        # _NET_WM_STRUT_PARTIAL also supplies a further four pairs, each being a
        # start and end position for the strut (they don't need to occupy the entire
        # edge).
        #
        # In the example, we set the top start to the current monitor's x co-ordinate
        # and the top-end to the same value plus that monitor's width, deducting one.
        # because the co-ordinate system starts at zero rather than 1. The net result
        # is that space is reserved only on the current monitor.
        #
        # co-ordinates are specified relative to the screen (i.e. all monitors together).
        #

        # main event loop
        # Gtk.main()
        # Control-C termination broken in GTK3 http://stackoverflow.com/a/33834721
        # https://bugzilla.gnome.org/show_bug.cgi?id=622084
        from gi.repository import GLib

        self.invoker = ActionInvoker()

        print(f"Timeout {self.timeout}")
        self.timer = Event()
        if self.timeout > 0:
            seconds = timeout / 1000

            def sleep_then_quit():
                self.timer.wait(seconds)
                self.quit()

            Thread(target=sleep_then_quit).start()

        print("Running main loop")

        Gtk.main()
Esempio n. 22
0
class WindowManager(AbstractWindowManager):
    def __init__(self):
        super(WindowManager, self).__init__()
        self.disp = Display()
        self.root = self.disp.screen().root
        self._listen_for_window_property_changes()

        self.NET_ACTIVE_WINDOW = self.disp.intern_atom('_NET_ACTIVE_WINDOW')

        self._active_window = None
        self._update_active_window()

    def run(self):
        self.notify_all()
        while True:  # next_event() sleeps until we get an event
            self._handle_xevent(self.disp.next_event())

    def get_active_program_name(self):
        try:
            return self._active_window.get_wm_class()[1]
        except:
            logger.exception("_xorg.WindowManager.get_active_program_name failed")
            return 'FAILED'

    def _handle_xevent(self, event):
        if event.type != Xlib.X.PropertyNotify:
            return

        if event.atom == self.NET_ACTIVE_WINDOW:
            if self._update_active_window():
                self.notify_all()

    def _update_active_window(self):
        active_win_id = self.root.get_full_property(self.NET_ACTIVE_WINDOW,
                                                    Xlib.X.AnyPropertyType).value[0]
        if self._has_focus_changed(active_win_id):
            new_win = self._window_obj(active_win_id)
            if new_win:
                if self._active_window:
                    self._active_window.change_attributes(event_mask=Xlib.X.NoEventMask)

                self._active_window = new_win
                self._active_window.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
                return True
        return False

    def _listen_for_window_property_changes(self):
        self.root.change_attributes(event_mask=Xlib.X.PropertyChangeMask)

    def _window_obj(self, xid):
        window_obj = None
        if xid:
            try:
                window_obj = self.disp.create_resource_object('window', xid)
            except Xlib.error.XError:
                pass
        return window_obj

    def _has_focus_changed(self, active_win_xid):
        if self._active_window:
            return active_win_xid != self._active_window.id
        return True
Esempio n. 23
0
#window.add(area)
#area.show()

label = Gtk.Label('<span size="38000" color="red">gmail.com</span>')
label.set_use_markup(True)
window.add(label)

window.connect("delete-event", Gtk.main_quit)
window.show_all()

# Reserve space on the top
display = Display()
topw = display.create_resource_object(
    'window',
    window.get_toplevel().get_window().get_xid())
topw.change_property(display.intern_atom('_NET_WM_STRUT'),
                     display.intern_atom('CARDINAL'), 32, [0, 0, 100, 0],
                     X.PropModeReplace)
topw.change_property(display.intern_atom('_NET_WM_STRUCT_PARTIAL'),
                     display.intern_atom('CARDINAL'), 32,
                     [0, 0, 100, 0, 0, 0, 0, 0, width - 1, 0, 0],
                     X.PropModeReplace)

from threading import Thread


class KeyboardReaderThread(Thread):
    def run(self):
        from evdev import InputDevice, categorize, ecodes
        dev = InputDevice(
            '/dev/input/by-id/usb-Apple__Inc_Apple_Keyboard-event-kbd')
Esempio n. 24
0
class ActiveWindowManager():
    # Based on code by Stephan Sokolow
    # Source: https://gist.github.com/ssokolow/e7c9aae63fb7973e4d64cff969a78ae8
    # Modified by hezral to add _get_window_class_name function

    """python-xlib example which reacts to changing the active window/title.

    Requires:
    - Python
    - python-xlib

    Tested with Python 2.x because my Kubuntu 14.04 doesn't come with python-xlib
    for Python 3.x.

    Design:
    -------

    Any modern window manager that isn't horrendously broken maintains an X11
    property on the root window named _NET_ACTIVE_WINDOW.

    Any modern application toolkit presents the window title via a property
    named _NET_WM_NAME.

    This listens for changes to both of them and then hides duplicate events
    so it only reacts to title changes once.

    Known Bugs:
    -----------

    - Under some circumstances, I observed that the first window creation and last
    window deletion on on an empty desktop (ie. not even a taskbar/panel) would
    go ignored when using this test setup:

        Xephyr :3 &
        DISPLAY=:3 openbox &
        DISPLAY=:3 python3 x11_watch_active_window.py

        # ...and then launch one or more of these in other terminals
        DISPLAY=:3 leafpad
    """

    stop_thread = False
    id_thread = None
    callback = None

    def __init__(self, gtk_application=None):
        super().__init__()

        self.app = gtk_application

        # Connect to the X server and get the root window
        self.disp = Display()
        self.root = self.disp.screen().root

        # Prepare the property names we use so they can be fed into X11 APIs
        self.NET_ACTIVE_WINDOW = self.disp.intern_atom('_NET_ACTIVE_WINDOW')
        self.NET_WM_NAME = self.disp.intern_atom('_NET_WM_NAME')  # UTF-8
        self.WM_NAME = self.disp.intern_atom('WM_NAME')           # Legacy encoding
        self.WM_CLASS = self.disp.intern_atom('WM_CLASS')

        self.last_seen = {'xid': None, 'title': None}  # type: Dict[str, Any]

    def _run(self, callback):

        self.callback = callback
        self.stop_thread = False

        def init_manager():
            # Listen for _NET_ACTIVE_WINDOW changes
            self.root.change_attributes(event_mask=X.PropertyChangeMask)

            # Prime last_seen with whatever window was active when we started this
            self.get_window_name(self.get_active_window()[0])
            self.handle_change(self.last_seen)

            while True:  # next_event() sleeps until we get an event
                self.handle_xevent(self.disp.next_event())
                if self.stop_thread:
                    print(datetime.now(), "active_window_manager stopped")
                    break

        self.thread = threading.Thread(target=init_manager)
        self.thread.daemon = True
        self.thread.start()
        print(datetime.now(), "active_window_manager started")

    def _stop(self):
        self.stop_thread = True

    @contextmanager
    def window_obj(self, win_id: Optional[int]) -> Window:
        """Simplify dealing with BadWindow (make it either valid or None)"""
        window_obj = None
        if win_id:
            try:
                window_obj = self.disp.create_resource_object('window', win_id)
            except XError:
                pass
        yield window_obj

    def get_active_window(self) -> Tuple[Optional[int], bool]:
        """Return a (window_obj, focus_has_changed) tuple for the active window."""
        response = self.root.get_full_property(self.NET_ACTIVE_WINDOW, X.AnyPropertyType)
        if not response:
            return None, False
        win_id = response.value[0]

        focus_changed = (win_id != self.last_seen['xid'])
        if focus_changed:
            with self.window_obj(self.last_seen['xid']) as old_win:
                if old_win:
                    old_win.change_attributes(event_mask=X.NoEventMask)

            self.last_seen['xid'] = win_id
            with self.window_obj(win_id) as new_win:
                if new_win:
                    new_win.change_attributes(event_mask=X.PropertyChangeMask)

        return win_id, focus_changed

    def _get_window_name_inner(self, win_obj: Window) -> str:
        """Simplify dealing with _NET_WM_NAME (UTF-8) vs. WM_NAME (legacy)"""
        for atom in (self.NET_WM_NAME, self.WM_NAME):
            try:
                window_name = win_obj.get_full_property(atom, 0)
            except UnicodeDecodeError:  # Apparently a Debian distro package bug
                title = "<could not decode characters>"
            else:
                if window_name:
                    win_name = window_name.value  # type: Union[str, bytes]
                    if isinstance(win_name, bytes):
                        # Apparently COMPOUND_TEXT is so arcane that this is how
                        # tools like xprop deal with receiving it these days
                        win_name = win_name.decode('latin1', 'replace')
                    return win_name
                else:
                    title = "<unnamed window>"

        return "{} (XID: {})".format(title, win_obj.id)

    def _get_window_class_name(self, win_obj: Window) -> str:
        """SReturn window class name"""
        try:
            window_name = win_obj.get_full_property(self.WM_CLASS, 0)
        except UnicodeDecodeError:  # Apparently a Debian distro package bug
            title = "<could not decode characters>"
        else:
            if window_name:
                win_class_name = window_name.value  # type: Union[str, bytes]
                if isinstance(win_class_name, bytes):
                    # Apparently COMPOUND_TEXT is so arcane that this is how
                    # tools like xprop deal with receiving it these days
                    win_class_name = win_class_name.replace(b'\x00',b' ').decode("utf-8").lower()
                return win_class_name
            else:
                title = "<undefined wm_class_name>"

        return "{} (XID: {})".format(title, win_obj.id)

    def get_window_name(self, win_id: Optional[int]) -> Tuple[Optional[str], bool]:
        """
        Look up the window class name for a given X11 window ID
        retrofitted to provide window class name instead of window title
        """
        if not win_id:
            self.last_seen['title'] = None
            return self.last_seen['title'], True

        title_changed = False
        with self.window_obj(win_id) as wobj:
            if wobj:
                try:
                    win_title = self._get_window_class_name(wobj)
                except XError:
                    pass
                else:
                    title_changed = (win_title != self.last_seen['title'])
                    self.last_seen['title'] = win_title

        return self.last_seen['title'], title_changed

    def handle_xevent(self, event: Event):
        """Handler for X events which ignores anything but focus/title change"""
        if event.type != X.PropertyNotify:
            return

        changed = False
        if event.atom == self.NET_ACTIVE_WINDOW:
            if self.get_active_window()[1]:
                self.get_window_name(self.last_seen['xid'])  # Rely on the side-effects
                changed = True
        elif event.atom in (self.NET_WM_NAME, self.WM_NAME):
            changed = changed or self.get_window_name(self.last_seen['xid'])[1]

        if changed:
            self.handle_change(self.last_seen)

    def handle_change(self, new_state: dict):
        """Replace this with whatever you want to actually do"""
        GLib.idle_add(self.callback, new_state['title'])
Esempio n. 25
0
def handleQuery(query):
    if not query.isTriggered:
        return []

    try:
        items = []

        # Prepare query string
        input = query.string
        needles = cgi.escape(input.lower()).strip().split(' ')

        # Create display handle
        display = Display()

        # Intern a few atoms we will use later
        NET_CLIENT_LIST = display.intern_atom('_NET_CLIENT_LIST')
        NET_WM_WINDOW_TYPE = display.intern_atom('_NET_WM_WINDOW_TYPE')
        NET_WM_WINDOW_TYPE_NORMAL = display.intern_atom(
            '_NET_WM_WINDOW_TYPE_NORMAL')
        NET_WM_NAME = display.intern_atom('_NET_WM_NAME')

        # Get the IDs of all windows on the display
        root = display.screen().root
        win_list = root.get_full_property(NET_CLIENT_LIST,
                                          X.AnyPropertyType).value

        for id in win_list:
            # If the user already typed something new, the query is cancelled
            # and we should just stop wasting resources
            if not query.isValid:
                return []

            # Get the window associated with that ID
            win = display.create_resource_object('window', id)

            # Check if the window type is "normal window"
            win_type = win.get_full_property(NET_WM_WINDOW_TYPE,
                                             X.AnyPropertyType).value[0]
            if win_type == NET_WM_WINDOW_TYPE_NORMAL:
                # Obtain the name of the window. Windows without the `_NET_WM_NAME`
                # property will be ignored
                name = win.get_full_property(NET_WM_NAME, X.AnyPropertyType)
                if not name:
                    continue

                name = name.value.decode('utf-8')

                # Apply filter to the name
                lowercase_name = name.lower()
                is_ok = True
                for needle in needles:
                    if needle not in lowercase_name:
                        is_ok = False
                        break

                if not is_ok:
                    continue

                for needle in needles:
                    start = lowercase_name.find(needle)
                    end = start + len(needle)
                    name = name[:start] + "<b>" + name[
                        start:end] + "</b>" + name[end:]
                    lowercase_name = name.lower()

                # Add the item
                def activate_win(id):
                    call(['xdotool', 'windowactivate', str(id)])

                # Generate icon
                icon_path = gen_icon(display, id, win)

                item = Item(id=__prettyname__, completion=query.rawString)
                item.text = name  #cgi.escape(str(type(name)))
                item.subtext = "Switch to"
                item.icon = icon_path
                item.addAction(
                    FuncAction("Switch to", lambda id=id: activate_win(id)))
                items.append(item)

        return items

    # We never know what could go wrong...
    except Exception as e:
        item = Item(id=__prettyname__, completion=query.rawString)
        item.text = e.__class__.__name__
        item.subtext = str(e)
        return item
Esempio n. 26
0
# Rule GUI keyname determination uses a local file generated
#   from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
#   and http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h
# because there does not seem to be a non-X11 file for this set of key names

XK_KEYS = _keysymdef.keysymdef

try:
    import Xlib
    from Xlib.display import Display
    xdisplay = Display()
    modifier_keycodes = xdisplay.get_modifier_mapping(
    )  # there should be a way to do this in Gdk
    x11 = True

    NET_ACTIVE_WINDOW = xdisplay.intern_atom('_NET_ACTIVE_WINDOW')
    NET_WM_PID = xdisplay.intern_atom('_NET_WM_PID')
    WM_CLASS = xdisplay.intern_atom('WM_CLASS')

    # set up to get keyboard state using ctypes interface to libx11
    import ctypes

    class XkbDisplay(ctypes.Structure):
        """ opaque struct """

    class XkbStateRec(ctypes.Structure):
        _fields_ = [
            ('group', ctypes.c_ubyte), ('locked_group', ctypes.c_ubyte),
            ('base_group', ctypes.c_ushort), ('latched_group',
                                              ctypes.c_ushort),
            ('mods', ctypes.c_ubyte), ('base_mods', ctypes.c_ubyte),
Esempio n. 27
0
    def __init__(self, discover, piggyback=None):
        Gtk.Window.__init__(self, type=self.detect_type())
        self.discover = discover
        screen = self.get_screen()
        self.compositing = False
        self.text_font = None
        self.text_size = None
        self.pos_x = None
        self.pos_y = None
        self.width = None
        self.height = None
        self.needsredraw = True
        self.hidden = False
        self.enabled = False

        self.set_size_request(50, 50)
        self.connect('draw', self.overlay_draw)
        # Set RGBA
        screen = self.get_screen()
        visual = screen.get_rgba_visual()
        if not self.get_display().supports_input_shapes():
            log.info("Input shapes not available. Quitting")
            sys.exit(1)
        if visual:
            # Set the visual even if we can't use it right now
            self.set_visual(visual)
        if screen.is_composited():
            self.compositing = True

        self.set_app_paintable(True)
        self.set_untouchable()
        self.set_skip_pager_hint(True)
        self.set_skip_taskbar_hint(True)
        self.set_keep_above(True)
        self.set_decorated(True)
        self.set_accept_focus(False)
        self.set_wayland_state()
        if not piggyback:
            self.show_all()
            if discover.steamos:
                display = Display()
                atom = display.intern_atom("GAMESCOPE_EXTERNAL_OVERLAY")
                opaq = display.intern_atom("_NET_WM_WINDOW_OPACITY")

                topw = display.create_resource_object(
                    "window",
                    self.get_toplevel().get_window().get_xid())

                topw.change_property(atom, Xatom.CARDINAL, 32, [1],
                                     X.PropModeReplace)
                # Keep for reference, but appears to be unnecessary
                # topw.change_property(opaq,
                #                     Xatom.CARDINAL,16,
                #                     [0xffff], X.PropModeReplace)

                log.info("Setting STEAM_EXTERNAL_OVERLAY")
                display.sync()
        self.monitor = 0
        self.align_right = True
        self.align_vert = 1
        self.floating = False
        self.force_xshape = False
        self.context = None
        self.autohide = False
        self.piggyback = None
        self.piggyback_parent = None
        if piggyback:
            self.set_piggyback(piggyback)
active_device_time = np.array(object=[], dtype=np.float32)
prev_device_time = None
prev_device_counter = None
start_device_time = None
prev_title = None
current_title = None
window_actives = {}

main_process_pid = None

# Connect to the X server and get the root window
display_focus = Display()
root = display_focus.screen().root

# Prepare the property names we use so they can be fed into X11 APIs
NET_ACTIVE_WINDOW = display_focus.intern_atom('_NET_ACTIVE_WINDOW')
NET_WM_NAME = display_focus.intern_atom('_NET_WM_NAME')  # UTF-8
WM_NAME = display_focus.intern_atom('WM_NAME')  # Legacy encoding

last_seen = {'xid': None, 'title': None}  # type: Dict[str, Any]


def print_window_actives(actives: dict):
    for title, list_times in actives.items():
        print(title)
        for (start_time, end_time) in list_times:
            print("{} - {}".format(start_time, end_time))
    print("---------------------------------------")


@contextmanager
Esempio n. 29
0
class Environment():
    def __init__(self):
        self.display = Display()
        self.screen = self.display.screen()
        self.root = self.screen.root
        self.region = Region(x=0,
                             y=0,
                             width=self.screen.width_in_pixels,
                             height=self.screen.height_in_pixels)
        self.desktops = []
        self.windows = self.get_window_set()
        self.window_desktop_map = {}
        self.hidden_windows = set()
        self.visible_windows = set()

        for i in range(self.number_of_desktops()):
            LOGGER.debug("\n\n\nCreating Desktop %d" % (i))
            d = Desktop(i, self)
            self.desktops.append(d)
            #d.print_windows()
            d.arrange()

        self.update_desktop_map()
        self.setup_listeners()

        #self.print_hierarchy(self.root, " - ")

    def setup_listeners(self):
        self.root.change_attributes(event_mask=X.SubstructureNotifyMask
                                    | X.PropertyChangeMask)

        anchor = self.root.create_window(0, 0, 1, 1, 1, self.screen.root_depth)

        anchor.xrandr_select_input(randr.RRScreenChangeNotifyMask
                                   | randr.RRCrtcChangeNotifyMask
                                   | randr.RROutputChangeNotifyMask
                                   | randr.RROutputPropertyNotifyMask)

    def update_all_the_things(self):
        self.display = Display()
        self.screen = self.display.screen()
        self.root = self.screen.root
        self.region = Region(x=0,
                             y=0,
                             width=self.screen.width_in_pixels,
                             height=self.screen.height_in_pixels - 32)

        LOGGER.debug("NEW REGION: %s" % (self.region))

        for d in self.desktops:
            d.resize()

        self.setup_listeners()

    def print_hierarchy(self, window, indent):
        children = window.query_tree().children
        for w in children:
            LOGGER.debug(indent, window.get_wm_class())
            self.print_hierarchy(w, indent + '-')

    def interesting_properties(self):
        #_NET_WM_DESKTOP
        # root: _NET_CURRENT_DESKTOP
        LOGGER.debug("Current desktop")
        LOGGER.debug(
            self.root.get_full_property(
                self.display.intern_atom('_NET_CURRENT_DESKTOP'),
                Xatom.CARDINAL).value[0])

    def current_desktop(self):
        return self.root.get_full_property(
            self.display.intern_atom('_NET_CURRENT_DESKTOP'),
            Xatom.CARDINAL).value[0]

    def number_of_desktops(self):
        return self.root.get_full_property(
            self.display.intern_atom('_NET_NUMBER_OF_DESKTOPS'),
            Xatom.CARDINAL).value[0]

    def update_window_states(self):
        window_ids = self.get_window_set(include_hidden=True)
        for window_id in window_ids:
            if self.is_window_hidden(window_id):
                self.hidden_windows.add(window_id)
            else:
                self.visible_windows.add(window_id)

    def update_desktop_map(self):
        self.window_desktop_map = {}
        for d in self.desktops:
            for window_id in d.get_window_set(include_hidden=True):
                self.window_desktop_map[window_id] = d

    def get_window_desktop(self, window):
        if type(window) is long:
            w = self.display.create_resource_object('window', window)
        else:
            w = window

        try:
            value = w.get_full_property(
                self.display.intern_atom('_NET_WM_DESKTOP'),
                Xatom.CARDINAL).value[0]
            if value > self.number_of_desktops():
                return None
            else:
                return value

        except AttributeError:
            return None
        except Xlib.error.BadWindow:
            return None

    def get_window_states(self, window_id):
        w = self.display.create_resource_object('window', window_id)
        #return w.get_full_property(self.display.intern_atom('_NET_WM_STATE'), Xatom.ATOM).value
        try:
            states = w.get_full_property(
                self.display.get_atom('_NET_WM_STATE'), Xatom.WINDOW)
        except Xlib.error.BadWindow:
            LOGGER.warn("Bad window fetching states...")
            states = None

        if states == None:
            return []
        else:
            res = w.get_full_property(self.display.get_atom('_NET_WM_STATE'),
                                      0).value.tolist()
            return res

    def is_window_hidden(self, window_id):
        hidden_state_atom = self.display.get_atom("_NET_WM_STATE_HIDDEN")
        states = self.get_window_states(window_id)
        return hidden_state_atom in states

    def is_window_visible(self, window_id):
        return not self.is_window_hidden(window_id)

    def listen_for_events(self):
        LOGGER.debug("Listening for change events!")
        while True:
            ev = self.display.next_event()
            self.handle_event(ev)

    def handle_event(self, event):
        old_hidden = set(self.hidden_windows)
        old_visible = set(self.visible_windows)
        self.update_window_states()
        changed_ids = set()
        changed_ids.update(old_hidden.symmetric_difference(
            self.hidden_windows))
        changed_ids.update(
            old_visible.symmetric_difference(self.visible_windows))

        if len(changed_ids) > 0:
            LOGGER.debug("Changed IDs: %s" % (changed_ids))

        needs_update = False

        wm_active_window = self.display.get_atom('_NET_ACTIVE_WINDOW')
        wm_move_window = self.display.get_atom('_NET_MOVERESIZE_WINDOW')
        wm_hidden_window = self.display.get_atom('_NET_WM_STATE_HIDDEN')
        wm_state = self.display.get_atom('_NET_WM_STATE')

        try:
            window_props = event.window.get_full_property(event.atom, 0)
            window_id = int(window_props.value.tolist()[0])
            LOGGER.debug("Window ID: %s" % (window_id))
        except AttributeError:
            pass
            #LOGGER.debug("Not a window-level event")

        for window_id in changed_ids:
            desktop = self.window_desktop_map.get(window_id, None)
            LOGGER.debug("Window changed: %s on desktop: %s" %
                         (window_id, desktop))
            if desktop is not None:
                desktop.arrange()
                needs_update = True

        if event.type == X.PropertyNotify:
            LOGGER.debug("Property changed...")
            if event.atom == wm_active_window:
                LOGGER.debug("Property changed on an active window....")

        elif event.type == X.CreateNotify or event.type == X.DestroyNotify:
            needs_update = True
            window_set = self.get_window_set()

            if event.type == X.CreateNotify:
                LOGGER.debug("Handling creation!")
                new_windows = window_set.difference(self.windows)
                for window in new_windows:
                    window_resource = self.display.create_resource_object(
                        'window', window)
                    window_desktop = self.get_window_desktop(window_resource)
                    if window_desktop is not None:
                        self.desktops[window_desktop].layout.add_window(
                            window_resource)

            if event.type == X.DestroyNotify:
                LOGGER.debug("Handling destruction!")
                missing_windows = self.windows.difference(window_set)
                for window in missing_windows:
                    window_resource = self.display.create_resource_object(
                        'window', window)
                    # TODO: optimize lookup by keeping old map?
                    for desktop in self.desktops:
                        LOGGER.debug("Trying to remove from desktop %s" %
                                     (desktop))
                        desktop.layout.remove_window(window_resource)

            self.windows = window_set

            for desktop in self.desktops:
                desktop.layout.redraw()

        elif event.__class__.__name__ == randr.ScreenChangeNotify.__name__:
            LOGGER.debug('Screen change')
            self.update_all_the_things()

        else:
            #LOGGER.debug("Unhandled event: %d" % (event.type))
            pass

        if needs_update:
            self.update_desktop_map()

    def get_window_set(self, include_hidden=False, desktop_number=None):
        windows = set([
            x for x in self.root.get_full_property(
                self.display.intern_atom('_NET_CLIENT_LIST'),
                Xatom.WINDOW).value
        ])

        if desktop_number is not None:
            #LOGGER.debug("Filtering windows not on: %d" % (desktop_number))
            windows = filter(
                lambda w: self.get_window_desktop(w) == desktop_number,
                windows)

        if include_hidden is False:
            #LOGGER.debug("Filtering hidden windows...")
            windows = filter(lambda w: self.is_window_visible(w) == True,
                             windows)

        return set(windows)
Esempio n. 30
0
    from Xlib.display import Display
    from Xlib.ext import record
    from Xlib.protocol import rq
    from Xlib import XK as _XK
    _XK.load_keysym_group('xf86')
    XK_KEYS = vars(_XK)
    disp_prog = Display()
    x11 = True
except Exception:
    _log.warn('X11 not available - rules will not be activated')
    XK_KEYS = {}
    x11 = False

if x11:
    # determine name of active process
    NET_ACTIVE_WINDOW = disp_prog.intern_atom('_NET_ACTIVE_WINDOW')
    NET_WM_PID = disp_prog.intern_atom('_NET_WM_PID')
    root2 = disp_prog.screen().root
    root2.change_attributes(event_mask=Xlib.X.PropertyChangeMask)

active_process_name = None


def active_program():
    try:
        window_id = root2.get_full_property(NET_ACTIVE_WINDOW,
                                            Xlib.X.AnyPropertyType).value[0]
        window = disp_prog.create_resource_object('window', window_id)
        window_pid = window.get_full_property(NET_WM_PID, 0).value[0]
        return psutil.Process(window_pid).name()
    except (Xlib.error.XError,
Esempio n. 31
0
class Prenestr(object):

    def __init__(self):
        self.ratio = 0.5
        self.wborder = 10
        self.hborder = 30
        self.disp = Display()
        self.root = self.disp.screen().root

        # we tell the X server we want to catch keyPress event
        self.root.change_attributes(event_mask=X.KeyPressMask)

        self.grab_key(K_L)
        self.grab_key(K_H)
        self.grab_key(K_L, X.Mod4Mask | X.ShiftMask)
        self.grab_key(K_H, X.Mod4Mask | X.ShiftMask)
        self.grab_key(K_T)
        self.grab_key(K_ENTER)
        while True:
            event = self.root.display.next_event()
            if event.type == X.KeyPress:
                self.keypress(event)

    def get_active(self):
        id = self.root.get_full_property(
            self.disp.intern_atom("_NET_ACTIVE_WINDOW"), 0).value[0]
        obj = self.disp.create_resource_object('window', id)
        return (id, obj)

    def _send_event(self, win, ctype, data, mask=None):
        data = (data + ([0] * (5 - len(data))))[:5]
        ev = protocol.event.ClientMessage(window=win,
                                          client_type=ctype, data=(32, (data)))
        self.root.send_event(ev, event_mask=X.SubstructureRedirectMask)

    def workarea(self):
        v = self.root.get_full_property(
            self.disp.intern_atom("_NET_WORKAREA"), 0).value
        return v[0], v[1], v[2], v[3]

    def move(self, win, to='left', y_pos=0, y_nbwin=1):
        id, obj = win
        rx, ry, rw, rh = self.workarea()

        if to == 'left':
            x = rx
            y = ry
            w = rw * self.ratio - self.wborder
            h = rh
        elif to == 'right':
            x = rx + rw * self.ratio + self.wborder
            y = ry + y_pos * (rh / y_nbwin)
            w = rw * (1 - self.ratio) - self.wborder
            h = rh / y_nbwin
            if y_nbwin > 1:
                h = h - self.hborder

        # Reset state
        self._send_event(id,
                self.disp.intern_atom("_NET_WM_STATE"),
                [0, self.disp.intern_atom("_NET_WM_STATE_MAXIMIZED_VERT"),
                    self.disp.intern_atom("_NET_WM_STATE_MAXIMIZED_HORZ")])
        obj.configure(x=x, y=y, width=w, height=h, stack_mode=X.Above)
        self._send_event(id,
                self.disp.intern_atom("_NET_ACTIVE_WINDOW"), [])
        self.disp.flush()

    def grab_key(self, key, mask=X.Mod4Mask, ungrab=False):
        self.root.grab_key(key, mask, 1, X.GrabModeAsync, X.GrabModeAsync)
        if ungrab:
            self.ungrab_list.append(key)

    def ungrab_key(self, key, mask=X.Mod4Mask):
        self.root.ungrab_key(key, mask, 1)

    def tile(self, master='position'):
        current_window = self.get_active()
        win_list = self.root.get_full_property(
            self.disp.intern_atom("_NET_CLIENT_LIST"),
            Xatom.WINDOW).value
        current_desktop = self.root.get_full_property(
            self.disp.intern_atom("_NET_CURRENT_DESKTOP"), 0).value[0]
        desk_list = []
        for win_id in win_list:
            obj = self.disp.create_resource_object('window', win_id)
            windesk = obj.get_full_property(
                self.disp.intern_atom("_NET_WM_DESKTOP"), 0).value[0]
            if windesk == current_desktop:
                # This window is on the current desktop

                # Skip if transient
                transient = obj.get_wm_transient_for()
                if transient and transient != self.root:
                    continue

                # Skip if hidden
                state = obj.get_full_property(
                    self.disp.intern_atom("_NET_WM_STATE"), Xatom.ATOM)
                dock = obj.get_full_property(
                    self.disp.intern_atom("_NET_WM_WINDOW_TYPE"), Xatom.ATOM)

                if (state and self.disp.intern_atom("_NET_WM_STATE_HIDDEN") in state.value
                    or self.disp.intern_atom("_NET_WM_STATE_SKIP_TASKBAR") in state.value
                    or self.disp.intern_atom("_NET_WM_STATE_SKIP_PAGER") in state.value):
                    # hidden
                    continue
                if (dock and self.disp.intern_atom("_NET_WM_WINDOW_TYPE_DOCK") in dock.value
                    and self.disp.intern_atom("_NET_WM_WINDOW_TYPE_TOOLBAR") in dock.value
                    and self.disp.intern_atom("_NET_WM_WINDOW_TYPE_MENU") in dock.value
                    and self.disp.intern_atom("_NET_ACTIVE_WINDOW_TYPE_SPLASH") in dock.value
                    and self.disp.intern_atom("_NET_ACTIVE_WINDOW_TYPE_DIALOG") in dock.value):
                    # hidden
                    continue

                desk_list.append((win_id, obj))

        if not desk_list:
            return

        def get_geom(window):
            wg = window.get_geometry()
            tl = window.translate_coords(self.root, wg.x, wg.y)
            return (-tl.x, -tl.y, wg.width, wg.height)

        geom = [(w, get_geom(w[1])) for w in desk_list]

        if master == 'position':
            left = min(geom, key=lambda l: l[1][0])[0]
        else:
            left = current_window

        self.move(left, to="left")
        others = [w for w in geom if w[0][0] != left[0]]
        others.sort(key=lambda l: l[1][1])

        for pos, win in enumerate(others):
            self.move(win[0], to="right", y_pos=pos, y_nbwin=len(others))


        # Reactivate window
        self._send_event(current_window[0],
                         self.disp.intern_atom("_NET_ACTIVE_WINDOW"), [])

        return

    def keypress(self, event):

        if event.detail == K_H:
            if event.state & X.ShiftMask:
                self.ratio -= 0.1
                if self.ratio < 0:
                    self.ratio = 0
                self.tile()
            else:
                self.move(self.get_active())
        elif event.detail == K_L:
            if event.state & X.ShiftMask:
                self.ratio += 0.1
                if self.ratio > 1:
                    self.ratio = 1
                self.tile()
            else:
                self.move(self.get_active(), to='right')
        elif event.detail == K_T:
            self.tile()
        elif event.detail == K_ENTER:
            self.tile(master='active')
Esempio n. 32
0
def get_pid_by_window_id(display: Xdisplay.Display, window_id: int):
    window = display.create_resource_object('window', window_id)
    prop = window.get_full_property(display.intern_atom('_NET_WM_PID'),
                                    Xlib.X.AnyPropertyType)
    return (prop.value[0] if prop else None)
Esempio n. 33
0
class XWindowFocusTracker:
    def __init__(self):
        self._callbacks: MutableSequence[Callback] = []
        self._disp = Display()
        self._current_window_id: Optional[XWindowId] = None
        self.NET_ACTIVE_WINDOW = self._disp.intern_atom('_NET_ACTIVE_WINDOW')
        self.NET_WM_NAME = self._disp.intern_atom('_NET_WM_NAME')
        self._screen_locked = False
        self._lock = threading.Lock()

    def register(self, callback: Callback) -> None:
        with self._lock:
            self._callbacks.append(callback)

    def run(self) -> None:
        screen_lock_tracker = ScreenLockTracker(self)
        screen_lock_tracker_thread = threading.Thread(
            target=screen_lock_tracker.run, daemon=True)
        screen_lock_tracker_thread.start()

        root = self._disp.screen().root
        root.change_attributes(event_mask=X.PropertyChangeMask)

        while True:
            self._handle_xevent(self._disp.next_event())

    def set_screen_locked(self, locked: bool) -> None:
        logging.info(f'XWindowFocusTracker.set_screen_locked(locked={locked})')
        with self._lock:
            self._screen_locked = locked
            if locked:
                window_id = -1
                window_name = 'locked'
            else:
                window_id = self._current_window_id
                window_name = self._get_window_name(window_id)
            for callback in self._callbacks:
                callback(window_id, window_name)

    def _handle_xevent(self, event: Event) -> None:
        """Handler for X events which ignores anything but focus/title change"""
        if event.type != X.PropertyNotify:
            return

        if event.atom != self.NET_ACTIVE_WINDOW:
            return

        window_id = event.window.get_full_property(self.NET_ACTIVE_WINDOW,
                                                   X.AnyPropertyType).value[0]

        with self._lock:
            if self._current_window_id == window_id:
                return
            self._current_window_id = window_id

            window_name = self._get_window_name(window_id)

            for callback in self._callbacks:
                callback(window_id, window_name)

    def _get_window_name(self, window_id: XWindowId) -> str:
        window_obj = self._disp.create_resource_object('window', window_id)
        try:
            window_name_property = window_obj.get_full_property(
                self.NET_WM_NAME, 0)
        except Xlib.error.BadWindow:
            return ''
        else:
            return window_name_property.value.decode('utf-8')