#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "update-notifier.h" #include "update.h" #include "trayappletui.h" static gboolean check_system_crashes(void) { int exitcode; if(!in_admin_group()) return FALSE; // check for system crashes gchar *argv[] = { CRASHREPORT_HELPER, "--system", NULL }; if(!g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &exitcode, NULL)) { g_warning("Can not run %s", CRASHREPORT_HELPER); return FALSE; } return exitcode == 0; } static gboolean ask_invoke_apport_with_pkexec(void) { GtkDialog *dialog; gchar *msg = _("System program problem detected"); gchar *descr = _("Do you want to report the problem " "now?"); dialog = (GtkDialog*)gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", msg); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", descr); gtk_dialog_add_button(dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button(dialog, _("Report problem…"), GTK_RESPONSE_ACCEPT); int res = gtk_dialog_run(dialog); gtk_widget_destroy(GTK_WIDGET(dialog)); if (res == GTK_RESPONSE_ACCEPT) return TRUE; return FALSE; } static gboolean run_apport(TrayApplet *ta) { g_debug("fire up the crashreport tool"); // be nice and always ask first before firing up pkexec if (check_system_crashes()) { // workaround, wayland doesn't allow pkexec use if (g_strcmp0 (g_getenv ("XDG_SESSION_TYPE"), "wayland") == 0) g_debug ("no pkexec for system reports under wayland"); else if (ask_invoke_apport_with_pkexec()) invoke_with_pkexec(CRASHREPORT_REPORT_APP); } else { return g_spawn_command_line_async(CRASHREPORT_REPORT_APP, NULL); } return TRUE; } static gboolean show_notification (TrayApplet *ta) { NotifyNotification *n; // check if the update-icon is still visible (in the delay time a // update may already have been performed) if(!tray_applet_ui_get_visible(ta)) return FALSE; n = tray_applet_ui_get_data (ta, "notification"); if (n) g_object_unref (n); tray_applet_ui_set_data (ta, "notification", NULL); // now show a notification handle n = notify_notification_new( _("Crash report detected"), _("An application has crashed on your " "system (now or in the past). " "Click on the notification icon to " "display details. " ), GTK_STOCK_DIALOG_INFO); notify_notification_set_timeout (n, 60000); notify_notification_show (n, NULL); tray_applet_ui_set_data (ta, "notification", n); return FALSE; } static void hide_crash_applet(TrayApplet *ta) { NotifyNotification *n; /* Hide any notification popup */ n = tray_applet_ui_get_data (ta, "notification"); if (n) { notify_notification_close (n, NULL); g_object_unref (n); } tray_applet_ui_destroy (ta); } static gboolean button_release_cb (GtkWidget *widget, TrayApplet *ta) { run_apport(ta); hide_crash_applet(ta); return TRUE; } gboolean crashreport_check (TrayApplet *ta) { int crashreports_found = 0; gboolean system_crashes; g_debug("crashreport_check"); // don't do anything if no apport-gtk is installed if(!g_file_test(CRASHREPORT_REPORT_APP, G_FILE_TEST_IS_EXECUTABLE)) return FALSE; // don't do anything if autoreport is enabled if (g_file_test(CRASHREPORT_AUTOREPORT, G_FILE_TEST_EXISTS)) return FALSE; // if whoopsie is installed, but disabled, don't do anything if (g_file_test(CRASHREPORT_WHOOPSIE_EXEC, G_FILE_TEST_IS_EXECUTABLE)) { int exitcode; gchar *argv[] = { "/bin/systemctl", "is-enabled", "-q", CRASHREPORT_WHOOPSIE_SERVICE, NULL }; if (g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &exitcode, NULL)) { if (exitcode != 0) { g_debug("whoopsie disabled, not displaying crashes"); return FALSE; } } } // Check whether the user doesn't want notifications if (!g_settings_get_boolean (ta->un->settings, SETTINGS_KEY_APPORT_NOTIFICATIONS)) { g_debug("apport notifications disabled, not displaying crashes"); return FALSE; } // check for (new) reports by calling CRASHREPORT_HELPER // and checking the return code int exitcode; gchar *argv[] = { CRASHREPORT_HELPER, NULL }; if(!g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &exitcode, NULL)) { g_warning("Can not run %s", CRASHREPORT_HELPER); return FALSE; } // exitcode == 0: reports found, else no reports system_crashes = check_system_crashes(); crashreports_found = !exitcode || system_crashes; if (crashreports_found > 0) { g_debug("crashreport found running apport now"); crashreports_found=0; run_apport(ta); return TRUE; } else return FALSE; // non-autolaunch will always use the notification area gboolean visible = tray_applet_ui_get_visible(ta); // crashreport found if(crashreports_found > 0 && !visible) { tray_applet_ui_ensure(ta); tray_applet_ui_set_single_action(ta, _("Crash report detected"), G_CALLBACK(button_release_cb), ta); tray_applet_ui_set_visible(ta, TRUE); /* Show the notification, after a delay so it doesn't look ugly * if we've just logged in */ g_timeout_add_seconds(5, (GSourceFunc)(show_notification), ta); } // no crashreports, but visible if((crashreports_found == 0) && visible) { hide_crash_applet(ta); } return TRUE; } static gboolean crashreport_check_initially(TrayApplet *ta) { crashreport_check(ta); // stop timeout handler return FALSE; } void crashreport_tray_icon_init (TrayApplet *ta) { /* Check for crashes for the first time */ g_timeout_add_seconds(1, (GSourceFunc)crashreport_check_initially, ta); }