emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: RFC: status icon support


From: Tom Tromey
Subject: Re: RFC: status icon support
Date: Fri, 11 Jan 2008 18:38:44 -0700
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.990 (gnu/linux)

>>>>> "Dan" == Dan Nicolaescu <address@hidden> writes:

Dan> Please no K&R in new code.  

Here is the updated patch.

Tom

ChangeLog:
2008-01-11  Tom Tromey  <address@hidden>

        * configure: Rebuild.
        * configure.in: Check for GtkStatusIcon, libnotify.

doc/lispref/ChangeLog:
2008-01-11  Tom Tromey  <address@hidden>

        * frames.texi (Status Icons): New node.
        (Frames): Update.

src/ChangeLog:
2008-01-11  Tom Tromey  <address@hidden>

        * xmenu.c: Include systray.h.
        (Fx_popup_menu): Update documentation.  Handle status-icon
        position argument.
        (create_and_show_popup_menu): Add status_icon and status_button
        arguments.  Update.  Use gtk_get_current_event_time.
        (xmenu_show): Add status_icon and status_button arguments.
        Update.
        * termhooks.h (enum event_kind) <STATUS_ICON_CLICK_EVENT>: New
        constant.
        * print.c (print_object): Handle status icons.
        * lisp.h (enum pvec_type) <PVEC_STATUS_ICON> New constant.
        <PVEC_TYPE_MASK>: Update.
        (STATUS_ICONP): New macro.
        (GC_STATUS_ICONP): Likewise.
        (allocate_status_icon, syms_of_systray): Declare.
        * keyboard.c (Qstatus_icon_click_event): New global.
        (kbd_buffer_get_event): Handle STATUS_ICON_CLICK_EVENT.
        (make_lispy_event): Likewise.
        (syms_of_keyboard): Initialize Qstatus_icon_click_event.  Define
        "status-icon-click-event" event.
        * emacs.c (main): Call syms_of_systray.
        * alloc.c: Include systray.h.
        (allocate_status_icon): New function.
        * config.in: Rebuild.
        * Makefile.in (LIBNOTIFY_CFLAGS): New variable.
        (LIBNOTIFY_LIBS): Likewise.
        (ALL_CFLAGS): Add LIBNOTIFY_CFLAGS.
        (GTK_OBJ): Add systray.o
        (LIBES): Add LIBNOTIFY_LIBS.
        (systray.o): New target.
        * systray.c: New file.
        * systray.h: New file.

Index: configure.in
===================================================================
RCS file: /sources/emacs/emacs/configure.in,v
retrieving revision 1.490
diff -u -r1.490 configure.in
--- configure.in        6 Jan 2008 11:49:25 -0000       1.490
+++ configure.in        12 Jan 2008 02:09:06 -0000
@@ -4,7 +4,7 @@
 dnl in the directory containing this script.
 dnl
 dnl  Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003,
-dnl    2004, 2005, 2006, 2007  Free Software Foundation, Inc.
+dnl    2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
 dnl
 dnl  This file is part of GNU Emacs.
 dnl
@@ -1777,6 +1777,15 @@
               [Define to 1 if GTK has both file selection and chooser dialog.])
   fi
 
+  dnl  Check if we have GtkStatusIcon.
+  HAVE_GTK_STATUS_ICON=no
+  AC_CHECK_FUNCS(gtk_status_icon_new, HAVE_GTK_STATUS_ICON=yes)
+
+  if test "$HAVE_GTK_STATUS_ICON" = yes; then
+    AC_DEFINE(HAVE_GTK_STATUS_ICON, 1,
+              [Define to 1 if GTK has GtkStatusIcon.])
+  fi
+
   dnl Check if pthreads are available.  Emacs only needs this when using
   dnl gtk_file_chooser under Gnome.
   if test "$HAVE_GTK_FILE_CHOOSER" = yes; then
@@ -1807,6 +1816,14 @@
    fi
 fi
 
+dnl  Check if we have libnotify.
+PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= 0.4.1, HAVE_LIBNOTIFY=yes,
+                  HAVE_LIBNOTIFY=no)
+if test "$HAVE_LIBNOTIFY" = yes; then
+  AC_DEFINE(HAVE_LIBNOTIFY, 1,
+            [Define to 1 if the system has libnotify.])
+fi
+
 ### Link with -lXft if available to work around a bug.
 HAVE_XFT=maybe
 if test "${HAVE_GTK}" = "yes"; then
Index: doc/lispref/frames.texi
===================================================================
RCS file: /sources/emacs/emacs/doc/lispref/frames.texi,v
retrieving revision 1.5
diff -u -r1.5 frames.texi
--- doc/lispref/frames.texi     28 Dec 2007 22:26:13 -0000      1.5
+++ doc/lispref/frames.texi     12 Jan 2008 02:09:07 -0000
@@ -1,7 +1,7 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Emacs Lisp Reference Manual.
 @c Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2001,
address@hidden   2002, 2003, 2004, 2005, 2006, 2007  Free Software Foundation, 
Inc.
address@hidden   2002, 2003, 2004, 2005, 2006, 2007, 2008  Free Software 
Foundation, Inc.
 @c See the file elisp.texi for copying conditions.
 @setfilename ../../info/frames
 @node Frames, Positions, Windows, Top
@@ -75,6 +75,7 @@
 * Text Terminal Colors::        Defining colors for text-only terminals.
 * Resources::                  Getting resource values from the server.
 * Display Feature Testing::     Determining the features of a terminal.
+* Status Icons::                Status icons and notifications.
 @end menu
 
   @xref{Display}, for information about the related topic of
@@ -2218,6 +2219,128 @@
 width and height of an X Window frame, measured in pixels.
 @end ignore
 
