Mercurial > projects > pk-update-icon
view pkui-icon.c @ 56:63347002d746
Simplify PkuiBackend
Make the "check-interval" property construct-only since it is never changed at
runtime and schedule the first check for updates in the "constructed" method.
Remove unused property get methods.
Destroy PkClient and remove periodic check in the "dispose" method.
author | Guido Berhoerster <guido+pk-update-icon@berhoerster.name> |
---|---|
date | Sun, 01 Jul 2018 22:38:11 +0200 |
parents | b2f6b6b25703 |
children |
line wrap: on
line source
/* * (C) 2011 Guido Berhoerster <guido+pk-update-icon@berhoerster.name> * * Licensed under the GNU General Public License Version 2 * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <glib/gi18n.h> #include <libnotify/notify.h> #include "pkui-backend.h" #include "pkui-icon.h" G_DEFINE_TYPE(PkuiIcon, pkui_icon, G_TYPE_OBJECT) #ifndef UPDATE_VIEWER_COMMAND #define UPDATE_VIEWER_COMMAND "" #endif /* UPDATE_VIEWER_COMMAND */ #define PKUI_ICON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ PKUI_TYPE_ICON, PkuiIconPrivate)) struct _PkuiIconPrivate { PkuiBackend *backend; GtkStatusIcon *status_icon; GtkWidget *status_icon_popup_menu; NotifyNotification *notification; gchar **update_viewer_argv; }; static GtkWidget* icon_popup_menu_create(PkuiIcon *self); static void icon_popup_menu_popup(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data); static void icon_activated(GtkStatusIcon *status_icon, gpointer user_data); static void hide_notification(PkuiIcon *self); static void backend_state_changed(PkuiBackend *backend, gpointer user_data); static void update_viewer_exited(GPid pid, gint status, gpointer user_data); static void pkui_icon_finalize(GObject *gobject) { PkuiIcon *self = PKUI_ICON(gobject); gtk_widget_destroy(self->priv->status_icon_popup_menu); g_object_unref(self->priv->status_icon_popup_menu); g_object_unref(self->priv->status_icon); if (self->priv->notification != NULL) { notify_notification_close(self->priv->notification, NULL); g_object_unref(self->priv->notification); } g_object_unref(self->priv->backend); g_strfreev(self->priv->update_viewer_argv); G_OBJECT_CLASS(pkui_icon_parent_class)->finalize(gobject); } static void pkui_icon_class_init(PkuiIconClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); gobject_class->finalize = pkui_icon_finalize; g_type_class_add_private(klass, sizeof (PkuiIconPrivate)); } static void pkui_icon_init(PkuiIcon *self) { self->priv = PKUI_ICON_GET_PRIVATE(self); gtk_window_set_default_icon_name("system-software-update"); self->priv->status_icon_popup_menu = icon_popup_menu_create(self); g_object_ref(self->priv->status_icon_popup_menu); g_object_ref_sink(GTK_OBJECT(self->priv->status_icon_popup_menu)); self->priv->status_icon = gtk_status_icon_new(); gtk_status_icon_set_title(self->priv->status_icon, _("Software Updates")); gtk_status_icon_set_visible(self->priv->status_icon, FALSE); g_signal_connect(G_OBJECT(self->priv->status_icon), "activate", G_CALLBACK(icon_activated), self); g_signal_connect(G_OBJECT(self->priv->status_icon), "popup-menu", G_CALLBACK(icon_popup_menu_popup), self); self->priv->notification = NULL; self->priv->backend = NULL; self->priv->update_viewer_argv = NULL; } static void exec_update_viewer(PkuiIcon *self) { GError *error = NULL; GPid pid; g_return_if_fail(PKUI_IS_BACKEND(self->priv->backend)); g_return_if_fail(self->priv->update_viewer_argv != NULL); g_debug("executing update viewer command"); if (!g_spawn_async(NULL, self->priv->update_viewer_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &error)) { g_warning("Could not execute command: %s", error->message); g_error_free(error); return; } g_child_watch_add(pid, (GChildWatchFunc)update_viewer_exited, self); pkui_backend_set_inhibit_check(self->priv->backend, TRUE); hide_notification(self); } static void about_dialog_show(GtkMenuItem *item, gpointer user_data) { static const gchar *copyright = "Copyright \xc2\xa9 2011 Guido " "Berhoerster\nCopyright \xc2\xa9 2011 Pavol Rusnak\n"; static const gchar *authors[3] = { "Guido Berhoerster <guido+pk-update-icon@berhoerster.name>", "Pavol Rusnak <stick@gk2.sk>", NULL }; static const gchar *documenters[2] = { "Guido Berhoerster <guido+pk-update-icon@berhoerster.name>", NULL }; static const gchar *license = "Licensed under the GNU General Public License Version 2\n\n" "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 2 of " "the License, or (at your option) any later version.\n\n" "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.\n\n" "You should have received a copy of the GNU General Public License " "along with this program; if not, write to the Free Software " "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, " "MA 02110-1301 USA."; const gchar *translators = _("translators"); if (strcmp(translators, "translators") == 0) translators = NULL; gtk_show_about_dialog (NULL, "version", VERSION, "copyright", copyright, "authors", authors, "documenters", documenters, "translator-credits", translators, "license", license, "wrap-license", TRUE, NULL); } static void backend_check_now(GtkMenuItem *menu_item, gpointer user_data) { PkuiIcon *self = PKUI_ICON(user_data); g_return_if_fail(PKUI_IS_BACKEND(self->priv->backend)); pkui_backend_check_now(self->priv->backend); } static GtkWidget* icon_popup_menu_create(PkuiIcon *self) { GtkWidget *popup_menu = gtk_menu_new(); GtkWidget *item; GtkWidget *image; item = gtk_image_menu_item_new_with_mnemonic(_("_Check for Updates")); image = gtk_image_new_from_icon_name(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(backend_check_now), self); item = gtk_image_menu_item_new_with_mnemonic(_("_About")); image = gtk_image_new_from_icon_name(GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(about_dialog_show), self); gtk_widget_show_all(GTK_WIDGET(popup_menu)); return (popup_menu); } static void icon_popup_menu_popup(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data) { PkuiIcon *self = PKUI_ICON(user_data); gtk_menu_popup(GTK_MENU(self->priv->status_icon_popup_menu), NULL, NULL, NULL, NULL, button, activate_time); } static void notification_handle_action(NotifyNotification *notification, gchar *action, gpointer user_data) { PkuiIcon *self = PKUI_ICON(user_data); if (strcmp(action, "install-updates") == 0) { exec_update_viewer(self); } } static void update_notification(PkuiIcon *self, guint updates_normal, guint updates_important) { gchar *message; gchar *message_a; gchar *message_b; gchar *title = updates_important ? /* TRANSLATORS: This is a message without number mentioned */ ngettext("Important Software Update", "Important Software Updates", updates_important + updates_normal) : /* TRANSLATORS: This is a message without number mentioned */ ngettext("Software Update", "Software Updates", updates_important + updates_normal); gchar *icon = updates_important ? "software-update-urgent" : "software-update-available"; gchar *program = NULL; if (updates_important > 0) { if (updates_normal > 0) { message_a = g_strdup_printf( /* * TRANSLATORS: This sentence contains two plurals. * Texts related to these plurals are mixed. That is * why it is split in three parts. Fill first two parts * as you need, and use them as %s in the last one to * construct a sentence. Note that if the first form of * plural relates only to singular form, it is never * used, and dedicated shorter sentences are used. */ ngettext("There is %d software update available,", "There are %d software updates available,", updates_normal + updates_important), updates_normal + updates_important); /* * TRANSLATORS: This is the sentence part in the * middle, form of which is related to the first * number. If your language does not need it, simply * use it as space or so. */ message_b = ngettext("of it", "of them", updates_normal + updates_important); message = g_strdup_printf( /* * TRANSLATORS: This forms the sentence. If you need to * swap parts, use %3$s and %1$s etc. Plurals are * related to second number. */ ngettext("%s %d %s is important.", "%s %d %s are important.", updates_important), message_a, updates_important, message_b); g_free(message_a); } else { message = g_strdup_printf(ngettext("There is %d " "important software update available.", "There are %d important software updates " "available.", updates_important), updates_important); } } else { message = g_strdup_printf(ngettext("There is %d software " "update available.", "There are %d software updates available.", updates_normal), updates_normal); } gtk_status_icon_set_tooltip(self->priv->status_icon, message); gtk_status_icon_set_from_icon_name(self->priv->status_icon, icon); gtk_status_icon_set_visible(self->priv->status_icon, TRUE); if (self->priv->notification == NULL) { self->priv->notification = notify_notification_new(title, message, icon #if (NOTIFY_VERSION_MAJOR == 0 && NOTIFY_VERSION_MINOR < 7) , NULL #endif ); } else { notify_notification_update(self->priv->notification, title, message, icon); } notify_notification_clear_actions(self->priv->notification); program = (self->priv->update_viewer_argv != NULL) ? g_find_program_in_path(self->priv->update_viewer_argv[0]) : NULL; if (program != NULL) { notify_notification_add_action(self->priv->notification, "install-updates", ngettext("Install Update", "Install Updates", updates_normal + updates_important), notification_handle_action, self, NULL); } notify_notification_set_timeout(self->priv->notification, NOTIFY_EXPIRES_NEVER); notify_notification_set_urgency(self->priv->notification, updates_important ? NOTIFY_URGENCY_CRITICAL : NOTIFY_URGENCY_NORMAL); notify_notification_show(self->priv->notification, NULL); g_free(program); g_free(message); } static void hide_notification(PkuiIcon *self) { gtk_status_icon_set_visible(self->priv->status_icon, FALSE); notify_notification_close(self->priv->notification, NULL); } static void backend_state_changed(PkuiBackend *backend, gpointer user_data) { PkuiIcon *self = PKUI_ICON(user_data); guint updates_normal; guint updates_important; g_return_if_fail(PKUI_IS_BACKEND(backend)); updates_normal = pkui_backend_get_updates_normal(backend); updates_important = pkui_backend_get_updates_important(backend); if (updates_normal > 0 || updates_important > 0) update_notification(self, updates_normal, updates_important); else if (updates_normal + updates_important == 0) hide_notification(self); } static void update_viewer_exited(GPid pid, gint status, gpointer user_data) { PkuiIcon *self = PKUI_ICON(user_data); g_return_if_fail(PKUI_IS_BACKEND(self->priv->backend)); g_spawn_close_pid(pid); pkui_backend_check_now(self->priv->backend); pkui_backend_set_inhibit_check(self->priv->backend, FALSE); } static void icon_activated(GtkStatusIcon *status_icon, gpointer user_data) { PkuiIcon *self = PKUI_ICON(user_data); gchar *program = NULL; program = (self->priv->update_viewer_argv != NULL) ? g_find_program_in_path(self->priv->update_viewer_argv[0]) : NULL; if (program != NULL) { exec_update_viewer(self); } g_free(program); } PkuiIcon * pkui_icon_new(guint startup_delay, guint check_interval, const gchar *update_viewer_command) { GError *error = NULL; PkuiIcon *icon = g_object_new(PKUI_TYPE_ICON, NULL); if (update_viewer_command == NULL) { update_viewer_command = UPDATE_VIEWER_COMMAND; } if (!g_shell_parse_argv(update_viewer_command, NULL, &icon->priv->update_viewer_argv, &error)) { g_warning("Could not parse command: %s", error->message); g_error_free(error); } icon->priv->backend = pkui_backend_new(startup_delay, check_interval); g_signal_connect(icon->priv->backend, "state-changed", G_CALLBACK(backend_state_changed), icon); return (icon); }