def show_stack_icons(self, stack, current_win): self.stack = stack if not stack: logger.warning("Stack empty") clist.hide() return self.width = self.orig_width self.height = len(stack) * self.width offset = 0 self.drawer.clear("000000") for client in stack: icon = self.get_window_icon(client) self.draw_icon(icon, offset) offset += self.width if current_win in stack: id = stack.index(current_win) self.drawer.set_source_rgb("00FFFF") self.drawer.rectangle(0, id * self.width, self.width, self.width) self.place() self.draw() self.unhide()
def _check_colors(self): """ dmenu needs colours to be in #rgb or #rrggbb format. Checks colour value, removes invalid values and adds # if missing. NB This should not be called in _Extension.__init__ as _Extension.global_defaults may not have been set at this point. """ for c in [ "background", "foreground", "selected_background", "selected_foreground" ]: col = getattr(self, c, None) if col is None: continue if not isinstance(col, str) or not RGB.match(col): logger.warning(f"Invalid extension '{c}' color: {col}. " f"Must be #RGB or #RRGGBB string.") setattr(self, c, None) continue if not col.startswith("#"): col = f"#{col}" setattr(self, c, col)
def find_batteries(self, *args): # Get all UPower devices that are named "battery" batteries = [ b for b in self.upower.EnumerateDevices() if "battery" in b ] if not batteries: logger.warning("No batteries found. No icons will be displayed.") # Get DBus object for each battery self.batteries = [self.bus.get(UPOWER_INTERFACE, b) for b in batteries] # If user only wants named battery, get it here if self.battery_name: self.batteries = [ b for b in self.batteries if b.NativePath == self.battery_name ] if not self.batteries: err = "No battery found matching {}.".format(self.battery_name) logger.warning(err) # Listen for change signals on DBus for battery in self.batteries: battery.onPropertiesChanged = self.battery_change
def setup_images(self): for key, name in self.icons.items(): try: path = os.path.join(self.theme_path, name) img = cairocffi.ImageSurface.create_from_png(path) except cairocffi.Error: self.theme_path = None logger.warning('Battery Icon switching to text mode') return input_width = img.get_width() input_height = img.get_height() sp = input_height / (self.bar.height - 1) width = input_width / sp if width > self.length: self.length = int(width) + self.actual_padding * 2 imgpat = cairocffi.SurfacePattern(img) scaler = cairocffi.Matrix() scaler.scale(sp, sp) scaler.translate(self.actual_padding * -1, 0) imgpat.set_matrix(scaler) imgpat.set_filter(cairocffi.FILTER_BEST) self.surfaces[key] = imgpat
def getCmus(qtile:Optional[Qtile]=None, max_title_len:int=20): try: output = subprocess.check_output(['cmus-remote', '-Q']).decode() except subprocess.CalledProcessError as e: logger.warn("getMpd: {}".format(e)) return getIcons()['error'] else: output = re.findall(r'file (.*)|duration (\d+)|position (\d+)|tag title (.*)', output, re.MULTILINE) try: if len(output) > 3: title = output[3][-1].strip() else: title = output[0][0].split('/')[-1].split('.')[0].strip() title = title[:max_title_len-3] + '...' if len(title) > max_title_len else "{}{}".format( title, " "*(max_title_len-len(title))) total_time_m = int(output[1][1])//60 total_time_s = int(output[1][1])%60 time_m = int(output[2][2])//60 time_s = int(output[2][2])%60 except Exception as e: logger.warning("{} {}".format(e, output)) return getIcons()['error'] else: return "{} {}:{}/{}:{}".format(title, time_m, time_s, total_time_m, total_time_s)
def clickMpd(qtile:Optional[Qtile]=None, button:int=1): keys = { # Left mouse button "toggle": 1, # Right mouse button "stop": 3, # Scroll up "previous": 4, # Scroll down "next": 5, # User defined command "command": None } cmd = ['mpc'] if button == keys["toggle"]: cmd.append('toggle') elif button == keys["stop"]: cmd.append('stop') elif button == keys["previous"]: cmd.append('prev') elif button == keys["next"]: cmd.append('next') try: subprocess.run(cmd) except subprocess.CalledProcessError as e: logger.warning(e.output.decode().strip())
def _on_destroy(self, _listener, _data): logger.debug("Signal: window destroy") if self.mapped: logger.warning("Window destroyed before unmap event.") self.mapped = False self.qtile.unmanage(self.wid) self.finalize()
def get_bar_text(qtile): """Primary function to be run from config with import tts lazy.function(tts.get_text) """ try: text = "" for i, s in enumerate(qtile.screens): text += "Screen number " + str(i) + ". " for pos in ["top", "bottom", "left", "right"]: if hasattr(s, pos): bar = getattr(s, pos) # can return None if bar: text += bar.cmd_info()["position"].capitalize() + " bar. " for w in bar.widgets: #text += w.__class__.__name__ + " widget. " text += _parse_widget(w) log_test(text) """Sending the text to the TTS engine may take awhile so mp is to ensure that qtile doesn't freeze during that time NOTE CURRENTLY NOT WORKING? """ p = Process(target=_play_audio, args=(text,), daemon=True) p.start() p.join() #log_test(p.is_alive()) #log_test("finished") except Exception as e: log_test(e) logger.warning(f"TTS failed: {e}")
def remove_rule(self, rule_id): rule = self.rules_map.get(rule_id) if rule: self.rules.remove(rule) del self.rules_map[rule_id] else: logger.warning('Rule "%s" not found', rule_id)
def setup_images(self): for key, name in self.icons.items(): try: path = os.path.join(self.theme_path, name) img = cairocffi.ImageSurface.create_from_png(path) except (cairocffi.Error, FileNotFoundError): self.theme_path = None logger.warning('VolumeIcons wrong icons path') return input_width = img.get_width() input_height = img.get_height() size = self.fontsize sp = input_height / size width = input_width / sp if width > self.length: # cast to `int` only after handling all potentially-float values self.length = int(width + self.actual_padding * 2) imgpat = cairocffi.SurfacePattern(img) scaler = cairocffi.Matrix() scaler.scale(sp, sp) translate_y = (self.bar.height - size) // 2 scaler.translate(self.actual_padding * -1, -translate_y) imgpat.set_matrix(scaler) imgpat.set_filter(cairocffi.FILTER_BEST) self.surfaces[key] = imgpat
def startup_once(): import glob prog_files = glob.glob(home + "/.config/autostart/*.desktop") progs = [] for prog in prog_files: try: executable = "" with open(prog, "r") as prog_f: for line in prog_f: if line.startswith("Exec="): executable = line[5:].strip() break if executable != "": progs.append(executable) except: logger.warning("qtile: can't open " + prog) for prog in progs: runInBackground(prog) runInBackground("/usr/lib/polkit-kde-authentication-agent-1", "authentication agent polkit-kde-agent") runInBackground("udiskie --smart-tray", "udisks2 automounter (mount helper)") runInBackground( "xss-lock -- " + screen_locker, "xss-lock subscribes to the systemd-events suspend, hibernate")
def register(self, callback): if not self.service: logger.warning( 'Registering %s without any dbus connection existing', callback.__name__, ) self.callbacks.append(callback)
def cmd_hide_show_bar(self, position="all"): """Toggle visibility of a given bar Parameters ========== position : one of: "top", "bottom", "left", "right", or "all" (default: "all") """ if position in ["top", "bottom", "left", "right"]: bar = getattr(self.current_screen, position) if bar: bar.show(not bar.is_show()) self.current_group.layout_all() else: logger.warning( "Not found bar in position '%s' for hide/show." % position) elif position == "all": screen = self.current_screen is_show = None for bar in [screen.left, screen.right, screen.top, screen.bottom]: if bar: if is_show is None: is_show = not bar.is_show() bar.show(is_show) if is_show is not None: self.current_group.layout_all() else: logger.warning("Not found bar for hide/show.") else: logger.error("Invalid position value:{0:s}".format(position))
def setMute(mute=2, refresh=False): ''' Sets active sink mute state Args: mute:int - 0-unmute, 1-mute, 2-toggle refresh:boolean - Re-fetches current data from pulse audio returns True is succeeded, False if error ''' global active_sink, sinks if refresh or not active_sink: sinks, active_sink = _getSinks() if not active_sink: logger.warning(f'Audio/toggleMuted: no active sink: {active_sink}') return False cmd = 'toggle' if mute == 2 else str(mute) muteCmd = f'pactl set-sink-mute {active_sink["index"]} {cmd}'.split() try: Popen(muteCmd) except CalledProcessError as err: logger.warning("SetMute error : {}".format(err)) return False return True
def update(self, theme): widgets = set() for prop_name, value in theme.items(): widgets |= self.set(prop_name, value) logger.warning("{} WIDGETS TO DRAW".format(len(widgets))) for widget in widgets: widget.draw()
def setupMonitors(): try: o = subprocess.check_output(['xrandr']).decode() except subprocess.CalledProcessError as e: logger.warning(e.output.decode().strip()) return cmd = ["xrandr"] x = 0 monitors = [] for i, e in enumerate(o.split('\n')): if not 'connected' in e: continue name = e.strip().split()[0] if ' connected' in e: res = o.split('\n')[i+1].strip().split()[0] cmd += ['--output', name, '--mode', res, '--pos', "{}x{}".format(x, 0), '--rotate', 'normal'] x += int(res.split('x')[0]) monitors.append(name) elif 'disconnected' in e: cmd += ['--output', name, '--off'] try: subprocess.run(cmd) except subprocess.CalledProcessError as e: logger.warning(e.output.decode().strip()) else: return monitors
def _configure(self, qtile, bar): base._Widget._configure(self, qtile, bar) self.img = None if not self.filename: logger.warning("Image filename not set!") return self.filename = os.path.expanduser(self.filename) if not os.path.exists(self.filename): logger.warning("Image does not exist: {}".format(self.filename)) return img = Img.from_path(self.filename) self.img = img img.theta = self.rotate if not self.scale: return if self.bar.horizontal: new_height = self.bar.height - (self.margin_y * 2) img.resize(height=new_height) else: new_width = self.bar.width - (self.margin_x * 2) img.resize(width=new_width)
def configure_device(device: InputDevice, configs: dict[str, InputConfig]) -> None: if not configs: return # Find a matching InputConfig name = device.name if name == " " or not name.isprintable(): name = "_" identifier = "%d:%d:%s" % (device.vendor, device.product, name) type_key = "type:" + device.device_type.name.lower() if type_key == "type:pointer": # This checks whether the pointer is a touchpad. handle = device.libinput_get_device_handle() if handle and libinput.libinput_device_config_tap_get_finger_count( handle) > 0: type_key = "type:touchpad" if identifier in configs: conf = configs[identifier] elif type_key in configs: conf = configs[type_key] elif "*" in configs: conf = configs["*"] else: return if device.device_type == input_device.InputDeviceType.POINTER: _configure_pointer(device, conf, name) elif device.device_type == input_device.InputDeviceType.KEYBOARD: _configure_keyboard(device, conf) else: logger.warning("Device not configured. Type '%s' not recognised.", device.device_type)
async def _notify(title, message, urgency, timeout, id): notification = [ "qtile", # Application name id, # id "", # icon title, # summary message, # body [""], # actions { "urgency": Variant("y", urgency) }, # hints timeout ] # timeout bus, msg = await _send_dbus_message(True, MessageType.METHOD_CALL, "org.freedesktop.Notifications", "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "Notify", "susssasa{sv}i", notification) if msg.message_type == MessageType.ERROR: logger.warning("Unable to send notification. " "Is a notification server running?") # a new bus connection is made each time a notification is sent so # we disconnect when the notification is done bus.disconnect()
async def _server_callback(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None: """Callback when a connection is made to the server Read the data sent from the client, execute the requested command, and send the reply back to the client. """ try: logger.debug("Connection made to server") data = await reader.read() logger.debug("EOF received by server") req, is_json = _IPC.unpack(data) except IPCError: logger.warning("Invalid data received, closing connection") else: rep = self.handler(req) result = _IPC.pack(rep, is_json=is_json) logger.debug("Sending result on receive EOF") writer.write(result) logger.debug("Closing connection on receive EOF") writer.write_eof() finally: writer.close() await writer.wait_closed()
def send_notification(title, message, urgent=False, timeout=10000, id=None): """ Send a notification. The id argument, if passed, requests the notification server to replace a visible notification with the same ID. An ID is returned for each call; this would then be passed when calling this function again to replace that notification. See: https://developer.gnome.org/notification-spec/ """ if not has_dbus: logger.warning( "dbus-next is not installed. Unable to send notifications.") return -1 id = randint(10, 1000) if id is None else id urgency = 2 if urgent else 1 try: loop = asyncio.get_running_loop() except RuntimeError: logger.warning("Eventloop has not started. Cannot send notification.") else: loop.create_task(_notify(title, message, urgency, timeout, id)) return id
def get_max(self): "Read the max brightness level for the device" maxval = self._read(self.max_path) if not maxval: logger.warning("Max value was not read. " "Module may behave unexpectedly.") return maxval
async def _config_async(self): subscribed = await add_signal_receiver(self._signal_received, session_bus=True, signal_name="layoutChanged", dbus_interface="ru.gentoo.kbdd") if not subscribed: logger.warning("Could not subscribe to kbdd signal.")
def _get_data(self, queue=None): try: data = self.tvh.get_upcoming() except TVHTimeOut: logger.warning("Couldn't connect to TVH server") data = [] return data
def getNumScreens(): try: o = subprocess.check_output(['xrandr']).decode() except subprocess.CalledProcessError as e: logger.warning(e.output.decode().strip()) return 1 else: return len(re.findall(r'\w+ connected \w+', o))
def get_current(self): "Read the current brightness level for the device" current = self._read(self.bright_path) if not current: logger.warning("Current value was not read. " "Module may behave unexpectedly.") return current
def wrapper(*args, **kwargs): return_value = return_on_exception try: return_value = func(*args, **kwargs) except excepts as err: logger.warning(str(err)) warnings.warn(str(err), warning) return return_value
def register(self, callback, capabilities=None): if not self.service: logger.warning( 'Registering %s without any dbus connection existing', callback.__name__, ) self.callbacks.append(callback) if capabilities: self._service.register_capabilities(capabilities)
def set_keymap(self, layout: Optional[str], options: Optional[str]) -> None: """ Set the keymap for the current keyboard. """ if self.keyboards: self.keyboards[-1].set_keymap(layout, options) else: logger.warning("Could not set keymap: no keyboards set up.")
async def start(self): # Create a proxy object connecting for the item. introspection = await self.bus.introspect(self.service, self.path) try: obj = self.bus.get_proxy_object(self.service, self.path, introspection) except InvalidBusNameError: return False # Try to connect to the bus object and verify there's a valid # interface available # TODO: This may not ever fail given we've specified the underying # schema so dbus-next has not attempted any introspection. interface_found = False for interface in ITEM_INTERFACES: try: self.item = obj.get_interface(interface) interface_found = True break except InterfaceNotFoundError: continue if not interface_found: logger.warning(f"Unable to find StatusNotifierItem" f"interface on {self.service}") return False # Default to XDG icon: icon_name = await self.item.get_icon_name() try: icon_path = await self.item.get_icon_theme_path() self.icon = self._get_custom_icon(icon_name, icon_path) except (AttributeError, DBusError): pass if not self.icon: self.icon = self._get_xdg_icon(icon_name) # If there's no XDG icon, try to use icon provided by application if self.icon is None: # Get initial application icons: for icon in ["Icon", "Attention", "Overlay"]: await self._get_icon(icon) # Attach listeners for when the icon is updated self.item.on_new_icon(self._new_icon) self.item.on_new_attention_icon(self._new_attention_icon) self.item.on_new_overlay_icon(self._new_overlay_icon) if not self.has_icons: logger.warning("Cannot find icon in current theme and " "no icon provided by StatusNotifierItem.") return True
def setup_images(self): """ Create image structures for each icon files. """ for img_name, iconfile in self.icons_files.items(): if iconfile is None: logger.warning( 'No icon found for application "%s" (%s) switch to text mode', img_name, iconfile) # if no icon is found and no default icon was set, we just # print the name, based on a textbox. textbox = base._TextBox() textbox._configure(self.qtile, self.bar) textbox.layout = self.drawer.textlayout( textbox.text, textbox.foreground, textbox.font, textbox.fontsize, textbox.fontshadow, markup=textbox.markup, ) # the name will be displayed textbox.text = img_name textbox.calculate_length() self.icons_widths[img_name] = textbox.width self.surfaces[img_name] = textbox continue else: try: img = cairocffi.ImageSurface.create_from_png(iconfile) except cairocffi.Error: logger.exception('Error loading icon for application "%s" (%s)', img_name, iconfile) return input_width = img.get_width() input_height = img.get_height() sp = input_height / (self.bar.height - 4) width = int(input_width / sp) imgpat = cairocffi.SurfacePattern(img) scaler = cairocffi.Matrix() scaler.scale(sp, sp) scaler.translate(self.padding * -1, -2) imgpat.set_matrix(scaler) imgpat.set_filter(cairocffi.FILTER_BEST) self.surfaces[img_name] = imgpat self.icons_widths[img_name] = width
def __init__(self, **config): _Graph.__init__(self, **config) self.add_defaults(NetGraph.defaults) if self.interface == "auto": try: self.interface = self.get_main_iface() except RuntimeError: logger.warning( "NetGraph - Automatic interface detection failed, " "falling back to 'eth0'" ) self.interface = "eth0" if self.bandwidth_type != "down" and self.bandwidth_type != "up": raise ValueError("bandwidth type {} not known!".format(self.bandwidth_type)) self.bytes = 0 self.bytes = self._get_values()
def __init__(self, **config): _Graph.__init__(self, **config) self.add_defaults(NetGraph.defaults) if self.interface == "auto": try: self.interface = self.get_main_iface() except RuntimeError: logger.warning( "NetGraph - Automatic interface detection failed, " "falling back to 'eth0'" ) self.interface = "eth0" self.filename = '/sys/class/net/{interface}/statistics/{type}'.format( interface=self.interface, type=self.bandwidth_type == 'down' and 'rx_bytes' or 'tx_bytes' ) self.bytes = 0 self.bytes = self._getValues()
def on_done(future): try: result = future.result() except Exception: logger.exception('poll() raised exceptions, not rescheduling') if result is not None: try: self.update(result) if self.update_interval is not None: self.timeout_add(self.update_interval, self.timer_setup) else: self.timer_setup() except Exception: logger.exception('Failed to reschedule.') else: logger.warning('poll() returned None, not rescheduling')
def safe_import(module_name, class_name): """ try to import a module, and if it fails because an ImporError it logs on WARNING, and logs the traceback on DEBUG level """ if type(class_name) is list: for name in class_name: safe_import(module_name, name) return package = __package__ # python 3.2 don't set __package__ if not package: package = __name__ try: module = importlib.import_module(module_name, package) globals()[class_name] = getattr(module, class_name) except ImportError as error: logger.warning("Can't Import Widget: '%s.%s', %s", module_name, class_name, error) logger.debug("%s", traceback.format_exc())
def connect(self, quiet=False): if self.connected: return True try: self.client.connect(host=self.host, port=self.port) except Exception: if not quiet: logger.exception('Failed to connect to mpd') return False if self.password: try: self.client.password(self.password) except Exception: logger.warning('Authentication failed. Disconnecting') try: self.client.disconnect() except Exception: pass self.connected = True return True
def __init__(self, fname=None, is_restart=False): if not fname: config_directory = os.path.expandvars('$XDG_CONFIG_HOME') if config_directory == '$XDG_CONFIG_HOME': # if variable wasn't set config_directory = os.path.expanduser("~/.config") fname = os.path.join(config_directory, "qtile", "config.py") # We delay importing here to avoid a circular import issue when # testing. from .resources import default_config if fname == "default": config = default_config elif os.path.isfile(fname): try: sys.path.insert(0, os.path.dirname(fname)) config = __import__(os.path.basename(fname)[:-3]) except Exception as v: tb = traceback.format_exc() # On restart, user potentially has some windows open, but they # screwed up their config. So as not to lose their apps, we # just load the default config here. if is_restart: logger.warning( 'Caught exception in configuration:\n\n' '%s\n\n' 'Qtile restarted with default config', tb) config = None else: raise ConfigError(tb) else: config = None # if you add something here, be sure to add a reasonable default value # to resources/default_config.py config_options = [ "keys", "mouse", "groups", "dgroups_key_binder", "dgroups_app_rules", "follow_mouse_focus", "focus_on_window_activation", "cursor_warp", "layouts", "floating_layout", "screens", "main", "auto_fullscreen", "widget_defaults", "bring_front_click", "wmname", "extentions", ] for option in config_options: if hasattr(config, option): v = getattr(config, option) else: v = getattr(default_config, option) if not hasattr(self, option): setattr(self, option, v)