address@hidden Status Icons
address@hidden Status Icons and Notifications
address@hidden status icons
address@hidden system tray
+
+Some platforms provide a ``system tray'', an area holding icons tied
+to particular applications.  Applications use these icons to
+unobtrusively communicate information to the user.  Status icons also
+support ``notifications'', which are pop-up windows displaying some
+text and perhaps having some buttons.  A notification is less
+intrusive than a dialog because it does not steal the focus and need
+not be manually dismissed.  Emacs can create and manipulate status
+icons, and send notifications.
+
+If status icons are available, the feature @code{systray} is provided.
+
address@hidden make-status-icon &optional alist
+This function creates and returns a new status icon.  The optional
+argument @var{alist} provides initial properties for the icon.  Some
+properties are specially recognized; unrecognized properties are
+retained (for use by @code{status-icon-parameters}) but otherwise
+ignored.
+
+The recognized properties are:
address@hidden @code
address@hidden icon-name
+The value is the file name of the image to display on the icon.
address@hidden means that Emacs should display a default image.
+
address@hidden blinking
+If the value is address@hidden, the icon will blink.  The default is
address@hidden
+
address@hidden visible
+If the value is @code{nil}, the icon will not be shown.  The default
+is @code{t}.
+
address@hidden help-echo
+The value is a string which will displayed as a tooltip for the icon.
+
address@hidden click-callback
+The value is a no-argument function which will be called when the user
+clicks on the icon.
+
address@hidden menu
+The value is a menu (of any kind recognized by @code{popup-menu})
+which will be displayed when the user right-clicks on the icon.
address@hidden table
address@hidden defun
+
address@hidden delete-status-icon icon
+Destroy @var{icon}.
address@hidden defun
+
address@hidden modify-status-icon-parameters icon alist
+Modify the parameters of @var{icon} according.  @var{alist} is an
+alist of parameters of the same kind accepted by
address@hidden
address@hidden defun
+
address@hidden status-iconp object
+Return address@hidden if @var{object} is a status icon.
address@hidden defun
+
address@hidden status-icon-live-p object
+Return address@hidden if @var{object} is an undestroyed status icon.
address@hidden defun
+
address@hidden status-icon-list
+Return a list of all undestroyed status icons.
address@hidden defun
+
address@hidden show-status-icon-message icon summary &rest args
+This function creates and displays a new notification.  Note that this
+function may not be available on all platforms, and can be missing
+even if the basic status icon support is available.
+
address@hidden is the status icon to which the notification should attach.
+If @var{icon} is @code{nil}, then the notification will not be
+attached to an icon, but instead will display in some default
+location.
+
address@hidden is the summary text of the notification, a string.
+
address@hidden, if given, is a list of key-value pairs.  The recognized
+keys and their meanings are:
address@hidden @code
address@hidden :body @var{string}
+Set the body text of the notification.  This is ordinarily displayed
+in a different font than the summary text.
+
address@hidden :timeout @var{value}
+By default a notification will time out.  The default timeout interval
+is system-specific.  If @var{value} is @code{nil}, the default is
+used; if it is @code{t}, the notification will never time out.
+Otherwise, if @var{value} is an integer, then it specifies the amount
+of time in milliseconds.
+
address@hidden :urgency @var{value}
+Set the urgency level.  @var{value} is a symbol, one of @samp{low},
address@hidden, @samp{critical}.  The default is @samp{normal}.  This
+setting may affect how the notification is displayed; for instance a
address@hidden notification may have a red background.
+
address@hidden :icon @var{value}
+Set the notification's icon.  @samp{value} is a symbol, currently one
+of @samp{warning}, @samp{info}, @samp{question}, @samp{error}.  The
+default is @samp{info}.
+
address@hidden :action (@var{label} . @var{function})
+Add an action to the notification, with label @var{label}.  An action
+typically appears on the notification as a small button.  Multiple
+actions can be added, to give the user a choice of how to react to a
+given event.  @var{function} is called with no arguments if the action
+is chosen.
+
address@hidden :closed-callback @var{function}
+Call @var{function} with no arguments when the notification is closed.
+This is not called when the user clicks an action button.
address@hidden table
address@hidden defun
+
 @ignore
    arch-tag: 94977df6-3dca-4730-b57b-c6329e9282ba
 @end ignore
Index: src/Makefile.in
===================================================================
RCS file: /sources/emacs/emacs/src/Makefile.in,v
retrieving revision 1.361
diff -u -r1.361 Makefile.in
--- src/Makefile.in     2 Dec 2007 16:23:40 -0000       1.361
+++ src/Makefile.in     12 Jan 2008 02:09:08 -0000
@@ -1,6 +1,6 @@
 # Makefile for GNU Emacs.
 # Copyright (C) 1985, 1987, 1988, 1993, 1994, 1995, 1999, 2000, 2001, 2002,
-#               2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+#               2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, 
Inc.
 
 # This file is part of GNU Emacs.
 
@@ -268,6 +268,11 @@
 DBUS_OBJ = dbusbind.o
 #endif
 
+#ifdef HAVE_LIBNOTIFY
+LIBNOTIFY_CFLAGS = @LIBNOTIFY_CFLAGS@
+LIBNOTIFY_LIBS = @LIBNOTIFY_LIBS@
+#endif
+
 /* DO NOT use -R.  There is a special hack described in lastfile.c
    which is used instead.  Some initialized data areas are modified
    at initial startup, then labeled as part of the text area when
@@ -281,7 +286,7 @@
 
 /* C_SWITCH_X_SITE must come before C_SWITCH_X_MACHINE and C_SWITCH_X_SYSTEM
    since it may have -I options that should override those two.  */
-ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. 
-I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE C_SWITCH_X_SITE 
C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS_SOUND} 
${RSVG_CFLAGS} ${DBUS_CFLAGS} ${CFLAGS}
+ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. 
-I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE C_SWITCH_X_SITE 
C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS_SOUND} 
${RSVG_CFLAGS} ${DBUS_CFLAGS} ${LIBNOTIFY_CFLAGS} ${CFLAGS}
 .c.o:
        $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<
 
@@ -309,7 +314,7 @@
 #ifdef HAVE_MENUS
 
 #ifdef USE_GTK
-GTK_OBJ= gtkutil.o
+GTK_OBJ= gtkutil.o systray.o
 #endif
 
 /* The X Menu stuff is present in the X10 distribution, but missing
@@ -945,6 +950,7 @@
    duplicated symbols.  If the standard libraries were compiled
    with GCC, we might need gnulib again after them.  */
 LIBES = $(LOADLIBES) $(LIBS) $(LIBX) $(LIBSOUND) $(RSVG_LIBS) $(DBUS_LIBS) \
+   $(LIBNOTIFY_LIBS) \
    LIBGPM LIBRESOLV LIBS_SYSTEM LIBS_MACHINE LIBS_TERMCAP \
    LIBS_DEBUG $(GETLOADAVG_LIBS) $(GNULIB_VAR) LIB_MATH LIB_STANDARD \
    $(GNULIB_VAR)
@@ -1190,6 +1196,7 @@
 sysdep.o: sysdep.c syssignal.h systty.h systime.h syswait.h blockinput.h \
    process.h dispextern.h termhooks.h termchar.h termopts.h \
    frame.h atimer.h window.h msdos.h dosfns.h keyboard.h cm.h $(config_h)
+systray.o: systray.c $(config_h) lisp.h frame.h
 term.o: term.c termchar.h termhooks.h termopts.h $(config_h) cm.h frame.h \
    disptab.h dispextern.h keyboard.h charset.h coding.h ccl.h msdos.h \
    window.h keymap.h blockinput.h atimer.h systime.h
