From c40a1744637b84682731d015420456d35b004182 Mon Sep 17 00:00:00 2001 From: Logan Connolly Date: Tue, 25 Jan 2022 17:50:25 +0100 Subject: [PATCH 01/17] feat(theme): add rose pine theme --- themes/rose-pine.json | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 themes/rose-pine.json diff --git a/themes/rose-pine.json b/themes/rose-pine.json new file mode 100644 index 0000000..e1ce49b --- /dev/null +++ b/themes/rose-pine.json @@ -0,0 +1,54 @@ +{ + "icons": ["awesome-fonts"], + "defaults": { + "separator-block-width": 0, + "warning": { + "fg": "#232136", + "bg": "#f6c177" + }, + "critical": { + "fg": "#232136", + "bg": "#eb6f92" + } + }, + "cycle": [ + { "fg": "#232136", "bg": "#ea9a97" }, + { "fg": "#e0def4", "bg": "#393552" } + ], + "dnf": { + "good": { + "fg": "#232136", + "bg": "#9ccfd8" + } + }, + "pacman": { + "good": { + "fg": "#232136", + "bg": "#9ccfd8" + } + }, + "battery": { + "charged": { + "fg": "#232136", + "bg": "#9ccfd8" + }, + "AC": { + "fg": "#232136", + "bg": "#9ccfd8" + } + }, + "pomodoro": { + "paused": { + "fg": "#232136", + "bg": "#f6c177" + }, + "work": { + "fg": "#232136", + "bg": "#9ccfd8" + }, + "break": { + "fg": "#232136", + "bg": "#c4a7e7" + } + } +} From 4c08cd812e7c436113c7e88245ea929dc35fef44 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Wed, 9 Feb 2022 21:15:08 +0100 Subject: [PATCH 02/17] Create codeql-analysis.yml Trying out CodeQL --- .github/workflows/codeql-analysis.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..5e39422 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '31 0 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 8458eef1e60fa19d862977b2b08c484e0261d55c Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Wed, 9 Feb 2022 21:24:35 +0100 Subject: [PATCH 03/17] [doc] add codeql badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 59533bc..ba6261f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ [![Code Climate](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/gpa.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status) [![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage) [![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status) +[![CodeQL](https://github.com/tobi-wan-kenobi/bumblebee-status/actions/workflows/codeql-analysis.yml/badge.svg?branch=main)](https://github.com/tobi-wan-kenobi/bumblebee-status/actions/workflows/codeql-analysis.yml) ![License](https://img.shields.io/github/license/tobi-wan-kenobi/bumblebee-status) **Many, many thanks to all contributors! I am still amazed by and deeply grateful for how many PRs this project gets.** From 4f9553f7ea4ca9d9166980384669c451b74cd019 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Fri, 11 Feb 2022 13:44:10 +0100 Subject: [PATCH 04/17] [modules/rss] fix insecure use of tempfile fixes #850 --- bumblebee_status/modules/contrib/rss.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bumblebee_status/modules/contrib/rss.py b/bumblebee_status/modules/contrib/rss.py index 7b8c032..7824e2e 100644 --- a/bumblebee_status/modules/contrib/rss.py +++ b/bumblebee_status/modules/contrib/rss.py @@ -55,7 +55,7 @@ class Module(core.module.Module): self._state = [] - self._newspaper_filename = tempfile.mktemp(".html") + self._newspaper_file = tempfile.NamedTemporaryFile(mode="w", suffix=".html") self._last_refresh = 0 self._last_update = 0 @@ -308,10 +308,11 @@ class Module(core.module.Module): while newspaper_items: content += self._create_news_section(newspaper_items) - open(self._newspaper_filename, "w").write( + self._newspaper_file.write( HTML_TEMPLATE.replace("[[CONTENT]]", content) ) - webbrowser.open("file://" + self._newspaper_filename) + self._newspaper_file.flush() + webbrowser.open("file://" + self._newspaper_file.name) self._update_history("newspaper") self._save_history() From 5c390be25cba3338c858e0fb77e4d446515fd5b1 Mon Sep 17 00:00:00 2001 From: Christopher Kepes Date: Sat, 12 Feb 2022 11:06:10 +0100 Subject: [PATCH 05/17] [modules/nic] Added strength indicator for wifi signals --- bumblebee_status/modules/core/nic.py | 46 ++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/bumblebee_status/modules/core/nic.py b/bumblebee_status/modules/core/nic.py index 7dde2f0..591fe1c 100644 --- a/bumblebee_status/modules/core/nic.py +++ b/bumblebee_status/modules/core/nic.py @@ -13,7 +13,9 @@ Parameters: * nic.exclude: Comma-separated list of interface prefixes (supporting regular expressions) to exclude (defaults to 'lo,virbr,docker,vboxnet,veth,br,.*:avahi') * nic.include: Comma-separated list of interfaces to include * nic.states: Comma-separated list of states to show (prefix with '^' to invert - i.e. ^down -> show all devices that are not in state down) - * nic.format: Format string (defaults to '{intf} {state} {ip} {ssid}') + * nic.format: Format string (defaults to '{intf} {state} {ip} {ssid} {strength}') + * nic.strength_warning: Integer to set the threshold for warning state (defaults to 50) + * nic.strength_critical: Integer to set the threshold for critical state (defaults to 30) """ import re @@ -28,7 +30,7 @@ import util.format class Module(core.module.Module): - @core.decorators.every(seconds=10) + @core.decorators.every(seconds=5) def __init__(self, config, theme): widgets = [] super().__init__(config, theme, widgets) @@ -45,7 +47,15 @@ class Module(core.module.Module): self._states["exclude"].append(state[1:]) else: self._states["include"].append(state) - self._format = self.parameter("format", "{intf} {state} {ip} {ssid}") + self._format = self.parameter("format", "{intf} {state} {ip} {ssid} {strength}") + + self._strength_threshold_critical = self.parameter("strength_critical", 30) + self._strength_threshold_warning = self.parameter("strength_warning", 50) + + # Limits for the accepted dBm values of wifi strength + self.__strength_dbm_lower_bound = -110 + self.__strength_dbm_upper_bound = -30 + self.iw = shutil.which("iw") self._update_widgets(widgets) @@ -64,6 +74,13 @@ class Module(core.module.Module): iftype = "wireless" if self._iswlan(intf) else "wired" iftype = "tunnel" if self._istunnel(intf) else iftype + # "strength" is none if interface type is not wlan + if self._iswlan(intf): + if widget.get("strength") < self._strength_threshold_critical: + states.append("critical") + elif widget.get("strength") < self._strength_threshold_warning: + states.append("warning") + states.append("{}-{}".format(iftype, widget.get("state"))) return states @@ -116,6 +133,9 @@ class Module(core.module.Module): ): continue + strength_dbm = self.get_strength_dbm(intf) + strength_percent = self.convert_strength_dbm_percent(strength_dbm) + widget = self.widget(intf) if not widget: widget = self.add_widget(name=intf) @@ -126,12 +146,14 @@ class Module(core.module.Module): ip=", ".join(addr), intf=intf, state=state, + strength=str(strength_percent) + "%" if strength_percent else "", ssid=self.get_ssid(intf), ).split() ) ) widget.set("intf", intf) widget.set("state", state) + widget.set("strength", strength_percent) def get_ssid(self, intf): if not self._iswlan(intf) or self._istunnel(intf) or not self.iw: @@ -145,5 +167,23 @@ class Module(core.module.Module): return "" + def get_strength_dbm(self, intf): + if not self._iswlan(intf) or self._istunnel(intf) or not self.iw: + return None + + with open("/proc/net/wireless", "r") as file: + for line in file: + if intf in line: + # Remove trailing . by slicing it off ;) + strength_dbm = line.split()[3][:-1] + return util.format.asint(strength_dbm, + minium=self.__strength_dbm_lower_bound, + maximum=self.__strength_dbm_upper_bound) + + return None + + def convert_strength_dbm_percent(self, signal): + return int(100 * ((signal + 100) / 70.0)) if signal else None + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 From 4784be40762601c656ce8964c15c11d556ab8b0d Mon Sep 17 00:00:00 2001 From: Pi-Yueh Chuang Date: Sat, 12 Feb 2022 12:54:31 -0500 Subject: [PATCH 06/17] typo in nic.py: minium -> minimum --- bumblebee_status/modules/core/nic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bumblebee_status/modules/core/nic.py b/bumblebee_status/modules/core/nic.py index 591fe1c..94a9e20 100644 --- a/bumblebee_status/modules/core/nic.py +++ b/bumblebee_status/modules/core/nic.py @@ -177,7 +177,7 @@ class Module(core.module.Module): # Remove trailing . by slicing it off ;) strength_dbm = line.split()[3][:-1] return util.format.asint(strength_dbm, - minium=self.__strength_dbm_lower_bound, + minimum=self.__strength_dbm_lower_bound, maximum=self.__strength_dbm_upper_bound) return None From 2a77e3a85c1f59318a7538028314e0edde9c3b57 Mon Sep 17 00:00:00 2001 From: Mihai Morariu Date: Mon, 14 Feb 2022 15:36:24 +0200 Subject: [PATCH 07/17] Fix exception in location.py. --- bumblebee_status/modules/contrib/sun.py | 10 +++++++++- bumblebee_status/util/location.py | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bumblebee_status/modules/contrib/sun.py b/bumblebee_status/modules/contrib/sun.py index e9eefd2..34a4b71 100644 --- a/bumblebee_status/modules/contrib/sun.py +++ b/bumblebee_status/modules/contrib/sun.py @@ -39,7 +39,11 @@ class Module(core.module.Module): self.__sun = None if not lat or not lon: - lat, lon = util.location.coordinates() + try: + lat, lon = util.location.coordinates() + except Exception: + pass + if lat and lon: self.__sun = Sun(float(lat), float(lon)) @@ -55,6 +59,10 @@ class Module(core.module.Module): return "n/a" def __calculate_times(self): + if not self.__sun: + self.__sunset = self.__sunrise = None + return + self.__isup = False order_matters = True diff --git a/bumblebee_status/util/location.py b/bumblebee_status/util/location.py index 12242ea..e48b71a 100644 --- a/bumblebee_status/util/location.py +++ b/bumblebee_status/util/location.py @@ -59,11 +59,11 @@ def __load(): __next = time.time() + 60 * 30 # error - try again every 30m -def __get(name, default=None): +def __get(name): global __data if not __data or __expired(): __load() - return __data.get(name, default) + return __data[name] def reset(): From 3aadab5628f0b4f839428231e28f1d7ab9d60d0c Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Mon, 14 Feb 2022 14:58:01 +0100 Subject: [PATCH 08/17] [modules/publicip] handle missing public ip more gracefully If location does not throw, but reports an empty public IP, return "n/a". Since this caused a bug, also add a test for it. fixes #853 --- bumblebee_status/modules/contrib/publicip.py | 4 ++-- tests/modules/contrib/test_publicip.py | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/bumblebee_status/modules/contrib/publicip.py b/bumblebee_status/modules/contrib/publicip.py index 17a23e3..a74d708 100644 --- a/bumblebee_status/modules/contrib/publicip.py +++ b/bumblebee_status/modules/contrib/publicip.py @@ -16,13 +16,13 @@ class Module(core.module.Module): self.__ip = "" def public_ip(self, widget): - return self.__ip + return self.__ip or "n/a" def update(self): try: self.__ip = util.location.public_ip() except Exception: - self.__ip = "n/a" + self.__ip = None # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/contrib/test_publicip.py b/tests/modules/contrib/test_publicip.py index 9584bd7..870ede6 100644 --- a/tests/modules/contrib/test_publicip.py +++ b/tests/modules/contrib/test_publicip.py @@ -26,6 +26,15 @@ class PublicIPTest(TestCase): assert widget(module).full_text() == '5.12.220.2' + @mock.patch('util.location.public_ip') + def test_public_ip(self, public_ip_mock): + public_ip_mock.return_value = None + + module = build_module() + module.update() + + assert widget(module).full_text() == 'n/a' + @mock.patch('util.location.public_ip') def test_public_ip_with_exception(self, public_ip_mock): public_ip_mock.side_effect = Exception From 03731136b6f2147ded54ce2881eddc4b1dba5d83 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Tue, 15 Feb 2022 16:34:02 +0100 Subject: [PATCH 09/17] [modules/nic] fix missing check for None --- bumblebee_status/modules/core/nic.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bumblebee_status/modules/core/nic.py b/bumblebee_status/modules/core/nic.py index 94a9e20..09fe487 100644 --- a/bumblebee_status/modules/core/nic.py +++ b/bumblebee_status/modules/core/nic.py @@ -75,10 +75,11 @@ class Module(core.module.Module): iftype = "tunnel" if self._istunnel(intf) else iftype # "strength" is none if interface type is not wlan - if self._iswlan(intf): - if widget.get("strength") < self._strength_threshold_critical: + strength = widget.get("strength") + if self._iswlan(intf) and strength: + if strength < self._strength_threshold_critical: states.append("critical") - elif widget.get("strength") < self._strength_threshold_warning: + elif strength < self._strength_threshold_warning: states.append("warning") states.append("{}-{}".format(iftype, widget.get("state"))) From 928f8258aabf5cb05b709fa3740099218d5acae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=BCftinger?= Date: Sun, 20 Feb 2022 12:29:49 +0100 Subject: [PATCH 10/17] fix case of Kelvin SI unit in redshift widget --- bumblebee_status/modules/core/redshift.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bumblebee_status/modules/core/redshift.py b/bumblebee_status/modules/core/redshift.py index c6735b1..d50463f 100644 --- a/bumblebee_status/modules/core/redshift.py +++ b/bumblebee_status/modules/core/redshift.py @@ -54,7 +54,7 @@ def get_redshift_value(module): for line in res.split("\n"): line = line.lower() if "temperature" in line: - widget.set("temp", line.split(" ")[2]) + widget.set("temp", line.split(" ")[2].upper()) if "period" in line: state = line.split(" ")[1] if "day" in state: From 950931e1b9e9619d556a57e3a576e2dc1b6bbc51 Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Mon, 28 Feb 2022 19:14:21 +0100 Subject: [PATCH 11/17] added new module 'pactl' * added new module 'pactl' which displays the current default sink and allows to select a different default sink from the popup menu. --- bumblebee_status/modules/contrib/pactl.py | 142 ++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 bumblebee_status/modules/contrib/pactl.py diff --git a/bumblebee_status/modules/contrib/pactl.py b/bumblebee_status/modules/contrib/pactl.py new file mode 100644 index 0000000..0abea68 --- /dev/null +++ b/bumblebee_status/modules/contrib/pactl.py @@ -0,0 +1,142 @@ +# pylint: disable=C0111,R0903 + +""" Displays the current default sink. + + Left click opens a popup menu that lists all available sinks and allows to change the default sink. + + Per default, this module uses the sink names returned by "pactl list sinks short" + + sample output of "pactl list sinks short": + + 2 alsa_output.pci-0000_00_1f.3.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED + 3 alsa_output.usb-Logitech_Logitech_USB_Headset-00.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDE + + As "alsa_output.usb-Logitech_Logitech_USB_Headset-00.analog-stereo" is not a particularly nice name, its possible to map the name to more a + user friendly name. e.g to map "alsa_output.usb-Logitech_Logitech_USB_Headset-00.analog-stereo" to the name "Headset", add the following + bumblebee-status config entry: pactl.alsa_output.usb-Logitech_Logitech_USB_Headset-00.analog-stereo=Headset + + The module also allows to specify individual (unicode) icons for all the sinks. e.g in order to use the icon 🎧 for the + "alsa_output.usb-Logitech_Logitech_USB_Headset-00.analog-stereo" sink, add the following bumblebee-status config entry: + pactl.icon.alsa_output.usb-Logitech_Logitech_USB_Headset-00.analog-stereo=🎧 + + Requirements: + * pulseaudio + * pactl +""" + +import logging +import functools + +import core.module +import core.widget +import core.input + +import util.cli +import util.popup + + +class Sink(object): + def __init__(self, id, internal_name, friendly_name, icon): + super().__init__() + self.__id = id + self.__internal_name = internal_name + self.__friendly_name = friendly_name + self.__icon = icon + + @property + def id(self): + return self.__id + + @property + def internal_name(self): + return self.__internal_name + + @property + def friendly_name(self): + return self.__friendly_name + + @property + def icon(self): + return self.__icon + + @property + def display_name(self): + display_name = ( + self.__icon + " " + self.__friendly_name + if self.__icon != "" + else self.__friendly_name + ) + return display_name + + +class Module(core.module.Module): + def __init__(self, config, theme): + super().__init__(config, theme, core.widget.Widget(self.default_sink)) + + self.__default_sink = None + + res = util.cli.execute("pactl list sinks short") + lines = res.splitlines() + + self.__sinks = [] + for line in lines: + info = line.split("\t") + try: + friendly_name = self.parameter(info[1], info[1]) + icon = self.parameter("icon." + info[1], "") + self.__sinks.append(Sink(info[0], info[1], friendly_name, icon)) + except: + logging.exception("Couldn't parse sink") + pass + + core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.popup) + + def __sink(self, internal_sink_name): + for sink in self.__sinks: + logging.info(sink.internal_name) + if internal_sink_name == sink.internal_name: + return sink + return None + + def update(self): + try: + res = util.cli.execute("pactl info") + lines = res.splitlines() + self.__default_sink = None + for line in lines: + if not line.startswith("Default Sink:"): + continue + internal_sink_name = line.replace("Default Sink: ", "") + self.__default_sink = self.__sink(internal_sink_name) + break + except Exception as e: + logging.exception("Could not get pactl info") + self.__default_sink = None + + def default_sink(self, widget): + if self.__default_sink is None: + return "unknown" + return self.__default_sink.display_name + + def __on_sink_selected(self, sink): + try: + util.cli.execute("pactl set-default-sink {}".format(sink.id)) + self.__default_sink = sink + except Exception as e: + logging.exception("Couldn't set default sink") + + def popup(self, widget): + menu = util.popup.menu() + + for sink in self.__sinks: + menu.add_menuitem( + sink.friendly_name, + callback=functools.partial(self.__on_sink_selected, sink), + ) + menu.show(widget) + + def state(self, widget): + return [] + + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 From 33d22c2637f0b667182b9b0c3a7b7db2b60578fd Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Mon, 28 Feb 2022 19:20:19 +0100 Subject: [PATCH 12/17] removed debug log from 'pactl' module --- bumblebee_status/modules/contrib/pactl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bumblebee_status/modules/contrib/pactl.py b/bumblebee_status/modules/contrib/pactl.py index 0abea68..cd62c9a 100644 --- a/bumblebee_status/modules/contrib/pactl.py +++ b/bumblebee_status/modules/contrib/pactl.py @@ -93,7 +93,6 @@ class Module(core.module.Module): def __sink(self, internal_sink_name): for sink in self.__sinks: - logging.info(sink.internal_name) if internal_sink_name == sink.internal_name: return sink return None From 07200c466bd746b4076db0547093f467d8c70254 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Wed, 2 Mar 2022 12:33:02 +0100 Subject: [PATCH 13/17] [themes] add zengarden light (powerline) --- themes/zengarden-powerline-light.json | 64 +++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 themes/zengarden-powerline-light.json diff --git a/themes/zengarden-powerline-light.json b/themes/zengarden-powerline-light.json new file mode 100644 index 0000000..ecf7de5 --- /dev/null +++ b/themes/zengarden-powerline-light.json @@ -0,0 +1,64 @@ +{ + "icons": [ "paxy97", "awesome-fonts" ], + "defaults": { + "warning": { + "fg": "#353839", + "bg": "#967117" + }, + "critical": { + "fg": "#353839", + "bg": "#ba1d58" + }, + "default-separators": false, + "separator-block-width": 0 + }, + "fg": "#353839", + "bg": "#c4b6a3", + "dnf": { + "good": { + "fg": "#353839", + "bg": "#177245" + } + }, + "apt": { + "good": { + "fg": "#353839", + "bg": "#177245" + } + }, + "battery": { + "charged": { + "fg": "#353839", + "bg": "#177245" + }, + "AC": { + "fg": "#353839", + "bg": "#177245" + } + }, + "bluetooth": { + "ON": { + "fg": "#353839", + "bg": "#177245" + } + }, + "git": { + "modified": { "bg": "#174572" }, + "deleted": { "bg": "#ba1d58" }, + "new": { "bg": "#967117" } + }, + "pomodoro": { + "paused": { + "fg": "#353839", + "bg": "#d79921" + }, + "work": { + "fg": "#353839", + "bg": "#177245" + }, + "break": { + "fg": "#353839", + "bg": "#177245" + } + } +} From 9a2e7637c9d5c6d4098b3bcff548dbf4045d31a2 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Wed, 2 Mar 2022 16:16:24 +0100 Subject: [PATCH 14/17] [themes/zengarden] lighter accents --- themes/zengarden-powerline-light.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/themes/zengarden-powerline-light.json b/themes/zengarden-powerline-light.json index ecf7de5..7fe0bc5 100644 --- a/themes/zengarden-powerline-light.json +++ b/themes/zengarden-powerline-light.json @@ -3,11 +3,11 @@ "defaults": { "warning": { "fg": "#353839", - "bg": "#967117" + "bg": "#b38a32" }, "critical": { "fg": "#353839", - "bg": "#ba1d58" + "bg": "#d94070" }, "default-separators": false, "separator-block-width": 0 @@ -17,29 +17,29 @@ "dnf": { "good": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" } }, "apt": { "good": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" } }, "battery": { "charged": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" }, "AC": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" } }, "bluetooth": { "ON": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" } }, "git": { @@ -54,11 +54,11 @@ }, "work": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" }, "break": { "fg": "#353839", - "bg": "#177245" + "bg": "#378c5d" } } } From c57daf65ce6da29d405570e1de09adbc9bad779b Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Thu, 3 Mar 2022 14:31:47 +0100 Subject: [PATCH 15/17] [themes/zengarden] add key colors --- themes/zengarden-powerline-light.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/themes/zengarden-powerline-light.json b/themes/zengarden-powerline-light.json index 7fe0bc5..097842a 100644 --- a/themes/zengarden-powerline-light.json +++ b/themes/zengarden-powerline-light.json @@ -60,5 +60,19 @@ "fg": "#353839", "bg": "#378c5d" } - } + }, + "keys": { + "Key.cmd": { + "bg": "#477ab7" + }, + "Key.shift": { + "bg": "#b38a32" + }, + "Key.ctrl": { + "bg": "#377c8b" + }, + "Key.alt": { + "bg": "#e05b1f" + } + } } From 7d33171749b0109ad55bb88b6dafc9b011b12f83 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Fri, 4 Mar 2022 09:35:43 +0100 Subject: [PATCH 16/17] [core/input] methods can be event callbacks When registering an event (especially mouse events), if the parameter is a valid method in the Module, execute that with the event as parameter. Add this in the core.spacer module as an example. fixes #858 see #857 --- bumblebee_status/core/input.py | 3 +++ bumblebee_status/modules/core/spacer.py | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bumblebee_status/core/input.py b/bumblebee_status/core/input.py index 2f9fdfc..5752dd8 100644 --- a/bumblebee_status/core/input.py +++ b/bumblebee_status/core/input.py @@ -54,8 +54,11 @@ def register(obj, button=None, cmd=None, wait=False): event_id = __event_id(obj.id if obj is not None else "", button) logging.debug("registering callback {}".format(event_id)) core.event.unregister(event_id) # make sure there's always only one input event + if callable(cmd): core.event.register_exclusive(event_id, cmd) + elif obj and hasattr(obj, cmd) and callable(getattr(obj, cmd)): + core.event.register_exclusive(event_id, lambda event: getattr(obj, cmd)(event)) else: core.event.register_exclusive(event_id, lambda event: __execute(event, cmd, wait)) diff --git a/bumblebee_status/modules/core/spacer.py b/bumblebee_status/modules/core/spacer.py index 7e4453a..e5a2d5e 100644 --- a/bumblebee_status/modules/core/spacer.py +++ b/bumblebee_status/modules/core/spacer.py @@ -9,7 +9,7 @@ Parameters: import core.module import core.widget import core.decorators - +import core.input class Module(core.module.Module): @core.decorators.every(minutes=60) @@ -20,5 +20,8 @@ class Module(core.module.Module): def text(self, _): return self.__text + def update_text(self, event): + self.__text = core.input.button_name(event["button"]) + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 From 9cbc39e462df8b2f732d22c1821938fef680bc4f Mon Sep 17 00:00:00 2001 From: Sadegh Hamedani Date: Fri, 4 Mar 2022 18:28:13 +0330 Subject: [PATCH 17/17] [contrib] added module persian_date --- .../modules/contrib/persian_date.py | 45 +++++++++++++++++++ themes/icons/awesome-fonts.json | 1 + 2 files changed, 46 insertions(+) create mode 100644 bumblebee_status/modules/contrib/persian_date.py diff --git a/bumblebee_status/modules/contrib/persian_date.py b/bumblebee_status/modules/contrib/persian_date.py new file mode 100644 index 0000000..6e3eded --- /dev/null +++ b/bumblebee_status/modules/contrib/persian_date.py @@ -0,0 +1,45 @@ +# pylint: disable=C0111,R0903 + +"""Displays the current date and time in Persian(Jalali) Calendar. + +Requires the following python packages: + * jdatetime + +Parameters: + * datetime.format: strftime()-compatible formatting string. default: "%A %d %B" e.g., "جمعه ۱۳ اسفند" + * datetime.locale: locale to use. default: "fa_IR" +""" + +from __future__ import absolute_import +import jdatetime +import locale + +import core.module +import core.widget +import core.input + + +class Module(core.module.Module): + def __init__(self, config, theme): + super().__init__(config, theme, core.widget.Widget(self.full_text)) + + l = ("fa_IR", "UTF-8") + lcl = self.parameter("locale", ".".join(l)) + try: + locale.setlocale(locale.LC_ALL, lcl.split(".")) + except Exception as e: + locale.setlocale(locale.LC_ALL, ("fa_IR", "UTF-8")) + + def default_format(self): + return "%A %d %B" + + def full_text(self, widget): + enc = locale.getpreferredencoding() + fmt = self.parameter("format", self.default_format()) + retval = jdatetime.datetime.now().strftime(fmt) + if hasattr(retval, "decode"): + return retval.decode(enc) + return retval + + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/themes/icons/awesome-fonts.json b/themes/icons/awesome-fonts.json index 9f14da9..f85dfd8 100644 --- a/themes/icons/awesome-fonts.json +++ b/themes/icons/awesome-fonts.json @@ -7,6 +7,7 @@ "default-separators": false }, "date": { "prefix": "" }, + "persian_date": { "prefix": "" }, "time": { "prefix": "" }, "datetime": { "prefix": "" }, "datetz": { "prefix": "" },