Commits

jjacky  committed 2111a44

add "Re-show last notifications" feature; move CmdLineLink option from Misc to News

It is now possible to have kalu re-show all notifications from the last ran checks. New option is the menu, and avaialble as action on single/double click.

All notifications from the last ran checks will be shown as they were originally (including action buttons), including any error notifications.
Should be noted that the tooltip doesn't display status from the last ran check, but last known info. Meaning if the last checks failed (e.g. Inernet connection was down), the tooltip will still show data from the (successful) check before, while re-show notifs will only show the error notification(s).

  • Participants
  • Parent commits 3c7cd8c

Comments (0)

Files changed (8)

                     {
                         *on_click = DO_TOGGLE_WINDOWS;
                     }
+                    else if (strcmp (value, "LAST_NOTIFS") == 0)
+                    {
+                        *on_click = DO_LAST_NOTIFS;
+                    }
                     else
                     {
                         add_error ("unknown value for %s: %s", key, value);
 
 extern kalpm_state_t kalpm_state;
 
+
+void
+free_notif (notif_t *notif)
+{
+    if (!notif)
+    {
+        return;
+    }
+    
+    free (notif->summary);
+    free (notif->text);
+    if (notif->type == CHECK_NEWS || notif->type == CHECK_AUR)
+    {
+        /* CHECK_NEWS has xml_news; CHECK_AUR has cmdline w/ $PACKAGES replaced */
+        free (notif->data);
+    }
+    else
+    {
+        /* CHECK_UPGRADES, CHECK_WATCHED & CHECK_WATCHED_AUR all use packages */
+        FREE_PACKAGE_LIST (notif->data);
+    }
+    free (notif);
+}
+
+void
+show_notif (notif_t *notif)
+{
+    NotifyNotification *notification;
+    
+    debug ("showing notif: %s", notif->summary);
+    notification = new_notification (notif->summary, notif->text);
+    if (notif->type & CHECK_UPGRADES)
+    {
+        if (   config->check_pacman_conflict
+            && is_pacman_conflicting ((alpm_list_t *) notif->data))
+        {
+            notify_notification_add_action (notification, "do_conflict_warn",
+                "Possible pacman/kalu conflict...",
+                (NotifyActionCallback) show_pacman_conflict,
+                NULL, NULL);
+        }
+        if (config->action != UPGRADE_NO_ACTION)
+        {
+            notify_notification_add_action (notification, "do_updates",
+                "Update system...", (NotifyActionCallback) action_upgrade,
+                NULL, NULL);
+        }
+    }
+    else if (notif->type & CHECK_AUR)
+    {
+        notify_notification_add_action (notification,
+                                        "do_updates_aur",
+                                        "Update AUR packages...",
+                                        (NotifyActionCallback) action_upgrade,
+                                        notif->data,
+                                        NULL);
+    }
+    else if (notif->type & CHECK_WATCHED)
+    {
+        notify_notification_add_action (notification,
+                                        "mark_watched",
+                                        "Mark packages...",
+                                        (NotifyActionCallback) action_watched,
+                                        notif->data,
+                                        NULL);
+    }
+    else if (notif->type & CHECK_WATCHED_AUR)
+    {
+        notify_notification_add_action (notification,
+                                        "mark_watched_aur",
+                                        "Mark packages...",
+                                        (NotifyActionCallback) action_watched_aur,
+                                        notif->data,
+                                        NULL);
+    }
+    else if (notif->type & CHECK_NEWS)
+    {
+        notify_notification_add_action (notification,
+                                        "mark_news",
+                                        "Show news...",
+                                        (NotifyActionCallback) action_news,
+                                        notif->data,
+                                        NULL);
+    }
+    /* we use a callback on "closed" to unref it, because when there's an action
+     * we need to keep a ref, otherwise said action won't work */
+    g_signal_connect (G_OBJECT (notification), "closed",
+                      G_CALLBACK (notification_closed_cb), NULL);
+    notify_notification_show (notification, NULL);
+}
+
 gboolean
 show_error_cmdline (gchar *arg[])
 {
     GError *error = NULL;
     
     set_kalpm_busy (TRUE);
+    debug ("run cmdline: %s", cmdline);
     if (!g_spawn_command_line_sync (cmdline, NULL, NULL, NULL, &error))
     {
         /* we can't just show the error message from here, because this is ran
 }
 
 static void
+show_last_notifs (void)
+{
+    alpm_list_t *i;
+    
+    for (i = config->last_notifs; i; i = alpm_list_next (i))
+    {
+        show_notif ((notif_t *) i->data);
+    }
+}
+
+static void
 menu_check_cb (GtkMenuItem *item _UNUSED_, gpointer data _UNUSED_)
 {
     kalu_check (FALSE);
     GtkWidget   *image;
     guint        pos = 0;
     
-    menu = gtk_menu_new();
+    menu = gtk_menu_new ();
+    
+    item = gtk_image_menu_item_new_with_label ("Re-show last notifications...");
+    gtk_widget_set_sensitive (item, !kalpm_state.is_busy && config->last_notifs);
+    image = gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU);
+    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+    gtk_widget_set_tooltip_text (item, "Show notifications from last ran checks");
+    g_signal_connect (G_OBJECT (item), "activate",
+                      G_CALLBACK (show_last_notifs), NULL);
+    gtk_widget_show (item);
+    gtk_menu_attach (GTK_MENU (menu), item, 0, 1, pos, pos + 1); ++pos;
+    
+    item = gtk_separator_menu_item_new ();
+    gtk_widget_show (item);
+    gtk_menu_attach (GTK_MENU (menu), item, 0, 1, pos, pos + 1); ++pos;
     
     item = gtk_image_menu_item_new_with_label ("Check for Upgrades...");
     gtk_widget_set_sensitive (item, !kalpm_state.is_busy);
         {                                           \
             toggle_open_windows ();                 \
         }                                           \
+        else if (on_click == DO_LAST_NOTIFS)        \
+        {                                           \
+            show_last_notifs ();                    \
+        }                                           \
     } while (0)
 
 static gboolean
 /* notify */
 #include <libnotify/notify.h>
 
+#define FREE_NOTIFS_LIST(p)                                                 \
+            do                                                              \
+            {                                                               \
+                alpm_list_free_inner (p, (alpm_list_fn_free) free_notif);   \
+                alpm_list_free (p);                                         \
+                p = NULL;                                                   \
+            } while(0)
+
+
+void
+free_notif (notif_t *notif);
+
+void
+show_notif (notif_t *notif);
+
 gboolean
 show_error_cmdline (gchar *arg[]);
 
     DO_NOTHING = 0,
     DO_CHECK,
     DO_SYSUPGRADE,
-    DO_TOGGLE_WINDOWS
+    DO_TOGGLE_WINDOWS,
+    DO_LAST_NOTIFS
 } on_click_t;
 
 typedef enum {
     #endif
     
     gboolean         is_curl_init;
+    #ifndef DISBALE_UPDATER
+    alpm_list_t     *last_notifs;
+    #endif
 } config_t;
 
 typedef struct _watched_package_t {
     gint        nb_news;
 } kalpm_state_t;
 
+typedef struct _notif_t {
+    check_t     type;
+    gchar      *summary;
+    gchar      *text;
+    gpointer    data;
+} notif_t;
+
 /* global variable */
 extern config_t *config;
 
-void
-debug (const char *fmt, ...);
+void debug (const char *fmt, ...);
 
 void free_package (kalu_package_t *package);
 void free_watched_package (watched_package_t *w_pkg);
 might differ.
 For example, images are not supported.
 
-Links are processed through B<xdg-open(1)> to be opened in your default browser.
+Links are opened using the command-line specified in B<PREFERENCES>, by default
+using B<xdg-open(1)> to be opened them in your default browser.
 
 =back
 
 
 =over
 
+=item I<Command line to open links>
+
+The command line to be executed when a link (on news) is clicked. Use variable
+B<$URL> as placeholder for the full URL to be opened.
+
+=back
+
+=over
+
 =item I<Notification template>
 
 =over
 
 Does the same as the menu by the same name, that is open the window to manage
 (add, edit, remove) the list of watched packages. This list is independent from
-the preferences, as data are saved in a different file, as saving the list will
+the preferences, its data are saved in a different file, and saving the list will
 not have an effect on preferences, and vice versa.
 
 =item I<Notification template>
 
 Does the same as the menu by the same name, that is open the window to manage
 (add, edit, remove) the list of watched AUR packages. This list is independent
-from the preferences, as data are saved in a different file, as saving the list
+from the preferences, its data are saved in a different file, and saving the list
 will not have an effect on preferences, and vice versa.
 
 =item I<Notification template>
 window is hidden, an indication will be featured on the tooltip (" +" next to
 "kalu") and triggering the action again will then show all hidden windows.
 
+=item B<* Re-show last notifications...>
+
+Will re-show all notifications resulting from the last time checks were ran
+(automatic or manual).
+
 =back
 
-=item I<Command line to open links (in news)>
-
-The command line to be executed when a link (on news) is clicked. Use variable
-B<$URL> as placeholder for the full URL to be opened.
-
 =back
 
 =head1 SYSTEM UPGRADE
         }                                                           \
     }
 