Index: src/alloc.c
===================================================================
RCS file: /sources/emacs/emacs/src/alloc.c,v
retrieving revision 1.432
diff -u -r1.432 alloc.c
--- src/alloc.c 16 Nov 2007 21:24:59 -0000      1.432
+++ src/alloc.c 12 Jan 2008 02:09:08 -0000
@@ -1,6 +1,6 @@
 /* Storage allocation and gc for GNU Emacs Lisp interpreter.
    Copyright (C) 1985, 1986, 1988, 1993, 1994, 1995, 1997, 1998, 1999,
-      2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007  Free Software 
Foundation, Inc.
+      2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008  Free Software 
Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -56,6 +56,7 @@
 #include "charset.h"
 #include "syssignal.h"
 #include "termhooks.h"         /* For struct terminal.  */
+#include "systray.h"
 #include <setjmp.h>
 
 /* GC_MALLOC_CHECK defined means perform validity checks of malloc'd
@@ -3021,6 +3022,17 @@
   return f;
 }
 
+struct status_icon *
+allocate_status_icon ()
+{
+  struct status_icon *s = ALLOCATE_PSEUDOVECTOR (struct status_icon,
+                                                notification_alist,
+                                                PVEC_STATUS_ICON);
+  /* Zero out the non-GC'd fields.  FIXME: This should be made unnecessary.  */
+  bzero (&(s->param_alist),
+        ((char*)(s+1)) - ((char*)&(s->notification_alist)));
+  return s;
+}
 
 struct Lisp_Process *
 allocate_process ()
Index: src/emacs.c
===================================================================
RCS file: /sources/emacs/emacs/src/emacs.c,v
retrieving revision 1.413
diff -u -r1.413 emacs.c
--- src/emacs.c 2 Dec 2007 16:23:40 -0000       1.413
+++ src/emacs.c 12 Jan 2008 02:09:08 -0000
@@ -1,6 +1,6 @@
 /* Fully extensible Emacs, running on Unix, intended for GNU.
    Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1997, 1998, 1999,
-                 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software 
Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software 
Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -1643,6 +1643,10 @@
       syms_of_dbusbind ();
 #endif /* HAVE_DBUS */
 
+#ifdef HAVE_GTK
+      syms_of_systray ();
+#endif
+
 #ifdef SYMS_SYSTEM
       SYMS_SYSTEM;
 #endif
Index: src/keyboard.c
===================================================================
RCS file: /sources/emacs/emacs/src/keyboard.c,v
retrieving revision 1.937
diff -u -r1.937 keyboard.c
--- src/keyboard.c      6 Jan 2008 21:34:57 -0000       1.937
+++ src/keyboard.c      12 Jan 2008 02:09:09 -0000
@@ -500,6 +500,8 @@
 #ifdef HAVE_DBUS
 Lisp_Object Qdbus_event;
 #endif
+Lisp_Object Qstatus_icon_click_event;
+
 /* Lisp_Object Qmouse_movement; - also an event header */
 
 /* Properties of event headers.  */
@@ -4298,6 +4300,11 @@
          kbd_fetch_ptr = event + 1;
        }
 #endif
+      else if (event->kind == STATUS_ICON_CLICK_EVENT)
+       {
+         obj = make_lispy_event (event);
+         kbd_fetch_ptr = event + 1;
+       }
       else
        {
          /* If this event is on a different frame, return a switch-frame this
@@ -6174,6 +6181,9 @@
       }
 #endif /* HAVE_DBUS */
 
+    case STATUS_ICON_CLICK_EVENT:
+      return Fcons (Qstatus_icon_click_event, event->arg);
+
 #ifdef HAVE_GPM
     case GPM_CLICK_EVENT:
       {
@@ -11781,6 +11791,9 @@
   staticpro (&Qdbus_event);
 #endif
 
+  Qstatus_icon_click_event = intern ("status-icon-click-event");
+  staticpro (&Qstatus_icon_click_event);
+
   Qmenu_enable = intern ("menu-enable");
   staticpro (&Qmenu_enable);
   Qmenu_alias = intern ("menu-alias");
@@ -12517,6 +12530,9 @@
   initial_define_lispy_key (Vspecial_event_map, "dbus-event",
                            "dbus-handle-event");
 #endif
+
+  initial_define_lispy_key (Vspecial_event_map, "status-icon-click-event",
+                           "status-icon-handle-click-event");
 }
 
 /* Mark the pointers in the kboard objects.
Index: src/lisp.h
===================================================================
RCS file: /sources/emacs/emacs/src/lisp.h,v
retrieving revision 1.603
diff -u -r1.603 lisp.h
--- src/lisp.h  22 Nov 2007 01:01:26 -0000      1.603
+++ src/lisp.h  12 Jan 2008 02:09:10 -0000
@@ -349,7 +349,8 @@
   PVEC_HASH_TABLE = 0x40000,
   PVEC_TERMINAL = 0x80000,
   PVEC_OTHER = 0x100000,
-  PVEC_TYPE_MASK = 0x1ffe00
+  PVEC_STATUS_ICON = 0x200000,
+  PVEC_TYPE_MASK = 0x2ffe00
 
 #if 0 /* This is used to make the value of PSEUDOVECTOR_FLAG available to
         GDB.  It doesn't work on OS Alpha.  Moved to a variable in
@@ -1552,6 +1553,8 @@
 #define GC_BOOL_VECTOR_P(x) GC_PSEUDOVECTORP (x, PVEC_BOOL_VECTOR)
 #define FRAMEP(x) PSEUDOVECTORP (x, PVEC_FRAME)
 #define GC_FRAMEP(x) GC_PSEUDOVECTORP (x, PVEC_FRAME)
+#define STATUS_ICONP(x) PSEUDOVECTORP (x, PVEC_STATUS_ICON)
+#define GC_STATUS_ICONP(x) GC_PSEUDOVECTORP (x, PVEC_STATUS_ICON)
 
 #define SUB_CHAR_TABLE_P(x) (CHAR_TABLE_P (x) && NILP (XCHAR_TABLE (x)->top))
 
@@ -2616,6 +2620,7 @@
 extern struct Lisp_Hash_Table *allocate_hash_table P_ ((void));
 extern struct window *allocate_window P_ ((void));
 extern struct frame *allocate_frame P_ ((void));
+extern struct status_icon *allocate_status_icon P_ ((void));
 extern struct Lisp_Process *allocate_process P_ ((void));
 extern struct terminal *allocate_terminal P_ ((void));
 extern int gc_in_progress;
@@ -3248,6 +3253,9 @@
 extern void syms_of_sound P_ ((void));
 extern void init_sound P_ ((void));
 
+/* Defined in systray.c */
+extern void syms_of_systray P_ ((void));
+
 /* Defined in category.c */
 extern void init_category_once P_ ((void));
 extern void syms_of_category P_ ((void));
Index: src/print.c
===================================================================
RCS file: /sources/emacs/emacs/src/print.c,v
retrieving revision 1.243
diff -u -r1.243 print.c
--- src/print.c 22 Nov 2007 16:16:02 -0000      1.243
+++ src/print.c 12 Jan 2008 02:09:10 -0000
@@ -2031,6 +2031,8 @@
          strout (buf, -1, -1, printcharfun, 0);
          PRINTCHAR ('>');
        }
