Commit 35f3e43f authored by Alberts Muktupāvels's avatar Alberts Muktupāvels
Browse files

system-indicators: add power indicator

parent 6c2f2a05
......@@ -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"], [
......
......@@ -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
......@@ -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 = \
......
......@@ -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);
}
......
/*
* 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);
}
/*
* 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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment