Esempio n. 1
0
def main():
    rename_process()
    q = make_qtile()
    try:
        q.loop()
    except Exception:
        logger.exception('Qtile crashed')
    logger.info('Exiting...')
Esempio n. 2
0
 def _format_sensors_output(self, sensors_out):
     """formats output of unix `sensors` command into a dict of
     {<sensor_name>: (<temperature>, <temperature symbol>), ..etc..}
     """
     temperature_values = {}
     logger.info(self.sensors_temp.findall(sensors_out))
     for name, temp, symbol in self.sensors_temp.findall(sensors_out):
         name = name.strip()
         temperature_values[name] = temp, symbol
     return temperature_values
Esempio n. 3
0
def _change_wallpaper():
    """change the wallpaper.

    If you put two files, first one will go to the first monitor, the other to the second, like this:

    $ feh --bg-center path/to/file/for/first/monitor path/to/file/for/second/monitor
    """
    cmd = (f"/usr/bin/feh --bg-fill --randomize {home_path}/backgrounds/* "
           f"{home_path}/backgrounds/* {home_path}/backgrounds/*")
    logger.info("change wallpaper...")
    return subprocess.run(cmd, shell=True)
Esempio n. 4
0
def restart_on_randr(qtile, ev):
    """Restart qtile when a screen change has been detected."""
    # this is a hack: we use this hook to get the current loop and start the screen
    # change schedule using this loop.
    # We ensure scheduling the change only once at startup.
    global first_start

    logger.info("Screen change event. qtile:%s, loop_qtile:%s", 
                qtile, qtile._eventloop)

    if first_start:
        qtile._eventloop.call_later(1, auto_wallpaper, qtile._eventloop)
        first_start = False
Esempio n. 5
0
    def poll(self):
        # if we don't have valid credentials, update them
        if not hasattr(self, "credentials") or self.credentials.invalid:
            self.cred_init()

        # Create an httplib2.Http object to handle our HTTP requests and
        # authorize it with our credentials from self.cred_init
        http = self.credentials.authorize(httplib2.Http())
        service = discovery.build("calendar", "v3", http=http)

        # current timestamp
        now = datetime.datetime.utcnow().isoformat("T") + "Z"
        data = {}

        # grab the next event
        events = (
            service.events()
            .list(calendarId=self.calendar, singleEvents=True, timeMin=now, maxResults="1", orderBy="startTime")
            .execute()
        )
        logger.info("calendar json data: %s", events)

        # get items list
        try:
            event = events.get("items", [])[0]
        except IndexError:
            return "No appointments scheduled"

        # get reminder time
        try:
            remindertime = datetime.timedelta(0, int(event["reminders"]["overrides"][0]["minutes"]) * 60)
        except (IndexError, ValueError, AttributeError, KeyError):
            remindertime = datetime.timedelta(0, 0)

        time = re.sub(":.{2}-.*$", "", event["start"]["dateTime"].replace("T", " "))

        try:
            data = event["summary"] + " " + time
        except KeyError:
            data = "Event summary not specified in calendar " + time

        # colorize the event if it is upcoming
        parse_result = dateutil.parser.parse(event["start"]["dateTime"], ignoretz=True)
        if parse_result - remindertime <= datetime.datetime.now():
            self.foreground = utils.hex(self.reminder_color)
        else:
            self.foreground = self.default_foreground

        # XXX: FIXME: qtile dies completely silently if we return unicode here
        # in python2.
        return str(data)
Esempio n. 6
0
    def _del(self, client):
        group = client.group

        def delete_client():
            # Delete group if empty and dont persist
            if group and group.name in self.groupMap and \
                    not self.groupMap[group.name].persist and \
                    len(group.windows) <= 0:
                self.qtile.delGroup(group.name)
                self.sort_groups()
            del self.timeout[client]

        # Wait the delay until really delete the group
        logger.info('Add dgroup timer')
        self.timeout[client] = self.qtile.call_later(
            self.delay, delete_client
        )
Esempio n. 7
0
    def _get_target_chain(self, event_type: str, event) -> List[Callable]:
        """Returns a chain of targets that can handle this event

        Finds functions named `handle_X`, either on the window object itself or
        on the Qtile instance, where X is the event name (e.g.  EnterNotify,
        ConfigureNotify, etc).

        The event will be passed to each target in turn for handling, until one
        of the handlers returns False or None, or the end of the chain is
        reached.
        """
        assert self.qtile is not None

        handler = "handle_{event_type}".format(event_type=event_type)
        # Certain events expose the affected window id as an "event" attribute.
        event_events = [
            "EnterNotify",
            "LeaveNotify",
            "MotionNotify",
            "ButtonPress",
            "ButtonRelease",
            "KeyPress",
        ]
        if hasattr(event, "window"):
            window = self.qtile.windows_map.get(event.window)
        elif hasattr(event, "drawable"):
            window = self.qtile.windows_map.get(event.drawable)
        elif event_type in event_events:
            window = self.qtile.windows_map.get(event.event)
        else:
            window = None

        chain = []
        if window is not None and hasattr(window, handler):
            chain.append(getattr(window, handler))

        if hasattr(self, handler):
            chain.append(getattr(self, handler))

        if not chain:
            logger.info("Unhandled event: {event_type}".format(event_type=event_type))
        return chain
