diff --git a/midori/marshal.list b/midori/marshal.list index 825f9730..5ca263be 100644 --- a/midori/marshal.list +++ b/midori/marshal.list @@ -4,3 +4,4 @@ VOID:BOOLEAN,STRING VOID:OBJECT,ENUM VOID:STRING,BOOLEAN VOID:STRING,INT,STRING +VOID:STRING,STRING diff --git a/midori/midori-app.c b/midori/midori-app.c index f79a307c..f70a0469 100644 --- a/midori/midori-app.c +++ b/midori/midori-app.c @@ -24,6 +24,20 @@ #include #endif +typedef struct _NotifyNotification NotifyNotification; + +typedef struct +{ + gboolean (*init) (const gchar* app_name); + void (*uninit) (void); + NotifyNotification* (*notification_new) (const gchar* summary, + const gchar* body, + const gchar* icon, + GtkWidget* attach); + gboolean (*notification_show) (NotifyNotification* notification, + GError** error); +} LibNotifyFuncs; + struct _MidoriApp { GObject parent_instance; @@ -41,6 +55,11 @@ struct _MidoriApp KatzeArray* browsers; gpointer instance; + + /* libnotify handling */ + gchar* program_notify_send; + GModule* libnotify_module; + LibNotifyFuncs libnotify_funcs; }; struct _MidoriAppClass @@ -89,6 +108,9 @@ static guint signals[LAST_SIGNAL]; static void midori_app_finalize (GObject* object); +static void +midori_app_init_libnotify (MidoriApp* app); + static void midori_app_set_property (GObject* object, guint prop_id, @@ -165,6 +187,8 @@ _midori_app_add_browser (MidoriApp* app, "signal::destroy", midori_browser_destroy_cb, app, "signal::quit", midori_browser_quit_cb, app, NULL); + g_signal_connect_swapped (browser, "send-notification", + G_CALLBACK (midori_app_send_notification), app); katze_array_add_item (app->browsers, browser); @@ -486,6 +510,8 @@ midori_app_init (MidoriApp* app) app->browsers = katze_array_new (MIDORI_TYPE_BROWSER); app->instance = NULL; + + midori_app_init_libnotify (app); } static void @@ -506,6 +532,13 @@ midori_app_finalize (GObject* object) katze_object_assign (app->instance, NULL); + if (app->libnotify_module) + { + app->libnotify_funcs.uninit (); + g_module_close (app->libnotify_module); + } + katze_object_assign (app->program_notify_send, NULL); + G_OBJECT_CLASS (midori_app_parent_class)->finalize (object); } @@ -808,3 +841,86 @@ midori_app_quit (MidoriApp* app) g_signal_emit (app, signals[QUIT], 0); } + +static void +midori_app_init_libnotify (MidoriApp* app) +{ + gint i; + const gchar* sonames[] = { "libnotify.so", "libnotify.so.1", NULL }; + + for (i = 0; sonames[i] != NULL && app->libnotify_module == NULL; i++ ) + { + app->libnotify_module = g_module_open (sonames[i], G_MODULE_BIND_LOCAL); + } + + if (app->libnotify_module != NULL) + { + g_module_symbol (app->libnotify_module, "notify_init", + (void*) &(app->libnotify_funcs.init)); + g_module_symbol (app->libnotify_module, "notify_uninit", + (void*) &(app->libnotify_funcs.uninit)); + g_module_symbol (app->libnotify_module, "notify_notification_new", + (void*) &(app->libnotify_funcs.notification_new)); + g_module_symbol (app->libnotify_module, "notify_notification_show", + (void*) &(app->libnotify_funcs.notification_show)); + + /* init libnotify */ + if (!app->libnotify_funcs.init || !app->libnotify_funcs.init ("midori")) + { + g_module_close (app->libnotify_module); + app->libnotify_module = NULL; + } + } + + app->program_notify_send = g_find_program_in_path ("notify-send"); +} + +/** + * midori_app_send_notification: + * @app: a #MidoriApp + * @title: title of the notification + * @message: text of the notification, or NULL + * + * Send #message to the notification daemon to display it. + * This is done by using libnotify if available or by using the program + * "notify-send" as a fallback. + * + * There is no guarantee that the message have been sent and displayed, as + * neither libnotify nor "notify-send" might be available or the + * notification daemon might not be running. + * + * Since 0.1.7 + **/ +void +midori_app_send_notification (MidoriApp* app, + const gchar* title, + const gchar* message) +{ + gboolean sent = FALSE; + + g_return_if_fail (MIDORI_IS_APP (app)); + g_return_if_fail (title); + + if (app->libnotify_module) + { + NotifyNotification* n; + + n = app->libnotify_funcs.notification_new (title, message, "midori", NULL); + sent = app->libnotify_funcs.notification_show (n, NULL); + g_object_unref (n); + } + /* Fall back to the command line program "notify-send" */ + if (!sent && app->program_notify_send) + { + gchar* msgq = g_shell_quote (message); + gchar* titleq = g_shell_quote (title); + gchar* command = g_strdup_printf ("%s -i midori %s %s", + app->program_notify_send, titleq, msgq); + + g_spawn_command_line_async (command, NULL); + + g_free (titleq); + g_free (msgq); + g_free (command); + } +} diff --git a/midori/midori-app.h b/midori/midori-app.h index a2f197e9..7b06ba30 100644 --- a/midori/midori-app.h +++ b/midori/midori-app.h @@ -64,6 +64,11 @@ midori_app_create_browser (MidoriApp* app); void midori_app_quit (MidoriApp* app); +void +midori_app_send_notification (MidoriApp* app, + const gchar* title, + const gchar* message); + G_END_DECLS #endif /* __MIDORI_APP_H__ */ diff --git a/midori/midori-browser.c b/midori/midori-browser.c index 662f6920..9f318403 100644 --- a/midori/midori-browser.c +++ b/midori/midori-browser.c @@ -26,6 +26,7 @@ #include "gtkiconentry.h" #include "compat.h" +#include "marshal.h" #include "sokoke.h" #include @@ -126,6 +127,7 @@ enum ACTIVATE_ACTION, CONTEXT_READY, ADD_DOWNLOAD, + SEND_NOTIFICATION, QUIT, LAST_SIGNAL @@ -970,25 +972,17 @@ midori_browser_download_notify_status_cb (WebKitDownload* download, if (browser->settings && katze_object_get_boolean ( browser->settings, "notify-transfer-completed")) { - gchar* program = g_find_program_in_path ("notify-send"); - if (program != NULL) - { - gchar* msg = g_strdup_printf ( - _("The file %s has been downloaded."), - webkit_download_get_suggested_filename (download)); - gchar* msgq = g_shell_quote (msg); - gchar* titleq = g_shell_quote (_("Transfer completed")); - gchar* command = g_strconcat (titleq, " ", msgq, NULL); - g_free (msg); - g_free (titleq); - g_free (msgq); - sokoke_spawn_program ("notify-send -i midori %s", command, FALSE); - g_free (command); - g_free (program); - } + gchar* msg = g_strdup_printf ( + _("The file %s has been downloaded."), + webkit_download_get_suggested_filename (download)); + + g_signal_emit (browser, signals[SEND_NOTIFICATION], 0, + _("Transfer completed"), msg); + + g_free (msg); } - } break; + } case WEBKIT_DOWNLOAD_STATUS_CANCELLED: case WEBKIT_DOWNLOAD_STATUS_ERROR: icon = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU); @@ -1411,6 +1405,29 @@ midori_browser_class_init (MidoriBrowserClass* class) G_TYPE_NONE, 1, G_TYPE_OBJECT); + /** + * MidoriBrowser::send-notification: + * @browser: the object on which the signal is emitted + * @title: the title for the notification + * @message: the message for the notification + * + * Emitted when a browser wants to display a notification message, + * e.g. when a download has been completed. + * + * Since: 0.1.7 + */ + signals[SEND_NOTIFICATION] = g_signal_new ( + "send-notification", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST), + 0, + 0, + NULL, + midori_cclosure_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); + signals[QUIT] = g_signal_new ( "quit", G_TYPE_FROM_CLASS (class), diff --git a/midori/midori-preferences.c b/midori/midori-preferences.c index 2d5fed31..3ce064fe 100644 --- a/midori/midori-preferences.c +++ b/midori/midori-preferences.c @@ -327,7 +327,6 @@ midori_preferences_set_settings (MidoriPreferences* preferences, GtkWidget* entry; GtkWidget* hbox; gint icon_width, icon_height; - gchar* program; g_return_if_fail (MIDORI_IS_PREFERENCES (preferences)); g_return_if_fail (MIDORI_IS_WEB_SETTINGS (settings)); @@ -433,9 +432,8 @@ midori_preferences_set_settings (MidoriPreferences* preferences, gtk_widget_set_sensitive (label, FALSE); INDENTED_ADD (label, 0, 1, 1, 2); button = katze_property_proxy (settings, "notify-transfer-completed", NULL); - if (!((program = g_find_program_in_path ("notify-send")))) - gtk_widget_set_sensitive (button, FALSE); - g_free (program); + /* FIXME: Disable the option if notifications presumably cannot be sent + gtk_widget_set_sensitive (button, FALSE); */ SPANNED_ADD (button, 1, 2, 1, 2); /* Page "Appearance" */