src/notification.c (-set_scaled_pixbuf, +zenity_notification_icon_update,
2006-07-27 Lucas Rocha <lucasr@gnome.org> * src/notification.c (-set_scaled_pixbuf, +zenity_notification_icon_update, -zenity_notification_icon_press_callback, +zenity_notification_icon_size_changed_cb, -zenity_notification_icon_expose_callback, -zenity_notification_icon_destroy_callback, +zenity_notification_icon_activate_cb, zenity_notification_handle_stdin, zenity_notification), src/util.[ch] (+zenity_util_stock_from_filename, zenity_util_pixbuf_new_from_file), Makefile.am, configure.in: Migration to gtk_status_icon (Fixes bug #341451). Patch from Christian Persch <chpe@gnome.org>. * src/eggtrayicon.[ch]: removed.
This commit is contained in:
parent
e46814b46a
commit
d373b3f3ce
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
||||
2006-07-27 Lucas Rocha <lucasr@gnome.org>
|
||||
|
||||
* src/notification.c (-set_scaled_pixbuf,
|
||||
+zenity_notification_icon_update,
|
||||
-zenity_notification_icon_press_callback,
|
||||
+zenity_notification_icon_size_changed_cb,
|
||||
-zenity_notification_icon_expose_callback,
|
||||
-zenity_notification_icon_destroy_callback,
|
||||
+zenity_notification_icon_activate_cb,
|
||||
zenity_notification_handle_stdin, zenity_notification),
|
||||
src/util.[ch] (+zenity_util_stock_from_filename,
|
||||
zenity_util_pixbuf_new_from_file), Makefile.am, configure.in:
|
||||
|
||||
Migration to gtk_status_icon (Fixes bug #341451). Patch from
|
||||
Christian Persch <chpe@gnome.org>.
|
||||
|
||||
* src/eggtrayicon.[ch]: removed.
|
||||
|
||||
2006-07-27 Lucas Rocha <lucasr@gnome.org>
|
||||
|
||||
* src/text.c (zenity_text_handle_stdin): correctly stdin input for
|
||||
|
@ -16,7 +16,7 @@ IT_PROG_INTLTOOL([0.34.90])
|
||||
|
||||
AC_PROG_CC
|
||||
|
||||
GTK_REQUIRED=2.9.0
|
||||
GTK_REQUIRED=2.9.2
|
||||
|
||||
PKG_CHECK_MODULES([ZENITY],[gtk+-2.0 >= $GTK_REQUIRED libglade-2.0 libgnomecanvas-2.0 glib-2.0])
|
||||
AC_SUBST([ZENITY_CFLAGS])
|
||||
@ -32,7 +32,7 @@ AC_PATH_PROG([PERL],[perl],)
|
||||
# libnotify check
|
||||
# *******************************
|
||||
|
||||
LIBNOTIFY_REQUIRED=0.3.2
|
||||
LIBNOTIFY_REQUIRED=0.4.1
|
||||
PKG_CHECK_MODULES([LIBNOTIFY],[libnotify >= $LIBNOTIFY_REQUIRED],
|
||||
[HAVE_LIBNOTIFY="yes"],[HAVE_LIBNOTIFY="no"])
|
||||
AC_SUBST([LIBNOTIFY_CFLAGS])
|
||||
|
@ -3,24 +3,22 @@ bin_PROGRAMS = zenity
|
||||
bin_SCRIPTS = gdialog
|
||||
|
||||
zenity_SOURCES = \
|
||||
about.c \
|
||||
calendar.c \
|
||||
entry.c \
|
||||
fileselection.c \
|
||||
main.c \
|
||||
msg.c \
|
||||
notification.c \
|
||||
option.c \
|
||||
option.h \
|
||||
zenity.h \
|
||||
calendar.c \
|
||||
msg.c \
|
||||
scale.c \
|
||||
fileselection.c \
|
||||
entry.c \
|
||||
text.c \
|
||||
progress.c \
|
||||
scale.c \
|
||||
text.c \
|
||||
tree.c \
|
||||
eggtrayicon.h \
|
||||
eggtrayicon.c \
|
||||
notification.c \
|
||||
about.c \
|
||||
util.c \
|
||||
util.h \
|
||||
util.c
|
||||
zenity.h
|
||||
|
||||
zenity_CPPFLAGS = \
|
||||
-I$(includedir) \
|
||||
|
@ -1,468 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/* eggtrayicon.c
|
||||
* Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "eggtrayicon.h"
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#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 &&
|
||||
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;
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/* eggtrayicon.h
|
||||
* Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
|
||||
*
|
||||
* 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 <gtk/gtkplug.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
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__ */
|
@ -2,6 +2,7 @@
|
||||
* notification.c
|
||||
*
|
||||
* Copyright (C) 2002 Sun Microsystems, Inc.
|
||||
* Copyright (C) 2006 Christian Persch
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
@ -23,6 +24,7 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glade/glade.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
@ -32,101 +34,71 @@
|
||||
#endif
|
||||
|
||||
#include "zenity.h"
|
||||
#include "eggtrayicon.h"
|
||||
#include "util.h"
|
||||
|
||||
static EggTrayIcon *tray_icon;
|
||||
static GtkWidget *icon_image;
|
||||
static GtkWidget *icon_event_box;
|
||||
static GtkTooltips *tooltips;
|
||||
|
||||
static GtkStatusIcon *status_icon;
|
||||
static gchar *icon_file;
|
||||
static const gchar *icon_stock;
|
||||
static gint icon_size;
|
||||
|
||||
static void
|
||||
set_scaled_pixbuf (GtkImage *image, GdkPixbuf *pixbuf, GtkIconSize icon_size)
|
||||
zenity_notification_icon_update (void)
|
||||
{
|
||||
GdkScreen *screen;
|
||||
GtkSettings *settings;
|
||||
int width, height, desired_width, desired_height;
|
||||
GdkPixbuf *new_pixbuf;
|
||||
GdkPixbuf *pixbuf;
|
||||
GError *error = NULL;
|
||||
|
||||
screen = gtk_widget_get_screen (GTK_WIDGET (image));
|
||||
settings = gtk_settings_get_for_screen (screen);
|
||||
if (!gtk_icon_size_lookup_for_settings (settings, icon_size,
|
||||
&desired_width, &desired_height))
|
||||
return;
|
||||
pixbuf = gdk_pixbuf_new_from_file_at_scale (icon_file, icon_size, icon_size, TRUE, &error);
|
||||
if (error) {
|
||||
g_warning ("Could not load notification icon '%s': %s",
|
||||
icon_file, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
if (!pixbuf) {
|
||||
pixbuf = gdk_pixbuf_new_from_file_at_scale (ZENITY_IMAGE_FULLPATH ("zenity-notification.png"),
|
||||
icon_size, icon_size, TRUE, NULL);
|
||||
}
|
||||
|
||||
width = gdk_pixbuf_get_width (pixbuf);
|
||||
height = gdk_pixbuf_get_height (pixbuf);
|
||||
if (height > desired_height || width > desired_width) {
|
||||
if (width * desired_height / height > desired_width)
|
||||
desired_height = height * desired_width / width;
|
||||
else
|
||||
desired_width = width * desired_height / height;
|
||||
gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
|
||||
|
||||
new_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
|
||||
desired_width,
|
||||
desired_height,
|
||||
GDK_INTERP_BILINEAR);
|
||||
gtk_image_set_from_pixbuf (image, new_pixbuf);
|
||||
g_object_unref (new_pixbuf);
|
||||
} else {
|
||||
gtk_image_set_from_pixbuf (image, pixbuf);
|
||||
if (pixbuf) {
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zenity_notification_icon_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer data)
|
||||
zenity_notification_icon_size_changed_cb (GtkStatusIcon *icon,
|
||||
gint size,
|
||||
gpointer user_data)
|
||||
{
|
||||
ZenityData *zen_data;
|
||||
icon_size = size;
|
||||
|
||||
zen_data = data;
|
||||
/* If we're displaying not a stock icon but a custom pixbuf,
|
||||
* we need to update the icon for the new size.
|
||||
*/
|
||||
if (!icon_stock) {
|
||||
zenity_notification_icon_update ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zenity_notification_icon_activate_cb (GtkWidget *widget,
|
||||
ZenityData *data)
|
||||
{
|
||||
data->exit_code = zenity_util_return_exit_code (ZENITY_OK);
|
||||
|
||||
zen_data->exit_code = zenity_util_return_exit_code (ZENITY_OK);
|
||||
gtk_main_quit ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zenity_notification_icon_expose_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
|
||||
{
|
||||
if (GTK_WIDGET_HAS_FOCUS (widget)) {
|
||||
gint focus_width, focus_pad;
|
||||
gint x, y, width, height;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"focus-line-width", &focus_width,
|
||||
"focus-padding", &focus_pad,
|
||||
NULL);
|
||||
x = widget->allocation.x + focus_pad;
|
||||
y = widget->allocation.y + focus_pad;
|
||||
width = widget->allocation.width - 2 * focus_pad;
|
||||
height = widget->allocation.height - 2 * focus_pad;
|
||||
|
||||
gtk_paint_focus (widget->style, widget->window,
|
||||
GTK_WIDGET_STATE (widget),
|
||||
&event->area, widget, "button",
|
||||
x, y, width, height);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
zenity_notification_icon_destroy_callback (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
ZenityData *zen_data;
|
||||
|
||||
zen_data = data;
|
||||
gtk_widget_destroy (GTK_WIDGET (tray_icon));
|
||||
|
||||
zen_data->exit_code = zenity_util_return_exit_code (ZENITY_ESC);
|
||||
gtk_main_quit ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
zenity_notification_handle_stdin (GIOChannel *channel,
|
||||
zenity_notification_handle_stdin (GIOChannel *channel,
|
||||
GIOCondition condition,
|
||||
gpointer user_data)
|
||||
gpointer user_data)
|
||||
{
|
||||
ZenityData *zen_data;
|
||||
|
||||
@ -137,7 +109,7 @@ zenity_notification_handle_stdin (GIOChannel *channel,
|
||||
GError *error = NULL;
|
||||
|
||||
string = g_string_new (NULL);
|
||||
while (channel->is_readable != TRUE)
|
||||
while (channel->is_readable == FALSE)
|
||||
;
|
||||
do {
|
||||
gint status;
|
||||
@ -167,60 +139,72 @@ zenity_notification_handle_stdin (GIOChannel *channel,
|
||||
continue;
|
||||
}
|
||||
/* split off the command and value */
|
||||
command = g_strndup (string->str, colon - string->str);
|
||||
command = g_strstrip (command);
|
||||
g_strdown (command);
|
||||
command = g_strstrip (g_strndup (string->str, colon - string->str));
|
||||
|
||||
value = colon + 1;
|
||||
while (*value && g_ascii_isspace (*value)) value++;
|
||||
|
||||
if (!strcmp (command, "icon")) {
|
||||
GdkPixbuf *pixbuf;
|
||||
if (!g_ascii_strcasecmp (command, "icon")) {
|
||||
icon_stock = zenity_util_stock_from_filename (value);
|
||||
|
||||
pixbuf = zenity_util_pixbuf_new_from_file (GTK_WIDGET (tray_icon),
|
||||
value);
|
||||
if (pixbuf != NULL) {
|
||||
set_scaled_pixbuf (GTK_IMAGE (icon_image), pixbuf,
|
||||
GTK_ICON_SIZE_BUTTON);
|
||||
gdk_pixbuf_unref (pixbuf);
|
||||
} else {
|
||||
g_warning ("Could not load notification icon : %s", value);
|
||||
}
|
||||
} else if (!strcmp (command, "message")) {
|
||||
g_free (icon_file);
|
||||
icon_file = g_strdup (value);
|
||||
|
||||
if (icon_stock) {
|
||||
gtk_status_icon_set_from_stock (status_icon, icon_stock);
|
||||
} else if (gtk_status_icon_get_visible (status_icon) &&
|
||||
gtk_status_icon_is_embedded (status_icon)) {
|
||||
zenity_notification_icon_update ();
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp (command, "message")) {
|
||||
#ifdef HAVE_LIBNOTIFY
|
||||
/* display a notification bubble */
|
||||
if (notify_is_initted ()) {
|
||||
GError *error = NULL;
|
||||
NotifyNotification *n;
|
||||
GdkPixbuf *icon;
|
||||
/* display a notification bubble */
|
||||
if (!g_utf8_validate (value, -1, NULL)) {
|
||||
g_warning ("Invalid UTF-8 in input!");
|
||||
} else if (notify_is_initted ()) {
|
||||
GError *error = NULL;
|
||||
NotifyNotification *notif;
|
||||
const gchar *icon = NULL;
|
||||
gchar *freeme = NULL;
|
||||
gchar *message;
|
||||
|
||||
n = notify_notification_new (g_strcompress (value), NULL, NULL,
|
||||
GTK_WIDGET (tray_icon));
|
||||
message = g_strcompress (value);
|
||||
|
||||
icon = gtk_image_get_pixbuf (GTK_IMAGE (icon_image));
|
||||
if (icon_stock) {
|
||||
icon = icon_stock;
|
||||
} else if (icon_file) {
|
||||
icon = freeme = g_filename_to_uri (icon_file, NULL, NULL);
|
||||
}
|
||||
|
||||
notify_notification_set_icon_from_pixbuf (n, icon);
|
||||
notif = notify_notification_new_with_status_icon (message, NULL /* summary */,
|
||||
icon, status_icon);
|
||||
g_free (message);
|
||||
g_free (freeme);
|
||||
|
||||
notify_notification_show (n, &error);
|
||||
notify_notification_show (notif, &error);
|
||||
if (error) {
|
||||
g_warning (error->message);
|
||||
g_warning ("Error showing notification: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (G_OBJECT (n));
|
||||
g_object_unref (notif);
|
||||
} else {
|
||||
#else
|
||||
{ /* this brace is for balance */
|
||||
#endif
|
||||
g_warning ("Notification framework not available");
|
||||
}
|
||||
} else if (!strcmp (command, "tooltip")) {
|
||||
gtk_tooltips_set_tip (tooltips, icon_event_box, value, value);
|
||||
} else if (!strcmp (command, "visible")) {
|
||||
if (!strcasecmp (value, "false")) {
|
||||
gtk_widget_hide (GTK_WIDGET (tray_icon));
|
||||
} else {
|
||||
gtk_widget_show (GTK_WIDGET (tray_icon));
|
||||
} else if (!g_ascii_strcasecmp (command, "tooltip")) {
|
||||
if (g_utf8_validate (value, -1, NULL)) {
|
||||
gtk_status_icon_set_tooltip (status_icon, value);
|
||||
} else {
|
||||
g_warning ("Invalid UTF-8 in input!");
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp (command, "visible")) {
|
||||
if (!g_ascii_strcasecmp (value, "false")) {
|
||||
gtk_status_icon_set_visible (status_icon, FALSE);
|
||||
} else {
|
||||
gtk_status_icon_set_visible (status_icon, TRUE);
|
||||
}
|
||||
} else {
|
||||
g_warning ("Unknown command '%s'", command);
|
||||
@ -256,64 +240,47 @@ zenity_notification_listen_on_stdin (ZenityData *data)
|
||||
void
|
||||
zenity_notification (ZenityData *data, ZenityNotificationData *notification_data)
|
||||
{
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
status_icon = gtk_status_icon_new ();
|
||||
g_signal_connect (status_icon, "size-changed",
|
||||
G_CALLBACK (zenity_notification_icon_size_changed_cb), data);
|
||||
|
||||
tray_icon = egg_tray_icon_new (_("Zenity notification"));
|
||||
tooltips = gtk_tooltips_new ();
|
||||
|
||||
if (data->window_icon != NULL)
|
||||
pixbuf = zenity_util_pixbuf_new_from_file (GTK_WIDGET (tray_icon), data->window_icon);
|
||||
else
|
||||
pixbuf = gdk_pixbuf_new_from_file (ZENITY_IMAGE_FULLPATH ("zenity-notification.png"), NULL);
|
||||
|
||||
icon_event_box = gtk_event_box_new ();
|
||||
icon_image = gtk_image_new ();
|
||||
|
||||
if (pixbuf) {
|
||||
set_scaled_pixbuf (GTK_IMAGE (icon_image), pixbuf,
|
||||
GTK_ICON_SIZE_BUTTON);
|
||||
gdk_pixbuf_unref (pixbuf);
|
||||
if (notification_data->notification_text) {
|
||||
gtk_status_icon_set_tooltip (status_icon, notification_data->notification_text);
|
||||
} else {
|
||||
if (data->window_icon != NULL) {
|
||||
g_warning ("Could not load notification icon : %s", data->window_icon);
|
||||
}
|
||||
else
|
||||
g_warning ("Could not load notification icon : %s", ZENITY_IMAGE_FULLPATH ("zenity-notification.png"));
|
||||
return;
|
||||
gtk_status_icon_set_tooltip (status_icon, _("Zenity notification"));
|
||||
}
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (icon_event_box), icon_image);
|
||||
icon_file = g_strdup (data->window_icon);
|
||||
icon_stock = zenity_util_stock_from_filename (data->window_icon);
|
||||
|
||||
if (notification_data->notification_text)
|
||||
gtk_tooltips_set_tip (tooltips, icon_event_box, notification_data->notification_text, notification_data->notification_text);
|
||||
else
|
||||
gtk_tooltips_set_tip (tooltips, icon_event_box, _("Zenity notification"), _("Zenity notification"));
|
||||
|
||||
gtk_widget_add_events (GTK_WIDGET (tray_icon), GDK_BUTTON_PRESS_MASK | GDK_FOCUS_CHANGE_MASK);
|
||||
gtk_container_add (GTK_CONTAINER (tray_icon), icon_event_box);
|
||||
|
||||
g_signal_connect (tray_icon, "destroy",
|
||||
G_CALLBACK (zenity_notification_icon_destroy_callback), data);
|
||||
|
||||
g_signal_connect (tray_icon, "expose_event",
|
||||
G_CALLBACK (zenity_notification_icon_expose_callback), data);
|
||||
|
||||
if (notification_data->listen) {
|
||||
zenity_notification_listen_on_stdin (data);
|
||||
} else {
|
||||
/* if we aren't listening for changes, then close on button_press */
|
||||
g_signal_connect (tray_icon, "button_press_event",
|
||||
G_CALLBACK (zenity_notification_icon_press_callback), data);
|
||||
/* Only set the stock icon here; if we're going to display a
|
||||
* custom pixbuf we wait for the size-changed signal to load
|
||||
* it at the right size.
|
||||
*/
|
||||
if (icon_stock) {
|
||||
gtk_status_icon_set_from_stock (status_icon, icon_stock);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBNOTIFY
|
||||
/* create the notification widget */
|
||||
if (!notify_is_initted ())
|
||||
notify_init (_("Zenity notification"));
|
||||
if (!notify_is_initted ()) {
|
||||
notify_init (_("Zenity notification"));
|
||||
}
|
||||
#endif
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (tray_icon));
|
||||
if (notification_data->listen) {
|
||||
zenity_notification_listen_on_stdin (data);
|
||||
} else {
|
||||
/* if we aren't listening for changes, then close on activate (left-click) */
|
||||
g_signal_connect (status_icon, "activate",
|
||||
G_CALLBACK (zenity_notification_icon_activate_cb), data);
|
||||
}
|
||||
|
||||
/* Does nothing at the moment */
|
||||
/* Show icon and wait */
|
||||
gtk_status_icon_set_visible (status_icon, TRUE);
|
||||
gtk_main ();
|
||||
|
||||
/* Cleanup */
|
||||
g_object_unref (status_icon);
|
||||
g_free (icon_file);
|
||||
}
|
||||
|
38
src/util.c
38
src/util.c
@ -145,19 +145,33 @@ zenity_util_fill_file_buffer (GtkTextBuffer *buffer, const gchar *filename)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
zenity_util_pixbuf_new_from_file (GtkWidget *widget, gchar *filename)
|
||||
const gchar *
|
||||
zenity_util_stock_from_filename (const gchar *filename)
|
||||
{
|
||||
if (!strcasecmp (filename, "warning"))
|
||||
return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_BUTTON, NULL);
|
||||
if (!strcasecmp (filename, "info"))
|
||||
return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_BUTTON, NULL);
|
||||
if (!strcasecmp (filename, "question"))
|
||||
return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_BUTTON, NULL);
|
||||
if (!strcasecmp (filename, "error"))
|
||||
return gtk_widget_render_icon (widget, GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_BUTTON, NULL);
|
||||
else
|
||||
return gdk_pixbuf_new_from_file (filename, NULL);
|
||||
if (!filename || !filename[0])
|
||||
return GTK_STOCK_DIALOG_WARNING; /* default */
|
||||
|
||||
if (!g_ascii_strcasecmp (filename, "warning"))
|
||||
return GTK_STOCK_DIALOG_WARNING;
|
||||
if (!g_ascii_strcasecmp (filename, "info"))
|
||||
return GTK_STOCK_DIALOG_INFO;
|
||||
if (!g_ascii_strcasecmp (filename, "question"))
|
||||
return GTK_STOCK_DIALOG_QUESTION;
|
||||
if (!g_ascii_strcasecmp (filename, "error"))
|
||||
return GTK_STOCK_DIALOG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
zenity_util_pixbuf_new_from_file (GtkWidget *widget, const gchar *filename)
|
||||
{
|
||||
const gchar *stock;
|
||||
|
||||
stock = zenity_util_stock_from_filename (filename);
|
||||
if (stock)
|
||||
return gtk_widget_render_icon (widget, stock, GTK_ICON_SIZE_BUTTON, NULL);
|
||||
|
||||
return gdk_pixbuf_new_from_file (filename, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -15,6 +15,7 @@ GladeXML* zenity_util_load_glade_file (const gchar *widge
|
||||
gchar * zenity_util_strip_newline (gchar *string);
|
||||
gboolean zenity_util_fill_file_buffer (GtkTextBuffer *buffer,
|
||||
const gchar *filename);
|
||||
const gchar * zenity_util_stock_from_filename (const gchar *filename);
|
||||
void zenity_util_set_window_icon (GtkWidget *widget,
|
||||
const gchar *filename,
|
||||
const gchar *default_file);
|
||||
@ -22,7 +23,7 @@ void zenity_util_set_window_icon_from_stock (GtkWidget *widge
|
||||
const gchar *filename,
|
||||
const gchar *default_stock_id);
|
||||
GdkPixbuf * zenity_util_pixbuf_new_from_file (GtkWidget *widget,
|
||||
gchar *filename);
|
||||
const gchar *filename);
|
||||
void zenity_util_show_help (GError **error);
|
||||
gint zenity_util_return_exit_code (ZenityExitCode value);
|
||||
void zenity_util_show_dialog (GtkWidget *widget);
|
||||
|
Reference in New Issue
Block a user