[gnome-flashback] system-indicators: add power indicator
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] system-indicators: add power indicator
- Date: Tue, 24 Dec 2019 23:21:32 +0000 (UTC)
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]