+      else if (STATUS_ICONP (obj))
+       strout ("#<status-icon>", -1, -1, printcharfun, 0);
       else
        {
          EMACS_INT size = XVECTOR (obj)->size;
Index: src/systray.c
===================================================================
RCS file: src/systray.c
diff -N src/systray.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/systray.c       12 Jan 2008 02:09:10 -0000
@@ -0,0 +1,667 @@
+/* Elisp bindings system tray icons
+   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Emacs 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+
+#include "lisp.h"
+#include "systray.h"
+#include "frame.h"
+#include "charset.h"
+#include "coding.h"
+#include "blockinput.h"
+#include "termhooks.h"
+#include "xterm.h"
+
+#include <gtk/gtk.h>
+
+#ifdef HAVE_LIBNOTIFY
+#include <libnotify/notify.h>
+#endif
+
+#ifdef HAVE_GTK_STATUS_ICON
+
+/* FIXME: should be in a header.  */
+extern Lisp_Object Qhelp_echo;
+extern Lisp_Object Qmenu;
+extern Lisp_Object Qstatus_icon_click_event;
+
+Lisp_Object Vstatus_icon_list;
+Lisp_Object Vstandalone_icon;
+
+Lisp_Object Qblinking;
+Lisp_Object Qstatus_icon_live_p;
+Lisp_Object Qclick_callback;
+Lisp_Object QCbody, QCtimeout, QCurgency, QCicon, QCaction, QCclosed_callback;
+Lisp_Object Qlow, Qcritical, Qwarning, Qquestion, Qerror;
+Lisp_Object Qpopup_menu;
+
+#define GET_ICON(s) ((GtkStatusIcon *) ((s)->icon))
+
+/* Callback which is called when the user clicks on a status icon.  */
+static void
+activate_icon (GtkWidget *widget, gpointer data)
+{
+  Lisp_Object icon = (Lisp_Object) data;
+
+  /* Just ignore garbage.  */
+  if (STATUS_ICON_LIVE_P (XSTATUS_ICON (icon)))
+    {
+      struct status_icon *sicon = XSTATUS_ICON (icon);
+      Lisp_Object elt = Fassq (Qmenu, sicon->param_alist);
+      if (CONSP (elt) && FUNCTIONP (XCDR (elt)))
+       {
+         struct input_event event;
+         EVENT_INIT (event);
+         event.kind = STATUS_ICON_CLICK_EVENT;
+         event.frame_or_window = Qnil;
+         event.arg = XCDR (elt);
+         kbd_buffer_store_event (&event);
+       }
+    }
+}
+
+static void
+pop_up_status_menu (GtkStatusIcon *gicon, guint button,
+                   guint activate_time, gpointer user_data)
+{
+  Lisp_Object icon = (Lisp_Object) user_data;
+
+  /* Just ignore garbage.  */
+  if (STATUS_ICON_LIVE_P (XSTATUS_ICON (icon)))
+    {
+      struct status_icon *sicon = XSTATUS_ICON (icon);
+      Lisp_Object elt = Fassq (Qmenu, sicon->param_alist);
+      if (CONSP (elt) && ! NILP (XCDR (elt)))
+       {
+         struct gcpro gcpro1;
+         struct input_event event;
+         Lisp_Object function;
+
+         GCPRO1 (function);
+         /* Construct the 'position' list.  */
+         function = Fcons (icon,
+                           Fcons (make_number (button), Qnil));
+         function = Fcons (Qquote,
+                           Fcons (function, Qnil));
+         /* Construct the call to `popup-menu'.  */
+         function = Fcons (Qpopup_menu,
+                           Fcons (Fcons (Qquote,
+                                         Fcons (XCDR (elt), Qnil)),
+                                  Fcons (function, Qnil)));
+         /* Construct the function.  */
+         function = Fcons (Qlambda,
+                           Fcons (Qnil,
+                                  Fcons (function, Qnil)));
+
+         EVENT_INIT (event);
+         event.kind = STATUS_ICON_CLICK_EVENT;
+         event.frame_or_window = Qnil;
+         event.arg = function;
+         kbd_buffer_store_event (&event);
+       }
+    }
+}
+
+/* Apply property KEY with value VALUE to icon SICON.  */
+static void
+apply_one_icon_property (struct status_icon *sicon, Lisp_Object key,
+                        Lisp_Object value)
+{
+  if (EQ (key, Qicon_name))
+    {
+      struct gcpro gcpro1;
+      Lisp_Object filename = Qnil;
+      GCPRO1 (filename);
+      if (NILP (value))
+       {
+         /* Default to the GNU.  */
+         filename = build_string ("emacs_48.png");
+       }
+      else
+       {
+         CHECK_STRING (value);
+         filename = value;
+       }
+      /* Not clear if x_find_image_file returns a string with the
+        correct encoding for Gtk.  However, it is already used this
+        way in gtkutil.c.  */
+      filename = x_find_image_file (filename);
+      if (NILP (filename))
+       {
+         /* No good choice, so choose a semi-appropriate stock
+            icon.  */
+         gtk_status_icon_set_from_stock (GET_ICON (sicon),
+                                         GTK_STOCK_DIALOG_QUESTION);
+       }
+      else
+       gtk_status_icon_set_from_file (GET_ICON (sicon),
+                                      (char *) SDATA (filename));
+      UNGCPRO;
+    }
+  else if (EQ (key, Qblinking))
+    gtk_status_icon_set_blinking (GET_ICON (sicon), ! NILP (value));
+  else if (EQ (key, Qvisible))
+    gtk_status_icon_set_visible (GET_ICON (sicon), ! NILP (value));
+  else if (EQ (key, Qhelp_echo))
+    {
+      struct gcpro gcpro1;
+      Lisp_Object tooltip = Qnil;
+      GCPRO1 (tooltip);
+      if (NILP (value))
+       gtk_status_icon_set_tooltip (GET_ICON (sicon), NULL);
+      else
+       {
+         /* FIXME: should accept a sexp to eval here.  */
+         CHECK_STRING (value);
+         tooltip = ENCODE_UTF_8 (value);
+         gtk_status_icon_set_tooltip (GET_ICON (sicon),
+                                      (char *) SDATA (tooltip));
+       }
+      UNGCPRO;
+    }
+  else
+    {
+      /* Ignore things we don't understand.  */
+    }
+}
+
+/* Apply the ALIST of properties to status icon ICON.  */
+static void
+apply_status_icon_alist (Lisp_Object icon, Lisp_Object alist)
+{
+  Lisp_Object tail;
+  struct status_icon *sicon;
+
+  CHECK_LIVE_STATUS_ICON (icon);
+  sicon = XSTATUS_ICON (icon);
+
+  for (tail = alist; CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object key, value;
+      Lisp_Object elt = XCAR (tail);
+      if (! CONSP (elt))
+       continue;
+      key = XCAR (elt);
+      value = XCDR (elt);
+
+      apply_one_icon_property (sicon, key, value);
+
+      /* Update frame parameters.  */
+      elt = Fassq (key, sicon->param_alist);
+      if (NILP (elt))
+       sicon->param_alist = Fcons (Fcons (key, value), sicon->param_alist);
+      else
+       Fsetcdr (elt, value);
+    }
+}
+
+DEFUN ("make-status-icon", Fmake_status_icon, Smake_status_icon,
+       0, 1, 0,
+       doc: /* Return a newly created status icon.
+Optional argument ALIST is an alist of parameters for the new frame.
+See `modify-status-icon-parameters' for a list of recognized parameters.*/)
+     (alist)
+     Lisp_Object alist;
+{
+  struct status_icon *sicon;
+  Lisp_Object icon, deflist;
+  struct gcpro gcpro1;
+
+  check_x ();
+
+  BLOCK_INPUT;
+
+  sicon = allocate_status_icon ();
+  XSETSTATUS_ICON (icon, sicon);
+  sicon->param_alist = Qnil;
+  sicon->notification_alist = Qnil;
+  sicon->icon = gtk_status_icon_new ();
+
+  g_signal_connect (sicon->icon, "activate", G_CALLBACK (activate_icon),
+                   (gpointer) icon);
+  g_signal_connect (sicon->icon, "popup-menu", G_CALLBACK (pop_up_status_menu),
+                   (gpointer) icon);
+
+  Vstatus_icon_list = Fcons (icon, Vstatus_icon_list);
+
+  GCPRO1 (deflist);
+
+  /* Make some defaults.  */
+  deflist = Fcons (Fcons (Qclick_callback, Qnil),
+                  Fcons (Fcons (Qicon_name, Qnil),
+                         Fcons (Fcons (Qblinking, Qnil),
+                                Fcons (Fcons (Qvisible, Qt),
+                                       Fcons (Fcons (Qhelp_echo, Qnil),
+                                              alist)))));
+  apply_status_icon_alist (icon, deflist);
+
+  UNBLOCK_INPUT;
+
+  RETURN_UNGCPRO (icon);
+}
+
+DEFUN ("modify-status-icon-parameters", Fmodify_status_icon_parameters,
+       Smodify_status_icon_parameters,
+       2, 2, 0,
+       doc: /* Modify the parameters of status icon ICON according to ALIST.
+Each element of alist has the form (PARM . VALUE), where PARM is a symbol.
+Undefined PARMs are ignored, but stored in the frame's parameter list
+so that `status-icon-parameters' will return them.
+
+Currently defined parameters and their values are:
+
+  icon-name       The file name of an icon to display.
+  blinking        If non-nil, the status icon will blink.
+  visible         If nil, status icon is invisible.
+  help-echo       A string which will be displayed as a tooltip for the
+                  status icon.
+  click-callback  A no-argument function which will be called when the
+                  user clicks on the icon.
+  menu            A menu which will pop up when the user clicks on the
+                  icon.  May not be available on all platforms.*/)
+     (icon, alist)
+     Lisp_Object icon, alist;
+{
+  BLOCK_INPUT;
+  apply_status_icon_alist (icon, alist);
+  UNBLOCK_INPUT;
+  return Qnil;
+}
+
+DEFUN ("status-icon-parameters", Fstatus_icon_parameters,
+       Sstatus_icon_parameters,
+       1, 1, 0,
+       doc: /* Return the parameters-alist of the status icon ICON.
+It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.*/)
+     (icon)
+     Lisp_Object icon;
+{
+  struct status_icon *sicon;
+  CHECK_LIVE_STATUS_ICON (icon);
+  sicon = XSTATUS_ICON (icon);
+  return Fcopy_alist (sicon->param_alist);
+}
+
+DEFUN ("status-icon-list", Fstatus_icon_list, Sstatus_icon_list,
+       0, 0, 0,
+       doc: /* Return a list of all status icons.  */)
+     ()
+{
+  return Fcopy_sequence (Vstatus_icon_list);
+}
+
+DEFUN ("delete-status-icon", Fdelete_status_icon, Sdelete_status_icon,
+       1, 1, 0,
+       doc: /* Delete the status icon ICON.  */)
+     (icon)
+     Lisp_Object icon;
+{
+  struct status_icon *sicon;
+  CHECK_LIVE_STATUS_ICON (icon);
+  sicon = XSTATUS_ICON (icon);
+  BLOCK_INPUT;
+  g_object_unref (sicon->icon);
+  UNBLOCK_INPUT;
+  sicon->icon = NULL;
+  Vstatus_icon_list = Fdelq (icon, Vstatus_icon_list);
+  return Qnil;
+}
+
+#ifdef HAVE_LIBNOTIFY
+
+/* Called in response to notification action clicks.  */
+static void
+handle_notification_event (NotifyNotification *notification,
+                          int action_number, Lisp_Object callback_arg)
+{
+  Lisp_Object icon = XCAR (callback_arg);
+  struct status_icon *sicon = XSTATUS_ICON (icon);
+  Lisp_Object callback = Fnth (make_number (action_number + 2), callback_arg);
+  if (FUNCTIONP (callback))
+    {
+      struct input_event event;
+      EVENT_INIT (event);
+      event.kind = STATUS_ICON_CLICK_EVENT;
+      event.frame_or_window = Qnil;
+      event.arg = callback;
+      kbd_buffer_store_event (&event);
+    }
+  sicon->notification_alist = Fdelq (callback_arg,
+                                    sicon->notification_alist);
+  g_object_unref (notification);
+}
+
+static void
+action_click (NotifyNotification *notification, gchar *actionid,
+             gpointer user_data)
+{
+  int id = atoi (actionid);
+  Lisp_Object callback_arg = (Lisp_Object) user_data;
+  handle_notification_event (notification, id, callback_arg);
+}
+
+static void
+cleanup_notification (NotifyNotification *notification, gpointer user_data)
+{
+  Lisp_Object callback_arg = (Lisp_Object) user_data;
+  handle_notification_event (notification, -1, callback_arg);
+}
+
+DEFUN ("show-status-icon-message", Fshow_status_icon_message,
+       Sshow_status_icon_message,
+       2, MANY, 0,
+       doc: /* Post a notification message attached to the icon ICON.
+ICON is a status icon created by `make-status-icon', or nil for a
+standalone notification.
+SUMMARY is the message to display, a string.
+
+The remaining arguments, if any, are a property list specifying
+additional parameters of the notification:
+
+  :body STRING     Set the body text of the notification.
+  :timeout VALUE   Set the timeout value.
+                   nil means use the default.
+                  t means never time out.
+                  An integer specifies the timeout in milliseconds.
+  :urgency VALUE   Set the urgency level.  VALUE is a symbol, one of
+                   'low', 'normal', 'critical'.  The default is 'normal'.
+  :icon VALUE      Set the notification icon.  VALUE is a symbol, currently
+                   one of 'warning', 'info', 'question', 'error'.  The
+                  default is 'info'.
+  :action (LABEL . FUNCTION)
+                   Add an action to the notification, with label LABEL.
+                  FUNCTION is called with no arguments if the action
+                  is chosen.
+  :closed-callback FUNCTION
+                   Call FUNCTION with no arguments when the notification
+                  is closed.  This is not called when the user clicks
+                  an action button.
+
+usage: (show-status-icon-message ICON SUMMARY &rest ARGS)  */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  struct status_icon *sicon;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  Lisp_Object gc_temp = Qnil;
+  Lisp_Object callback_list = Qnil;
+  Lisp_Object closed_callback = Qnil;
+  Lisp_Object callback_arg = Qnil;
+  NotifyNotification *notification;
+
+  int i;
+  int action_count = 0;
+  Lisp_Object icon = args[0];
+  Lisp_Object summary = args[1];
+
+  check_x ();
+  if ((nargs - 2) % 2 != 0)
+    error ("Invalid number of arguments");
+
+  if (! NILP (icon))
+    CHECK_LIVE_STATUS_ICON (icon);
+  CHECK_STRING (summary);
+
+  BLOCK_INPUT;
+
+  if (! notify_is_initted () && ! notify_init ("Emacs"))
+    {
+      UNBLOCK_INPUT;
+      error ("Couldn't connect to notification server");
+    }
+
+  GCPRO4 (gc_temp, callback_list, closed_callback, callback_arg);
+  gc_temp = ENCODE_UTF_8 (summary);
+
+  /* Pre-allocate the cons that will be passed to all callbacks.  We
+     will fill it in later.  */
+  callback_arg = Fcons (Qnil, Qnil);
+
+  if (! NILP (icon))
+    {
+      sicon = XSTATUS_ICON (icon);
+      notification
+       = notify_notification_new_with_status_icon (SDATA (gc_temp), NULL,
+                                                   GTK_STOCK_DIALOG_INFO,
+                                                   GET_ICON (XSTATUS_ICON 
(icon)));
+    }
+  else
+    {
+      icon = Vstandalone_icon;
+      sicon = XSTATUS_ICON (icon);
+      notification
+       = notify_notification_new (SDATA (gc_temp), NULL, GTK_STOCK_DIALOG_INFO,
+                                  NULL);
+    }
+
+  for (i = 2; i < nargs; i += 2)
+    {
+      Lisp_Object key = args[i];
+      Lisp_Object value = args[i + 1];
+      /* FIXME: still no access to: setting the icon from a pixbuf,
+        maybe hints (what are they good for?), closing the
+        notification by caller.  */
+      if (EQ (key, QCbody))
+       {
+         /* Ignore things we don't understand.  */
+         if (STRINGP (value))
+           {
+             gc_temp = ENCODE_UTF_8 (value);
+             g_object_set (G_OBJECT (notification), "body", SDATA (gc_temp),
+                           NULL);
+           }
+       }
+      else if (EQ (key, QCtimeout))
+       {
+         gint timeout = NOTIFY_EXPIRES_DEFAULT;
+         if (EQ (value, Qt))
+           timeout = NOTIFY_EXPIRES_NEVER;
+         else if (INTEGERP (value))
+           {
+             timeout = XINT (value);
+             if (timeout <= 0)
+               timeout = NOTIFY_EXPIRES_DEFAULT;
+           }
+         notify_notification_set_timeout (notification, timeout);
+       }
+      else if (EQ (key, QCurgency))
+       {
+         NotifyUrgency urgency = NOTIFY_URGENCY_NORMAL;
+         if (EQ (value, Qlow))
+           urgency = NOTIFY_URGENCY_LOW;
+         else if (EQ (value, Qcritical))
+           urgency = NOTIFY_URGENCY_CRITICAL;
+         notify_notification_set_urgency (notification, urgency);
+       }
+      else if (EQ (key, QCicon))
+       {
+         char *icon_name = GTK_STOCK_DIALOG_INFO;
+         if (EQ (value, Qwarning))
+           icon_name = GTK_STOCK_DIALOG_WARNING;
+         else if (EQ (value, Qquestion))
+           icon_name = GTK_STOCK_DIALOG_QUESTION;
+         else if (EQ (value, Qerror))
+           icon_name = GTK_STOCK_DIALOG_ERROR;
+         g_object_set (G_OBJECT (notification), "icon-name", icon_name, NULL);
+       }
+      else if (EQ (key, QCaction))
+       {
+         /* Ignore if we don't understand the value.  */
+         if (CONSP (value) && STRINGP (XCAR (value)))
+           {
+             char actionid[20];
+             Lisp_Object label = XCAR (value);
+             gc_temp = ENCODE_UTF_8 (label);
+             /* Use a plain integer for the action id, because we
+                will use it later to look up the action.  */
+             sprintf (actionid, "%d", action_count);
+             ++action_count;
+             notify_notification_add_action (notification, actionid,
+                                             SDATA (gc_temp),
+                                             action_click,
+                                             (gpointer) callback_arg, NULL);
+
+             /* We build the list from the back, the reverse it
+                later.  */
+             callback_list = Fcons (XCDR (value), callback_list);
+           }
+       }
+      else if (EQ (key, QCclosed_callback))
+       closed_callback = value;
+    }
+
+  /* Put the callback list into the right order, then put the 'closed'
+     callback at the start of the list.  */
+  callback_list = Fcons (closed_callback, Fnreverse (callback_list));
+
+  XSETCAR (callback_arg, icon);
+  XSETCDR (callback_arg, callback_list);
+  sicon->notification_alist = Fcons (callback_arg, sicon->notification_alist);
+
+  /* Arrange to clean up when this notification goes away.  */
+  g_signal_connect (G_OBJECT (notification), "closed",
+                   G_CALLBACK (cleanup_notification),
+                   (gpointer) callback_arg);
+
+  /* Ignore errors here for now.  */
+  notify_notification_show (notification, NULL);
+
+  UNBLOCK_INPUT;
+
+  RETURN_UNGCPRO (Qnil);
+}
+
+#endif /* HAVE_LIBNOTIFY */
+
+DEFUN ("status-iconp", Fstatus_iconp, Sstatus_iconp,
+       1, 1, 0, doc: /* Return non-nil if OBJECT is a status icon.  */)
+     (object)
+     Lisp_Object object;
+{
+  return STATUS_ICONP (object) ? Qt : Qnil;
+}
+
+DEFUN ("status-icon-live-p", Fstatus_icon_live_p, Sstatus_icon_live_p,
+       1, 1, 0,
+       doc: /* Return non-nil if OBJECT is a status icon which has not been 
deleted.*/)
+     (object)
+     Lisp_Object object;
+{
+  return ((STATUS_ICONP (object) && STATUS_ICON_LIVE_P (XSTATUS_ICON (object)))
+         ? Qt : Qnil);
+}
+
+DEFUN ("status-icon-handle-click-event", Fstatus_icon_handle_click_event,
+       Sstatus_icon_handle_click_event,
+       1, 1, "e",
+       doc: /* Internal handler for status icon click events.
+A status icon click event is generated in response to the user clicking
+on a status icon.  This handler calls the specified callback function,
+if any.*/)
+     (event)
+     Lisp_Object event;
+{
+  Lisp_Object fun;
+  struct gcpro gcpro1;
+
+  /* Just ignore garbage.  */
+  if (! CONSP (event) || ! EQ (XCAR (event), Qstatus_icon_click_event)
+      || ! FUNCTIONP (XCDR (event)))
+    return Qnil;
+
+  GCPRO1 (fun);
+  fun = XCDR (event);
+  Ffuncall (1, &fun);
+  RETURN_UNGCPRO (Qnil);
+}
+
+void
+syms_of_systray ()
+{
+  struct status_icon *sicon;
+
+  Qstatus_icon_live_p = intern ("status-icon-live-p");
+  staticpro (&Qstatus_icon_live_p);
+  Qblinking = intern ("blinking");
+  staticpro (&Qblinking);  
+  Qclick_callback = intern ("click-callback");
+  staticpro (&Qclick_callback);
+  QCbody = intern (":body");
+  staticpro (&QCbody);
+  QCtimeout = intern (":timeout");
+  staticpro (&QCtimeout);
+  QCurgency = intern (":urgency");
+  staticpro (&QCurgency);
+  QCicon = intern (":icon");
+  staticpro (&QCicon);
+  QCaction = intern (":action");
+  staticpro (&QCaction);
+  QCclosed_callback = intern (":closed-callback");
+  staticpro (&QCclosed_callback);
+  Qlow = intern ("low");
+  staticpro (&Qlow);
+  Qcritical = intern ("critical");
+  staticpro (&Qcritical);
+  Qwarning = intern ("warning");
+  staticpro (&Qwarning);
+  Qquestion = intern ("question");
+  staticpro (&Qquestion);
+  Qerror = intern ("error");
+  staticpro (&Qerror);
+  Qpopup_menu = intern ("popup-menu");
+  staticpro (&Qpopup_menu);
+
+  staticpro (&Vstatus_icon_list);
+  Vstatus_icon_list = Qnil;
+
+  defsubr (&Smake_status_icon);
+  defsubr (&Smodify_status_icon_parameters);
+  defsubr (&Sdelete_status_icon);
+  defsubr (&Sstatus_icon_parameters);
+  defsubr (&Sstatus_icon_list);
+#ifdef HAVE_LIBNOTIFY
+  defsubr (&Sshow_status_icon_message);
+#endif /* HAVE_LIBNOTIFY */
+  defsubr (&Sstatus_iconp);
+  defsubr (&Sstatus_icon_live_p);
+  defsubr (&Sstatus_icon_handle_click_event);
+
+  /* We make a dummy status icon so that standalone notifications have
+     a place to store their user-data.  This icon never has a GUI or
+     associated native state.  */
+  staticpro (&Vstandalone_icon);
+  sicon = allocate_status_icon ();
+  sicon->param_alist = Qnil;
+  sicon->notification_alist = Qnil;
+  XSETSTATUS_ICON (Vstandalone_icon, sicon);
+
+  Fprovide (intern ("systray"), Qnil);
+}
+
+#else /* HAVE_GTK_STATUS_ICON */
+
+void
+syms_of_systray ()
+{
+  /* Nothing.  */
+}
+
+#endif
Index: src/systray.h
===================================================================
RCS file: src/systray.h
diff -N src/systray.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/systray.h       12 Jan 2008 02:09:10 -0000
@@ -0,0 +1,56 @@
+/* Define systray object for GNU Emacs.
+   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Emacs 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#ifndef EMACS_SYSTRAY_H
+#define EMACS_SYSTRAY_H
+
+extern Lisp_Object Qstatus_icon_live_p;
+
+struct status_icon
+{
+  EMACS_UINT size;
+  struct Lisp_Vector *next;
+
+  /* Parameter alist of this status icon.  */
+  Lisp_Object param_alist;
+
+  /* List holding objects we want to keep live while a notification is
+     up.  */
+  Lisp_Object notification_alist;
+
+  /* Beyond here, there should be no more Lisp_Object components.  */
+
+  /* The icon widget, or NULL if it has been destroyed.  Really a
+     'GtkStatusIcon *'.  */
+  void *icon;
+};
+
+#define XSTATUS_ICON(p) \
+  (eassert (GC_STATUS_ICONP (p)), (struct status_icon *) XPNTR (p))
+
+#define XSETSTATUS_ICON(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_STATUS_ICON))
+
+#define STATUS_ICON_LIVE_P(s) (((s)->icon) != 0)
+
+#define CHECK_LIVE_STATUS_ICON(s)                                      \
+  CHECK_TYPE (STATUS_ICONP (s) && STATUS_ICON_LIVE_P (XSTATUS_ICON (s)), \
+             Qstatus_icon_live_p, s)
+
+#endif /* EMACS_SYSTRAY_H */
Index: src/termhooks.h
===================================================================
RCS file: /sources/emacs/emacs/src/termhooks.h,v
retrieving revision 1.90
diff -u -r1.90 termhooks.h
--- src/termhooks.h     2 Dec 2007 16:23:40 -0000       1.90
+++ src/termhooks.h     12 Jan 2008 02:09:10 -0000
@@ -201,6 +201,8 @@
   , DBUS_EVENT
 #endif
 
