From 83a6ce9ad4b1828e163dc7172ef603201b748473 Mon Sep 17 00:00:00 2001 From: Nikola Pajkovsky Date: Tue, 10 Aug 2010 10:21:25 +0200 Subject: lower case direcotry(no code changed) Signed-off-by: Nikola Pajkovsky --- src/applet/Applet.cpp | 302 +++++++++++++++++++++++++ src/applet/CCApplet.cpp | 456 ++++++++++++++++++++++++++++++++++++++ src/applet/CCApplet.h | 88 ++++++++ src/applet/Makefile.am | 43 ++++ src/applet/abrt-applet.desktop.in | 9 + 5 files changed, 898 insertions(+) create mode 100644 src/applet/Applet.cpp create mode 100644 src/applet/CCApplet.cpp create mode 100644 src/applet/CCApplet.h create mode 100644 src/applet/Makefile.am create mode 100644 src/applet/abrt-applet.desktop.in (limited to 'src/applet') diff --git a/src/applet/Applet.cpp b/src/applet/Applet.cpp new file mode 100644 index 00000000..85ee0db8 --- /dev/null +++ b/src/applet/Applet.cpp @@ -0,0 +1,302 @@ +/* + Copyright (C) 2009 Jiri Moskovcak (jmoskovc@redhat.com) + Copyright (C) 2009 RedHat inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#if HAVE_CONFIG_H +# include +#endif +#if HAVE_LOCALE_H +# include +#endif +#if ENABLE_NLS +# include +# define _(S) gettext(S) +#else +# define _(S) (S) +#endif +#include "abrtlib.h" +#include "abrt_dbus.h" +#include "dbus_common.h" +#include "CCApplet.h" + + +static CApplet* applet; + + +static void Crash(DBusMessage* signal) +{ + int r; + DBusMessageIter in_iter; + dbus_message_iter_init(signal, &in_iter); + + /* 1st param: package */ + const char* package_name; + r = load_val(&in_iter, package_name); + + /* 2nd param: crash_id */ + const char* crash_id = NULL; + if (r != ABRT_DBUS_MORE_FIELDS) + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + r = load_val(&in_iter, crash_id); + + /* Optional 3rd param: uid */ + const char* uid_str = NULL; + if (r == ABRT_DBUS_MORE_FIELDS) + { + r = load_val(&in_iter, uid_str); + } + if (r != ABRT_DBUS_LAST_FIELD) + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + + if (uid_str != NULL) + { + char *end; + errno = 0; + unsigned long uid_num = strtoul(uid_str, &end, 10); + if (errno || *end != '\0' || uid_num != getuid()) + { + return; + } + } + + const char* message = _("A crash in the %s package has been detected"); + if (package_name[0] == '\0') + message = _("A crash has been detected"); + //applet->AddEvent(uid, package_name); + applet->SetIconTooltip(message, package_name); + applet->ShowIcon(); + + /* If this crash seems to be repeating, do not annoy user with popup dialog. + * (The icon in the tray is not suppressed) + */ + static time_t last_time = 0; + static char* last_package_name = NULL; + static char* last_crash_id = NULL; + time_t cur_time = time(NULL); + if (last_package_name && strcmp(last_package_name, package_name) == 0 + && last_crash_id && strcmp(last_crash_id, crash_id) == 0 + && (unsigned)(cur_time - last_time) < 2 * 60 * 60 + ) { + log_msg("repeated crash in %s, not showing the notification", package_name); + return; + } + last_time = cur_time; + free(last_package_name); + last_package_name = xstrdup(package_name); + free(last_crash_id); + last_crash_id = xstrdup(crash_id); + + applet->CrashNotify(crash_id, message, package_name); +} + +static void QuotaExceed(DBusMessage* signal) +{ + int r; + DBusMessageIter in_iter; + dbus_message_iter_init(signal, &in_iter); + const char* str; + r = load_val(&in_iter, str); + if (r != ABRT_DBUS_LAST_FIELD) + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + + //if (m_pSessionDBus->has_name("com.redhat.abrt.gui")) + // return; + applet->ShowIcon(); + applet->MessageNotify("%s", str); +} + +static void NameOwnerChanged(DBusMessage* signal) +{ + int r; + DBusMessageIter in_iter; + dbus_message_iter_init(signal, &in_iter); + const char* name; + r = load_val(&in_iter, name); + if (r != ABRT_DBUS_MORE_FIELDS) + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + + /* We are only interested in (dis)appearances of our daemon */ + if (strcmp(name, "com.redhat.abrt") != 0) + return; + + const char* old_owner; + r = load_val(&in_iter, old_owner); + if (r != ABRT_DBUS_MORE_FIELDS) + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + const char* new_owner; + r = load_val(&in_iter, new_owner); + if (r != ABRT_DBUS_LAST_FIELD) + { + error_msg("dbus signal %s: parameter type mismatch", __func__); + return; + } + +// hide icon if it's visible - as NM and don't show it, if it's not + if (!new_owner[0]) + applet->HideIcon(); +} + +static DBusHandlerResult handle_message(DBusConnection* conn, DBusMessage* msg, void* user_data) +{ + const char* member = dbus_message_get_member(msg); + + VERB1 log("%s(member:'%s')", __func__, member); + + int type = dbus_message_get_type(msg); + if (type != DBUS_MESSAGE_TYPE_SIGNAL) + { + log("The message is not a signal. ignoring"); + return DBUS_HANDLER_RESULT_HANDLED; + } + + if (strcmp(member, "NameOwnerChanged") == 0) + NameOwnerChanged(msg); + else if (strcmp(member, "Crash") == 0) + Crash(msg); + else if (strcmp(member, "QuotaExceed") == 0) + QuotaExceed(msg); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +//TODO: move to abrt_dbus.cpp +static void die_if_dbus_error(bool error_flag, DBusError* err, const char* msg) +{ + if (dbus_error_is_set(err)) + { + error_msg("dbus error: %s", err->message); + /*dbus_error_free(&err); - why bother, we will exit in a microsecond */ + error_flag = true; + } + if (!error_flag) + return; + error_msg_and_die("%s", msg); +} + +int main(int argc, char** argv) +{ + const char * app_name = "abrt-gui"; + /* I18n */ + setlocale(LC_ALL, ""); +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + + /* Need to be thread safe */ + g_thread_init(NULL); + gdk_threads_init(); + gdk_threads_enter(); + + /* Parse options */ + int opt; + while ((opt = getopt(argc, argv, "dv")) != -1) + { + switch (opt) + { + case 'v': + g_verbose++; + break; + default: + error_msg_and_die( + "Usage: abrt-applet [-v]\n" + "\nOptions:" + "\n\t-v\tVerbose" + ); + } + } + gtk_init(&argc, &argv); + + /* Prevent zombies when we spawn abrt-gui */ + signal(SIGCHLD, SIG_IGN); + + /* Initialize our (dbus_abrt) machinery: hook _system_ dbus to glib main loop. + * (session bus is left to be handled by libnotify, see below) */ + DBusError err; + dbus_error_init(&err); + DBusConnection* system_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + die_if_dbus_error(system_conn == NULL, &err, "Can't connect to system dbus"); + attach_dbus_conn_to_glib_main_loop(system_conn); + if (!dbus_connection_add_filter(system_conn, handle_message, NULL, NULL)) + error_msg_and_die("Can't add dbus filter"); + /* which messages do we want to be fed to handle_message()? */ + //signal sender=org.freedesktop.DBus -> path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged + // string "com.redhat.abrt" + // string "" + // string ":1.70" + dbus_bus_add_match(system_conn, "type='signal',member='NameOwnerChanged'", &err); + die_if_dbus_error(false, &err, "Can't add dbus match"); + //signal sender=:1.73 -> path=/com/redhat/abrt; interface=com.redhat.abrt; member=Crash + // string "coreutils-7.2-3.fc11" + // string "0" + dbus_bus_add_match(system_conn, "type='signal',path='/com/redhat/abrt'", &err); + die_if_dbus_error(false, &err, "Can't add dbus match"); + + /* Initialize GUI stuff. + * Note: inside CApplet ctor, libnotify hooks session dbus + * to glib main loop */ + 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); + die_if_dbus_error(session_conn == NULL, &err, "Can't connect to session dbus"); + int r = dbus_bus_request_name(session_conn, + "com.redhat.abrt.applet", + /* flags */ DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); + die_if_dbus_error(r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER, &err, + "Problem connecting to dbus, or applet is already running"); + + /* show the warning in terminal, as nm-applet does */ + if (!dbus_bus_name_has_owner(system_conn, ABRTD_DBUS_NAME, &err)) + { + const char* msg = _("ABRT service is not running"); + puts(msg); + } + + /* dbus_bus_request_name can already read some data. Thus while dbus fd hasn't + * any data anymore, dbus library can buffer a message or two. + * If we don't do this, the data won't be processed until next dbus data arrives. + */ + int cnt = 10; + while (dbus_connection_dispatch(system_conn) != DBUS_DISPATCH_COMPLETE && --cnt) + continue; + + /* Enter main loop */ + gtk_main(); + + gdk_threads_leave(); + delete applet; + return 0; +} diff --git a/src/applet/CCApplet.cpp b/src/applet/CCApplet.cpp new file mode 100644 index 00000000..5349c7a5 --- /dev/null +++ b/src/applet/CCApplet.cpp @@ -0,0 +1,456 @@ +/* + Copyright (C) 2009 Jiri Moskovcak (jmoskovc@redhat.com) + Copyright (C) 2009 RedHat inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#if HAVE_CONFIG_H +# include +#endif +#if ENABLE_NLS +# include +# define _(S) gettext(S) +#else +# define _(S) (S) +#endif +#include "abrtlib.h" +#include "CCApplet.h" + +static void 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; +} + + +static void on_hide_cb(GtkMenuItem *menuitem, gpointer applet) +{ + if (applet) + ((CApplet*)applet)->HideIcon(); +} + +static void on_about_cb(GtkMenuItem *menuitem, gpointer dialog) +{ + if (dialog) + { + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_hide(GTK_WIDGET(dialog)); + } +} + +static GtkWidget *create_about_dialog() +{ + const char *copyright_str = "Copyright © 2009 Red Hat, Inc\nCopyright © 2010 Red Hat, Inc"; + const char *license_str = "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; either version 2 of the License, or (at your option) any later version." + "\n\nThis 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." + "\n\nYou should have received a copy of the GNU General Public License along with this program. If not, see ."; + + const char *website_url = "https://fedorahosted.org/abrt/"; + const char *authors[] = {"Anton Arapov ", + "Karel Klic ", + "Jiri Moskovcak ", + "Nikola Pajkovsky ", + "Zdenek Prikryl ", + "Denys Vlasenko ", + NULL}; + + const char *artists[] = {"Patrick Connelly ", + "Lapo Calamandrei", + NULL}; + + const char *comments = _("Notification area applet that notifies users about " + "issues detected by ABRT"); + GtkWidget *about_d = gtk_about_dialog_new(); + if (about_d) + { + gtk_window_set_default_icon_name("abrt"); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_d), VERSION); + gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(about_d), "abrt"); + gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about_d), comments); + gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about_d), "ABRT"); + gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_d), copyright_str); + gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about_d), license_str); + gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(about_d),true); + gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_d), website_url); + gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about_d), authors); + gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about_d), artists); + gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about_d), _("translator-credits")); + } + return about_d; +} + +static GtkWidget *create_menu(CApplet *applet) +{ + GtkWidget *menu = gtk_menu_new(); + GtkWidget *b_quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); + g_signal_connect(b_quit, "activate", gtk_main_quit, NULL); + GtkWidget *b_hide = gtk_menu_item_new_with_label(_("Hide")); + g_signal_connect(b_hide, "activate", G_CALLBACK(on_hide_cb), applet); + GtkWidget *b_about = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL); + GtkWidget *about_dialog = create_about_dialog(); + g_signal_connect(b_about, "activate", G_CALLBACK(on_about_cb), about_dialog); + GtkWidget *separator = gtk_separator_menu_item_new(); + if (menu) + { + gtk_menu_shell_append(GTK_MENU_SHELL(menu),b_hide); + gtk_widget_show(b_hide); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),b_about); + gtk_widget_show(b_about); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),separator); + gtk_widget_show(separator); + gtk_menu_shell_append(GTK_MENU_SHELL(menu),b_quit); + gtk_widget_show(b_quit); + } + return menu; +} + +CApplet::CApplet(const char* app_name) +{ + m_bDaemonRunning = true; + /* set-up icon buffers */ + m_iAnimator = 0; + m_iAnimationStage = ICON_DEFAULT; + m_bIconsLoaded = load_icons(); + /* - animation - */ + if (m_bIconsLoaded == true) + { + //FIXME: animation is disabled for now + m_pStatusIcon = gtk_status_icon_new_from_pixbuf(icon_stages_buff[ICON_DEFAULT]); + } + else + { + m_pStatusIcon = gtk_status_icon_new_from_icon_name("abrt"); + } + notify_init(app_name); + + gtk_status_icon_set_visible(m_pStatusIcon, FALSE); + + g_signal_connect(G_OBJECT(m_pStatusIcon), "activate", GTK_SIGNAL_FUNC(CApplet::OnAppletActivate_CB), this); + g_signal_connect(G_OBJECT(m_pStatusIcon), "popup_menu", GTK_SIGNAL_FUNC(CApplet::OnMenuPopup_cb), this); + +// SetIconTooltip(_("Pending events: %i"), m_mapEvents.size()); + + m_pMenu = create_menu(this); +} + +CApplet::~CApplet() +{ + if (notify_is_initted()) + notify_uninit(); +} + +void CApplet::SetIconTooltip(const char *format, ...) +{ + va_list args; + int n; + char *buf; + + va_start(args, format); + buf = NULL; + n = vasprintf(&buf, format, args); + va_end(args); + + gtk_status_icon_set_tooltip_text(m_pStatusIcon, (n >= 0 && buf) ? buf : ""); + free(buf); +} + +void CApplet::action_report(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 */ + 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 execute 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 execute 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); + + 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; + notify_notification_show(notification, &err); + if (err != NULL) + { + error_msg("%s", err->message); + g_error_free(err); + } +} + +void CApplet::OnAppletActivate_CB(GtkStatusIcon *status_icon, 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 execute abrt-gui"); + } + gtk_status_icon_set_visible(applet->m_pStatusIcon, false); + applet->stop_animate_icon(); + } +} + +void CApplet::OnMenuPopup_cb(GtkStatusIcon *status_icon, + guint button, + guint activate_time, + gpointer user_data) +{ + CApplet *applet = (CApplet *)user_data; + /* stop the animation */ + applet->stop_animate_icon(); + + if (applet->m_pMenu != NULL) + { + gtk_menu_popup(GTK_MENU(((CApplet *)user_data)->m_pMenu), + NULL, NULL, + gtk_status_icon_position_menu, + status_icon, button, activate_time); + } +} + +void CApplet::ShowIcon() +{ + gtk_status_icon_set_visible(m_pStatusIcon, true); + /* only animate if all icons are loaded, use the "gtk-warning" instead */ + if (m_bIconsLoaded) + animate_icon(); +} + +void CApplet::HideIcon() +{ + gtk_status_icon_set_visible(m_pStatusIcon, false); + stop_animate_icon(); +} + +void CApplet::Disable(const char *reason) +{ + /* + FIXME: once we have our icon + */ + m_bDaemonRunning = false; + GdkPixbuf *gray_scaled; + GdkPixbuf *pixbuf = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), + GTK_STOCK_DIALOG_WARNING, 24, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); + if (pixbuf) + { + gray_scaled = gdk_pixbuf_copy(pixbuf); + gdk_pixbuf_saturate_and_pixelate(pixbuf, gray_scaled, 0.0, false); + gtk_status_icon_set_from_pixbuf(m_pStatusIcon, gray_scaled); +//do we need to free pixbufs nere? + } + else + error_msg("Can't load icon"); + SetIconTooltip(reason); + ShowIcon(); +} + +void CApplet::Enable(const char *reason) +{ + /* restore the original icon */ + m_bDaemonRunning = true; + SetIconTooltip(reason); + gtk_status_icon_set_from_stock(m_pStatusIcon, GTK_STOCK_DIALOG_WARNING); + ShowIcon(); +} + +gboolean CApplet::update_icon(void *user_data) +{ + CApplet* applet = (CApplet*)user_data; + if (applet->m_pStatusIcon && applet->m_iAnimationStage < ICON_STAGE_LAST) + { + gtk_status_icon_set_from_pixbuf(applet->m_pStatusIcon, + applet->icon_stages_buff[applet->m_iAnimationStage++]); + } + if (applet->m_iAnimationStage == ICON_STAGE_LAST) + { + applet->m_iAnimationStage = 0; + } + if (--applet->m_iAnimCountdown == 0) + { + applet->stop_animate_icon(); + } + return true; +} + +void CApplet::animate_icon() +{ + if (m_iAnimator == 0) + { + m_iAnimator = g_timeout_add(100, update_icon, this); + m_iAnimCountdown = 10 * 3; /* 3 sec */ + } +} + +void CApplet::stop_animate_icon() +{ + /* animator should be 0 if icons are not loaded, so this should be safe */ + if (m_iAnimator != 0) + { + g_source_remove(m_iAnimator); + gtk_status_icon_set_from_pixbuf(m_pStatusIcon, icon_stages_buff[ICON_DEFAULT]); + m_iAnimator = 0; + } +} + +bool CApplet::load_icons() +{ + //FIXME: just a tmp workaround + return false; + int stage; + for (stage = ICON_DEFAULT; stage < ICON_STAGE_LAST; stage++) + { + char name[sizeof(ICON_DIR"/abrt%02d.png")]; + GError *error = NULL; + if (snprintf(name, sizeof(ICON_DIR"/abrt%02d.png"), ICON_DIR"/abrt%02d.png", stage) > 0) + { + icon_stages_buff[stage] = gdk_pixbuf_new_from_file(name, &error); + if (error != NULL) + { + error_msg("Can't load pixbuf from %s, animation is disabled", name); + return false; + } + } + } + return true; +} + + +//int CApplet::AddEvent(int pUUID, const char *pProgname) +//{ +// m_mapEvents[pUUID] = "pProgname"; +// SetIconTooltip(_("Pending events: %i"), m_mapEvents.size()); +// return 0; +//} +// +//int CApplet::RemoveEvent(int pUUID) +//{ +// m_mapEvents.erase(pUUID); +// return 0; +//} diff --git a/src/applet/CCApplet.h b/src/applet/CCApplet.h new file mode 100644 index 00000000..a58ec687 --- /dev/null +++ b/src/applet/CCApplet.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2009 Jiri Moskovcak (jmoskovc@redhat.com) + Copyright (C) 2009 RedHat inc. + + 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; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef CC_APPLET_H_ +#define CC_APPLET_H_ + +#include +#include +#include +#include + +class CApplet +{ + private: + GtkStatusIcon* m_pStatusIcon; + GtkWidget *m_pMenu; + +// 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 + { + ICON_DEFAULT, + ICON_STAGE1, + ICON_STAGE2, + ICON_STAGE3, + ICON_STAGE4, + ICON_STAGE5, + /* this must be always the last */ + ICON_STAGE_LAST + } icon_stages; + GdkPixbuf *icon_stages_buff[ICON_STAGE_LAST]; + + public: + CApplet(const char* app_name); + ~CApplet(); + void ShowIcon(); + void HideIcon(); + void SetIconTooltip(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 + // or ask the daemon every time? + // maybe just events which occured during current session + // map:: +// int AddEvent(int pUUID, const char *pProgname); +// int RemoveEvent(int pUUID); + + 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, + gpointer user_data); + static gboolean update_icon(void *data); + void animate_icon(); + void stop_animate_icon(); + bool load_icons(); +}; + +#endif diff --git a/src/applet/Makefile.am b/src/applet/Makefile.am new file mode 100644 index 00000000..743c18df --- /dev/null +++ b/src/applet/Makefile.am @@ -0,0 +1,43 @@ +bin_PROGRAMS = abrt-applet + +abrt_applet_SOURCES = \ + Applet.cpp \ + CCApplet.h CCApplet.cpp +abrt_applet_CPPFLAGS = \ + -Wall -Werror \ + -I$(srcdir)/../../inc \ + -I$(srcdir)/../../lib/utils \ + -I/usr/include/glib-2.0 \ + -I/usr/lib/glib-2.0/include \ + -DBIN_DIR=\"$(bindir)\" \ + -DVAR_RUN=\"$(VAR_RUN)\" \ + -DCONF_DIR=\"$(CONF_DIR)\" \ + -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ + -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ + -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + -DICON_DIR=\"${datadir}/abrt/icons/hicolor/48x48/status\" \ + $(GTK_CFLAGS) \ + $(DBUS_CFLAGS) \ + -D_GNU_SOURCE +# $(LIBNOTIFY_CFLAGS) +# $(DBUS_GLIB_CFLAGS) +abrt_applet_LDADD = \ + ../../lib/utils/libABRTUtils.la \ + -lglib-2.0 \ + -lgthread-2.0 \ + $(DBUS_LIBS) \ + $(LIBNOTIFY_LIBS) \ + $(GTK_LIBS) +# ../../lib/Utils/libABRTdUtils.la +# $(DL_LIBS) + +DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ + +@INTLTOOL_DESKTOP_RULE@ + +autostartdir = $(sysconfdir)/xdg/autostart +autostart_in_files = abrt-applet.desktop.in + +autostart_DATA = $(autostart_in_files:.desktop.in=.desktop) + +EXTRA_DIST = $(autostart_in_files) diff --git a/src/applet/abrt-applet.desktop.in b/src/applet/abrt-applet.desktop.in new file mode 100644 index 00000000..57a6278e --- /dev/null +++ b/src/applet/abrt-applet.desktop.in @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +_Name=Automatic Bug Reporting Tool +_Comment=ABRT notification applet +Icon=abrt +Exec=abrt-applet +Terminal=false +Type=Application +X-GNOME-Autostart-enabled=true -- cgit