From 370ae655619c8e0fbd8a092d7dc8dc6ad4ab1445 Mon Sep 17 00:00:00 2001 From: William Jon McCann Date: Mon, 2 Nov 2009 17:15:45 -0500 Subject: [PATCH 1/3] Add an API to show a message on the locked screen Fixes https://bugzilla.gnome.org/show_bug.cgi?id=599258 --- src/gs-listener-dbus.c | 68 ++++++++++++++++++++++++++++++ src/gs-listener-dbus.h | 4 ++ src/gs-manager.c | 17 ++++++++ src/gs-manager.h | 4 ++ src/gs-marshal.list | 1 + src/gs-monitor.c | 16 +++++++ src/gs-window-x11.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ src/gs-window.h | 4 ++ 8 files changed, 221 insertions(+), 0 deletions(-) diff --git a/src/gs-listener-dbus.c b/src/gs-listener-dbus.c index 85a0328..e7690a5 100644 --- a/src/gs-listener-dbus.c +++ b/src/gs-listener-dbus.c @@ -108,6 +108,7 @@ enum { SIMULATE_USER_ACTIVITY, ACTIVE_CHANGED, THROTTLE_CHANGED, + SHOW_MESSAGE, LAST_SIGNAL }; @@ -1223,6 +1224,52 @@ listener_get_active_time (GSListener *listener, } static DBusHandlerResult +listener_show_message (GSListener *listener, + DBusConnection *connection, + DBusMessage *message) +{ + DBusMessageIter iter; + DBusMessage *reply; + DBusError error; + + reply = dbus_message_new_method_return (message); + + dbus_message_iter_init_append (reply, &iter); + + if (reply == NULL) { + g_error ("No memory"); + } + + if (listener->priv->active) { + char *summary; + char *body; + char *icon; + + /* if we're not active we ignore the request */ + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &summary, + DBUS_TYPE_STRING, &body, + DBUS_TYPE_STRING, &icon, + DBUS_TYPE_INVALID)) { + raise_syntax (connection, message, "ShowMessage"); + return DBUS_HANDLER_RESULT_HANDLED; + } + + g_signal_emit (listener, signals [SHOW_MESSAGE], 0, summary, body, icon); + } + + if (! dbus_connection_send (connection, reply, NULL)) { + g_error ("No memory"); + } + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult do_introspect (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface) @@ -1278,6 +1325,11 @@ do_introspect (DBusConnection *connection, " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -1362,6 +1414,9 @@ listener_dbus_handle_session_message (DBusConnection *connection, if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "GetActiveTime")) { return listener_get_active_time (listener, connection, message); } + if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "ShowMessage")) { + return listener_show_message (listener, connection, message); + } if (dbus_message_is_method_call (message, GS_LISTENER_SERVICE, "SimulateUserActivity")) { g_signal_emit (listener, signals [SIMULATE_USER_ACTIVITY], 0); return DBUS_HANDLER_RESULT_HANDLED; @@ -1796,6 +1851,19 @@ gs_listener_class_init (GSListenerClass *klass) G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals [SHOW_MESSAGE] = + g_signal_new ("show-message", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GSListenerClass, show_message), + NULL, + NULL, + gs_marshal_VOID__STRING_STRING_STRING, + G_TYPE_NONE, + 3, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING); g_object_class_install_property (object_class, PROP_ACTIVE, diff --git a/src/gs-listener-dbus.h b/src/gs-listener-dbus.h index a788e40..c57f367 100644 --- a/src/gs-listener-dbus.h +++ b/src/gs-listener-dbus.h @@ -52,6 +52,10 @@ typedef struct gboolean active); void (* throttle_changed) (GSListener *listener, gboolean throttled); + void (* show_message) (GSListener *listener, + const char *summary, + const char *body, + const char *icon); } GSListenerClass; diff --git a/src/gs-manager.c b/src/gs-manager.c index bb0ddf6..1609f83 100644 --- a/src/gs-manager.c +++ b/src/gs-manager.c @@ -1174,6 +1174,23 @@ find_window_at_pointer (GSManager *manager) return window; } +void +gs_manager_show_message (GSManager *manager, + const char *summary, + const char *body, + const char *icon) +{ + GSWindow *window; + + g_return_if_fail (GS_IS_MANAGER (manager)); + + /* Find the GSWindow that contains the pointer */ + window = find_window_at_pointer (manager); + gs_window_show_message (window, summary, body, icon); + + gs_manager_request_unlock (manager); +} + static gboolean manager_maybe_grab_window (GSManager *manager, GSWindow *window) diff --git a/src/gs-manager.h b/src/gs-manager.h index b0493ab..3a3e349 100644 --- a/src/gs-manager.h +++ b/src/gs-manager.h @@ -95,6 +95,10 @@ void gs_manager_set_themes (GSManager *manager, GSList *themes); void gs_manager_set_mode (GSManager *manager, GSSaverMode mode); +void gs_manager_show_message (GSManager *manager, + const char *summary, + const char *body, + const char *icon); gboolean gs_manager_request_unlock (GSManager *manager); void gs_manager_cancel_unlock_request (GSManager *manager); diff --git a/src/gs-marshal.list b/src/gs-marshal.list index 228ba92..9a4d620 100644 --- a/src/gs-marshal.list +++ b/src/gs-marshal.list @@ -1,3 +1,4 @@ BOOLEAN:VOID BOOLEAN:INT BOOLEAN:BOOLEAN +VOID:STRING,STRING,STRING diff --git a/src/gs-monitor.c b/src/gs-monitor.c index 0fd4402..640ee74 100644 --- a/src/gs-monitor.c +++ b/src/gs-monitor.c @@ -220,6 +220,19 @@ listener_cycle_cb (GSListener *listener, gs_manager_cycle (monitor->priv->manager); } +static void +listener_show_message_cb (GSListener *listener, + const char *summary, + const char *body, + const char *icon, + GSMonitor *monitor) +{ + gs_manager_show_message (monitor->priv->manager, + summary, + body, + icon); +} + static gboolean listener_active_changed_cb (GSListener *listener, gboolean active, @@ -334,6 +347,7 @@ disconnect_listener_signals (GSMonitor *monitor) g_signal_handlers_disconnect_by_func (monitor->priv->listener, listener_active_changed_cb, monitor); g_signal_handlers_disconnect_by_func (monitor->priv->listener, listener_throttle_changed_cb, monitor); g_signal_handlers_disconnect_by_func (monitor->priv->listener, listener_simulate_user_activity_cb, monitor); + g_signal_handlers_disconnect_by_func (monitor->priv->listener, listener_show_message_cb, monitor); } static void @@ -351,6 +365,8 @@ connect_listener_signals (GSMonitor *monitor) G_CALLBACK (listener_throttle_changed_cb), monitor); g_signal_connect (monitor->priv->listener, "simulate-user-activity", G_CALLBACK (listener_simulate_user_activity_cb), monitor); + g_signal_connect (monitor->priv->listener, "show-message", + G_CALLBACK (listener_show_message_cb), monitor); } static void diff --git a/src/gs-window-x11.c b/src/gs-window-x11.c index 2a74e10..5e0ebe5 100644 --- a/src/gs-window-x11.c +++ b/src/gs-window-x11.c @@ -52,6 +52,7 @@ enum { }; #define MAX_QUEUED_EVENTS 16 +#define INFO_BAR_SECONDS 30 #define GS_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_WINDOW, GSWindowPrivate)) @@ -77,6 +78,8 @@ struct GSWindowPrivate GtkWidget *lock_box; GtkWidget *lock_socket; GtkWidget *keyboard_socket; + GtkWidget *info_bar; + GtkWidget *info_content; GdkPixmap *background_pixmap; @@ -87,6 +90,7 @@ struct GSWindowPrivate guint dialog_response_signal_id; guint watchdog_timer_id; + guint info_bar_timer_id; gint lock_pid; gint lock_watch_id; @@ -896,6 +900,96 @@ gs_window_real_show (GtkWidget *widget) gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, window); } +static void +set_info_text_and_icon (GSWindow *window, + const char *icon_stock_id, + const char *primary_text, + const char *secondary_text) +{ + GtkWidget *content_area; + GtkWidget *hbox_content; + GtkWidget *image; + GtkWidget *vbox; + gchar *primary_markup; + gchar *secondary_markup; + GtkWidget *primary_label; + GtkWidget *secondary_label; + + hbox_content = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox_content); + + image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG); + gtk_widget_show (image); + gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox_content), vbox, FALSE, FALSE, 0); + + primary_markup = g_strdup_printf ("%s", primary_text); + primary_label = gtk_label_new (primary_markup); + g_free (primary_markup); + gtk_widget_show (primary_label); + gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0); + gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5); + + if (secondary_text != NULL) { + secondary_markup = g_strdup_printf ("%s", + secondary_text); + secondary_label = gtk_label_new (secondary_markup); + g_free (secondary_markup); + gtk_widget_show (secondary_label); + gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0); + gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5); + } + + /* remove old content */ + content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (window->priv->info_bar)); + if (window->priv->info_content != NULL) { + gtk_container_remove (GTK_CONTAINER (content_area), window->priv->info_content); + } + gtk_box_pack_start (GTK_BOX (content_area), + hbox_content, + TRUE, FALSE, 0); + window->priv->info_content = hbox_content; +} + +static gboolean +info_bar_timeout (GSWindow *window) +{ + window->priv->info_bar_timer_id = 0; + gtk_widget_hide (window->priv->info_bar); + return FALSE; +} + +void +gs_window_show_message (GSWindow *window, + const char *summary, + const char *body, + const char *icon) +{ + g_return_if_fail (GS_IS_WINDOW (window)); + + set_info_text_and_icon (window, + icon, + summary, + body); + gtk_widget_show (window->priv->info_bar); + + if (window->priv->info_bar_timer_id > 0) { + g_source_remove (window->priv->info_bar_timer_id); + } + + window->priv->info_bar_timer_id = g_timeout_add_seconds (INFO_BAR_SECONDS, + (GSourceFunc)info_bar_timeout, + window); +} + void gs_window_show (GSWindow *window) { @@ -2218,6 +2312,14 @@ gs_window_class_init (GSWindowClass *klass) } static void +create_info_bar (GSWindow *window) +{ + window->priv->info_bar = gtk_info_bar_new (); + gtk_widget_set_no_show_all (window->priv->info_bar, TRUE); + gtk_box_pack_end (GTK_BOX (window->priv->vbox), window->priv->info_bar, FALSE, FALSE, 0); +} + +static void gs_window_init (GSWindow *window) { window->priv = GS_WINDOW_GET_PRIVATE (window); @@ -2258,6 +2360,7 @@ gs_window_init (GSWindow *window) window->priv->drawing_area = gtk_drawing_area_new (); gtk_widget_show (window->priv->drawing_area); gtk_box_pack_start (GTK_BOX (window->priv->vbox), window->priv->drawing_area, TRUE, TRUE, 0); + create_info_bar (window); force_no_pixmap_background (window->priv->drawing_area); } @@ -2290,6 +2393,10 @@ gs_window_finalize (GObject *object) g_free (window->priv->logout_command); g_free (window->priv->keyboard_command); + if (window->priv->info_bar_timer_id > 0) { + g_source_remove (window->priv->info_bar_timer_id); + } + remove_watchdog_timer (window); remove_popup_dialog_idle (window); diff --git a/src/gs-window.h b/src/gs-window.h index 6440a6d..fc2287e 100644 --- a/src/gs-window.h +++ b/src/gs-window.h @@ -83,6 +83,10 @@ void gs_window_set_logout_command (GSWindow *window, const char *command); void gs_window_set_status_message (GSWindow *window, const char *status_message); +void gs_window_show_message (GSWindow *window, + const char *summary, + const char *body, + const char *icon); void gs_window_request_unlock (GSWindow *window); void gs_window_cancel_unlock_request (GSWindow *window); -- 1.6.5.2