+  , STATUS_ICON_CLICK_EVENT
+
 #ifdef WINDOWSNT
   /* Generated when an APPCOMMAND event is received, in response to
      Multimedia or Internet buttons on some keyboards.
Index: src/xmenu.c
===================================================================
RCS file: /sources/emacs/emacs/src/xmenu.c,v
retrieving revision 1.324
diff -u -r1.324 xmenu.c
--- src/xmenu.c 13 Oct 2007 12:10:07 -0000      1.324
+++ src/xmenu.c 12 Jan 2008 02:09:10 -0000
@@ -1,6 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
    Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
-                 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -51,6 +51,7 @@
 #include "charset.h"
 #include "coding.h"
 #include "sysselect.h"
+#include "systray.h"
 
 #ifdef MSDOS
 #include "msdos.h"
@@ -156,7 +157,7 @@
                                Lisp_Object, Lisp_Object));
 static int update_frame_menubar P_ ((struct frame *));
 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
-                                  Lisp_Object, char **));
+                                  Lisp_Object, char **, void *, int));
 static void keymap_panes P_ ((Lisp_Object *, int, int));
 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
                                     int, int));
@@ -780,6 +781,9 @@
 corner of WINDOW.  (WINDOW may be a window or a frame object.)
 This controls the position of the top left of the menu as a whole.
 If POSITION is t, it means to use the current mouse position.
+POSITION can also be a list (STATUS-ICON BUTTON-TIME),
+where STATUS-ICON is a status icon and BUTTON is an integer.
+In this case the menu is displayed over the indicated status icon.
 
 MENU is a specifier for a menu.  For the simplest case, MENU is a keymap.
 The menu items come from key bindings that have a menu string as well as
@@ -829,6 +833,8 @@
   int for_click = 0;
   int specpdl_count = SPECPDL_INDEX ();
   struct gcpro gcpro1;
+  void *status_icon = NULL;
+  int status_button = 0;
 
 #ifdef HAVE_MENUS
   if (! NILP (position))
@@ -843,6 +849,19 @@
        {
           get_current_pos_p = 1;
         }
+      else if (CONSP (position) && STATUS_ICONP (XCAR (position)))
+       {
+         Lisp_Object icon = XCAR (position);
+
+         CHECK_LIVE_STATUS_ICON (icon);
+         status_icon = XSTATUS_ICON (icon)->icon;
+         status_button = XINT (Fcar (Fcdr (position)));
+         for_click = 1;
+         /* Placate later code.  */
+         XSETINT (x, 0);
+         XSETINT (y, 0);
+         window = selected_window;
+       }
       else
        {
          tem = Fcar (position);
@@ -1029,7 +1048,8 @@
   BLOCK_INPUT;
 
   selection = xmenu_show (f, xpos, ypos, for_click,
-                         keymaps, title, &error_name);
+                         keymaps, title, &error_name,
+                         status_icon, status_button);
   UNBLOCK_INPUT;
 
   discard_menu_items ();
