import subprocess import psutil import re from libqtile import widget, bar #region Custom_Memory class MemoryC(widget.base.ThreadPoolText): orientations = widget.base.ORIENTATION_HORIZONTAL defaults = [ ("format", "{MemUsed}GB/{MemTotal}GB", "Formatting for field names."), ("update_interval", 1.0, "Update interval for the Memory"), ] def __init__(self, **config): super().__init__("", **config) self.add_defaults(MemoryC.defaults) def poll(self): mem = psutil.virtual_memory() swap = psutil.swap_memory() val = {} val["MemUsed"] = mem.used // 1024 // 1024 // 102.4 / 10 val["MemTotal"] = mem.total // 1024 // 1024 // 102.4 / 10 val["MemPercent"] = mem.percent val["MemFree"] = mem.free // 1024 // 1024 // 102.4 / 10 val["Buffers"] = mem.buffers // 1024 // 1024 // 102.4 / 10 val["Active"] = mem.active // 1024 // 1024 // 102.4 / 10 val["Inactive"] = mem.inactive // 1024 // 1024 // 102.4 / 10 val["Shmem"] = mem.shared // 1024 // 1024 // 102.4 / 10 val["SwapTotal"] = swap.total // 1024 // 1024 // 102.4 / 10 val["Swapfree"] = swap.free // 1024 // 1024 // 102.4 / 10 val["SwapUsed"] = swap.used // 1024 // 1024 // 102.4 / 10 val["SwapPercent"] = swap.percent return self.format.format(**val) #endregion #region Microphone_Widget re_vol = re.compile(r'\[(\d?\d?\d?)%\]') BUTTON_MUTE = 1 class Mic(widget.base._TextBox): """ Custom Microphone widget """ orientations = widget.base.ORIENTATION_HORIZONTAL defaults = [ ("cardid", None, "Card Id"), ("device", "default", "Device Name"), ("channel", "Capture", "Channel"), ("padding", 3, "Padding left and right. Calculated if None."), ("update_interval", 0.2, "Update time in seconds."), ("theme_path", None, "Path of the icons"), ("emoji", False, "Use emoji to display volume states, only if ``theme_path`` is not set." "The specified font needs to contain the correct unicode characters."), ("mute_command", None, "Mute command"), ("volume_app", None, "App to control volume"), ("volume_up_command", None, "Volume up command"), ("volume_down_command", None, "Volume down command"), ("get_volume_command", None, "Command to get the current volume"), ("step", 2, "Volume change for up an down commands in percentage." "Only used if ``volume_up_command`` and ``volume_down_command`` are not set.") ] def __init__(self, **config): widget.base._TextBox.__init__(self, '0', width=bar.CALCULATED, **config) self.add_defaults(Mic.defaults) if self.theme_path: self.length_type = bar.STATIC self.length = 0 self.surfaces = {} self.volume = None def timer_setup(self): self.timeout_add(self.update_interval, self.update) if self.theme_path: self.setup_images() def create_amixer_command(self, *args): cmd = ['amixer'] cmd.extend([x for x in args]) return cmd def button_press(self, x, y, button): if button == BUTTON_MUTE: if self.mute_command is not None: subprocess.call(self.mute_command, shell=True) else: subprocess.call(self.create_amixer_command('-q', 'sset', self.channel, 'toggle')) self.draw() def update(self): vol = self.get_volume() if vol != self.volume: self.volume = vol # Update the underlying canvas size before actually attempting # to figure out how big it is and draw it. self._update_drawer() self.bar.draw() self.timeout_add(self.update_interval, self.update) def _update_drawer(self): if self.emoji: if self.volume > 0: self.text = '' elif self.volume <= 0: self.text = '' else: if self.volume == -1: self.text = 'M' else: self.text = '{}%'.format(self.volume) def get_volume(self): try: get_volume_cmd = self.create_amixer_command('sget', self.channel) if self.get_volume_command: get_volume_cmd = self.get_volume_command mixer_out = self.call_process(get_volume_cmd) except subprocess.CalledProcessError: return -1 if '[off]' in mixer_out: return -1 volgroups = re_vol.search(mixer_out) if volgroups: return int(volgroups.groups()[0]) else: # this shouldn't happen return -1 def draw(self): if self.theme_path: self.drawer.draw(offsetx=self.offset, width=self.length) else: widget.base._TextBox.draw(self) def cmd_mute(self): # Emulate button press. self.button_press(0, 0, BUTTON_MUTE) #endregion