Esempio n. 8
0
    def organise_layers(self) -> None:
        """Organise the positioning of layer shell surfaces."""
        logger.info("Output: organising layers")
        ow, oh = self.wlr_output.effective_resolution()

        for layer in self.layers:
            for win in layer:
                assert isinstance(win.surface, LayerSurfaceV1)
                state = win.surface.current
                margin = state.margin
                ww = state.desired_width
                wh = state.desired_height

                # Horizontal axis
                if (state.anchor & LayerSurfaceV1Anchor.HORIZONTAL) and ww == 0:
                    x = margin.left
                    ww = ow - margin.left - margin.right
                elif (state.anchor & LayerSurfaceV1Anchor.LEFT):
                    x = margin.left
                elif (state.anchor & LayerSurfaceV1Anchor.RIGHT):
                    x = ow - ww - margin.right
                else:
                    x = int(ow / 2 - ww / 2)

                # Vertical axis
                if (state.anchor & LayerSurfaceV1Anchor.VERTICAL) and wh == 0:
                    y = margin.top
                    wh = oh - margin.top - margin.bottom
                elif (state.anchor & LayerSurfaceV1Anchor.TOP):
                    y = margin.top
                elif (state.anchor & LayerSurfaceV1Anchor.BOTTOM):
                    y = oh - wh - margin.bottom
                else:
                    y = int(oh / 2 - wh / 2)

                if ww <= 0 or wh <= 0:
                    win.kill()
                    continue

                win.place(x, y, ww, wh, 0, None)

        self._get_windows()
Esempio n. 9
0
 def handle_PropertyNotify(self, e):  # noqa: N802
     name = self.qtile.conn.atoms.get_name(e.atom)
     logger.debug("PropertyNotifyEvent: %s", name)
     if name == "WM_TRANSIENT_FOR":
         pass
     elif name == "WM_HINTS":
         self.update_hints()
     elif name == "WM_NORMAL_HINTS":
         self.update_hints()
     elif name == "WM_NAME":
         self.update_name()
     elif name == "_NET_WM_NAME":
         self.update_name()
     elif name == "_NET_WM_VISIBLE_NAME":
         self.update_name()
     elif name == "WM_ICON_NAME":
         pass
     elif name == "_NET_WM_ICON_NAME":
         pass
     elif name == "_NET_WM_ICON":
         self.update_wm_net_icon()
     elif name == "ZOOM":
         pass
     elif name == "_NET_WM_WINDOW_OPACITY":
         pass
     elif name == "WM_STATE":
         pass
     elif name == "_NET_WM_STATE":
         self.update_state()
     elif name == "WM_PROTOCOLS":
         pass
     elif name == "_NET_WM_DESKTOP":
         # Some windows set the state(fullscreen) when starts,
         # update_state is here because the group and the screen
         # are set when the property is emitted
         # self.update_state()
         self.update_state()
     else:
         logger.info("Unknown window property: %s", name)
     return False
Esempio n. 10
0
def guess_terminal(preference=None):
    """Try to guess terminal."""
    test_terminals = []
    if isinstance(preference, str):
        test_terminals += [preference]
    elif isinstance(preference, Sequence):
        test_terminals += list(preference)
    test_terminals += [
        "roxterm",
        "sakura",
        "hyper",
        "alacritty",
        "terminator",
        "termite",
        "gnome-terminal",
        "konsole",
        "xfce4-terminal",
        "lxterminal",
        "mate-terminal",
        "kitty",
        "yakuake",
        "tilda",
        "guake",
        "eterm",
        "st",
        "urxvt",
        "xterm",
        "x-terminal-emulator",
    ]

    for terminal in test_terminals:
        logger.debug("Guessing terminal: {}".format(terminal))
        if not which(terminal, os.X_OK):
            continue

        logger.info("Terminal found: {}".format(terminal))
        return terminal

    logger.error("Default terminal has not been found.")
Esempio n. 11
0
def guess_terminal(preference=None):
    """Try to guess terminal."""
    test_terminals = []
    if isinstance(preference, str):
        test_terminals += [preference]
    elif isinstance(preference, Sequence):
        test_terminals += list(preference)
    test_terminals += [
        'roxterm',
        'sakura',
        'hyper',
        'alacritty',
        'terminator',
        'termite',
        'gnome-terminal',
        'konsole',
        'xfce4-terminal',
        'lxterminal',
        'mate-terminal',
        'kitty',
        'yakuake',
        'tilda',
        'guake',
        'eterm',
        'st',
        'urxvt',
        'xterm',
        'x-terminal-emulator',
    ]

    for terminal in test_terminals:
        logger.debug('Guessing terminal: {}'.format(terminal))
        if not which(terminal, os.X_OK):
            continue

        logger.info('Terminal found: {}'.format(terminal))
        return terminal

    logger.error('Default terminal has not been found.')
Esempio n. 12
0
 def f(cmd):
     if cmd:
         # c here is used in eval() below
         q = QtileCommandInterface(self)
         c = InteractiveCommandClient(q)  # noqa: F841
         try:
             cmd_arg = str(cmd).split(' ')
         except AttributeError:
             return
         cmd_len = len(cmd_arg)
         if cmd_len == 0:
             logger.info('No command entered.')
             return
         try:
             result = eval(u'c.{0:s}'.format(cmd))
         except (CommandError, CommandException, AttributeError) as err:
             logger.error(err)
             result = None
         if result is not None:
             from pprint import pformat
             message = pformat(result)
             if messenger:
                 self.cmd_spawn('{0:s} "{1:s}"'.format(messenger, message))
             logger.debug(result)
Esempio n. 13
0
 def cmd_next(self):
     # LV
     from libqtile import qtile
     #logger.info("Qtile groups: {}".format([g.windows for g in qtile.groups]))
     logger.info("Info: {}".format(self.info()))
     if self.group is not None:
         clients = self.find_clients(self.group)
         #logger.info("Clients: {}".format([c.window.wid for c in clients]))
         if len(clients) > 1:
             win = self.group.current_window
             logger.info("Top window was: {}".format(self.group.current_window.window.wid))
             index = clients.index(win)
             index = (index + 1) % len(clients)
             logger.info("Trying to raise window: {}".format(clients[index].window.wid))
             # don't use cmd_bring_to_front(), because it activates Floating
             self.win_bring_to_front(clients[index])