-static void
-free_packages (alpm_list_t *packages)
-{
-    FREE_PACKAGE_LIST (packages);
-}
-
 #endif /* DISABLE_GUI*/
 
 static void
     double      size_h;
     replacement_t *replacements[7];
     GString    *string_pkgs = NULL;     /* list of AUR packages */
-    gchar      *cmdline;                /* cmdline w/ $PACKAGES replaced */
     
     #ifdef DISABLE_GUI
     (void) xml_news;
     #ifndef DISABLE_GUI
     }
     
-    NotifyNotification *notification;
+    notif_t *notif;
+    notif = malloc (sizeof (*notif));
+    notif->type = type;
+    notif->summary = summary;
+    notif->text = text;
+    notif->data = NULL;
     
-    notification = new_notification (summary, text);
-    if (type & CHECK_UPGRADES)
+    if (type & CHECK_AUR)
     {
-        if (config->check_pacman_conflict && is_pacman_conflicting (packages))
+        if (config->cmdline_aur && string_pkgs)
         {
-            notify_notification_add_action (notification, "do_conflict_warn",
-                "Possible pacman/kalu conflict...",
-                (NotifyActionCallback) show_pacman_conflict,
-                NULL, NULL);
+            /* if we have a list of pkgs, update the cmdline */
+            notif->data = strreplace (config->cmdline_aur, "$PACKAGES", string_pkgs->str);
+            g_string_free (string_pkgs, TRUE);
         }
-        if (config->action != UPGRADE_NO_ACTION)
-        {
-            notify_notification_add_action (notification, "do_updates",
-                "Update system...", (NotifyActionCallback) action_upgrade,
-                NULL, NULL);
-        }
-    }
-    else if (type & CHECK_AUR)
-    {
-        if (config->cmdline_aur)
-        {
-            if (string_pkgs)
-            {
-                /* if we have a list of pkgs, update the cmdline */
-                cmdline = strreplace (config->cmdline_aur, "$PACKAGES", string_pkgs->str);
-                g_string_free (string_pkgs, TRUE);
-            }
-            else
-            {
-                /* else no user data, so it'll default to config->cmdline_aur
-                 * So we'll always be able to call free (cmdline) in action_upgrade */
-                cmdline = NULL;
-            }
-            
-            notify_notification_add_action (notification,
-                                            "do_updates_aur",
-                                            "Update AUR packages...",
-                                            (NotifyActionCallback) action_upgrade,
-                                            cmdline,
-                                            (GFreeFunc) free);
-        }
-    }
-    else if (type & CHECK_WATCHED)
-    {
-        notify_notification_add_action (notification,
-                                        "mark_watched",
-                                        "Mark packages...",
-                                        (NotifyActionCallback) action_watched,
-                                        packages,
-                                        (GFreeFunc) free_packages);
-    }
-    else if (type & CHECK_WATCHED_AUR)
-    {
-        notify_notification_add_action (notification,
-                                        "mark_watched_aur",
-                                        "Mark packages...",
-                                        (NotifyActionCallback) action_watched_aur,
-                                        packages,
-                                        (GFreeFunc) free_packages);
+        /* else no user data, so it'll default to config->cmdline_aur
+         * So we'll always be able to call free (cmdline) in action_upgrade */
     }
     else if (type & CHECK_NEWS)
     {
-        notify_notification_add_action (notification,
-                                        "mark_news",
-                                        "Show news...",
-                                        (NotifyActionCallback) action_news,
-                                        xml_news,
-                                        (GFreeFunc) free);
+        notif->data = xml_news;
     }
