Patch by chpe to add support for using the new GtkStatusIcon in GTK+ 2.9.x. These functions are #ifdef'd to only be provided in supported versions of GTK. The patch also added support for GObject properties on the NotifyNotification objects. This closes ticket #60.

This commit is contained in:
Christian Hammond 2006-06-05 00:48:56 +00:00
parent 51ecbc7a2b
commit d986aaf233
4 changed files with 372 additions and 72 deletions

View File

@ -1,3 +1,12 @@
Sun Jun 04 17:44:27 PDT 2006 Christian Hammond <chipx86@chipx86.com>
* libnotify/notification.c:
* libnotify/notification.h:
- Patch by chpe to add support for using the new GtkStatusIcon in
GTK+ 2.9.x. These functions are #ifdef'd to only be provided in
supported versions of GTK. The patch also added support for GObject
properties on the NotifyNotification objects. This closes ticket #60.
Sun Jun 04 16:12:05 PDT 2006 Christian Hammond <chipx86@chipx86.com> Sun Jun 04 16:12:05 PDT 2006 Christian Hammond <chipx86@chipx86.com>
* libnotify/notify.c: * libnotify/notify.c:

7
NEWS
View File

@ -1,3 +1,10 @@
version 0.4.1:
* Added support for attaching to a GtkStatusIcon. Patch by chpe. (Bug #60)
* Added GObject properties to NotifyNotification. Patch by chpe. (Bug #60)
* Fixed up libnotify.pc to support dependencies correctly. (Bug #58)
* Fixed notify_uninit() to properly set _initted to FALSE after being
called. (Bug #56)
version 0.4.0 (26-April-2006): version 0.4.0 (26-April-2006):
* Patch by M.S. to switch notify-send to use GOption instead of popt, * Patch by M.S. to switch notify-send to use GOption instead of popt,
to add -v, --version, -h, and --hint options, and to rename to add -v, --version, -h, and --hint options, and to rename

View File

@ -26,10 +26,23 @@
#include <libnotify/notify.h> #include <libnotify/notify.h>
#include <libnotify/internal.h> #include <libnotify/internal.h>
#include <gtk/gtkversion.h>
#if GTK_CHECK_VERSION(2, 9, 2)
# define HAVE_STATUS_ICON
# include <gtk/gtkstatusicon.h>
#endif
#define CHECK_DBUS_VERSION(major, minor) \ #define CHECK_DBUS_VERSION(major, minor) \
(DBUS_MAJOR_VER > (major) || \ (DBUS_MAJOR_VER > (major) || \
(DBUS_MAJOR_VER == (major) && DBUS_MINOR_VER >= (minor))) (DBUS_MAJOR_VER == (major) && DBUS_MINOR_VER >= (minor)))
#if !defined(G_PARAM_STATIC_NAME) && !defined(G_PARAM_STATIC_NICK) && \
!defined(G_PARAM_STATIC_BLURB)
# define G_PARAM_STATIC_NAME 0
# define G_PARAM_STATIC_NICK 0
# define G_PARAM_STATIC_BLURB 0
#endif
static void notify_notification_class_init(NotifyNotificationClass *klass); static void notify_notification_class_init(NotifyNotificationClass *klass);
static void notify_notification_init(NotifyNotification *sp); static void notify_notification_init(NotifyNotification *sp);
static void notify_notification_finalize(GObject *object); static void notify_notification_finalize(GObject *object);
@ -69,8 +82,9 @@ struct _NotifyNotificationPrivate
GHashTable *hints; GHashTable *hints;
GtkWidget *attached_widget; GtkWidget *attached_widget;
gint widget_old_x; #ifdef HAVE_STATUS_ICON
gint widget_old_y; GtkStatusIcon *status_icon;
#endif
gboolean has_nondefault_actions; gboolean has_nondefault_actions;
gboolean updates_pending; gboolean updates_pending;
@ -83,10 +97,38 @@ enum
LAST_SIGNAL LAST_SIGNAL
}; };
enum
{
PROP_0,
PROP_SUMMARY,
PROP_BODY,
PROP_ICON_NAME,
PROP_ATTACH_WIDGET,
PROP_STATUS_ICON
};
static void notify_notification_set_property(GObject *object, guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void notify_notification_get_property(GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static guint signals[LAST_SIGNAL] = { 0 }; static guint signals[LAST_SIGNAL] = { 0 };
static GObjectClass *parent_class = NULL; static GObjectClass *parent_class = NULL;
G_DEFINE_TYPE(NotifyNotification, notify_notification, G_TYPE_OBJECT); G_DEFINE_TYPE(NotifyNotification, notify_notification, G_TYPE_OBJECT)
static GObject *
notify_notification_constructor(GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GObject *object = parent_class->constructor(type, n_construct_properties,
construct_params);
_notify_cache_add_notification(NOTIFY_NOTIFICATION(object));
return object;
}
static void static void
notify_notification_class_init(NotifyNotificationClass *klass) notify_notification_class_init(NotifyNotificationClass *klass)
@ -95,6 +137,9 @@ notify_notification_class_init(NotifyNotificationClass *klass)
parent_class = g_type_class_peek_parent(klass); parent_class = g_type_class_peek_parent(klass);
object_class->constructor = notify_notification_constructor;
object_class->get_property = notify_notification_get_property;
object_class->set_property = notify_notification_set_property;
object_class->finalize = notify_notification_finalize; object_class->finalize = notify_notification_finalize;
/* Create signals here: */ /* Create signals here: */
@ -105,6 +150,157 @@ notify_notification_class_init(NotifyNotificationClass *klass)
G_STRUCT_OFFSET(NotifyNotificationClass, closed), G_STRUCT_OFFSET(NotifyNotificationClass, closed),
NULL, NULL, NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
g_object_class_install_property
(object_class,
PROP_SUMMARY,
g_param_spec_string("summary",
"Summary",
"Summary",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_class_install_property
(object_class,
PROP_BODY,
g_param_spec_string("body",
"Message Body",
"Message body",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_class_install_property
(object_class,
PROP_ICON_NAME,
g_param_spec_string("icon-name",
"Icon Name",
"Icon name",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_object_class_install_property
(object_class,
PROP_ATTACH_WIDGET,
g_param_spec_object("attach-widget",
"Attach Widget",
"Attach Widget",
GTK_TYPE_WIDGET,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
#ifdef HAVE_STATUS_ICON
g_object_class_install_property
(object_class,
PROP_STATUS_ICON,
g_param_spec_object("status-icon",
"Status Icon",
"Status Icon",
GTK_TYPE_STATUS_ICON,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
#endif /* HAVE_STATUS_ICON */
}
static void
notify_notification_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NotifyNotification *notification = NOTIFY_NOTIFICATION(object);
NotifyNotificationPrivate *priv = notification->priv;
switch (prop_id)
{
case PROP_SUMMARY:
notify_notification_update(notification, g_value_get_string(value),
priv->body, priv->icon_name);
break;
case PROP_BODY:
notify_notification_update(notification, priv->summary,
g_value_get_string(value),
priv->icon_name);
break;
case PROP_ICON_NAME:
notify_notification_update(notification, priv->summary,
priv->body, g_value_get_string(value));
break;
case PROP_ATTACH_WIDGET:
notify_notification_attach_to_widget(notification,
g_value_get_object(value));
break;
#ifdef HAVE_STATUS_ICON
case PROP_STATUS_ICON:
notify_notification_attach_to_status_icon(notification,
g_value_get_object(value));
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
notify_notification_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NotifyNotification *notification = NOTIFY_NOTIFICATION(object);
NotifyNotificationPrivate *priv = notification->priv;
switch (prop_id)
{
case PROP_SUMMARY:
g_value_set_string(value, priv->summary);
break;
case PROP_BODY:
g_value_set_string(value, priv->body);
break;
case PROP_ICON_NAME:
g_value_set_string(value, priv->icon_name);
break;
case PROP_ATTACH_WIDGET:
g_value_set_object(value, priv->attached_widget);
break;
#ifdef HAVE_STATUS_ICON
case PROP_STATUS_ICON:
g_value_set_object(value, priv->status_icon);
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
} }
static void static void
@ -165,6 +361,12 @@ notify_notification_finalize(GObject *object)
if (priv->attached_widget != NULL) if (priv->attached_widget != NULL)
g_object_unref(G_OBJECT(priv->attached_widget)); g_object_unref(G_OBJECT(priv->attached_widget));
#if HAVE_STATUS_ICON
if (priv->status_icon != NULL)
g_object_remove_weak_pointer(G_OBJECT(priv->status_icon),
(gpointer)&priv->status_icon);
#endif
if (priv->signals_registered) if (priv->signals_registered)
{ {
dbus_g_proxy_disconnect_signal(proxy, "NotificationClosed", dbus_g_proxy_disconnect_signal(proxy, "NotificationClosed",
@ -180,60 +382,58 @@ notify_notification_finalize(GObject *object)
G_OBJECT_CLASS(parent_class)->finalize(object); G_OBJECT_CLASS(parent_class)->finalize(object);
} }
static gboolean static void
_notify_notification_update_applet_hints(NotifyNotification *n) _notify_notification_update_applet_hints(NotifyNotification *n)
{ {
NotifyNotificationPrivate *priv = n->priv; NotifyNotificationPrivate *priv = n->priv;
gboolean update_pending = FALSE; GdkScreen *screen = NULL;
GdkRectangle rect;
#ifdef HAVE_STATUS_ICON
if (priv->status_icon != NULL)
{
if (!gtk_status_icon_get_geometry(priv->status_icon, &screen,
&rect, NULL))
{
return;
}
}
else
#endif /* HAVE_STATUS_ICON */
if (priv->attached_widget != NULL) if (priv->attached_widget != NULL)
{ {
gint x, y, h, w;
GtkWidget *widget = priv->attached_widget; GtkWidget *widget = priv->attached_widget;
GtkRequisition requisition; GtkRequisition requisition;
screen = gtk_widget_get_screen(widget);
gtk_widget_size_request(widget, &requisition); gtk_widget_size_request(widget, &requisition);
w = requisition.width; rect.width = requisition.width;
h = requisition.height; rect.height = requisition.height;
gdk_window_get_origin(widget->window, &x, &y); gdk_window_get_origin(widget->window, &rect.x, &rect.y);
if (GTK_WIDGET_NO_WINDOW(widget)) if (GTK_WIDGET_NO_WINDOW(widget))
{ {
x += widget->allocation.x; rect.x += widget->allocation.x;
y += widget->allocation.y; rect.y += widget->allocation.y;
} }
x += widget->allocation.width / 2; rect.x += widget->allocation.width / 2;
y += widget->allocation.height / 2; rect.y += widget->allocation.height / 2;
if (x != priv->widget_old_x)
{
notify_notification_set_hint_int32(n, "x", x);
priv->widget_old_x = x;
update_pending = TRUE;
} }
else
return;
if (y != priv->widget_old_y) notify_notification_set_geometry_hints(n, screen, &rect);
{
notify_notification_set_hint_int32(n, "y", y);
priv->widget_old_y = y;
update_pending = TRUE;
}
}
return update_pending;
} }
#if 0 #if 0
/*
/* This is left here just incase we revisit autoupdating * This is left here just incase we revisit autoupdating
One thought would be to check for updates every time the icon * One thought would be to check for updates every time the icon
is redrawn but we still have to deal with the race conditions * is redrawn but we still have to deal with the race conditions
that could occure between the server and the client so we will * that could occure between the server and the client so we will
leave this alone for now. * leave this alone for now.
*/ */
static gboolean static gboolean
_idle_check_updates(void *user_data) _idle_check_updates(void *user_data)
@ -264,31 +464,33 @@ NotifyNotification *
notify_notification_new(const gchar *summary, const gchar *body, notify_notification_new(const gchar *summary, const gchar *body,
const gchar *icon, GtkWidget *attach) const gchar *icon, GtkWidget *attach)
{ {
NotifyNotification *obj;
g_return_val_if_fail(summary != NULL && *summary != '\0', NULL);
g_return_val_if_fail(attach == NULL || GTK_IS_WIDGET(attach), NULL); g_return_val_if_fail(attach == NULL || GTK_IS_WIDGET(attach), NULL);
obj = NOTIFY_NOTIFICATION(g_object_new(NOTIFY_TYPE_NOTIFICATION, NULL)); return g_object_new(NOTIFY_TYPE_NOTIFICATION,
"summary", summary,
"body", body,
"icon-name", icon,
"attach-widget", attach,
NULL);
}
obj->priv->summary = g_strdup(summary); #ifdef HAVE_STATUS_ICON
NotifyNotification *
if (body != NULL && *body != '\0') notify_notification_new_with_status_icon(const gchar *summary,
obj->priv->body = g_strdup(body); const gchar *message,
const gchar *icon,
if (icon != NULL && *icon != '\0') GtkStatusIcon *status_icon)
obj->priv->icon_name = g_strdup(icon);
if (attach != NULL)
{ {
g_object_ref(G_OBJECT(attach)); g_return_val_if_fail(status_icon == NULL || GTK_IS_STATUS_ICON(status_icon), NULL);
obj->priv->attached_widget = attach;
}
_notify_cache_add_notification(obj); return g_object_new(NOTIFY_TYPE_NOTIFICATION,
"summary", summary,
return obj; "body", message,
"icon-name", icon,
"status-icon", status_icon,
NULL);
} }
#endif /* HAVE_STATUS_ICON */
gboolean gboolean
notify_notification_update(NotifyNotification *notification, notify_notification_update(NotifyNotification *notification,
@ -299,17 +501,28 @@ notify_notification_update(NotifyNotification *notification,
g_return_val_if_fail(NOTIFY_IS_NOTIFICATION(notification), FALSE); g_return_val_if_fail(NOTIFY_IS_NOTIFICATION(notification), FALSE);
g_return_val_if_fail(summary != NULL && *summary != '\0', FALSE); g_return_val_if_fail(summary != NULL && *summary != '\0', FALSE);
if (notification->priv->summary != summary)
{
g_free(notification->priv->summary); g_free(notification->priv->summary);
g_free(notification->priv->body);
g_free(notification->priv->icon_name);
notification->priv->summary = g_strdup(summary); notification->priv->summary = g_strdup(summary);
g_object_notify(G_OBJECT(notification), "summary");
}
if (body != NULL && *body != '\0') if (notification->priv->body != body)
notification->priv->body = g_strdup(body); {
g_free(notification->priv->body);
notification->priv->body =
(body != NULL && *body != '\0' ? g_strdup(body) : NULL);
g_object_notify(G_OBJECT(notification), "body");
}
if (icon != NULL && *icon != '\0') if (notification->priv->icon_name != icon)
notification->priv->icon_name = g_strdup(icon); {
g_free(notification->priv->icon_name);
notification->priv->icon_name =
(icon != NULL && *icon != '\0' ? g_strdup(icon) : NULL);
g_object_notify(G_OBJECT(notification), "icon-name");
}
notification->priv->updates_pending = TRUE; notification->priv->updates_pending = TRUE;
@ -320,14 +533,70 @@ void
notify_notification_attach_to_widget(NotifyNotification *notification, notify_notification_attach_to_widget(NotifyNotification *notification,
GtkWidget *attach) GtkWidget *attach)
{ {
g_return_if_fail(notification != NULL);
g_return_if_fail(NOTIFY_IS_NOTIFICATION(notification)); g_return_if_fail(NOTIFY_IS_NOTIFICATION(notification));
if (notification->priv->attached_widget == attach)
return;
if (notification->priv->attached_widget != NULL) if (notification->priv->attached_widget != NULL)
g_object_unref(notification->priv->attached_widget); g_object_unref(notification->priv->attached_widget);
notification->priv->attached_widget = notification->priv->attached_widget =
(attach != NULL ? g_object_ref(attach) : NULL); (attach != NULL ? g_object_ref(attach) : NULL);
g_object_notify(G_OBJECT(notification), "attach-widget");
}
#ifdef HAVE_STATUS_ICON
void
notify_notification_attach_to_status_icon(NotifyNotification *notification,
GtkStatusIcon *status_icon)
{
g_return_if_fail(NOTIFY_IS_NOTIFICATION(notification));
g_return_if_fail(status_icon == NULL || GTK_IS_STATUS_ICON(status_icon));
if (notification->priv->status_icon == status_icon)
return;
if (priv->status_icon != NULL)
{
g_object_remove_weak_pointer(G_OBJECT(priv->status_icon),
(gpointer)&priv->status_icon);
}
priv->status_icon = status_icon;
if (priv->status_icon != NULL)
{
g_object_add_weak_pointer(G_OBJECT(priv->status_icon),
(gpointer)&priv->status_icon);
}
g_object_notify(G_OBJECT(notification), "attach-icon");
}
#endif /* HAVE_STATUS_ICON */
void
notify_notification_set_geometry_hints(NotifyNotification *notification,
GdkScreen *screen,
GdkRectangle *rect)
{
char *display_name;
g_return_if_fail(notification != NULL);
g_return_if_fail(NOTIFY_IS_NOTIFICATION(notification));
g_return_if_fail(screen != NULL);
g_return_if_fail(GDK_IS_SCREEN(screen));
g_return_if_fail(rect != NULL);
notify_notification_set_hint_int32(notification, "x", rect->x);
notify_notification_set_hint_int32(notification, "y", rect->y);
notify_notification_set_hint_int32(notification, "width", rect->width);
notify_notification_set_hint_int32(notification, "height", rect->height);
display_name = gdk_screen_make_display_name(screen);
notify_notification_set_hint_string(notification, "xdisplay", display_name);
g_free(display_name);
} }
static void static void
@ -405,7 +674,7 @@ notify_notification_show(NotifyNotification *notification, GError **error)
priv->signals_registered = TRUE; priv->signals_registered = TRUE;
} }
/* If attached to a widget, modify x and y in hints */ /* If attached to a widget or status icon, modify x and y in hints */
_notify_notification_update_applet_hints(notification); _notify_notification_update_applet_hints(notification);
action_array = _gslist_to_string_array(priv->actions); action_array = _gslist_to_string_array(priv->actions);

View File

@ -25,6 +25,7 @@
#include <glib.h> #include <glib.h>
#include <glib-object.h> #include <glib-object.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gtk/gtkversion.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -86,6 +87,11 @@ NotifyNotification *notify_notification_new(const gchar *summary,
const gchar *message, const gchar *message,
const gchar *icon, const gchar *icon,
GtkWidget *attach); GtkWidget *attach);
#if GTK_CHECK_VERSION(2, 9, 2)
NotifyNotification *notify_notification_new_with_status_icon(
const gchar *summary, const gchar *message,
const gchar *icon, GtkStatusIcon *status_icon);
#endif
gboolean notify_notification_update(NotifyNotification *notification, gboolean notify_notification_update(NotifyNotification *notification,
const gchar *summary, const gchar *summary,
@ -95,6 +101,15 @@ gboolean notify_notification_update(NotifyNotification *notification,
void notify_notification_attach_to_widget(NotifyNotification* notification, void notify_notification_attach_to_widget(NotifyNotification* notification,
GtkWidget *attach); GtkWidget *attach);
#if GTK_CHECK_VERSION(2, 9, 2)
void notify_notification_attach_to_status_icon(NotifyNotification *notification,
GtkStatusIcon *status_icon);
#endif
void notify_notification_set_geometry_hints(NotifyNotification *notification,
GdkScreen *screen,
GdkRectangle *rect);
gboolean notify_notification_show(NotifyNotification *notification, gboolean notify_notification_show(NotifyNotification *notification,
GError **error); GError **error);
@ -107,8 +122,8 @@ void notify_notification_set_category(NotifyNotification *notification,
void notify_notification_set_urgency(NotifyNotification *notification, void notify_notification_set_urgency(NotifyNotification *notification,
NotifyUrgency l); NotifyUrgency l);
void notify_notification_set_icon_from_pixbuf( void notify_notification_set_icon_from_pixbuf(NotifyNotification *notification,
NotifyNotification *notification, GdkPixbuf *icon); GdkPixbuf *icon);
void notify_notification_set_hint_int32(NotifyNotification *notification, void notify_notification_set_hint_int32(NotifyNotification *notification,
const gchar *key, gint value); const gchar *key, gint value);