From cc5d09509812c1feb4495b9db32f4d3f6e94d144 Mon Sep 17 00:00:00 2001
From: David Mohammed <fossfreedom@ubuntu.com>
Date: Fri, 26 Dec 2025 22:58:20 +0000
Subject: [PATCH] Restructure the project to use meson

---
 Makefile                                      |  35 ---
 README.md                                     |   9 +-
 .../BudgieSysMonitor.plugin.in                |   2 +-
 .../budgiesysmonitor.py                       |  24 +-
 budgie/budgiesysmonitor.py.in                 | 280 ++++++++++++++++++
 budgie/meson.build                            |  36 +++
 .../indicator-sysmonitor.desktop              |   0
 data/meson.build                              |   6 +
 .../indicator-sysmonitor                      |   6 +-
 indicator_sysmonitor/meson.build              |   7 +
 meson.build                                   |  16 +
 meson_options.txt                             |  13 +
 sysmonitor_common/meson.build                 |   8 +
 .../preferences.py                            |   9 +-
 .../preferences.ui                            |   0
 sensors.py => sysmonitor_common/sensors.py    |   4 +-
 16 files changed, 403 insertions(+), 52 deletions(-)
 delete mode 100644 Makefile
 rename BudgieSysMonitor.plugin => budgie/BudgieSysMonitor.plugin.in (93%)
 rename budgiesysmonitor.py => budgie/budgiesysmonitor.py (94%)
 create mode 100644 budgie/budgiesysmonitor.py.in
 create mode 100644 budgie/meson.build
 rename indicator-sysmonitor.desktop => data/indicator-sysmonitor.desktop (100%)
 create mode 100644 data/meson.build
 rename indicator-sysmonitor => indicator_sysmonitor/indicator-sysmonitor (98%)
 create mode 100644 indicator_sysmonitor/meson.build
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 sysmonitor_common/meson.build
 rename preferences.py => sysmonitor_common/preferences.py (98%)
 rename preferences.ui => sysmonitor_common/preferences.ui (100%)
 rename sensors.py => sysmonitor_common/sensors.py (99%)