-    /* we use a callback on "closed" to unref it, because when there's an action
-     * we need to keep a ref, otherwise said action won't work */
-    g_signal_connect (G_OBJECT (notification), "closed",
-                      G_CALLBACK (notification_closed_cb), NULL);
-    notify_notification_show (notification, NULL);
-    free (summary);
-    free (text);
+    else
+    {
+        /* CHECK_UPGRADES, CHECK_WATCHED & CHECK_WATCHED_AUR all use packages */
+        notif->data = packages;
+    }
+    
+    /* add the notif to the last of last notifications, so we can re-show it later */
+    debug ("adding new notif (%s) to last_notifs", notif->summary);
+    config->last_notifs = alpm_list_add (config->last_notifs, notif);
+    /* show it */
+    show_notif (notif);
+    
     #endif /* DISABLE_GUI */
 }
 
     #endif /* DISABLE_GUI */
     unsigned int checks = (is_auto) ? config->checks_auto : config->checks_manual;
     
+    #ifndef DISABLE_GUI
+    /* drop the list of last notifs, since we'll be making up a new one */
+    debug ("drop last_notifs");
+    FREE_NOTIFS_LIST (config->last_notifs);
+    #endif
+    
+    /* we will not free packages nor xml_news, because they'll be stored in
+     * notif_t (inside config->last_notifs) so we can re-show notifications.
+     * Everything gets free-d through the FREE_NOTIFS_LIST above */
+    
     if (checks & CHECK_NEWS)
     {
         packages = NULL;
             #endif /* DISABLE_GUI */
             notify_updates (packages, CHECK_NEWS, xml_news);
             FREELIST (packages);
-            /* we dont free xml_news because it might be used by the notification
-             * action (to show the news). hence, it'll be done when the notif is over */
         }
         else if (error != NULL)
         {
                 nb_upgrades = (gint) alpm_list_count (packages);
                 #endif /* DISABLE_GUI */
                 notify_updates (packages, CHECK_UPGRADES, NULL);
-                FREE_PACKAGE_LIST (packages);
             }
             #ifndef DISABLE_GUI
             else if (error == NULL)
                 nb_watched = (gint) alpm_list_count (packages);
                 #endif
                 notify_updates (packages, CHECK_WATCHED, NULL);
