[gnome-flashback] system-indicators: add power indicator



commit 35f3e43fa3ad42fd96abb1e5648cb9053209a956
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Wed Dec 25 01:11:12 2019 +0200

    system-indicators: add power indicator

 configure.ac                  |   1 +
 po/POTFILES.in                |   1 +
 system-indicators/Makefile.am |   2 +
 system-indicators/si-applet.c |  15 ++
 system-indicators/si-power.c  | 415 ++++++++++++++++++++++++++++++++++++++++++
 system-indicators/si-power.h  |  33 ++++
 6 files changed, 467 insertions(+)
---
diff --git a/configure.ac b/configure.ac
index c5bab88..ec9934e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -326,6 +326,7 @@ AS_IF([test "x$with_system_indicators" != "xno"], [
       gio-unix-2.0 >= $GLIB_REQUIRED
       gnome-bluetooth-1.0
       libgnome-panel
+      upower-glib
     ])
   ], [
     AS_IF([test "x$with_system_indicators" = "xyes"], [
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 687af59..65e5cda 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -46,3 +46,4 @@ gnome-flashback/libsound-applet/gvc-stream-status-icon.c
 system-indicators/si-bluetooth.c
 system-indicators/si-input-source.c
 system-indicators/si-module.c
+system-indicators/si-power.c
diff --git a/system-indicators/Makefile.am b/system-indicators/Makefile.am
index 96a8f47..8207589 100644
--- a/system-indicators/Makefile.am
+++ b/system-indicators/Makefile.am
@@ -30,6 +30,8 @@ system_indicators_la_SOURCES = \
        si-menu-bar.c \
        si-menu-bar.h \
        si-module.c \
+       si-power.c \
+       si-power.h \
        $(NULL)
 
 system_indicators_la_LIBADD = \
diff --git a/system-indicators/si-applet.c b/system-indicators/si-applet.c
index c2df05c..e1f5941 100644
--- a/system-indicators/si-applet.c
+++ b/system-indicators/si-applet.c
@@ -21,6 +21,7 @@
 #include "si-bluetooth.h"
 #include "si-input-source.h"
 #include "si-menu-bar.h"
+#include "si-power.h"
 
 struct _SiApplet
 {
@@ -30,10 +31,22 @@ struct _SiApplet
 
   SiIndicator *bluetooth;
   SiIndicator *input_source;
+  SiIndicator *power;
 };
 
 G_DEFINE_TYPE (SiApplet, si_applet, GP_TYPE_APPLET)
 
+static void
+append_power (SiApplet *self)
+{
+  GtkWidget *item;
+
+  self->power = si_power_new (GP_APPLET (self));
+
+  item = si_indicator_get_menu_item (self->power);
+  gtk_menu_shell_append (GTK_MENU_SHELL (self->menu_bar), item);
+}
+
 static void
 append_bluetooth (SiApplet *self)
 {
@@ -79,6 +92,7 @@ setup_applet (SiApplet *self)
 
   append_input_source (self);
   append_bluetooth (self);
+  append_power (self);
 }
 
 static void
@@ -97,6 +111,7 @@ si_applet_dispose (GObject *object)
 
   g_clear_object (&self->bluetooth);
   g_clear_object (&self->input_source);
+  g_clear_object (&self->power);
 
   G_OBJECT_CLASS (si_applet_parent_class)->dispose (object);
 }
diff --git a/system-indicators/si-power.c b/system-indicators/si-power.c
new file mode 100644
index 0000000..8dcd3b0
--- /dev/null
+++ b/system-indicators/si-power.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2019 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "si-power.h"
+
+#include <glib/gi18n.h>
+#include <gio/gdesktopappinfo.h>
+#include <libupower-glib/upower.h>
+#include <math.h>
+
+#include "dbus/gf-upower-device-gen.h"
+
+struct _SiPower
+{
+  SiIndicator        parent;
+
+  GtkWidget         *menu;
+
+  guint              bus_name_id;
+
+  GCancellable      *cancellable;
+
+  GfUPowerDeviceGen *device;
+};
+
+G_DEFINE_TYPE (SiPower, si_power, SI_TYPE_INDICATOR)
+
+static void
+activate_desktop_cb (GtkMenuItem *item,
+                     const char  *desktop_id)
+{
+  GDesktopAppInfo *info;
+  GError *error;
+
+  info = g_desktop_app_info_new (desktop_id);
+
+  if (info == NULL)
+    return;
+
+  error = NULL;
+  g_app_info_launch (G_APP_INFO (info), NULL, NULL, &error);
+
+  if (error != NULL)
+    {
+      g_warning ("%s", error->message);
+      g_error_free (error);
+    }
+
+  g_clear_object (&info);
+}
+
+static void
+free_desktop_id (gpointer  data,
+                 GClosure *closure)
+{
+  g_free (data);
+}
+
+static void
+remove_item_cb (GtkWidget *widget,
+                gpointer   data)
+{
+  gtk_widget_destroy (widget);
+}
+
+static const char *
+get_type_text (SiPower *self)
+{
+  UpDeviceKind type;
+
+  type = gf_upower_device_gen_get_type_ (self->device);
+
+  if (type == UP_DEVICE_KIND_UPS)
+    return _("UPS");
+
+  return _("Battery");
+}
+
+static char *
+get_state_text (SiPower *self)
+{
+  UpDeviceState state;
+  int64_t seconds;
+  double time;
+  double minutes;
+  double hours;
+  double percentage;
+
+  state = gf_upower_device_gen_get_state (self->device);
+
+  if (state == UP_DEVICE_STATE_FULLY_CHARGED)
+    return g_strdup (_("Fully Charged"));
+  else if (state == UP_DEVICE_STATE_EMPTY)
+    return g_strdup (_("Empty"));
+  else if (state == UP_DEVICE_STATE_CHARGING)
+    seconds = gf_upower_device_gen_get_time_to_full (self->device);
+  else if (state == UP_DEVICE_STATE_DISCHARGING)
+    seconds = gf_upower_device_gen_get_time_to_empty (self->device);
+  else if (state == UP_DEVICE_STATE_PENDING_CHARGE)
+    return g_strdup (_("Not Charging"));
+  else
+    return g_strdup (_("Estimating..."));
+
+  time = round (seconds / 60.0);
+
+  if (time == 0)
+    return g_strdup (_("Estimating..."));
+
+  minutes = fmod (time, 60);
+  hours = floor (time / 60);
+  percentage = gf_upower_device_gen_get_percentage (self->device);
+
+  if (state == UP_DEVICE_STATE_DISCHARGING)
+    {
+      /* Translators: this is <hours>:<minutes> Remaining (<percentage>) */
+      return g_strdup_printf (_("%.0f:%02.0f Remaining (%.0f%%)"),
+                              hours, minutes, percentage);
+    }
+
+  if (state == UP_DEVICE_STATE_CHARGING)
+    {
+      /* Translators: this is <hours>:<minutes> Until Full (<percentage>) */
+      return g_strdup_printf (_("%.0f:%02.0f Until Full (%.0f%%)"),
+                              hours, minutes, percentage);
+    }
+
+  return NULL;
+}
+
+static void
+update_indicator_menu (SiPower *self)
+{
+  const char *type_text;
+  char *state_text;
+  char *label;
+  GtkWidget *separator;
+  GtkWidget *item;
+
+  gtk_container_foreach (GTK_CONTAINER (self->menu), remove_item_cb, NULL);
+
+  type_text = get_type_text (self);
+  state_text = get_state_text (self);
+
+  label = g_strdup_printf ("%s: %s", type_text, state_text);
+  g_free (state_text);
+
+  item = gtk_menu_item_new_with_label (label);
+  g_free (label);
+
+  gtk_menu_shell_append (GTK_MENU_SHELL (self->menu), item);
+  gtk_widget_show (item);
+
+  g_signal_connect_data (item,
+                         "activate",
+                         G_CALLBACK (activate_desktop_cb),
+                         g_strdup ("org.gnome.PowerStats.desktop"),
+                         free_desktop_id,
+                         0);
+
+  separator = gtk_separator_menu_item_new ();
+  gtk_menu_shell_append (GTK_MENU_SHELL (self->menu), separator);
+  gtk_widget_show (separator);
+
+  item = gtk_menu_item_new_with_label (_("Power Settings"));
+  gtk_menu_shell_append (GTK_MENU_SHELL (self->menu), item);
+  gtk_widget_show (item);
+
+  g_signal_connect_data (item,
+                         "activate",
+                         G_CALLBACK (activate_desktop_cb),
+                         g_strdup ("gnome-power-panel.desktop"),
+                         free_desktop_id,
+                         0);
+}
+
+static void
+update_indicator_icon (SiPower *self)
+{
+  GpApplet *applet;
+  char *icon_name;
+
+  if (self->device == NULL)
+    return;
+
+  applet = si_indicator_get_applet (SI_INDICATOR (self));
+  icon_name = g_strdup (gf_upower_device_gen_get_icon_name (self->device));
+
+  if (icon_name != NULL && icon_name[0] != '\0')
+    {
+      if (!gp_applet_get_prefer_symbolic_icons (applet) &&
+          g_str_has_suffix (icon_name, "-symbolic"))
+        {
+          char *symbolic;
+
+          symbolic = g_strrstr (icon_name, "-symbolic");
+          g_strlcpy (symbolic, "", sizeof (symbolic));
+        }
+    }
+  else
+    {
+      g_free (icon_name);
+
+      if (gp_applet_get_prefer_symbolic_icons (applet))
+        icon_name = g_strdup ("battery-symbolic");
+      else
+        icon_name = g_strdup ("battery");
+    }
+
+  si_indicator_set_icon_name (SI_INDICATOR (self), icon_name);
+  g_free (icon_name);
+}
+
+static void
+update_indicator (SiPower *self)
+{
+  GtkWidget *menu_item;
+  char *tooltip;
+
+  menu_item = si_indicator_get_menu_item (SI_INDICATOR (self));
+
+  if (self->device == NULL ||
+      !gf_upower_device_gen_get_is_present (self->device))
+    {
+      gtk_widget_hide (menu_item);
+      return;
+    }
+
+  update_indicator_icon (self);
+  update_indicator_menu (self);
+
+  tooltip = get_state_text (self);
+  gtk_widget_set_tooltip_text (menu_item , tooltip);
+  g_free (tooltip);
+
+  gtk_widget_show (menu_item);
+}
+
+static void
+prefer_symbolic_icons_cb (GObject    *object,
+                          GParamSpec *pspec,
+                          SiPower    *self)
+{
+  update_indicator_icon (self);
+}
+
+static void
+properties_changed_cb (GDBusProxy *proxy,
+                       GVariant   *changed_properties,
+                       GStrv       invalidated_properties,
+                       SiPower    *self)
+{
+  update_indicator (self);
+}
+
+static void
+device_proxy_ready_cb (GObject      *source_object,
+                       GAsyncResult *res,
+                       gpointer      user_data)
+{
+  GError *error;
+  GfUPowerDeviceGen *device;
+  SiPower *self;
+
+  error = NULL;
+  device = gf_upower_device_gen_proxy_new_for_bus_finish (res, &error);
+
+  if (error != NULL)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        g_warning ("%s", error->message);
+
+      g_error_free (error);
+      return;
+    }
+
+  self = SI_POWER (user_data);
+  self->device = device;
+
+  g_signal_connect (self->device,
+                    "g-properties-changed",
+                    G_CALLBACK (properties_changed_cb),
+                    self);
+
+  update_indicator (self);
+}
+
+static void
+name_appeared_handler_cb (GDBusConnection *connection,
+                          const char      *name,
+                          const char      *name_owner,
+                          gpointer         user_data)
+{
+  SiPower *self;
+
+  self = SI_POWER (user_data);
+
+  g_cancellable_cancel (self->cancellable);
+  g_clear_object (&self->cancellable);
+
+  self->cancellable = g_cancellable_new ();
+
+  gf_upower_device_gen_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+                                          G_DBUS_PROXY_FLAGS_NONE,
+                                          "org.freedesktop.UPower",
+                                          "/org/freedesktop/UPower/devices/DisplayDevice",
+                                          self->cancellable,
+                                          device_proxy_ready_cb,
+                                          self);
+}
+
+static void
+name_vanished_handler_cb (GDBusConnection *connection,
+                          const char      *name,
+                          gpointer         user_data)
+{
+  SiPower *self;
+
+  self = SI_POWER (user_data);
+
+  g_clear_object (&self->device);
+  update_indicator (self);
+}
+
+static void
+si_power_constructed (GObject *object)
+{
+  SiPower *self;
+  GtkWidget *menu_item;
+  GpApplet *applet;
+
+  self = SI_POWER (object);
+
+  G_OBJECT_CLASS (si_power_parent_class)->constructed (object);
+
+  self->menu = gtk_menu_new ();
+
+  menu_item = si_indicator_get_menu_item (SI_INDICATOR (self));
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), self->menu);
+
+  applet = si_indicator_get_applet (SI_INDICATOR (self));
+
+  g_signal_connect (applet,
+                    "notify::prefer-symbolic-icons",
+                    G_CALLBACK (prefer_symbolic_icons_cb),
+                    self);
+
+  update_indicator (self);
+}
+
+static void
+si_power_dispose (GObject *object)
+{
+  SiPower *self;
+
+  self = SI_POWER (object);
+
+  if (self->bus_name_id)
+    {
+      g_bus_unwatch_name (self->bus_name_id);
+      self->bus_name_id = 0;
+    }
+
+  g_cancellable_cancel (self->cancellable);
+  g_clear_object (&self->cancellable);
+
+  g_clear_object (&self->device);
+
+  G_OBJECT_CLASS (si_power_parent_class)->dispose (object);
+}
+
+static void
+si_power_class_init (SiPowerClass *self_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (self_class);
+
+  object_class->constructed = si_power_constructed;
+  object_class->dispose = si_power_dispose;
+}
+
+static void
+si_power_init (SiPower *self)
+{
+  self->bus_name_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
+                                        "org.freedesktop.UPower",
+                                        G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                        name_appeared_handler_cb,
+                                        name_vanished_handler_cb,
+                                        self,
+                                        NULL);
+}
+
+SiIndicator *
+si_power_new (GpApplet *applet)
+{
+  return g_object_new (SI_TYPE_POWER,
+                       "applet", applet,
+                       NULL);
+}
diff --git a/system-indicators/si-power.h b/system-indicators/si-power.h
new file mode 100644
index 0000000..fe59544
--- /dev/null
+++ b/system-indicators/si-power.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SI_POWER_H
+#define SI_POWER_H
+
+#include <libgnome-panel/gp-applet.h>
+#include "si-indicator.h"
+
+G_BEGIN_DECLS
+
+#define SI_TYPE_POWER (si_power_get_type ())
+G_DECLARE_FINAL_TYPE (SiPower, si_power, SI, POWER, SiIndicator)
+
+SiIndicator *si_power_new (GpApplet *applet);
+
+G_END_DECLS
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]