Esempio n. 14
0
    def _add(self, client):
        if client in self.timeout:
            logger.info('Remove dgroup source')
            self.timeout.pop(client).cancel()

        # ignore static windows
        if client.defunct:
            return

        # ignore windows whose groups is already set (e.g. from another hook or
        # when it was set on state restore)
        if client.group is not None:
            return

        group_set = False
        intrusive = False

        for rule in self.rules:
            # Matching Rules
            if rule.matches(client):
                if rule.group:
                    try:
                        layout = self.groupMap[rule.group].layout
                    except KeyError:
                        layout = None
                    try:
                        layouts = self.groupMap[rule.group].layouts
                    except KeyError:
                        layouts = None
                    group_added = self.qtile.addGroup(rule.group, layout, layouts)
                    client.togroup(rule.group)

                    group_set = True

                    group_obj = self.qtile.groupMap[rule.group]
                    group = self.groupMap.get(rule.group)
                    if group and group_added:
                        for k, v in list(group.layout_opts.items()):
                            if isinstance(v, collections.Callable):
                                v(group_obj.layout)
                            else:
                                setattr(group_obj.layout, k, v)
                        affinity = group.screen_affinity
                        if affinity and len(self.qtile.screens) > affinity:
                            self.qtile.screens[affinity].setGroup(group_obj)

                if rule.float:
                    client.enablefloating()

                if rule.intrusive:
                    intrusive = rule.intrusive

                if rule.break_on_match:
                    break

        # If app doesn't have a group
        if not group_set:
            current_group = self.qtile.currentGroup.name
            if current_group in self.groupMap and \
                    self.groupMap[current_group].exclusive and \
                    not intrusive:

                wm_class = client.window.get_wm_class()

                if wm_class:
                    if len(wm_class) > 1:
                        wm_class = wm_class[1]
                    else:
                        wm_class = wm_class[0]

                    group_name = wm_class
                else:
                    group_name = client.name or 'Unnamed'

                self.add_dgroup(Group(group_name, persist=False), start=True)
                client.togroup(group_name)
        self.sort_groups()
Esempio n. 15
0
def get_screen_count():
    count = 0

    d = display.Display()
    s = d.screen()
    window = s.root.create_window(0, 0, 1, 1, 1, s.root_depth)
    res = randr.get_screen_resources(window)
    for id in res.outputs:
        output = randr.get_output_info(window, id, 0)
        count += output.connection ^ 1  # connection = 0 means display active
    window.destroy()
    return count


screen_count = get_screen_count()
logger.info("Counted {} screens".format(screen_count))
screen_count = 2
screens = [
    Screen(top=generic_bar(systray=i == 0)) for i in range(0, screen_count)
]

###############################################################################
### Configuration variables
###############################################################################

