From d3fff839380fa1e165b92d3dc79fb7eafaf2a976 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Thu, 11 Mar 2010 16:27:14 +0100 Subject: GUI: added action to applet to directly report last crash Revieved by: Denys Vlasenko --- src/Applet/Applet.cpp | 20 ++++-- src/Applet/CCApplet.cpp | 134 ++++++++++++++++++++++++++++++++++--- src/Applet/CCApplet.h | 11 ++- src/Daemon/CommLayerServer.h | 2 +- src/Daemon/CommLayerServerDBus.cpp | 10 ++- src/Daemon/CommLayerServerDBus.h | 4 +- src/Daemon/Daemon.cpp | 12 +++- 7 files changed, 168 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/Applet/Applet.cpp b/src/Applet/Applet.cpp index 8972dcb5..ccd6f393 100644 --- a/src/Applet/Applet.cpp +++ b/src/Applet/Applet.cpp @@ -47,7 +47,18 @@ static void Crash(DBusMessage* signal) dbus_message_iter_init(signal, &in_iter); const char* package_name; r = load_val(&in_iter, package_name); - /* Optional 2nd param: uid */ + /* 2nd param: crash_id */ + const char* crash_id = NULL; + if (r == ABRT_DBUS_MORE_FIELDS) + { + r = load_val(&in_iter, crash_id); + } + else + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + /* Optional 3rd param: uid */ const char* uid_str = NULL; if (r == ABRT_DBUS_MORE_FIELDS) { @@ -80,7 +91,7 @@ static void Crash(DBusMessage* signal) //applet->AddEvent(uid, package_name); applet->SetIconTooltip(message, package_name); applet->ShowIcon(); - applet->CrashNotify(message, package_name); + applet->CrashNotify(crash_id, message, package_name); } static void QuotaExceed(DBusMessage* signal) @@ -99,7 +110,7 @@ static void QuotaExceed(DBusMessage* signal) //if (m_pSessionDBus->has_name("com.redhat.abrt.gui")) // return; applet->ShowIcon(); - applet->CrashNotify("%s", str); + applet->MessageNotify("%s", str); } static void NameOwnerChanged(DBusMessage* signal) @@ -178,6 +189,7 @@ static void die_if_dbus_error(bool error_flag, DBusError* err, const char* msg) int main(int argc, char** argv) { + const char * app_name = "abrt-gui"; /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS @@ -237,7 +249,7 @@ int main(int argc, char** argv) /* Initialize GUI stuff. * Note: inside CApplet ctor, libnotify hooks session dbus * to glib main loop */ - applet = new CApplet; + applet = new CApplet(app_name); /* dbus_abrt cannot handle more than one bus, and we don't really need to. * The only thing we want to do is to announce ourself on session dbus */ DBusConnection* session_conn = dbus_bus_get(DBUS_BUS_SESSION, &err); diff --git a/src/Applet/CCApplet.cpp b/src/Applet/CCApplet.cpp index 13a6eb6f..63b23a87 100644 --- a/src/Applet/CCApplet.cpp +++ b/src/Applet/CCApplet.cpp @@ -113,7 +113,29 @@ Patrick Connelly <pcon@fedoraproject.org>\ \ "; -CApplet::CApplet() +void static on_notify_close(NotifyNotification *notification, gpointer user_data) +{ + g_object_unref(notification); +} + +static NotifyNotification *new_warn_notification() +{ + NotifyNotification *notification; + notification = notify_notification_new(_("Warning"), NULL, NULL, NULL); + g_signal_connect(notification, "closed", G_CALLBACK(on_notify_close), NULL); + + GdkPixbuf *pixbuf = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), + GTK_STOCK_DIALOG_WARNING, 48, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); + + if (pixbuf) + notify_notification_set_icon_from_pixbuf(notification, pixbuf); + notify_notification_set_urgency(notification, NOTIFY_URGENCY_NORMAL); + notify_notification_set_timeout(notification, NOTIFY_EXPIRES_DEFAULT); + + return notification; +} + +CApplet::CApplet(const char* app_name) { m_bDaemonRunning = true; /* set-up icon buffers */ @@ -129,10 +151,7 @@ CApplet::CApplet() { m_pStatusIcon = gtk_status_icon_new_from_stock(GTK_STOCK_DIALOG_WARNING); } - notify_init("ABRT"); - m_pNotification = notify_notification_new_with_status_icon("Warning", NULL, NULL, m_pStatusIcon); - notify_notification_set_urgency(m_pNotification, NOTIFY_URGENCY_CRITICAL); - notify_notification_set_timeout(m_pNotification, 5000); + notify_init(app_name); gtk_status_icon_set_visible(m_pStatusIcon, FALSE); @@ -171,6 +190,8 @@ CApplet::CApplet() CApplet::~CApplet() { + if (notify_is_initted()) + notify_uninit(); } void CApplet::SetIconTooltip(const char *format, ...) @@ -188,19 +209,112 @@ void CApplet::SetIconTooltip(const char *format, ...) free(buf); } -void CApplet::CrashNotify(const char *format, ...) +void CApplet::action_report(NotifyNotification *notification, gchar *action, gpointer user_data) { - va_list args; + CApplet *applet = (CApplet *)user_data; + if (applet->m_bDaemonRunning) + { + pid_t pid = vfork(); + if (pid < 0) + perror_msg("vfork"); + if (pid == 0) + { /* child */ + char *buf = xasprintf("--report=%s", applet->m_pLastCrashID); + signal(SIGCHLD, SIG_DFL); /* undo SIG_IGN in abrt-applet */ + execl(BIN_DIR"/abrt-gui", "abrt-gui", buf, (char*) NULL); + /* Did not find abrt-gui in installation directory. Oh well */ + /* Trying to find it in PATH */ + execlp("abrt-gui", "abrt-gui", buf, (char*) NULL); + perror_msg_and_die("Can't exec abrt-gui"); + } + GError *err = NULL; + notify_notification_close(notification, &err); + if (err != NULL) + { + error_msg("%s", err->message); + g_error_free(err); + } + gtk_status_icon_set_visible(applet->m_pStatusIcon, false); + applet->stop_animate_icon(); + } +} +void CApplet::action_open_gui(NotifyNotification *notification, gchar *action, gpointer user_data) +{ + CApplet *applet = (CApplet *)user_data; + if (applet->m_bDaemonRunning) + { + pid_t pid = vfork(); + if (pid < 0) + perror_msg("vfork"); + if (pid == 0) + { /* child */ + signal(SIGCHLD, SIG_DFL); /* undo SIG_IGN in abrt-applet */ + execl(BIN_DIR"/abrt-gui", "abrt-gui", (char*) NULL); + /* Did not find abrt-gui in installation directory. Oh well */ + /* Trying to find it in PATH */ + execlp("abrt-gui", "abrt-gui", (char*) NULL); + perror_msg_and_die("Can't exec abrt-gui"); + } + GError *err = NULL; + notify_notification_close(notification, &err); + if (err != NULL) + { + error_msg("%s", err->message); + g_error_free(err); + } + gtk_status_icon_set_visible(applet->m_pStatusIcon, false); + applet->stop_animate_icon(); + } +} + +void CApplet::CrashNotify(const char* crash_id, const char *format, ...) +{ + m_pLastCrashID = crash_id; + va_list args; va_start(args, format); char *buf = xvasprintf(format, args); va_end(args); - notify_notification_update(m_pNotification, _("Warning"), buf, NULL); + NotifyNotification *notification = new_warn_notification(); + notify_notification_add_action(notification, "REPORT", _("Report"), + NOTIFY_ACTION_CALLBACK(CApplet::action_report), + this, NULL); + notify_notification_add_action(notification, "OPEN_MAIN_WINDOW", "Open ABRT", + NOTIFY_ACTION_CALLBACK(CApplet::action_open_gui), + this, NULL); + notify_notification_update(notification, _("Warning"), buf, NULL); + free(buf); + GError *err = NULL; + notify_notification_show(notification, &err); + if (err != NULL) + { + error_msg("%s", err->message); + g_error_free(err); + } +} + +void CApplet::MessageNotify(const char *format, ...) +{ + va_list args; + + va_start(args, format); + char *buf = xvasprintf(format, args); + va_end(args); + + /* we don't want to show any buttons now, + maybe later we can add action binded to message + like >>Clear old dumps<< for quota exceeded + */ + NotifyNotification *notification = new_warn_notification(); + notify_notification_add_action(notification, "OPEN_MAIN_WINDOW", "Open ABRT", + NOTIFY_ACTION_CALLBACK(CApplet::action_open_gui), + this, NULL); + notify_notification_update(notification, _("Warning"), buf, NULL); + free(buf); GError *err = NULL; - if (gtk_status_icon_is_embedded(m_pStatusIcon)) - notify_notification_show(m_pNotification, &err); + notify_notification_show(notification, &err); if (err != NULL) { error_msg("%s", err->message); diff --git a/src/Applet/CCApplet.h b/src/Applet/CCApplet.h index a14498e8..ca92f082 100644 --- a/src/Applet/CCApplet.h +++ b/src/Applet/CCApplet.h @@ -35,13 +35,13 @@ class CApplet GObject *m_pmiAbout; GObject *m_pAboutDialog; - NotifyNotification *m_pNotification; // std::map m_mapEvents; bool m_bDaemonRunning; int m_iAnimationStage; guint m_iAnimator; unsigned m_iAnimCountdown; bool m_bIconsLoaded; + const char *m_pLastCrashID; enum ICON_STAGES { @@ -57,14 +57,15 @@ class CApplet GdkPixbuf *icon_stages_buff[ICON_STAGE_LAST]; public: - CApplet(); + CApplet(const char* app_name); ~CApplet(); void ShowIcon(); void HideIcon(); //void DisableIcon(); // void BlinkIcon(bool pBlink); void SetIconTooltip(const char *format, ...); - void CrashNotify(const char *format, ...); + void CrashNotify(const char* crash_id, const char *format, ...); + void MessageNotify(const char *format, ...); void Disable(const char *reason); void Enable(const char *reason); // create some event storage, to let user choose @@ -77,6 +78,10 @@ class CApplet protected: //@@TODO applet menus static void OnAppletActivate_CB(GtkStatusIcon *status_icon, gpointer user_data); + //this action should open the reporter dialog directly, without showing the main window + static void action_report(NotifyNotification *notification, gchar *action, gpointer user_data); + //this action should open the main window + static void action_open_gui(NotifyNotification *notification, gchar *action, gpointer user_data); static void OnMenuPopup_cb(GtkStatusIcon *status_icon, guint button, guint activate_time, diff --git a/src/Daemon/CommLayerServer.h b/src/Daemon/CommLayerServer.h index 2daaf93a..9e095c39 100644 --- a/src/Daemon/CommLayerServer.h +++ b/src/Daemon/CommLayerServer.h @@ -30,7 +30,7 @@ class CCommLayerServer { virtual ~CCommLayerServer(); /* just stubs to be called when not implemented in specific comm layer */ - virtual void Crash(const char *package_name, const char *uid_str) {} + virtual void Crash(const char *package_name, const char* crash_id, const char *uid_str) {} virtual void JobDone(const char* peer) = 0; virtual void QuotaExceed(const char* str) {} diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp index 517a9e2a..103f8675 100644 --- a/src/Daemon/CommLayerServerDBus.cpp +++ b/src/Daemon/CommLayerServerDBus.cpp @@ -64,23 +64,27 @@ static void send_flush_and_unref(DBusMessage* msg) } /* Notify the clients (UI) about a new crash */ -void CCommLayerServerDBus::Crash(const char *package_name, const char *uid_str) +void CCommLayerServerDBus::Crash(const char *package_name, + const char* crash_id, + const char *uid_str) { DBusMessage* msg = new_signal_msg("Crash"); if (uid_str) { dbus_message_append_args(msg, DBUS_TYPE_STRING, &package_name, + DBUS_TYPE_STRING, &crash_id, DBUS_TYPE_STRING, &uid_str, DBUS_TYPE_INVALID); - VERB2 log("Sending signal Crash('%s','%s')", package_name, uid_str); + VERB2 log("Sending signal Crash('%s','%s','%s')", package_name, crash_id, uid_str); } else { dbus_message_append_args(msg, DBUS_TYPE_STRING, &package_name, + DBUS_TYPE_STRING, &crash_id, DBUS_TYPE_INVALID); - VERB2 log("Sending signal Crash('%s')", package_name); + VERB2 log("Sending signal Crash('%s','%s')", package_name, crash_id); } send_flush_and_unref(msg); } diff --git a/src/Daemon/CommLayerServerDBus.h b/src/Daemon/CommLayerServerDBus.h index c62d9a9f..7ccad083 100644 --- a/src/Daemon/CommLayerServerDBus.h +++ b/src/Daemon/CommLayerServerDBus.h @@ -29,7 +29,9 @@ class CCommLayerServerDBus virtual ~CCommLayerServerDBus(); /* DBus signal senders */ - virtual void Crash(const char *package_name, const char *uid_str); + virtual void Crash(const char *package_name, + const char *crash_id, + const char *uid_str); virtual void JobDone(const char* peer); virtual void QuotaExceed(const char* str); diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 46bd9502..66f1d6e9 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -75,7 +75,7 @@ using namespace std; * - SetSettings(map_abrt_settings_t): returns void * * DBus signals we emit: - * - Crash(progname,uid) - a new crash occurred (new /var/cache/abrt/DIR is found) + * - Crash(progname, crash_id, uid) - a new crash occurred (new /var/cache/abrt/DIR is found) * - JobDone(client_dbus_ID) - see StartJob above. * Sent as unicast to the client which did StartJob. * - Warning(msg) @@ -542,11 +542,17 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin } } } - /* Send dbus signal */ if (analyzer_has_InformAllUsers(analyzer)) uid_str = NULL; - g_pCommLayer->Crash(get_crash_data_item_content(crashinfo, FILENAME_PACKAGE).c_str(), uid_str); + char *crash_id = xasprintf("%s:%s", + get_crash_data_item_content(crashinfo, CD_UID).c_str(), + get_crash_data_item_content(crashinfo, CD_UUID).c_str() + ); + g_pCommLayer->Crash(get_crash_data_item_content(crashinfo, FILENAME_PACKAGE).c_str(), + crash_id, + uid_str); + free(crash_id); break; #undef fullname } -- cgit