comparison pui-application.c @ 55:24cba399757f

Add new setting "always-active" The setting determines whether the indicator status is set to "active" when packages are up to date, i.e. whether it is visible and/or can be interacted with. It defaults to true which reflects the previous behavior.
author Guido Berhoerster <guido+pui@berhoerster.name>
date Wed, 17 Aug 2022 16:55:17 +0200
parents c4b8785d0b75
children 08747f3a718b
comparison
equal deleted inserted replaced
54:b4b36627c1c1 55:24cba399757f
46 GtkWidget *about_dialog; 46 GtkWidget *about_dialog;
47 GIcon *icons[PUI_STATE_LAST]; 47 GIcon *icons[PUI_STATE_LAST];
48 PuiState state; 48 PuiState state;
49 gchar *update_command; 49 gchar *update_command;
50 gchar *error_message; 50 gchar *error_message;
51 gboolean always_active;
51 }; 52 };
52 53
53 G_DEFINE_TYPE(PuiApplication, pui_application, G_TYPE_APPLICATION) 54 G_DEFINE_TYPE(PuiApplication, pui_application, G_TYPE_APPLICATION)
54 55
55 enum { 56 enum {
56 PROP_0, 57 PROP_0,
57 PROP_UPDATE_COMMAND, 58 PROP_UPDATE_COMMAND,
59 PROP_ALWAYS_ACTIVE,
58 PROP_LAST 60 PROP_LAST
59 }; 61 };
60 62
61 extern gboolean restart; 63 extern gboolean restart;
62 64
187 g_error_free(error); 189 g_error_free(error);
188 } 190 }
189 } 191 }
190 192
191 static void 193 static void
194 update_indicator(PuiApplication *self, const gchar *title)
195 {
196 switch (self->state) {
197 case PUI_STATE_INITIAL:
198 app_indicator_set_status(self->indicator,
199 APP_INDICATOR_STATUS_PASSIVE);
200 break;
201 case PUI_STATE_UP_TO_DATE:
202 app_indicator_set_status(self->indicator, self->always_active ?
203 APP_INDICATOR_STATUS_ACTIVE :
204 APP_INDICATOR_STATUS_PASSIVE);
205 break;
206 case PUI_STATE_NORMAL_UPDATES_AVAILABLE: /* FALLTHGROUGH */
207 case PUI_STATE_IMPORTANT_UPDATES_AVAILABLE: /* FALLTHGROUGH */
208 case PUI_STATE_SESSION_RESTART_REQUIRED: /* FALLTHGROUGH */
209 case PUI_STATE_SYSTEM_RESTART_REQUIRED: /* FALLTHGROUGH */
210 case PUI_STATE_ERROR:
211 app_indicator_set_status(self->indicator,
212 APP_INDICATOR_STATUS_ACTIVE);
213 break;
214 }
215 app_indicator_set_icon_full(self->indicator, icon_names[self->state],
216 title);
217 }
218
219 static void
220 update_notification(PuiApplication *self, const gchar *title, const gchar *body)
221 {
222 GSimpleAction *install_updates_action;
223 GApplication *application = G_APPLICATION(self);
224 GNotification *notification = NULL;
225
226 install_updates_action =
227 G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(self),
228 "install-updates"));
229
230 switch (self->state) {
231 case PUI_STATE_INITIAL: /* FALLTHGROUGH */
232 case PUI_STATE_UP_TO_DATE: /* FALLTHGROUGH */
233 case PUI_STATE_ERROR:
234 /* withdraw exisiting notification */
235 g_application_withdraw_notification(application,
236 "package-updates-or-restart-required");
237 break;
238 case PUI_STATE_NORMAL_UPDATES_AVAILABLE: /* FALLTHGROUGH */
239 case PUI_STATE_IMPORTANT_UPDATES_AVAILABLE: /* FALLTHGROUGH */
240 case PUI_STATE_SESSION_RESTART_REQUIRED: /* FALLTHGROUGH */
241 case PUI_STATE_SYSTEM_RESTART_REQUIRED:
242 /* create notification */
243 notification = g_notification_new(title);
244 g_notification_set_body(notification, body);
245 g_notification_set_icon(notification, self->icons[self->state]);
246 g_notification_set_priority(notification,
247 G_NOTIFICATION_PRIORITY_NORMAL);
248 if (g_action_get_enabled(G_ACTION(install_updates_action))) {
249 g_notification_add_button(notification,
250 _("Install Updates"),
251 "app.install-updates");
252 }
253 g_application_send_notification(application,
254 "package-updates-or-restart-required", notification);
255 break;
256 }
257
258 if (notification != NULL) {
259 g_object_unref(notification);
260 }
261 }
262
263 static void
192 update_ui(PuiApplication *self) 264 update_ui(PuiApplication *self)
193 { 265 {
194 GSimpleAction *install_updates_action; 266 GSimpleAction *install_updates_action;
195 guint important_updates = 0; 267 guint important_updates = 0;
196 guint normal_updates = 0; 268 guint normal_updates = 0;
197 gchar *title = NULL; 269 gchar *title = NULL;
198 gchar *body = NULL; 270 gchar *body = NULL;
199 GApplication *application = G_APPLICATION(self); 271 GApplication *application = G_APPLICATION(self);
200 GNotification *notification = NULL;
201 272
202 install_updates_action = 273 install_updates_action =
203 G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(self), 274 G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(self),
204 "install-updates")); 275 "install-updates"));
205 276
283 case PUI_STATE_ERROR: 354 case PUI_STATE_ERROR:
284 title = g_strdup(self->error_message); 355 title = g_strdup(self->error_message);
285 break; 356 break;
286 } 357 }
287 358
288 /* indicator */ 359 update_indicator(self, title);
289 switch (self->state) { 360 update_notification(self, title, body);
290 case PUI_STATE_INITIAL:
291 app_indicator_set_status(self->indicator,
292 APP_INDICATOR_STATUS_PASSIVE);
293 break;
294 case PUI_STATE_UP_TO_DATE: /* FALLTHGROUGH */
295 case PUI_STATE_NORMAL_UPDATES_AVAILABLE: /* FALLTHGROUGH */
296 case PUI_STATE_IMPORTANT_UPDATES_AVAILABLE: /* FALLTHGROUGH */
297 case PUI_STATE_SESSION_RESTART_REQUIRED: /* FALLTHGROUGH */
298 case PUI_STATE_SYSTEM_RESTART_REQUIRED: /* FALLTHGROUGH */
299 case PUI_STATE_ERROR:
300 app_indicator_set_status(self->indicator,
301 APP_INDICATOR_STATUS_ACTIVE);
302 break;
303 }
304 app_indicator_set_icon_full(self->indicator, icon_names[self->state],
305 title);
306
307 /* notification */
308 switch (self->state) {
309 case PUI_STATE_INITIAL: /* FALLTHGROUGH */
310 case PUI_STATE_UP_TO_DATE: /* FALLTHGROUGH */
311 case PUI_STATE_ERROR:
312 /* withdraw exisiting notification */
313 g_application_withdraw_notification(application,
314 "package-updates-or-restart-required");
315 break;
316 case PUI_STATE_NORMAL_UPDATES_AVAILABLE: /* FALLTHGROUGH */
317 case PUI_STATE_IMPORTANT_UPDATES_AVAILABLE: /* FALLTHGROUGH */
318 case PUI_STATE_SESSION_RESTART_REQUIRED: /* FALLTHGROUGH */
319 case PUI_STATE_SYSTEM_RESTART_REQUIRED:
320 /* create notification */
321 notification = g_notification_new(title);
322 g_notification_set_body(notification, body);
323 g_notification_set_icon(notification, self->icons[self->state]);
324 g_notification_set_priority(notification,
325 G_NOTIFICATION_PRIORITY_NORMAL);
326 if (g_action_get_enabled(G_ACTION(install_updates_action))) {
327 g_notification_add_button(notification,
328 _("Install Updates"),
329 "app.install-updates");
330 }
331 g_application_send_notification(application,
332 "package-updates-or-restart-required", notification);
333 break;
334 }
335
336 if (notification != NULL) {
337 g_object_unref(notification);
338 }
339 361
340 g_debug("indicator icon: %s, notification title: \"%s\", " 362 g_debug("indicator icon: %s, notification title: \"%s\", "
341 "notification body: \"%s\"", icon_names[self->state], title, body); 363 "notification body: \"%s\"", icon_names[self->state], title, body);
342 364
343 g_free(body); 365 g_free(body);
476 /* load icons */ 498 /* load icons */
477 for (i = 0; i < G_N_ELEMENTS(self->icons); i++) { 499 for (i = 0; i < G_N_ELEMENTS(self->icons); i++) {
478 self->icons[i] = g_themed_icon_new(icon_names[i]); 500 self->icons[i] = g_themed_icon_new(icon_names[i]);
479 } 501 }
480 502
481 /* create settings */ 503 /* create settings backend */
482 self->settings = pui_settings_new(); 504 self->settings = pui_settings_new();
483 g_settings_bind(self->settings, "update-command", self,
484 "update-command", G_SETTINGS_BIND_GET);
485 505
486 /* start instantiating backend */ 506 /* start instantiating backend */
487 pui_backend_new_async(self->cancellable, on_pui_backend_finished, self); 507 pui_backend_new_async(self->cancellable, on_pui_backend_finished, self);
488 508
489 /* create indicator */ 509 /* create indicator */
498 menu = GTK_WIDGET(gtk_builder_get_object(builder, "menu")); 518 menu = GTK_WIDGET(gtk_builder_get_object(builder, "menu"));
499 gtk_widget_insert_action_group(menu, "app", G_ACTION_GROUP(self)); 519 gtk_widget_insert_action_group(menu, "app", G_ACTION_GROUP(self));
500 gtk_widget_show_all(menu); 520 gtk_widget_show_all(menu);
501 app_indicator_set_menu(self->indicator, GTK_MENU(menu)); 521 app_indicator_set_menu(self->indicator, GTK_MENU(menu));
502 522
523 /*
524 * bind settings to properties after indicator with its menu are
525 * initialized, if the setting "always-active" is set by the user the
526 * corresponding property is set accordingly which in turn invokes
527 * update_ui() so order matters here
528 */
529 g_settings_bind(self->settings, "update-command", self,
530 "update-command", G_SETTINGS_BIND_GET);
531 g_settings_bind(self->settings, "always-active", self,
532 "always-active", G_SETTINGS_BIND_GET);
533
534 /* ensure the ui reflects the current state */
503 update_ui(self); 535 update_ui(self);
504 536
505 /* keep GApplication running */ 537 /* keep GApplication running */
506 g_application_hold(application); 538 g_application_hold(application);
507 539
601 g_free(self->update_command); 633 g_free(self->update_command);
602 self->update_command = g_value_dup_string(value); 634 self->update_command = g_value_dup_string(value);
603 g_debug("property \"update-command\" set to \"%s\"", 635 g_debug("property \"update-command\" set to \"%s\"",
604 self->update_command); 636 self->update_command);
605 break; 637 break;
638 case PROP_ALWAYS_ACTIVE:
639 self->always_active = g_value_get_boolean(value);
640 g_debug("property \"always-active\" set to \"%s\"",
641 self->always_active ? "TRUE" : "FALSE");
642 update_ui(self);
643 break;
606 default: 644 default:
607 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 645 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
608 break; 646 break;
609 } 647 }
610 } 648 }
617 655
618 switch (property_id) { 656 switch (property_id) {
619 case PROP_UPDATE_COMMAND: 657 case PROP_UPDATE_COMMAND:
620 g_value_set_string(value, self->update_command); 658 g_value_set_string(value, self->update_command);
621 break; 659 break;
660 case PROP_ALWAYS_ACTIVE:
661 g_value_set_boolean(value, self->always_active);
662 break;
622 default: 663 default:
623 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 664 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
624 break; 665 break;
625 } 666 }
626 } 667 }
648 if (self->indicator != NULL) { 689 if (self->indicator != NULL) {
649 g_clear_object(&self->indicator); 690 g_clear_object(&self->indicator);
650 } 691 }
651 692
652 if (self->about_dialog != NULL) { 693 if (self->about_dialog != NULL) {
653 g_clear_pointer(&self->about_dialog, 694 g_clear_pointer(&self->about_dialog, gtk_widget_destroy);
654 (GDestroyNotify)(gtk_widget_destroy));
655 } 695 }
656 696
657 for (i = 0; i < G_N_ELEMENTS(self->icons); i++) { 697 for (i = 0; i < G_N_ELEMENTS(self->icons); i++) {
658 if (self->icons[i] != NULL) { 698 if (self->icons[i] != NULL) {
659 g_clear_object(&self->icons[i]); 699 g_clear_object(&self->icons[i]);
686 object_class->finalize = pui_application_finalize; 726 object_class->finalize = pui_application_finalize;
687 727
688 properties[PROP_UPDATE_COMMAND] = g_param_spec_string("update-command", 728 properties[PROP_UPDATE_COMMAND] = g_param_spec_string("update-command",
689 "Update command", "Command for installing updates", NULL, 729 "Update command", "Command for installing updates", NULL,
690 G_PARAM_READWRITE); 730 G_PARAM_READWRITE);
731 properties[PROP_ALWAYS_ACTIVE] = g_param_spec_boolean("always-active",
732 "Whether the indicator is always active",
733 "Whether the indicator is active even when packages are up to date",
734 TRUE, G_PARAM_READWRITE);
691 735
692 g_object_class_install_properties(object_class, PROP_LAST, properties); 736 g_object_class_install_properties(object_class, PROP_LAST, properties);
693 737
694 application_class->startup = pui_application_startup; 738 application_class->startup = pui_application_startup;
695 application_class->shutdown = pui_application_shutdown; 739 application_class->shutdown = pui_application_shutdown;