diff --git a/Makefile b/Makefile
deleted file mode 100644
index 0cb5de9..0000000
--- a/Makefile
+++ /dev/null
@@ -1,35 +0,0 @@
-PREFIX=/usr
-BUDGIELIB=lib/budgie-desktop/plugins/budgiesysmonitor
-
-all:
-
-install:
-	mkdir -p "$(DESTDIR)$(PREFIX)/lib/indicator-sysmonitor"
-	cp indicator-sysmonitor "$(DESTDIR)$(PREFIX)/lib/indicator-sysmonitor"
-	cp preferences.py "$(DESTDIR)$(PREFIX)/lib/indicator-sysmonitor"
-	cp sensors.py "$(DESTDIR)$(PREFIX)/lib/indicator-sysmonitor"
-	cp preferences.ui "$(DESTDIR)$(PREFIX)/lib/indicator-sysmonitor"
-	mkdir -p "$(DESTDIR)$(PREFIX)/bin/"
-	ln -s ../lib/indicator-sysmonitor/indicator-sysmonitor "$(DESTDIR)$(PREFIX)/bin/indicator-sysmonitor"
-	mkdir -p "$(DESTDIR)$(PREFIX)/share/applications"
-	cp indicator-sysmonitor.desktop "$(DESTDIR)$(PREFIX)/share/applications/"
-	
-installbudgie:
-	mkdir -p "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	cp budgiesysmonitor.py "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	cp preferences.py "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	cp sensors.py "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	cp preferences.ui "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	cp BudgieSysMonitor.plugin "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	
-clean:
-	rm -rf ../*.xz ../*.deb ../*.tar.gz ../*.changes ../*.dsc ../*.upload ../*.build ../*.cdbs-config_list
-	
-uninstall:
-	rm -rf "$(DESTDIR)$(PREFIX)/lib/indicator-sysmonitor"
-	rm -f "$(DESTDIR)$(PREFIX)/bin/indicator-sysmonitor"
-	rm -f "$(DESTDIR)$(PREFIX)/share/applications/indicator-sysmonitor.desktop"
-	rm -rf "$(DESTDIR)$(PREFIX)/$(BUDGIELIB)"
-	# ~/.indicator-sysmonitor.json
-
-.PHONY: clean install all
diff --git a/README.md b/README.md
index 7fa2cd6..2f99c00 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Quick setup, suited to the desktop interfaces of at least GNOME, MATE and Budgie
+# Quick setup, suited to the desktop interfaces of at least GNOME, MATE, XFCE and Budgie
 
 ```Bash
 
@@ -13,9 +13,10 @@ Then:
 
 git clone https://github.com/fossfreedom/indicator-sysmonitor.git
 cd indicator-sysmonitor
-sudo make install
-cd ..
-rm -rf indicator-sysmonitor
+mkdir build
+cd build
+meson --prefix=/usr
+sudo meson install
 nohup indicator-sysmonitor &
 ```
 
diff --git a/BudgieSysMonitor.plugin b/budgie/BudgieSysMonitor.plugin.in
similarity index 93%
rename from BudgieSysMonitor.plugin
rename to budgie/BudgieSysMonitor.plugin.in
index 7bbc1e5..bb64f3e 100644
--- a/BudgieSysMonitor.plugin
+++ b/budgie/BudgieSysMonitor.plugin.in
@@ -1,5 +1,5 @@
 [Plugin]
-Loader=python3
+Loader=@PYTHON@
 Module=budgiesysmonitor
 Name=System Monitor
 Description=Panel System Monitor
diff --git a/budgiesysmonitor.py b/budgie/budgiesysmonitor.py
similarity index 94%
rename from budgiesysmonitor.py
rename to budgie/budgiesysmonitor.py
index d523858..e709e4b 100644
--- a/budgiesysmonitor.py
+++ b/budgie/budgiesysmonitor.py
@@ -12,21 +12,33 @@
 from gettext import gettext as _
 from gettext import textdomain, bindtextdomain
 import gi
-gi.require_version('Budgie', '1.0')
-from gi.repository import Budgie, GObject, GLib
 import sys
+sys.path.insert(0, '/usr/share/indicator-sysmonitor')
 import os
 import logging
 import json
 import tempfile
 from threading import Event
 
-gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
+from gi.repository import Gdk, GdkX11
+is_wayland = not isinstance(Gdk.Display.get_default(), GdkX11.X11Display)
+
+if is_wayland == True:
+    gi.require_version('Budgie', '3.0')
+else:
+    try:
+        gi.require_version('Budgie', '2.0')
+    except:
+        gi.require_version('Budgie', '1.0')
+
+from gi.repository import Budgie, GObject, GLib
+
 from gi.repository import Gtk
 
-from preferences import Preferences
-from preferences import __version__
-from sensors import SensorManager
+from sysmonitor_common.preferences import Preferences
+from sysmonitor_common.preferences import __version__
+from sysmonitor_common.sensors import SensorManager
 
 logging.basicConfig(level=logging.INFO)
 
diff --git a/budgie/budgiesysmonitor.py.in b/budgie/budgiesysmonitor.py.in
new file mode 100644
index 0000000..9d19a22
--- /dev/null
+++ b/budgie/budgiesysmonitor.py.in
@@ -0,0 +1,280 @@
+#!/usr/bin/python3
+# coding: utf-8
+#
+# A simple indicator applet displaying cpu and memory information
+# for the budgie-desktop
+#
+# Author: fossfreedom <foss.freedom@gmail.com>
+# Original Homepage: http://launchpad.net/indicator-sysmonitor
+# Homepage: https://github.com/fossfreedom/indicator-sysmonitor
+# License: GPL v3
+#
+from gettext import gettext as _
+from gettext import textdomain, bindtextdomain
+import gi
+gi.require_version('Budgie', '1.0')
+from gi.repository import Budgie, GObject, GLib
+import sys
+import os
+import logging
+import json
+import tempfile
+from threading import Event
+
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+from sysmonitor_common/preferences import Preferences
+from sysmonitor_common/preferences import __version__
+from sysmonitor_common/sensors import SensorManager
+
+logging.basicConfig(level=logging.INFO)
+
+HELP_MSG = """<span underline="single" size="x-large">{title}</span>
+
+{introduction}
+
+{basic}
+• cpu: {cpu_desc}
+• mem: {mem_desc}
+• bat<i>%d</i>: {bat_desc}
+• net: {net_desc}
+• netcomp: {netcomp_desc}
+• totalnet: {totalnet_desc}
+• upordown: {upordown_desc}
+• publicip: {publicip_desc}
+
+{compose}
+• fs//<i>mount-point</i> : {fs_desc}
+
+<big>{example}</big>
+CPU {{cpu}} | MEM {{mem}} | root {{fs///}}
+""".format(
+    title=_("Help Page"),
+    introduction=_("The sensors are the names of the devices from which you want to retrive information. They must be placed between brackets."),
+    basic=_("The basics are:"),
+    cpu_desc=_("It shows the average of CPU usage."),
+    mem_desc=_("It shows the physical memory in use."),
+    bat_desc=_("It shows the available battery which id is %d."),
+    net_desc=_("It shows the amount of data you are downloading and uploading through your network."),
+    netcomp_desc=_("It shows the amount of data you are downloading and uploading through your network in a compact way."),
+    totalnet_desc=("It shows the total amount of data you downloaded and uploaded through your network."),
+    upordown_desc=_("It shows whether your internet connection is up or down (the sensor is refreshed every 10 seconds)."),
+    publicip_desc=_("It shows your public IP address (the sensor is refreshed every 10 minutes)."),
+    compose=_("Also there are the following sensors that are composed with two parts divided by two slashes."),
+    fs_desc=_("Show available space in the file system."),
+    example=_("Example:"))
+
+
+class IndicatorSysmonitor(object):
+    SENSORS_DISABLED = False
+
+    def __init__(self):
+        self._preferences_dialog = None
+        self._help_dialog = None
+
+        self.ind = Gtk.Button.new()
+        self.ind.set_label("Init...")
+
+        self._create_menu()
+
+        self.alive = Event()
+        self.alive.set()
+
+        self.sensor_mgr = SensorManager()
+        self.load_settings()
+
+    def _create_menu(self):
+        """Creates the main menu and shows it."""
+        # create menu {{{
+        menu = Gtk.Menu()
+        # add System Monitor menu item
+        full_sysmon = Gtk.MenuItem(_('System Monitor'))
+        full_sysmon.connect('activate', self.on_full_sysmon_activated)
+        menu.add(full_sysmon)
+        menu.add(Gtk.SeparatorMenuItem())
+
+        # add preferences menu item
+        pref_menu = Gtk.MenuItem(_('Preferences'))
+        pref_menu.connect('activate', self.on_preferences_activated)
+        menu.add(pref_menu)
+
+        # add help menu item
+        help_menu = Gtk.MenuItem(_('Help'))
+        help_menu.connect('activate', self._on_help)
+        menu.add(help_menu)
+
+        menu.show_all()
+
+        self.popup = menu
+        self.ind.connect('clicked', self.popup_menu)
+        logging.info("Menu shown")
+        # }}} menu done!
+
+    def popup_menu(self, *args):
+        self.popup.popup(None, None, None, None, 0, Gtk.get_current_event_time())
+
+    def update_indicator_guide(self):
+
+        guide = self.sensor_mgr.get_guide()
+
+    def update(self, data):
+        # data is the dict of all sensors and their values
+        # { name, label }
+
+        # look through data and find out if there are any icons to be set
+        for sensor in data:
+            test_str = data[sensor].lower()
+            if "use_icon" in test_str:
+                path = data[sensor].split(":")[1]
+                print(path)
+                self.ind.set_icon_full(path, "")
+                # now strip the icon output from data so that it is not displayed
+                remaining = test_str.split("use_icon")[0].strip()
+                if not remaining:
+                    remaining = " "
+
+                data[sensor] = remaining
+
+            if "clear_icon" in test_str:
+                self.ind.set_icon_full(self.tindicator, "")
+
+                remaining = test_str.split("clear_icon")[0].strip()
+                if not remaining:
+                    remaining = " "
+
+                data[sensor] = remaining
+
+        label = self.sensor_mgr.get_label(data)
+
+
+        def update_label(label):
+            self.ind.set_label(label)
+            return False
+        if label and self.ind:
+            GLib.idle_add(update_label, label.strip())
+
+    def load_settings(self):
+
+        self.sensor_mgr.load_settings()
+        self.sensor_mgr.initiate_fetcher(self)
+        self.update_indicator_guide()
+
+    # @staticmethod
+    def save_settings(self):
+        self.sensor_mgr.save_settings()
+
+    def update_settings(self):
+        self.sensor_mgr.initiate_fetcher(self)
+
+    # actions raised from menu
+    def on_preferences_activated(self, event=None):
+        """Raises the preferences dialog. If it's already open, it's
+        focused"""
+        if self._preferences_dialog is not None:
+            self._preferences_dialog.present()
+            return
+
+        self._preferences_dialog = Preferences(self)
+        self._preferences_dialog.run()
+        self._preferences_dialog = None
+
+    def on_full_sysmon_activated(self, event=None):
+        if GLib.find_program_in_path('mate-system-monitor') is not None:
+            os.system('mate-system-monitor &')
+            return
+
+        if GLib.find_program_in_path('gnome-system-monitor') is not None:
+            os.system('gnome-system-monitor &')
+
+    def on_exit(self, event=None, data=None):
+        """Action call when the main programs is closed."""
+        # cleanup temporary indicator icon
+        os.remove(self.tindicator)
+        # close the open dialogs
+        if self._help_dialog is not None:
+            self._help_dialog.destroy()
+
+        if self._preferences_dialog is not None:
+            self._preferences_dialog.destroy()
+
+        logging.info("Terminated")
+        self.alive.clear()  # DM: why bother with Event() ???
+
+        try:
+            Gtk.main_quit()
+        except RuntimeError:
+            pass
+
+    def _on_help(self, event=None, data=None):
+        """Raise a dialog with info about the app."""
+        if self._help_dialog is not None:
+            self._help_dialog.present()
+            return
+
+        self._help_dialog = Gtk.MessageDialog(
+            None, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO,
+            Gtk.ButtonsType.OK, None)
+
+        self._help_dialog.set_title(_("Help"))
+        self._help_dialog.set_markup(HELP_MSG)
+        self._help_dialog.run()
+        self._help_dialog.destroy()
+        self._help_dialog = None
+
+class BudgieSysMonitor(GObject.Object, Budgie.Plugin):
+    """ This is simply an entry point into the SysMonitor applet
+        Note you must always override Object, and implement Plugin.
+    """
+
+    # Good manners, make sure we have unique name in GObject type system
+    __gtype_name__ = "BudgieSysMonitor"
+
+    def __init__(self):
+        """ Initialisation is important.
+        """
+        GObject.Object.__init__(self)
+
+    def do_get_panel_widget(self, uuid):
+        """ This is where the real fun happens. Return a new Budgie.Applet
+            instance with the given UUID. The UUID is determined by the
+            BudgiePanelManager, and is used for lifetime tracking.
+        """
+        return BudgieSysMonitorApplet(uuid)
+
+class BudgieSysMonitorApplet(Budgie.Applet):
+    """ Budgie.Applet is in fact a Gtk.Bin """
+
+    button = None
+
+    def __init__(self, uuid):
+        Budgie.Applet.__init__(self)
+
+        # Add a button to our UI
+        logging.info("start")
+
+        if not os.path.exists(SensorManager.SETTINGS_FILE):
+            sensor_mgr = SensorManager()
+            sensor_mgr.save_settings()
+        else:
+            try:
+                with open(SensorManager.SETTINGS_FILE,"r") as f:
+                    cfg = json.load(f)
+                f.close()
+            except:
+                settings = {
+                    'custom_text': 'cpu: {cpu} mem: {mem}',
+                    'interval': 2,
+                    'on_startup': False,
+                    'sensors': {
+                    }
+                }
+                with open(SensorManager.SETTINGS_FILE,"w") as f:
+                    f.write(json.dumps(settings, indent=4, ensure_ascii=False))
+                f.close()
+
+        self.app = IndicatorSysmonitor()
+        self.button = self.app.ind
+        self.button.set_relief(Gtk.ReliefStyle.NONE)
+        self.add(self.button)
+        self.show_all()
diff --git a/budgie/meson.build b/budgie/meson.build
new file mode 100644
index 0000000..e0a78c8
--- /dev/null
+++ b/budgie/meson.build
@@ -0,0 +1,36 @@
+libdir = get_option('libdir')
+
+# Prefer newest ABI first
+budgie_pc_names = [
+  'budgie-3.0',
+  'budgie-2.0',
+  'budgie-1.0',
+]
+
+budgie_dep = dependency(
+  budgie_pc_names,
+  required: true
+)
+
+message('Using Budgie ABI: ' + budgie_dep.name())
+
+budgie_plugin_dir = libdir / 'budgie-desktop' / 'plugins' / 'budgiesysmonitor'
+
+install_data(
+  'budgiesysmonitor.py',
+  install_dir: budgie_plugin_dir,
+  install_mode: 'rwxr-xr-x'
+)
+
+budgie_2 = get_option('for-wayland')
+
+plugininstall = configure_file(
+    input: 'BudgieSysMonitor.plugin.in',
+    output: 'BudgieSysMonitor.plugin',
+    configuration: {'PYTHON': budgie_2 ? 'python' : 'python3' }
+)
+
+install_data(
+  plugininstall,
+  install_dir: budgie_plugin_dir
+)
diff --git a/indicator-sysmonitor.desktop b/data/indicator-sysmonitor.desktop
similarity index 100%
rename from indicator-sysmonitor.desktop
rename to data/indicator-sysmonitor.desktop
diff --git a/data/meson.build b/data/meson.build
new file mode 100644
index 0000000..13200b5
--- /dev/null
+++ b/data/meson.build
@@ -0,0 +1,6 @@
+datadir = get_option('datadir')
+
+install_data(
+  'indicator-sysmonitor.desktop',
+  install_dir: datadir / 'applications'
+)
diff --git a/indicator-sysmonitor b/indicator_sysmonitor/indicator-sysmonitor
similarity index 98%
rename from indicator-sysmonitor
rename to indicator_sysmonitor/indicator-sysmonitor
index 6a3b54d..8047853 100755
--- a/indicator-sysmonitor
+++ b/indicator_sysmonitor/indicator-sysmonitor
@@ -12,6 +12,8 @@
 import logging
 import os
 import sys
+sys.path.insert(0, '/usr/share/indicator-sysmonitor')
+
 import json
 import tempfile
 from argparse import ArgumentParser
@@ -29,8 +31,8 @@ except ValueError:
 
 from gi.repository import GLib, Gtk
 
-from preferences import __version__, Preferences
-from sensors import SensorManager
+from sysmonitor_common.preferences import __version__, Preferences
+from sysmonitor_common.sensors import SensorManager
 
 textdomain("indicator-sysmonitor")
 bindtextdomain("indicator-sysmonitor", "./lang")
diff --git a/indicator_sysmonitor/meson.build b/indicator_sysmonitor/meson.build
new file mode 100644
index 0000000..dac2a3c
--- /dev/null
+++ b/indicator_sysmonitor/meson.build
@@ -0,0 +1,7 @@
+bindir = get_option('bindir')
+
+install_subdir(
+  '.',
+  install_dir: bindir,
+  install_mode: 'rwxr-xr-x'
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..3b11ded
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,16 @@
+project(
+  'indicator-sysmonitor',
+  version: '0.11.0',
+  meson_version: '>= 0.59'
+)
+
+python = import('python').find_installation()
+
+subdir('sysmonitor_common')
+subdir('indicator_sysmonitor')
+subdir('data')
+#subdir('icons')
+
+if get_option('budgie')
+  subdir('budgie')
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..09aa6eb
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,13 @@
+option(
+  'budgie',
+  type: 'boolean',
+  value: false,
+  description: 'Enable Budgie Desktop plugin support'
+)
+
+option(
+  'for-wayland',
+  type: 'boolean',
+  value: false,
+  description: 'build with wayland support'
+)
diff --git a/sysmonitor_common/meson.build b/sysmonitor_common/meson.build
new file mode 100644
index 0000000..96ff820
--- /dev/null
+++ b/sysmonitor_common/meson.build
@@ -0,0 +1,8 @@
+datadir = get_option('datadir')
+
+shared_dir = datadir / 'indicator-sysmonitor' / 'sysmonitor_common'
+
+install_subdir(
+  '.',
+  install_dir: shared_dir
+)
diff --git a/preferences.py b/sysmonitor_common/preferences.py
similarity index 98%
rename from preferences.py
rename to sysmonitor_common/preferences.py
index 4a1e8af..897b200 100644
--- a/preferences.py
+++ b/sysmonitor_common/preferences.py
@@ -19,11 +19,14 @@
 from gi.repository import Gtk
 from gi.repository import Gio
 
-from sensors import SensorManager
-from sensors import ISMError
+import sys
+sys.path.insert(0, '/usr/share/indicator-sysmonitor')
 
+from sysmonitor_common.sensors import SensorManager
+from sysmonitor_common.sensors import ISMError
 
-__version__ = '0.10.2'
+
+__version__ = '0.11.0'
 
 
 def raise_dialog(parent, flags, type_, buttons, msg, title):
diff --git a/preferences.ui b/sysmonitor_common/preferences.ui
similarity index 100%
rename from preferences.ui
rename to sysmonitor_common/preferences.ui
diff --git a/sensors.py b/sysmonitor_common/sensors.py
similarity index 99%
rename from sensors.py
rename to sysmonitor_common/sensors.py
index 861b8ad..abe6bc4 100755
--- a/sensors.py
+++ b/sysmonitor_common/sensors.py
@@ -276,7 +276,9 @@ def get_results(self):
             """Return a dict whose element are the sensors
             and their values"""
             res = {}
-            from preferences import Preferences
+            import sys
+            sys.path.insert(0, '/usr/share/indicator-sysmonitor')
+            from sysmonitor_common.preferences import Preferences
 
             # We call this only once per update
             global cpu_load