# Drag floating layouts
mouse = [
    Drag([mod],
         "Button1",
         lazy.window.set_position_floating(),
         start=lazy.window.get_position()),
Esempio n. 16
0
File: bar.py Progetto: m-col/qtile
    def _configure(self, qtile, screen, reconfigure=False):
        """
        Configure the bar. `reconfigure` is set to True when screen dimensions
        change, forcing a recalculation of the bar's dimensions.
        """
        # We only want to adjust margin sizes once unless there's a new strut or we're
        # reconfiguring the bar because the screen has changed
        if not self._configured or self._add_strut or reconfigure:
            Gap._configure(self, qtile, screen)
            self._borders_drawn = False

            if sum(self._initial_margin) or sum(
                    self.border_width) or self._add_strut:

                try:
                    # Check if colours are valid but don't convert to rgba here
                    if isinstance(self.border_color, list) and len(
                            self.border_color) == 4:
                        [rgb(col) for col in self.border_color]
                    else:
                        rgb(self.border_color)
                        self.border_color = [self.border_color] * 4
                except (ValueError, TypeError):
                    logger.warning(
                        "Invalid border_color specified. Borders will not be displayed."
                    )
                    self.border_width = [0, 0, 0, 0]

                # Increase the margin size for the border. The border will be drawn
                # in this space so the empty space will just be the margin.
                self.margin = [
                    m + b + s for m, b, s in zip(
                        self._initial_margin, self.border_width, self.struts)
                ]

                if self.horizontal:
                    self.x += self.margin[3] - self.border_width[3]
                    self.width -= self.margin[1] + self.margin[3]
                    self.length = self.width
                    if self.size == self.initial_size:
                        self.size += self.margin[0] + self.margin[2]
                    if self.screen.top is self:
                        self.y += self.margin[0] - self.border_width[0]
                    else:
                        self.y -= self.margin[2] + self.border_width[2]

                else:
                    self.y += self.margin[0] - self.border_width[0]
                    self.height -= self.margin[0] + self.margin[2]
                    self.length = self.height
                    self.size += self.margin[1] + self.margin[3]
                    if self.screen.left is self:
                        self.x += self.margin[3]
                    else:
                        self.x -= self.margin[1]

        width = self.width + (self.border_width[1] + self.border_width[3])
        height = self.height + (self.border_width[0] + self.border_width[2])

        if self.window:
            # We get _configure()-ed with an existing window when screens are getting
            # reconfigured but this screen is present both before and after
            self.window.place(self.x, self.y, width, height, 0, None)

        else:
            # Whereas we won't have a window if we're startup up for the first time or
            # the window has been killed by us no longer using the bar's screen

            # X11 only:
            # To preserve correct display of SysTray widget, we need a 24-bit
            # window where the user requests an opaque bar.
            if self.qtile.core.name == "x11":
                depth = (32 if has_transparency(self.background) else
                         self.qtile.core.conn.default_screen.root_depth)

                self.window = self.qtile.core.create_internal(
                    self.x, self.y, width, height, depth)

            else:
                self.window = self.qtile.core.create_internal(
                    self.x, self.y, width, height)

            self.window.opacity = self.opacity
            self.window.unhide()

            self.window.process_window_expose = self.process_window_expose
            self.window.process_button_click = self.process_button_click
            self.window.process_button_release = self.process_button_release
            self.window.process_pointer_enter = self.process_pointer_enter
            self.window.process_pointer_leave = self.process_pointer_leave
            self.window.process_pointer_motion = self.process_pointer_motion
            self.window.process_key_press = self.process_key_press

        # We create a new drawer even if there's already a window to ensure the
        # drawer is the right size.
        self.drawer = self.window.create_drawer(width, height)
        self.drawer.clear(self.background)

        self.crashed_widgets = []
        self.qtile.renamed_widgets = []
        if self._configured:
            for i in self.widgets:
                self._configure_widget(i)
        else:
            for idx, i in enumerate(self.widgets):
                # Create a mirror if this widget is already configured but isn't a Mirror
                # We don't do isinstance(i, Mirror) because importing Mirror (at the top)
                # would give a circular import as libqtile.widget.base imports lbqtile.bar
                if i.configured and i.__class__.__name__ != "Mirror":
                    i = i.create_mirror()
                    self.widgets[idx] = i
                success = self._configure_widget(i)
                if success:
                    qtile.register_widget(i)

        # Alert the user that we've renamed some widgets
        if self.qtile.renamed_widgets:
            logger.info(
                "The following widgets were renamed in qtile.widgets_map: %s "
                "To bind commands, rename the widget or use lazy.widget[new_name].",
                ", ".join(self.qtile.renamed_widgets),
            )
            self.qtile.renamed_widgets.clear()

        self._remove_crashed_widgets()
        self.draw()
        self._resize(self.length, self.widgets)
        self._configured = True
        self._add_strut = False
Esempio n. 17
0
    def __init__(self):
        """Setup the Wayland core backend"""
        self.qtile: Optional[Qtile] = None
        self.desktops: int = 1
        self.current_desktop: int = 0

        self.display = Display()
        self.event_loop = self.display.get_event_loop()
        self.compositor, self.backend = wlroots_helper.build_compositor(
            self.display)
        self.renderer = self.backend.renderer
        self.socket = self.display.add_socket()
        self.fd = None

        # set up inputs
        self.keyboards: List[keyboard.Keyboard] = []
        self.grabbed_keys: List[Tuple[int, int]] = []
        self.grabbed_buttons: List[Tuple[int, int]] = []
        self.device_manager = DataDeviceManager(self.display)
        self.seat = seat.Seat(self.display, "seat0")
        self._on_request_set_selection_listener = Listener(
            self._on_request_set_selection)
        self._on_new_input_listener = Listener(self._on_new_input)
        self.seat.request_set_selection_event.add(
            self._on_request_set_selection_listener)
        self.backend.new_input_event.add(self._on_new_input_listener)

        # set up outputs
        self.output_layout = OutputLayout()
        self.outputs: List[output.Output] = []
        self._on_new_output_listener = Listener(self._on_new_output)
        self.backend.new_output_event.add(self._on_new_output_listener)

        # set up cursor
        self.cursor = Cursor(self.output_layout)
        self.cursor_manager = XCursorManager(24)
        self._on_request_cursor_listener = Listener(self._on_request_cursor)
        self.seat.request_set_cursor_event.add(
            self._on_request_cursor_listener)
        self._on_cursor_axis_listener = Listener(self._on_cursor_axis)
        self._on_cursor_frame_listener = Listener(self._on_cursor_frame)
        self._on_cursor_button_listener = Listener(self._on_cursor_button)
        self._on_cursor_motion_listener = Listener(self._on_cursor_motion)
        self._on_cursor_motion_absolute_listener = Listener(
            self._on_cursor_motion_absolute)
        self.cursor.axis_event.add(self._on_cursor_axis_listener)
        self.cursor.frame_event.add(self._on_cursor_frame_listener)
        self.cursor.button_event.add(self._on_cursor_button_listener)
        self.cursor.motion_event.add(self._on_cursor_motion_listener)
        self.cursor.motion_absolute_event.add(
            self._on_cursor_motion_absolute_listener)

        # set up shell
        self.xdg_shell = xdg_shell.XdgShell(self.display)
        self._on_new_xdg_surface_listener = Listener(self._on_new_xdg_surface)
        self.xdg_shell.new_surface_event.add(self._on_new_xdg_surface_listener)

        # Add support for additional protocols
        XdgOutputManagerV1(self.display, self.output_layout)
        ScreencopyManagerV1(self.display)
        GammaControlManagerV1(self.display)
        self._virtual_keyboard_manager_v1 = VirtualKeyboardManagerV1(
            self.display)
        self._on_new_virtual_keyboard_listener = Listener(
            self._on_new_virtual_keyboard)
        self._virtual_keyboard_manager_v1.new_virtual_keyboard_event.add(
            self._on_new_virtual_keyboard_listener)

        # start
        os.environ["WAYLAND_DISPLAY"] = self.socket.decode()
        logger.info("Starting core with WAYLAND_DISPLAY=" +
                    self.socket.decode())
        self.backend.start()
Esempio n. 18
0
 def _add_new_keyboard(self, device: input_device.InputDevice):
     logger.info("Adding new keyboard")
     self.keyboards.append(keyboard.Keyboard(self, device))
     self.seat.set_keyboard(device)
Esempio n. 19
0
def make_qtile():
    from argparse import ArgumentParser
    parser = ArgumentParser(
        description='A full-featured, pure-Python tiling window manager.',
        prog='qtile',
    )
    parser.add_argument(
        '--version',
        action='version',
        version=VERSION,
    )
    parser.add_argument(
        "-c",
        "--config",
        action="store",
        default=path.expanduser(
            path.join(getenv('XDG_CONFIG_HOME', '~/.config'), 'qtile',
                      'config.py')),
        dest="configfile",
        help='Use the specified configuration file',
    )
    parser.add_argument("-s",
                        "--socket",
                        action="store",
                        default=None,
                        dest="socket",
                        help='Path of the Qtile IPC socket.')
    parser.add_argument("-n",
                        "--no-spawn",
                        action="store_true",
                        default=False,
                        dest="no_spawn",
                        help='Avoid spawning apps. (Used for restart)')
    parser.add_argument('-l',
                        '--log-level',
                        default='WARNING',
                        dest='log_level',
                        choices=('DEBUG', 'INFO', 'WARNING', 'ERROR',
                                 'CRITICAL'),
                        help='Set qtile log level')
    parser.add_argument(
        '--with-state',
        default=None,
        dest='state',
        help='Pickled QtileState object (typically used only internally)',
    )
    options = parser.parse_args()
    log_level = getattr(logging, options.log_level)
    init_log(log_level=log_level)
    kore = xcore.XCore()

    try:
        if not path.isfile(options.configfile):
            try:
                makedirs(path.dirname(options.configfile), exist_ok=True)
                from shutil import copyfile
                default_config_path = path.join(path.dirname(__file__), "..",
                                                "resources",
                                                "default_config.py")
                copyfile(default_config_path, options.configfile)
                logger.info('Copied default_config.py to %s',
                            options.configfile)
            except Exception as e:
                logger.exception(
                    'Failed to copy default_config.py to %s: (%s)',
                    options.configfile, e)

        config = confreader.Config.from_file(options.configfile, kore=kore)
    except Exception as e:
        logger.exception('Error while reading config file (%s)', e)
        config = confreader.Config()
        from libqtile.widget import TextBox
        widgets = config.screens[0].bottom.widgets
        widgets.insert(0, TextBox('Config Err!'))

    # XXX: the import is here because we need to call init_log
    # before start importing stuff
    from libqtile.core import session_manager
    return session_manager.SessionManager(
        kore,
        config,
        fname=options.socket,
        no_spawn=options.no_spawn,
        state=options.state,
    )
Esempio n. 20
0
    def update_bar_background():
        if top.screen == top.qtile.current_screen:
            top.background = '#000000'
        else:
            top.background = '#666666'
        top.draw()

    hook.subscribe.current_screen_change(update_bar_background)

    return Screen(top=top)


screens = []
if screeninfo:
    monitors = screeninfo.get_monitors()
    logger.info('screeninfo detected %d monitors', len(monitors))
    main = monitors[0]
    if monitors[0].name.startswith('e') and len(monitors) > 1:
        main = monitors[1]
    for monitor in monitors:
        screens.append(screen(main == monitor))
else:
    logger.info('screeninfo not available, only configuring a single screen')
    screens.append(screen(True))

# Drag floating layouts.
mouse = [
    Drag([mod],
         "Button1",
         lazy.window.set_position_floating(),
         start=lazy.window.get_position()),
Esempio n. 21
0
    def handle_ClientMessage(self, event):  # noqa: N802
        atoms = self.qtile.conn.atoms

        opcode = event.type
        data = event.data
        if atoms["_NET_WM_STATE"] == opcode:
            prev_state = self.window.get_property('_NET_WM_STATE',
                                                  'ATOM',
                                                  unpack=int)

            current_state = set(prev_state)

            action = data.data32[0]
            for prop in (data.data32[1], data.data32[2]):
                if not prop:
                    # skip 0
                    continue

                if action == _NET_WM_STATE_REMOVE:
                    current_state.discard(prop)
                elif action == _NET_WM_STATE_ADD:
                    current_state.add(prop)
                elif action == _NET_WM_STATE_TOGGLE:
                    current_state ^= set([prop])  # toggle :D

            self.window.set_property('_NET_WM_STATE', list(current_state))
        elif atoms["_NET_ACTIVE_WINDOW"] == opcode:
            source = data.data32[0]
            if source == 2:  # XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL
                logger.info("Focusing window by pager")
                self.qtile.current_screen.set_group(self.group)
                self.group.focus(self)
            else:  # XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER
                focus_behavior = self.qtile.config.focus_on_window_activation
                if focus_behavior == "focus":
                    logger.info("Focusing window")
                    self.qtile.current_screen.set_group(self.group)
                    self.group.focus(self)
                elif focus_behavior == "smart":
                    if not self.group.screen:
                        logger.info("Ignoring focus request")
                        return
                    if self.group.screen == self.qtile.current_screen:
                        logger.info("Focusing window")
                        self.qtile.current_screen.set_group(self.group)
                        self.group.focus(self)
                    else:  # self.group.screen != self.qtile.current_screen:
                        logger.info("Setting urgent flag for window")
                        self.urgent = True
                elif focus_behavior == "urgent":
                    logger.info("Setting urgent flag for window")
                    self.urgent = True
                elif focus_behavior == "never":
                    logger.info("Ignoring focus request")
                else:
                    logger.warning(
                        "Invalid value for focus_on_window_activation: {}".
                        format(focus_behavior))
        elif atoms["_NET_CLOSE_WINDOW"] == opcode:
            self.kill()
        elif atoms["WM_CHANGE_STATE"] == opcode:
            state = data.data32[0]
            if state == NormalState:
                self.minimized = False
            elif state == IconicState:
                self.minimized = True
        else:
            logger.info("Unhandled client message: %s", atoms.get_name(opcode))
Esempio n. 22
0
 def button_press(self, x, y, button):
     if button == 1:  # down
         if self.launch:
             logger.info("launching %s" % self.launch)
             subprocess.Popen(self.launch)
Esempio n. 23
0
    def organise_layers(self) -> None:
        """Organise the positioning of layer shell surfaces."""
        logger.info("Output: organising layers")
        ow, oh = self.wlr_output.effective_resolution()

        for layer in self.layers:
            for win in layer:
                assert isinstance(win.surface, LayerSurfaceV1)
                state = win.surface.current
                margin = state.margin
                ww = state.desired_width
                wh = state.desired_height

                # Horizontal axis
                if (state.anchor & LayerSurfaceV1Anchor.HORIZONTAL) and ww == 0:
                    x = margin.left
                    ww = ow - margin.left - margin.right
                elif (state.anchor & LayerSurfaceV1Anchor.LEFT):
                    x = margin.left
                elif (state.anchor & LayerSurfaceV1Anchor.RIGHT):
                    x = ow - ww - margin.right
                else:
                    x = int(ow / 2 - ww / 2)

                # Vertical axis
                if (state.anchor & LayerSurfaceV1Anchor.VERTICAL) and wh == 0:
                    y = margin.top
                    wh = oh - margin.top - margin.bottom
                elif (state.anchor & LayerSurfaceV1Anchor.TOP):
                    y = margin.top
                elif (state.anchor & LayerSurfaceV1Anchor.BOTTOM):
                    y = oh - wh - margin.bottom
                else:
                    y = int(oh / 2 - wh / 2)

                if ww <= 0 or wh <= 0:
                    win.kill()
                    continue

                if 0 < state.exclusive_zone:
                    # Reserve space if:
                    #    - layer is anchored to an edge and both perpendicular edges, or
                    #    - layer is anchored to a single edge only.
                    space = [0, 0, 0, 0]

                    if state.anchor & LayerSurfaceV1Anchor.HORIZONTAL:
                        if state.anchor & LayerSurfaceV1Anchor.TOP:
                            space[2] = state.exclusive_zone
                        elif state.anchor & LayerSurfaceV1Anchor.BOTTOM:
                            space[3] = state.exclusive_zone
                    elif state.anchor & LayerSurfaceV1Anchor.VERTICAL:
                        if state.anchor & LayerSurfaceV1Anchor.LEFT:
                            space[0] = state.exclusive_zone
                        elif state.anchor & LayerSurfaceV1Anchor.RIGHT:
                            space[1] = state.exclusive_zone
                    else:
                        # Single edge only
                        if state.anchor == LayerSurfaceV1Anchor.TOP:
                            space[2] = state.exclusive_zone
                        elif state.anchor == LayerSurfaceV1Anchor.BOTTOM:
                            space[3] = state.exclusive_zone
                        if state.anchor == LayerSurfaceV1Anchor.LEFT:
                            space[0] = state.exclusive_zone
                        elif state.anchor == LayerSurfaceV1Anchor.RIGHT:
                            space[1] = state.exclusive_zone

                    to_reserve: Tuple[int, int, int, int] = tuple(space)  # type: ignore
                    if win.reserved_space != to_reserve:
                        # Don't reserve more space if it's already been reserved
                        assert self.core.qtile is not None
                        self.core.qtile.reserve_space(to_reserve, self.screen)
                        win.reserved_space = to_reserve

                win.place(x + self.x, y + self.y, ww, wh, 0, None)

        self.core.stack_windows()
Esempio n. 24
0
    def __init__(self) -> None:
        """Setup the Wayland core backend"""
        self.qtile: Qtile | None = None
        self.desktops: int = 1
        self.current_desktop: int = 0
        self._hovered_internal: window.Internal | None = None
        self.focused_internal: window.Internal | None = None

        self.fd: int | None = None
        self.display = Display()
        self.event_loop = self.display.get_event_loop()
        (
            self.compositor,
            self._allocator,
            self.renderer,
            self.backend,
        ) = wlroots_helper.build_compositor(self.display)
        self.socket = self.display.add_socket()
        os.environ["WAYLAND_DISPLAY"] = self.socket.decode()
        logger.info("Starting core with WAYLAND_DISPLAY=" +
                    self.socket.decode())

        # These windows have not been mapped yet; they'll get managed when mapped
        self.pending_windows: set[window.WindowType] = set()

        # mapped_windows contains just regular windows
        self.mapped_windows: list[window.WindowType] = []  # Ascending in Z
        # stacked_windows also contains layer_shell windows from the current output
        self.stacked_windows: Sequence[window.WindowType] = [
        ]  # Ascending in Z
        self._current_output: Output | None = None

        # set up inputs
        self.keyboards: list[inputs.Keyboard] = []
        self.grabbed_keys: list[tuple[int, int]] = []
        self.grabbed_buttons: list[tuple[int, int]] = []
        DataDeviceManager(self.display)
        self.live_dnd: wlrq.Dnd | None = None
        DataControlManagerV1(self.display)
        self.seat = seat.Seat(self.display, "seat0")
        self.add_listener(self.seat.request_set_selection_event,
                          self._on_request_set_selection)
        self.add_listener(self.seat.request_start_drag_event,
                          self._on_request_start_drag)
        self.add_listener(self.seat.start_drag_event, self._on_start_drag)
        self.add_listener(self.backend.new_input_event, self._on_new_input)
        # Some devices are added early, so we need to remember to configure them
        self._pending_input_devices: list[input_device.InputDevice] = []
        hook.subscribe.startup_complete(self._configure_pending_inputs)

        # set up outputs
        self.outputs: list[Output] = []
        self.add_listener(self.backend.new_output_event, self._on_new_output)
        self.output_layout = OutputLayout()
        self.add_listener(self.output_layout.change_event,
                          self._on_output_layout_change)
        self.output_manager = OutputManagerV1(self.display)
        self.add_listener(self.output_manager.apply_event,
                          self._on_output_manager_apply)
        self.add_listener(self.output_manager.test_event,
                          self._on_output_manager_test)

        # set up cursor
        self.cursor = Cursor(self.output_layout)
        self.cursor_manager = XCursorManager(24)
        self.add_listener(self.seat.request_set_cursor_event,
                          self._on_request_cursor)
        self.add_listener(self.cursor.axis_event, self._on_cursor_axis)
        self.add_listener(self.cursor.frame_event, self._on_cursor_frame)
        self.add_listener(self.cursor.button_event, self._on_cursor_button)
        self.add_listener(self.cursor.motion_event, self._on_cursor_motion)
        self.add_listener(self.cursor.motion_absolute_event,
                          self._on_cursor_motion_absolute)

        # set up shell
        self.xdg_shell = XdgShell(self.display)
        self.add_listener(self.xdg_shell.new_surface_event,
                          self._on_new_xdg_surface)
        self.layer_shell = LayerShellV1(self.display)
        self.add_listener(self.layer_shell.new_surface_event,
                          self._on_new_layer_surface)

        # Add support for additional protocols
        XdgOutputManagerV1(self.display, self.output_layout)
        ScreencopyManagerV1(self.display)
        GammaControlManagerV1(self.display)
        output_power_manager = OutputPowerManagerV1(self.display)
        self.add_listener(output_power_manager.set_mode_event,
                          self._on_output_power_manager_set_mode)
        self.idle = Idle(self.display)
        idle_ihibitor_manager = IdleInhibitorManagerV1(self.display)
        self.add_listener(idle_ihibitor_manager.new_inhibitor_event,
                          self._on_new_inhibitor)
        PrimarySelectionV1DeviceManager(self.display)
        self._virtual_keyboard_manager_v1 = VirtualKeyboardManagerV1(
            self.display)
        self.add_listener(
            self._virtual_keyboard_manager_v1.new_virtual_keyboard_event,
            self._on_new_virtual_keyboard,
        )
        xdg_decoration_manager_v1 = xdg_decoration_v1.XdgDecorationManagerV1.create(
            self.display)
        self.add_listener(
            xdg_decoration_manager_v1.new_toplevel_decoration_event,
            self._on_new_toplevel_decoration,
        )
        # wlr_server_decoration will be removed in a future version of wlroots
        server_decoration_manager = ServerDecorationManager.create(
            self.display)
        server_decoration_manager.set_default_mode(
            ServerDecorationManagerMode.SERVER)
        pointer_constraints_v1 = PointerConstraintsV1(self.display)
        self.add_listener(
            pointer_constraints_v1.new_constraint_event,
            self._on_new_pointer_constraint,
        )
        self.pointer_constraints: set[window.PointerConstraint] = set()
        self.active_pointer_constraint: window.PointerConstraint | None = None
        self._relative_pointer_manager_v1 = RelativePointerManagerV1(
            self.display)
        self.foreign_toplevel_manager_v1 = ForeignToplevelManagerV1.create(
            self.display)

        # Set up XWayland
        self._xwayland = xwayland.XWayland(self.display, self.compositor, True)
        if self._xwayland:
            os.environ["DISPLAY"] = self._xwayland.display_name or ""
            logger.info("Set up XWayland with DISPLAY=" +
                        os.environ["DISPLAY"])
            self.add_listener(self._xwayland.ready_event,
                              self._on_xwayland_ready)
            self.add_listener(self._xwayland.new_surface_event,
                              self._on_xwayland_new_surface)
        else:
            logger.info("Failed to set up XWayland. Continuing without.")

        # Start
        self.backend.start()
Esempio n. 25
0
    def _add(self, client):
        if client in self.timeout:
            logger.info('Remove dgroup source')
            self.timeout.pop(client).cancel()

        # ignore static windows
        if client.defunct:
            return

        # ignore windows whose groups is already set (e.g. from another hook or
        # when it was set on state restore)
        if client.group is not None:
            return

        group_set = False
        intrusive = False

        for rule in self.rules:
            # Matching Rules
            if rule.matches(client):
                if rule.group:
                    if rule.group in self.groups_map:
                        layout = self.groups_map[rule.group].layout
                        layouts = self.groups_map[rule.group].layouts
                        label = self.groups_map[rule.group].label
                    else:
                        layout = None
                        layouts = None
                        label = None
                    group_added = self.qtile.add_group(rule.group, layout, layouts, label)
                    client.togroup(rule.group)

                    group_set = True

                    group_obj = self.qtile.groups_map[rule.group]
                    group = self.groups_map.get(rule.group)
                    if group and group_added:
                        for k, v in list(group.layout_opts.items()):
                            if isinstance(v, collections.Callable):
                                v(group_obj.layout)
                            else:
                                setattr(group_obj.layout, k, v)
                        affinity = group.screen_affinity
                        if affinity and len(self.qtile.screens) > affinity:
                            self.qtile.screens[affinity].set_group(group_obj)

                if rule.float:
                    client.enablefloating()

                if rule.intrusive:
                    intrusive = rule.intrusive

                if rule.break_on_match:
                    break

        # If app doesn't have a group
        if not group_set:
            current_group = self.qtile.current_group.name
            if current_group in self.groups_map and \
                    self.groups_map[current_group].exclusive and \
                    not intrusive:

                wm_class = client.window.get_wm_class()

                if wm_class:
                    if len(wm_class) > 1:
                        wm_class = wm_class[1]
                    else:
                        wm_class = wm_class[0]

                    group_name = wm_class
                else:
                    group_name = client.name or 'Unnamed'

                self.add_dgroup(Group(group_name, persist=False), start=True)
                client.togroup(group_name)
        self.sort_groups()
Esempio n. 26
0
 def f(group):
     if group:
         try:
             self.groups_map[group].cmd_toscreen()
         except KeyError:
             logger.info("No group named '{0:s}' present.".format(group))
Esempio n. 27
0
 def _add_new_pointer(self, device: input_device.InputDevice):
     logger.info("Adding new pointer")
     self.cursor.attach_input_device(device)
Esempio n. 28
0
 def cmd_info(self):
     """Set log level to INFO"""
     logger.setLevel(logging.INFO)
     logger.info('Switching to INFO threshold')
Esempio n. 29
0
    def __init__(self):
        """Setup the Wayland core backend"""
        self.qtile: Optional[Qtile] = None
        self.desktops: int = 1
        self.current_desktop: int = 0

        self.display = Display()
        self.event_loop = self.display.get_event_loop()
        self.compositor, self.backend = wlroots_helper.build_compositor(
            self.display)
        self.renderer = self.backend.renderer
        self.socket = self.display.add_socket()
        self.fd = None
        self._hovered_internal: Optional[window.Internal] = None

        # These windows have not been mapped yet; they'll get managed when mapped
        self.pending_windows: List[window.WindowType] = []

        # mapped_windows contains just regular windows
        self.mapped_windows: List[window.WindowType] = []  # Ascending in Z
        # stacked_windows also contains layer_shell windows from the current output
        self.stacked_windows: List[window.WindowType] = []  # Ascending in Z
        self._current_output: Optional[Output] = None

        # set up inputs
        self.keyboards: List[keyboard.Keyboard] = []
        self.grabbed_keys: List[Tuple[int, int]] = []
        self.grabbed_buttons: List[Tuple[int, int]] = []
        DataDeviceManager(self.display)
        DataControlManagerV1(self.display)
        self.seat = seat.Seat(self.display, "seat0")
        self.add_listener(self.seat.request_set_selection_event,
                          self._on_request_set_selection)
        self.add_listener(self.backend.new_input_event, self._on_new_input)

        # set up outputs
        self.outputs: List[Output] = []
        self.add_listener(self.backend.new_output_event, self._on_new_output)
        self.output_layout = OutputLayout()
        self.add_listener(self.output_layout.change_event,
                          self._on_output_layout_change)
        self.output_manager = OutputManagerV1(self.display)
        self.add_listener(self.output_manager.apply_event,
                          self._on_output_manager_apply)
        self.add_listener(self.output_manager.test_event,
                          self._on_output_manager_test)

        # set up cursor
        self.cursor = Cursor(self.output_layout)
        self.cursor_manager = XCursorManager(24)
        self.add_listener(self.seat.request_set_cursor_event,
                          self._on_request_cursor)
        self.add_listener(self.cursor.axis_event, self._on_cursor_axis)
        self.add_listener(self.cursor.frame_event, self._on_cursor_frame)
        self.add_listener(self.cursor.button_event, self._on_cursor_button)
        self.add_listener(self.cursor.motion_event, self._on_cursor_motion)
        self.add_listener(self.cursor.motion_absolute_event,
                          self._on_cursor_motion_absolute)

        # set up shell
        self.xdg_shell = XdgShell(self.display)
        self.add_listener(self.xdg_shell.new_surface_event,
                          self._on_new_xdg_surface)
        self.layer_shell = LayerShellV1(self.display)
        self.add_listener(self.layer_shell.new_surface_event,
                          self._on_new_layer_surface)

        # Add support for additional protocols
        XdgOutputManagerV1(self.display, self.output_layout)
        ScreencopyManagerV1(self.display)
        GammaControlManagerV1(self.display)
        PrimarySelectionV1DeviceManager(self.display)
        self._virtual_keyboard_manager_v1 = VirtualKeyboardManagerV1(
            self.display)
        self.add_listener(
            self._virtual_keyboard_manager_v1.new_virtual_keyboard_event,
            self._on_new_virtual_keyboard)
        xdg_decoration_manager_v1 = xdg_decoration_v1.XdgDecorationManagerV1.create(
            self.display)
        self.add_listener(
            xdg_decoration_manager_v1.new_toplevel_decoration_event,
            self._on_new_toplevel_decoration,
        )
        # wlr_server_decoration will be removed in a future version of wlroots
        server_decoration_manager = ServerDecorationManager.create(
            self.display)
        server_decoration_manager.set_default_mode(
            ServerDecorationManagerMode.SERVER)

        # start
        os.environ["WAYLAND_DISPLAY"] = self.socket.decode()
        logger.info("Starting core with WAYLAND_DISPLAY=" +
                    self.socket.decode())
        self.backend.start()
Esempio n. 30
0
def autostart():
    logger.info('start')
    home = f'{HOME}/.config/qtile/autostart.sh'
    subprocess.call([home])