/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * startup-monitor - A tray app that provides feedback * on application startup. * * Copyright 2004 - 2013, Intel Corp * By Matthew Allum , * Stefan Schmidt * Ross Burton * * SPDX-License-Identifier: GPL-2.0-or-later * * Based on mb-applet-startup-monitor * * 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; version 2 of the license. * * 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. */ #include #include #include #include #include #include #include #include #include #define SN_API_NOT_YET_FROZEN 1 #include #include #include #include #define TIMEOUT 20 #define HOURGLASS_PIXMAPS 8 typedef struct LaunchItem { char *id; time_t when; guint timeout_id; } LaunchItem; typedef struct { MBPanelScalingImage2 *image; GdkWindow *root_window; SnDisplay *sn_display; SnMonitorContext *sn_context; GList *launch_list; gboolean hourglass_shown; int hourglass_cur_frame_n; } StartupApplet; static GdkFilterReturn filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, StartupApplet *applet); static gboolean timeout (StartupApplet *applet); /* Destroy applet */ static void startup_applet_free (StartupApplet *applet) { /* TODO: this should be in unrealize */ gdk_window_remove_filter (applet->root_window, (GdkFilterFunc) filter_func, applet); g_slice_free (StartupApplet, applet); } static void show_hourglass (StartupApplet *applet) { gtk_widget_show (GTK_WIDGET (applet->image)); applet->hourglass_shown = TRUE; } static void hide_hourglass (StartupApplet *applet) { gtk_widget_hide (GTK_WIDGET (applet->image)); applet->hourglass_shown = FALSE; } static void monitor_event_func (SnMonitorEvent *event, gpointer user_data) { SnStartupSequence *sequence; const char *id; time_t t; StartupApplet *applet = (StartupApplet *) user_data; sequence = sn_monitor_event_get_startup_sequence (event); id = sn_startup_sequence_get_id (sequence); switch (sn_monitor_event_get_type (event)) { case SN_MONITOR_EVENT_INITIATED: { /* Reset counter */ applet->hourglass_cur_frame_n = 0; LaunchItem *item; item = malloc (sizeof (LaunchItem)); /* Fillup list item with current launchee * informations */ item->id = g_strdup (id); t = time (NULL); item->when = t + TIMEOUT; /* Set up a timeout that will be called every 0.5 * seconds */ item->timeout_id = g_timeout_add (500, (GSourceFunc) timeout, applet); /* Add a new launch at the end of list */ applet->launch_list = g_list_append (applet->launch_list, (gpointer) item); if (!applet->hourglass_shown) show_hourglass (applet); } break; case SN_MONITOR_EVENT_COMPLETED: case SN_MONITOR_EVENT_CANCELED: { GList *tmp = applet->launch_list; /* Find actual list item and free it*/ while( tmp != NULL) { LaunchItem *item = (LaunchItem*) tmp->data; if (!strcmp (item->id, id)) { applet->launch_list = g_list_remove (tmp, item); g_source_remove (item->timeout_id); free (item->id); free (item); break; } tmp = tmp->next; } if (applet->launch_list == NULL && applet->hourglass_shown) hide_hourglass (applet); } break; default: break; /* Nothing */ } } static gboolean timeout (StartupApplet *applet) { time_t t; char *icon; if (!applet->hourglass_shown) return TRUE; t = time (NULL); GList *tmp = applet->launch_list; /* handle launchee timeouts */ while (tmp != NULL) { GList *tmp_next = tmp->next; LaunchItem *item = (LaunchItem *) tmp->data; if ((item->when - t) <= 0) { applet->launch_list = g_list_delete_link (applet->launch_list, tmp); g_source_remove (item->timeout_id); free (item->id); free (item); break; } tmp = tmp_next; } if (applet->launch_list == NULL && applet->hourglass_shown) { hide_hourglass (applet); return TRUE; } applet->hourglass_cur_frame_n++; if (applet->hourglass_cur_frame_n == 8) applet->hourglass_cur_frame_n = 0; icon = malloc (sizeof(DATADIR) + 16); sprintf (icon, "%s/hourglass-%i.png", DATADIR, applet->hourglass_cur_frame_n); mb_panel_scaling_image2_set_icon (applet->image, icon); free (icon); return TRUE; } static GdkFilterReturn filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, StartupApplet *applet) { XEvent *xevent; xevent = (XEvent *) gdk_xevent; sn_display_process_event (applet->sn_display, xevent); return GDK_FILTER_CONTINUE; } static void on_realize (GtkWidget *widget, gpointer user_data) { StartupApplet *applet = user_data; GdkDisplay *display; GdkScreen *screen; Display *xdisplay; screen = gtk_widget_get_screen (widget); display = gdk_screen_get_display (screen); xdisplay = GDK_DISPLAY_XDISPLAY (display); applet->root_window = gdk_screen_get_root_window (screen); applet->sn_display = sn_display_new (xdisplay, NULL, NULL); applet->sn_context = sn_monitor_context_new (applet->sn_display, gdk_screen_get_number (screen), monitor_event_func, applet, NULL); XSelectInput (xdisplay, GDK_WINDOW_XID (applet->root_window), PropertyChangeMask); gdk_window_add_filter (applet->root_window, (GdkFilterFunc)filter_func, applet); } G_MODULE_EXPORT GtkWidget * mb_panel_applet_create (const char *id, GtkOrientation orientation) { StartupApplet *applet; /* Create applet data structure */ applet = g_slice_new0 (StartupApplet); applet->launch_list = NULL; applet->hourglass_shown = FALSE; /* Create image */ applet->image = MB_PANEL_SCALING_IMAGE2 (mb_panel_scaling_image2_new (orientation, NULL)); gtk_widget_set_name (GTK_WIDGET(applet->image), "MatchboxPanelStartupMonitor"); g_object_weak_ref (G_OBJECT(applet->image), (GWeakNotify) startup_applet_free, applet); g_signal_connect (applet->image, "realize", G_CALLBACK (on_realize), applet); return GTK_WIDGET (applet->image); }