-                /* watched are a special case, because the list of packages must not be
-                 * free-d right now, but later when the notification is over. this is
-                 * because the notification might use it to show the "mark packages"
-                 * window/list */
             }
             #ifndef DISABLE_GUI
             else if (error == NULL)
             nb_watched_aur = (gint) alpm_list_count (packages);
             #endif
             notify_updates (packages, CHECK_WATCHED_AUR, NULL);
-            /* watched are a special case, because the list of packages must not be
-             * free-d right now, but later when the notification is over. this is
-             * because the notification might use it to show the "mark packages"
-             * window/list */
         }
         #ifndef DISABLE_GUI
         else if (error == NULL)

File preferences.c

 static GtkWidget *manual_watched_aur        = NULL;
 static GtkWidget *manual_news               = NULL;
 /* News */
+static GtkWidget *cmdline_link_entry        = NULL;
 static GtkWidget *news_title_entry          = NULL;
 static GtkWidget *news_package_entry        = NULL;
 static GtkWidget *news_sep_entry            = NULL;
 static GtkWidget *syncdbs_in_tooltip        = NULL;
 static GtkWidget *on_sgl_click              = NULL;
 static GtkWidget *on_dbl_click              = NULL;
-static GtkWidget *cmdline_link_entry        = NULL;
 
 /* we keep a copy of templates like so, so that we can use it when refreshing
  * the different templates. that is, values shown when a template is not set
                  );
     new_config.checks_manual = type;
     
+    /* News */
+    s = (char *) gtk_entry_get_text (GTK_ENTRY (cmdline_link_entry));
+    if (s == NULL || *s == '\0')
+    {
+        error_on_page (1, "You need to specify the command-line to open links.");
+    }
+    else if (!strstr (s, "$URL"))
+    {
+        error_on_page (1, "You need to use $URL on the command line to open links.");
+    }
+    add_to_conf ("CmdLineLink = %s\n", s);
+    new_config.cmdline_link = strdup (s);
+    
     /* Upgrades */
     new_config.check_pacman_conflict = gtk_toggle_button_get_active (
         GTK_TOGGLE_BUTTON (check_pacman_conflict));
     {
         add_to_conf ("OnSglClick = TOGGLE_WINDOWS\n");
     }