@@ -2664,18 +2684,22 @@
    menu pops down.
    menu_item_selection will be set to the selection.  */
 static void
-create_and_show_popup_menu (f, first_wv, x, y, for_click)
+create_and_show_popup_menu (f, first_wv, x, y, for_click,
+                           status_icon, status_button)
      FRAME_PTR f;
      widget_value *first_wv;
      int x;
      int y;
      int for_click;
+     void *status_icon;
+     int status_button;
 {
   int i;
   GtkWidget *menu;
   GtkMenuPositionFunc pos_func = 0;  /* Pop up at pointer.  */
   struct next_popup_x_y popup_x_y;
   int specpdl_count = SPECPDL_INDEX ();
+  gpointer user_data = &popup_x_y;
 
   if (! FRAME_X_P (f))
     abort ();
@@ -2702,6 +2726,14 @@
 
       i = 0;  /* gtk_menu_popup needs this to be 0 for a non-button popup.  */
     }
+#ifdef HAVE_GTK_STATUS_ICON
+  else if (status_icon)
+    {
+      user_data = status_icon;
+      i = status_button;
+      pos_func = gtk_status_icon_position_menu;
+    }
+#endif /* HAVE_GTK_STATUS_ICON */
   else
     {
       for (i = 0; i < 5; i++)
@@ -2711,7 +2743,8 @@
 
   /* Display the menu.  */
   gtk_widget_show_all (menu);
-  gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
+  gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, user_data, i,
+                 gtk_get_current_event_time ());
 
   record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
 
