From 4d56989d9080bf79a7c2b126a96a4c0549a305b3 Mon Sep 17 00:00:00 2001 From: Jesse van den Kieboom Date: Thu, 5 Jan 2006 23:30:07 +0000 Subject: [PATCH] Initial import --- gnoemoe/widgets/eggtrayicon.c | 468 ++++++++++++++++++++++++++++++++++ gnoemoe/widgets/eggtrayicon.h | 77 ++++++ gnoemoe/widgets/gm-tray.c | 207 +++++++++++++++ gnoemoe/widgets/gm-tray.h | 76 ++++++ 4 files changed, 828 insertions(+) create mode 100644 gnoemoe/widgets/eggtrayicon.c create mode 100644 gnoemoe/widgets/eggtrayicon.h create mode 100644 gnoemoe/widgets/gm-tray.c create mode 100644 gnoemoe/widgets/gm-tray.h diff --git a/gnoemoe/widgets/eggtrayicon.c b/gnoemoe/widgets/eggtrayicon.c new file mode 100644 index 0000000..3a517cd --- /dev/null +++ b/gnoemoe/widgets/eggtrayicon.c @@ -0,0 +1,468 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eggtrayicon.c + * Copyright (C) 2002 Anders Carlsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include "eggtrayicon.h" + +#include +#include + +#ifndef EGG_COMPILATION +#ifndef _ +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x +#endif +#else +#define _(x) x +#define N_(x) x +#endif + +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + +#define SYSTEM_TRAY_ORIENTATION_HORZ 0 +#define SYSTEM_TRAY_ORIENTATION_VERT 1 + +enum { + PROP_0, + PROP_ORIENTATION +}; + +static GtkPlugClass *parent_class = NULL; + +static void egg_tray_icon_init (EggTrayIcon *icon); +static void egg_tray_icon_class_init (EggTrayIconClass *klass); + +static void egg_tray_icon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void egg_tray_icon_realize (GtkWidget *widget); +static void egg_tray_icon_unrealize (GtkWidget *widget); + +static void egg_tray_icon_update_manager_window (EggTrayIcon *icon); + +GType +egg_tray_icon_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EggTrayIconClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_tray_icon_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (EggTrayIcon), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_tray_icon_init + }; + + our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0); + } + + return our_type; +} + +static void +egg_tray_icon_init (EggTrayIcon *icon) +{ + icon->stamp = 1; + icon->orientation = GTK_ORIENTATION_HORIZONTAL; + + gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK); +} + +static void +egg_tray_icon_class_init (EggTrayIconClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->get_property = egg_tray_icon_get_property; + + widget_class->realize = egg_tray_icon_realize; + widget_class->unrealize = egg_tray_icon_unrealize; + + g_object_class_install_property (gobject_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + _("Orientation"), + _("The orientation of the tray."), + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + G_PARAM_READABLE)); +} + +static void +egg_tray_icon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggTrayIcon *icon = EGG_TRAY_ICON (object); + + switch (prop_id) + { + case PROP_ORIENTATION: + g_value_set_enum (value, icon->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +egg_tray_icon_get_orientation_property (EggTrayIcon *icon) +{ + Display *xdisplay; + Atom type; + int format; + union { + gulong *prop; + guchar *prop_ch; + } prop = { NULL }; + gulong nitems; + gulong bytes_after; + int error, result; + + g_assert (icon->manager_window != None); + + xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); + + gdk_error_trap_push (); + type = None; + result = XGetWindowProperty (xdisplay, + icon->manager_window, + icon->orientation_atom, + 0, G_MAXLONG, FALSE, + XA_CARDINAL, + &type, &format, &nitems, + &bytes_after, &(prop.prop_ch)); + error = gdk_error_trap_pop (); + + if (error || result != Success) + return; + + if (type == XA_CARDINAL) + { + GtkOrientation orientation; + + orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ? + GTK_ORIENTATION_HORIZONTAL : + GTK_ORIENTATION_VERTICAL; + + if (icon->orientation != orientation) + { + icon->orientation = orientation; + + g_object_notify (G_OBJECT (icon), "orientation"); + } + } + + if (prop.prop) + XFree (prop.prop); +} + +static GdkFilterReturn +egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data) +{ + EggTrayIcon *icon = user_data; + XEvent *xev = (XEvent *)xevent; + + if (xev->xany.type == ClientMessage && + xev->xclient.message_type == icon->manager_atom && + (Atom)(xev->xclient.data.l[1]) == icon->selection_atom) + { + egg_tray_icon_update_manager_window (icon); + } + else if (xev->xany.window == icon->manager_window) + { + if (xev->xany.type == PropertyNotify && + xev->xproperty.atom == icon->orientation_atom) + { + egg_tray_icon_get_orientation_property (icon); + } + if (xev->xany.type == DestroyNotify) + { + egg_tray_icon_update_manager_window (icon); + } + } + + return GDK_FILTER_CONTINUE; +} + +static void +egg_tray_icon_unrealize (GtkWidget *widget) +{ + EggTrayIcon *icon = EGG_TRAY_ICON (widget); + GdkWindow *root_window; + + if (icon->manager_window != None) + { + GdkWindow *gdkwin; + + gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget), + icon->manager_window); + + gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); + } + + root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); + + gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon); + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void +egg_tray_icon_send_manager_message (EggTrayIcon *icon, + long message, + Window window, + long data1, + long data2, + long data3) +{ + XClientMessageEvent ev; + Display *display; + + ev.type = ClientMessage; + ev.window = window; + ev.message_type = icon->system_tray_opcode_atom; + ev.format = 32; + ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window); + ev.data.l[1] = message; + ev.data.l[2] = data1; + ev.data.l[3] = data2; + ev.data.l[4] = data3; + + display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); + + gdk_error_trap_push (); + XSendEvent (display, + icon->manager_window, False, NoEventMask, (XEvent *)&ev); + XSync (display, False); + gdk_error_trap_pop (); +} + +static void +egg_tray_icon_send_dock_request (EggTrayIcon *icon) +{ + egg_tray_icon_send_manager_message (icon, + SYSTEM_TRAY_REQUEST_DOCK, + icon->manager_window, + gtk_plug_get_id (GTK_PLUG (icon)), + 0, 0); +} + +static void +egg_tray_icon_update_manager_window (EggTrayIcon *icon) +{ + Display *xdisplay; + + xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); + + if (icon->manager_window != None) + { + GdkWindow *gdkwin; + + gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), + icon->manager_window); + + gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); + } + + XGrabServer (xdisplay); + + icon->manager_window = XGetSelectionOwner (xdisplay, + icon->selection_atom); + + if (icon->manager_window != None) + XSelectInput (xdisplay, + icon->manager_window, StructureNotifyMask|PropertyChangeMask); + + XUngrabServer (xdisplay); + XFlush (xdisplay); + + if (icon->manager_window != None) + { + GdkWindow *gdkwin; + + gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), + icon->manager_window); + + gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon); + + /* Send a request that we'd like to dock */ + egg_tray_icon_send_dock_request (icon); + + egg_tray_icon_get_orientation_property (icon); + } +} + +static void +egg_tray_icon_realize (GtkWidget *widget) +{ + EggTrayIcon *icon = EGG_TRAY_ICON (widget); + GdkScreen *screen; + GdkDisplay *display; + Display *xdisplay; + char buffer[256]; + GdkWindow *root_window; + + if (GTK_WIDGET_CLASS (parent_class)->realize) + GTK_WIDGET_CLASS (parent_class)->realize (widget); + + screen = gtk_widget_get_screen (widget); + display = gdk_screen_get_display (screen); + xdisplay = gdk_x11_display_get_xdisplay (display); + + /* Now see if there's a manager window around */ + g_snprintf (buffer, sizeof (buffer), + "_NET_SYSTEM_TRAY_S%d", + gdk_screen_get_number (screen)); + + icon->selection_atom = XInternAtom (xdisplay, buffer, False); + + icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False); + + icon->system_tray_opcode_atom = XInternAtom (xdisplay, + "_NET_SYSTEM_TRAY_OPCODE", + False); + + icon->orientation_atom = XInternAtom (xdisplay, + "_NET_SYSTEM_TRAY_ORIENTATION", + False); + + egg_tray_icon_update_manager_window (icon); + + root_window = gdk_screen_get_root_window (screen); + + /* Add a root window filter so that we get changes on MANAGER */ + gdk_window_add_filter (root_window, + egg_tray_icon_manager_filter, icon); +} + +EggTrayIcon * +egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL); +} + +EggTrayIcon* +egg_tray_icon_new (const gchar *name) +{ + return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL); +} + +guint +egg_tray_icon_send_message (EggTrayIcon *icon, + gint timeout, + const gchar *message, + gint len) +{ + guint stamp; + + g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0); + g_return_val_if_fail (timeout >= 0, 0); + g_return_val_if_fail (message != NULL, 0); + + if (icon->manager_window == None) + return 0; + + if (len < 0) + len = strlen (message); + + stamp = icon->stamp++; + + /* Get ready to send the message */ + egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE, + (Window)gtk_plug_get_id (GTK_PLUG (icon)), + timeout, len, stamp); + + /* Now to send the actual message */ + gdk_error_trap_push (); + while (len > 0) + { + XClientMessageEvent ev; + Display *xdisplay; + + xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); + + ev.type = ClientMessage; + ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon)); + ev.format = 8; + ev.message_type = XInternAtom (xdisplay, + "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); + if (len > 20) + { + memcpy (&ev.data, message, 20); + len -= 20; + message += 20; + } + else + { + memcpy (&ev.data, message, len); + len = 0; + } + + XSendEvent (xdisplay, + icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev); + XSync (xdisplay, False); + } + gdk_error_trap_pop (); + + return stamp; +} + +void +egg_tray_icon_cancel_message (EggTrayIcon *icon, + guint id) +{ + g_return_if_fail (EGG_IS_TRAY_ICON (icon)); + g_return_if_fail (id > 0); + + egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE, + (Window)gtk_plug_get_id (GTK_PLUG (icon)), + id, 0, 0); +} + +GtkOrientation +egg_tray_icon_get_orientation (EggTrayIcon *icon) +{ + g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL); + + return icon->orientation; +} diff --git a/gnoemoe/widgets/eggtrayicon.h b/gnoemoe/widgets/eggtrayicon.h new file mode 100644 index 0000000..007f4c1 --- /dev/null +++ b/gnoemoe/widgets/eggtrayicon.h @@ -0,0 +1,77 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eggtrayicon.h + * Copyright (C) 2002 Anders Carlsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TRAY_ICON_H__ +#define __EGG_TRAY_ICON_H__ + +#include +#include + +G_BEGIN_DECLS + +#define EGG_TYPE_TRAY_ICON (egg_tray_icon_get_type ()) +#define EGG_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon)) +#define EGG_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass)) +#define EGG_IS_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON)) +#define EGG_IS_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON)) +#define EGG_TRAY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass)) + +typedef struct _EggTrayIcon EggTrayIcon; +typedef struct _EggTrayIconClass EggTrayIconClass; + +struct _EggTrayIcon +{ + GtkPlug parent_instance; + + guint stamp; + + Atom selection_atom; + Atom manager_atom; + Atom system_tray_opcode_atom; + Atom orientation_atom; + Window manager_window; + + GtkOrientation orientation; +}; + +struct _EggTrayIconClass +{ + GtkPlugClass parent_class; +}; + +GType egg_tray_icon_get_type (void); + +EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen *screen, + const gchar *name); + +EggTrayIcon *egg_tray_icon_new (const gchar *name); + +guint egg_tray_icon_send_message (EggTrayIcon *icon, + gint timeout, + const char *message, + gint len); +void egg_tray_icon_cancel_message (EggTrayIcon *icon, + guint id); + +GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon); + +G_END_DECLS + +#endif /* __EGG_TRAY_ICON_H__ */ diff --git a/gnoemoe/widgets/gm-tray.c b/gnoemoe/widgets/gm-tray.c new file mode 100644 index 0000000..0afb654 --- /dev/null +++ b/gnoemoe/widgets/gm-tray.c @@ -0,0 +1,207 @@ +#include +#include "gm-tray.h" +#include "eggtrayicon.h" + +#define GM_TRAY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_TRAY, GmTrayPrivate)) + +struct _GmTrayPrivate { + GtkWidget *event_box; + GtkImage *image; + GtkTooltips *tooltips; + + guint flash_timeout; + GmTrayState current_state; + GmTrayState prev_state; + GdkPixbuf *icons[NUM_TRAY_STATES]; +}; + +/* Signals + +enum { + NUM_SIGNALS +}; + +static guint tray_signals[NUM_SIGNALS] = {0};*/ + +G_DEFINE_TYPE(GmTray, gm_tray, EGG_TYPE_TRAY_ICON) + +static void +gm_tray_finalize(GObject *object) { + GmTray *tray = GM_TRAY(object); + guint i; + + if (tray->priv->flash_timeout) { + g_source_remove(tray->priv->flash_timeout); + } + + for (i = 0; i < NUM_TRAY_STATES; ++i) { + g_object_unref(tray->priv->icons[i]); + } + + G_OBJECT_CLASS(gm_tray_parent_class)->finalize(object); +} + +static void +gm_tray_class_init(GmTrayClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->finalize = gm_tray_finalize; + g_type_class_add_private(object_class, sizeof(GmTrayPrivate)); +} + +static void +gm_tray_init(GmTray *tray) { + guint i; + GtkWidget *image; + + tray->priv = GM_TRAY_GET_PRIVATE(tray); + + tray->priv->event_box = gtk_event_box_new(); + tray->priv->current_state = TRAY_STATE_NORMAL; + + for (i = 0; i < NUM_TRAY_STATES; ++i) { + tray->priv->icons[i] = NULL; + } + + image = gtk_image_new(); + + gtk_container_add(GTK_CONTAINER(tray->priv->event_box), image); + tray->priv->tooltips = gtk_tooltips_new(); + + gtk_widget_show(tray->priv->event_box); + gtk_widget_show(image); + + gtk_container_add(GTK_CONTAINER(tray), tray->priv->event_box); + gtk_widget_add_events(GTK_WIDGET(tray), GDK_BUTTON_PRESS_MASK); + + tray->priv->image = GTK_IMAGE(image); +} + +static void +gm_tray_update_icon(GmTray *tray) { + gtk_image_set_from_pixbuf(tray->priv->image, + tray->priv->icons[tray->priv->current_state]); +} + +static void +gm_tray_set_state(GmTray *tray, GmTrayState state) { + if (tray->priv->current_state == state) { + return; + } + + if (tray->priv->flash_timeout) { + g_source_remove(tray->priv->flash_timeout); + tray->priv->flash_timeout = 0; + } + + tray->priv->prev_state = tray->priv->current_state; + tray->priv->current_state = state; + + gm_tray_update_icon(tray); +} + +static gboolean +gm_tray_restore_from_activity(gpointer user_data) { + GmTray *tray = GM_TRAY(user_data); + + tray->priv->flash_timeout = 0; + gm_tray_set_state(tray, tray->priv->prev_state); + + return FALSE; +} + +/* Public */ + +GmTray * +gm_tray_new(gchar const *title) { + return g_object_new(GM_TYPE_TRAY, "title", title, NULL); +} + +void +gm_tray_activate(GmTray *tray) { + if (tray->priv->flash_timeout) { + g_source_remove(tray->priv->flash_timeout); + } + + if (tray->priv->current_state == TRAY_STATE_NORMAL) { + tray->priv->current_state = TRAY_STATE_ACTIVE; + } + + gm_tray_set_state(tray, TRAY_STATE_ACTIVITY); + tray->priv->flash_timeout = g_timeout_add(1000, + gm_tray_restore_from_activity, tray); +} + +void +gm_tray_normal(GmTray *tray) { + gm_tray_set_state(tray, TRAY_STATE_NORMAL); + + gm_tray_set_tip(tray, NULL); +} + +void +gm_tray_active(GmTray *tray) { + gm_tray_set_state(tray, TRAY_STATE_ACTIVE); +} + +void +gm_tray_notify(GmTray *tray, gchar const *message) { + gm_tray_set_state(tray, TRAY_STATE_NOTIFY); + + gm_tray_message(tray, message); + gm_tray_set_tip(tray, message); +} + +void +gm_tray_set_icon(GmTray *tray, GmTrayState state, GdkPixbuf *icon) { + if (tray->priv->icons[state]) { + g_object_unref(tray->priv->icons[state]); + } + + tray->priv->icons[state] = g_object_ref(icon); + + if (state == tray->priv->current_state) { + gm_tray_update_icon(tray); + } +} + +void +gm_tray_message(GmTray *tray, gchar const *message) { + egg_tray_icon_send_message(EGG_TRAY_ICON(tray), 2000, message, + g_utf8_strlen(message, -1)); +} + +void +gm_tray_set_tip(GmTray *tray, gchar const *message) { + gtk_tooltips_set_tip(tray->priv->tooltips, tray->priv->event_box, + message, message); +} + +GmTrayState +gm_tray_get_state(GmTray *tray) { + if (tray->priv->current_state == TRAY_STATE_ACTIVITY) { + return tray->priv->prev_state; + } + + return tray->priv->current_state; +} + + +gboolean +gm_tray_has_manager() { + Screen *xscreen = DefaultScreenOfDisplay(gdk_display); + Atom selection_atom; + char *selection_atom_name; + + selection_atom_name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", + XScreenNumberOfScreen(xscreen)); + selection_atom = XInternAtom(DisplayOfScreen(xscreen), + selection_atom_name, FALSE); + g_free(selection_atom_name); + + if (XGetSelectionOwner(DisplayOfScreen(xscreen), selection_atom)) { + return TRUE; + } else { + return FALSE; + } +} diff --git a/gnoemoe/widgets/gm-tray.h b/gnoemoe/widgets/gm-tray.h new file mode 100644 index 0000000..d9fd99a --- /dev/null +++ b/gnoemoe/widgets/gm-tray.h @@ -0,0 +1,76 @@ +#ifndef __GM_TRAY_H__ +#define __GM_TRAY_H__ + +#include +#include "eggtrayicon.h" + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define GM_TYPE_TRAY (gm_tray_get_type()) +#define GM_TRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GM_TYPE_TRAY, GmTray)) +#define GM_TRAY_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GM_TYPE_TRAY, GmTray const)) +#define GM_TRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + GM_TYPE_TRAY, GmTrayClass)) +#define GM_IS_TRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ + GM_TYPE_TRAY)) +#define GM_IS_TRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GM_TYPE_TRAY)) +#define GM_TRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GM_TYPE_TRAY, GmTrayClass)) + +/* Private structure type */ +typedef struct _GmTrayPrivate GmTrayPrivate; + +typedef enum _GmTrayState { + TRAY_STATE_NORMAL, + TRAY_STATE_ACTIVE, + TRAY_STATE_ACTIVITY, + TRAY_STATE_NOTIFY, + NUM_TRAY_STATES +} GmTrayState; + +/* + * Main object structure + */ +typedef struct _GmTray GmTray; + +struct _GmTray { + EggTrayIcon trayicon; + + /*< private > */ + GmTrayPrivate *priv; +}; + +/* + * Class definition + */ +typedef struct _GmTrayClass GmTrayClass; + +struct _GmTrayClass { + EggTrayIconClass parent_class; + + /* Signals */ +}; + +GType gm_tray_get_type(void) G_GNUC_CONST; +GmTray *gm_tray_new(gchar const *title); +void gm_tray_set_icon(GmTray *tray, GmTrayState state, GdkPixbuf *icon); + +void gm_tray_activate(GmTray *tray); +void gm_tray_normal(GmTray *tray); +void gm_tray_active(GmTray *tray); +void gm_tray_notify(GmTray *tray, gchar const *message); + +void gm_tray_message(GmTray *tray, gchar const *message); +void gm_tray_set_tip(GmTray *tray, gchar const *message); +GmTrayState gm_tray_get_state(GmTray *tray); + +gboolean gm_tray_has_manager(); + +G_END_DECLS +#endif /* __GM_TRAY_H__ */