def main(): rename_process() q = make_qtile() try: q.loop() except Exception: logger.exception('Qtile crashed') logger.info('Exiting...')
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
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)
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
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)
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 )
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
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()
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
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.")
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.')
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)
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])
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()
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()),
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
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()
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)
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, )
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()),
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))
def button_press(self, x, y, button): if button == 1: # down if self.launch: logger.info("launching %s" % self.launch) subprocess.Popen(self.launch)
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()
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()
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()
def f(group): if group: try: self.groups_map[group].cmd_toscreen() except KeyError: logger.info("No group named '{0:s}' present.".format(group))
def _add_new_pointer(self, device: input_device.InputDevice): logger.info("Adding new pointer") self.cursor.attach_input_device(device)
def cmd_info(self): """Set log level to INFO""" logger.setLevel(logging.INFO) logger.info('Switching to INFO threshold')
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()
def autostart(): logger.info('start') home = f'{HOME}/.config/qtile/autostart.sh' subprocess.call([home])