@@ -2772,14 +2805,18 @@
 
 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
    menu pops down.
-   menu_item_selection will be set to the selection.  */
+   menu_item_selection will be set to the selection.
+   The status-icon-related arguments are ignore in this implementation.  */
 static void
-create_and_show_popup_menu (f, first_wv, x, y, for_click)
+create_and_show_popup_menu (f, first_wv, x, y, for_click,
+                           status_icon, status_button)
      FRAME_PTR f;
      widget_value *first_wv;
      int x;
      int y;
      int for_click;
+     void *status_icon;
+     int status_button;
 {
   int i;
   Arg av[2];
@@ -2848,7 +2885,8 @@
 #endif /* not USE_GTK */
 
 static Lisp_Object
-xmenu_show (f, x, y, for_click, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error,
+           status_icon, status_button)
      FRAME_PTR f;
      int x;
      int y;
@@ -2856,6 +2894,8 @@
      int keymaps;
      Lisp_Object title;
      char **error;
+     void *status_icon;
+     int status_button;
 {
   int i;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
@@ -3062,7 +3102,8 @@
   menu_item_selection = 0;
 
   /* Actually create and show the menu until popped down.  */
-  create_and_show_popup_menu (f, first_wv, x, y, for_click);
+  create_and_show_popup_menu (f, first_wv, x, y, for_click,
+                             status_icon, status_button);
 
   /* Free the widget_value objects we used to specify the contents.  */
   free_menubar_widget_value_tree (first_wv);
@@ -3523,6 +3564,10 @@
      int keymaps;
      Lisp_Object title;
      char **error;
+     /* Note that status-icon-related arguments are ignored in this
+       implementation  */
+     void *status_icon;
+     int status_button;
 {
   Window root;
   XMenu *menu;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]