From 733d4928e512c31baf076c6b97267c6b4691ba73 Mon Sep 17 00:00:00 2001 From: hiro Date: Tue, 23 Aug 2005 09:49:26 +0000 Subject: initial implementation of the tray icon. git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@501 ee746299-78ed-0310-b773-934348b2243d --- src/Makefile.am | 1 + src/eggtrayicon.c | 486 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/eggtrayicon.h | 81 +++++++++ src/mainwindow.c | 38 +++++ src/mainwindow.h | 4 + src/stock_pixmap.c | 18 ++ src/stock_pixmap.h | 6 + 7 files changed, 634 insertions(+) create mode 100644 src/eggtrayicon.c create mode 100644 src/eggtrayicon.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 805f559a..a889be52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -108,6 +108,7 @@ sylpheed_SOURCES = \ simple-gettext.c \ manual.c manual.h \ stringtable.c stringtable.h \ + eggtrayicon.c eggtrayicon.h \ quote_fmt_lex.l quote_fmt_lex.h \ quote_fmt_parse.y quote_fmt.h \ sylpheed-marshal.c sylpheed-marshal.h diff --git a/src/eggtrayicon.c b/src/eggtrayicon.c new file mode 100644 index 00000000..56d686a2 --- /dev/null +++ b/src/eggtrayicon.c @@ -0,0 +1,486 @@ +/* -*- 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. + */ +/* Added WINDOWING ifdef 2005-07-09 by Yoichi Imai */ + +#include +#include +#include + +#include "eggtrayicon.h" + +#ifdef GDK_WINDOWING_X11 +#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 && + 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; + + g_return_if_fail(GTK_IS_WIDGET(icon)); + + 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_xscreen (Screen *xscreen, const char *name) +{ + GdkDisplay *display; + GdkScreen *screen; + + display = gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen)); + screen = gdk_display_get_screen (display, XScreenNumberOfScreen (xscreen)); + + return egg_tray_icon_new_for_screen (screen, name); +} + +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; +} + +#endif diff --git a/src/eggtrayicon.h b/src/eggtrayicon.h new file mode 100644 index 00000000..c70c887c --- /dev/null +++ b/src/eggtrayicon.h @@ -0,0 +1,81 @@ +/* -*- 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 + +#ifdef GDK_WINDOWING_X11 +#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 /* GDK_WINDOWING_X11 */ +#endif /* __EGG_TRAY_ICON_H__ */ diff --git a/src/mainwindow.c b/src/mainwindow.c index faca8664..9e928ef2 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -77,6 +77,7 @@ #include "alertpanel.h" #include "statusbar.h" #include "inputdialog.h" +#include "eggtrayicon.h" #include "utils.h" #include "gtkutils.h" #include "codeconv.h" @@ -159,6 +160,10 @@ static void ac_label_button_pressed (GtkWidget *widget, static void ac_menu_popup_closed (GtkMenuShell *menu_shell, gpointer data); +static void tray_icon_button_pressed (GtkWidget *widget, + GdkEventButton *event, + gpointer data); + static gint main_window_close_cb (GtkWidget *widget, GdkEventAny *event, gpointer data); @@ -799,6 +804,11 @@ MainWindow *main_window_create(SeparateType type) GtkWidget *ac_button; GtkWidget *ac_label; + GtkWidget *tray_icon; + GtkWidget *tray_icon_img; + GtkWidget *eventbox; + GtkTooltips *tray_icon_tip; + FolderView *folderview; SummaryView *summaryview; MessageView *messageview; @@ -904,6 +914,21 @@ MainWindow *main_window_create(SeparateType type) gtk_widget_show_all(statusbar); + tray_icon = GTK_WIDGET(egg_tray_icon_new("Sylpheed")); + + eventbox = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(tray_icon), eventbox); + g_signal_connect(G_OBJECT(eventbox), "button_press_event", + G_CALLBACK(tray_icon_button_pressed), mainwin); + tray_icon_img = stock_pixbuf_widget_scale(NULL, STOCK_PIXMAP_SYLPHEED, + 24, 24); + gtk_container_add(GTK_CONTAINER(eventbox), tray_icon_img); + + tray_icon_tip = gtk_tooltips_new(); + gtk_tooltips_set_tip(tray_icon_tip, tray_icon, _("Sylpheed"), NULL); + + gtk_widget_show_all(tray_icon); + /* create views */ mainwin->folderview = folderview = folderview_create(); mainwin->summaryview = summaryview = summary_create(); @@ -937,6 +962,10 @@ MainWindow *main_window_create(SeparateType type) mainwin->ac_button = ac_button; mainwin->ac_label = ac_label; + mainwin->tray_icon = tray_icon; + mainwin->tray_icon_img = tray_icon_img; + mainwin->tray_icon_tip = tray_icon_tip; + /* set context IDs for status bar */ mainwin->mainwin_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR(statusbar), "Main Window"); @@ -2541,6 +2570,15 @@ static void ac_menu_popup_closed(GtkMenuShell *menu_shell, gpointer data) manage_window_focus_in(mainwin->window, NULL, NULL); } +static void tray_icon_button_pressed(GtkWidget *widget, GdkEventButton *event, + gpointer data) +{ + MainWindow *mainwin = (MainWindow *)data; + + if (event && event->button == 1) + gtk_window_present(GTK_WINDOW(mainwin->window)); +} + static gint main_window_close_cb(GtkWidget *widget, GdkEventAny *event, gpointer data) { diff --git a/src/mainwindow.h b/src/mainwindow.h index c763f99b..97363cd8 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -111,6 +111,10 @@ struct _MainWindow GtkWidget *ac_label; GtkWidget *ac_menu; + GtkWidget *tray_icon; + GtkWidget *tray_icon_img; + GtkTooltips *tray_icon_tip; + /* context IDs for status bar */ gint mainwin_cid; gint folderview_cid; diff --git a/src/stock_pixmap.c b/src/stock_pixmap.c index 7f53ff3d..b803f547 100644 --- a/src/stock_pixmap.c +++ b/src/stock_pixmap.c @@ -161,6 +161,24 @@ GtkWidget *stock_pixbuf_widget(GtkWidget *window, StockPixmap icon) return gtk_image_new_from_pixbuf(pixbuf); } +GtkWidget *stock_pixbuf_widget_scale(GtkWidget *window, StockPixmap icon, + gint width, gint height) +{ + GdkPixbuf *pixbuf; + GdkPixbuf *scaled_pixbuf; + GtkWidget *image; + + g_return_val_if_fail(icon >= 0 && icon < N_STOCK_PIXMAPS, NULL); + + stock_pixbuf_gdk(window, icon, &pixbuf); + scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf, width, height, + GDK_INTERP_HYPER); + image = gtk_image_new_from_pixbuf(scaled_pixbuf); + g_object_unref(scaled_pixbuf); + + return image; +} + /* create GdkPixmap if it has not created yet */ gint stock_pixmap_gdk(GtkWidget *window, StockPixmap icon, GdkPixmap **pixmap, GdkBitmap **mask) diff --git a/src/stock_pixmap.h b/src/stock_pixmap.h index a3a3f419..57fcbb3a 100644 --- a/src/stock_pixmap.h +++ b/src/stock_pixmap.h @@ -80,6 +80,12 @@ GtkWidget *stock_pixmap_widget (GtkWidget *window, StockPixmap icon); GtkWidget *stock_pixbuf_widget (GtkWidget *window, StockPixmap icon); + +GtkWidget *stock_pixbuf_widget_scale (GtkWidget *window, + StockPixmap icon, + gint width, + gint height); + gint stock_pixmap_gdk (GtkWidget *window, StockPixmap icon, GdkPixmap **pixmap, -- cgit v1.2.3