+    else if (new_config.on_sgl_click == DO_LAST_NOTIFS)
+    {
+        add_to_conf ("OnSglClick = LAST_NOTIFS\n");
+    }
     else /* if (new_config.on_sgl_click == DO_NOTHING) */
     {
         add_to_conf ("OnSglClick = NOTHING\n");
     {
         add_to_conf ("OnDblClick = TOGGLE_WINDOWS\n");
     }
+    else if (new_config.on_dbl_click == DO_LAST_NOTIFS)
+    {
+        add_to_conf ("OnDblClick = LAST_NOTIFS\n");
+    }
     else /* if (new_config.on_dbl_click == DO_NOTHING) */
     {
         add_to_conf ("OnDblClick = NOTHING\n");
     }
     
-    s = (char *) gtk_entry_get_text (GTK_ENTRY (cmdline_link_entry));
-    if (s == NULL || *s == '\0')
-    {
-        error_on_page (6, "You need to specify the command-line to open links.");
-    }
-    else if (!strstr (s, "$URL"))
-    {
-        error_on_page (6, "You need to use $URL on the command line to open links.");
-    }
-    add_to_conf ("CmdLineLink = %s\n", s);
-    new_config.cmdline_link = strdup (s);
-    
     /* ** TEMPLATES ** */
     
     /* Upgrades */
     grid = gtk_grid_new ();
     lbl_page = gtk_label_new ("News");
     
+    label = gtk_label_new ("Command line to open links :");
+    gtk_grid_attach (GTK_GRID (grid), label, 0, top, 1, 1);
+    gtk_widget_show (label);
+    
+    cmdline_link_entry = gtk_entry_new ();
+    gtk_widget_set_tooltip_markup (cmdline_link_entry,
+        "Use variable <b>$URL</b> for the URL to open");
+    if (config->cmdline_link != NULL)
+    {
+        gtk_entry_set_text (GTK_ENTRY (cmdline_link_entry), config->cmdline_link);
+    }
+    gtk_grid_attach (GTK_GRID (grid), cmdline_link_entry, 1, top, 1, 1);
+    gtk_widget_show (cmdline_link_entry);
+    
+    ++top;
     add_template (grid, top,
                   &news_title_entry,
                   &news_package_entry,
         "Hide/show opened windows"
         #endif
         );
+    gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (on_sgl_click), "4",
+        "Re-show last notifications...");
     gtk_grid_attach (GTK_GRID (grid), on_sgl_click, 1, top, 1, 1);
     gtk_widget_show (on_sgl_click);
     if (config->on_sgl_click == DO_CHECK)
     {
         gtk_combo_box_set_active (GTK_COMBO_BOX (on_sgl_click), 3);
     }
+    else if (config->on_sgl_click == DO_LAST_NOTIFS)
+    {
+        gtk_combo_box_set_active (GTK_COMBO_BOX (on_sgl_click), 4);
+    }
     else /* DO_NOTHING */
     {
         gtk_combo_box_set_active (GTK_COMBO_BOX (on_sgl_click), 0);
         "Hide/show opened windows"
         #endif
         );
+    gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (on_dbl_click), "4",
+        "Re-show last notifications...");
     gtk_grid_attach (GTK_GRID (grid), on_dbl_click, 1, top, 1, 1);
     gtk_widget_show (on_dbl_click);
     if (config->on_dbl_click == DO_CHECK)
     {
         gtk_combo_box_set_active (GTK_COMBO_BOX (on_dbl_click), 3);
     }
+    else if (config->on_sgl_click == DO_LAST_NOTIFS)
+    {
+        gtk_combo_box_set_active (GTK_COMBO_BOX (on_sgl_click), 4);
+    }
     else /* DO_NOTHING */
     {
         gtk_combo_box_set_active (GTK_COMBO_BOX (on_dbl_click), 0);
     }
     
-    ++top;
-    label = gtk_label_new ("Command line to open links (in news) :");
-    gtk_grid_attach (GTK_GRID (grid), label, 0, top, 1, 1);
-    gtk_widget_show (label);
-    
-    cmdline_link_entry = gtk_entry_new ();
-    gtk_widget_set_tooltip_markup (cmdline_link_entry,
-        "Use variable <b>$URL</b> for the URL to open");
-    if (config->cmdline_link != NULL)
-    {
-        gtk_entry_set_text (GTK_ENTRY (cmdline_link_entry), config->cmdline_link);
-    }
-    gtk_grid_attach (GTK_GRID (grid), cmdline_link_entry, 1, top, 1, 1);
-    gtk_widget_show (cmdline_link_entry);
-    
     /* add page */
     gtk_widget_show (grid);
     gtk_notebook_append_page (GTK_NOTEBOOK (notebook), grid, lbl_page);
 /* kalu */
 #include "util-gtk.h"
 #include "util.h"
+#include "gui.h" /* show_notif() */
 
 static void renderer_toggle_cb (GtkCellRendererToggle *, gchar *, GtkTreeModel *);
 
 void
 notify_error (const gchar *summary, const gchar *text)
 {
-    NotifyNotification *notification;
+    notif_t *notif;
     
-    notification = new_notification (summary, text);
-    notify_notification_show (notification, NULL);
-    g_object_unref (notification);
+    notif = malloc (sizeof (*notif));
+    notif->type = 0;
+    notif->summary = strdup (summary);
+    notif->text = strdup (text);
+    notif->data = NULL;
+    
+    /* add the notif to the last of last notifications, so we can re-show it later */
+    debug ("adding new notif (%s) to last_notifs", notif->summary);
+    config->last_notifs = alpm_list_add (config->last_notifs, notif);
+    /* show it */
+    show_notif (notif);
 }
 
 static void