From c95a97954405c34d49c3ebdd0ffd664a858f98c0 Mon Sep 17 00:00:00 2001 From: Yann Leboulanger <asterix@lagaule.org> Date: Wed, 9 Jun 2004 14:22:27 +0000 Subject: [PATCH] icon in systray (it represents state and changes when we recieve a message not poped up) --- Makefile | 13 +- common/i18n.py | 0 plugins/gtkgui/Makefile | 26 +++ plugins/gtkgui/eggtrayicon.c | 344 +++++++++++++++++++++++++++++++ plugins/gtkgui/eggtrayicon.h | 76 +++++++ plugins/gtkgui/gtkgui.glade | 7 +- plugins/gtkgui/gtkgui.py | 38 +++- plugins/gtkgui/trayicon.defs | 58 ++++++ plugins/gtkgui/trayicon.override | 28 +++ plugins/gtkgui/trayiconmodule.c | 25 +++ 10 files changed, 607 insertions(+), 8 deletions(-) mode change 100755 => 100644 common/i18n.py create mode 100644 plugins/gtkgui/Makefile create mode 100644 plugins/gtkgui/eggtrayicon.c create mode 100644 plugins/gtkgui/eggtrayicon.h create mode 100644 plugins/gtkgui/trayicon.defs create mode 100644 plugins/gtkgui/trayicon.override create mode 100644 plugins/gtkgui/trayiconmodule.c diff --git a/Makefile b/Makefile index 6f079def80..d1bbe307b8 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,13 @@ +MODULES = common plugins/gtkgui + all: - python setup.py build_ext -i - mv idle.so common/ msgfmt Messages/fr/LC_MESSAGES/gajim.po -o Messages/fr/LC_MESSAGES/gajim.mo + for dir in ${MODULES}; do \ + (cd $$dir; make all); \ + done + +clean: + find -name *.pyc -exec rm {} \; + for dir in ${MODULES}; do \ + (cd $$dir; make clean); \ + done diff --git a/common/i18n.py b/common/i18n.py old mode 100755 new mode 100644 diff --git a/plugins/gtkgui/Makefile b/plugins/gtkgui/Makefile new file mode 100644 index 0000000000..0bf06f78f9 --- /dev/null +++ b/plugins/gtkgui/Makefile @@ -0,0 +1,26 @@ +# Set the C flags to include the GTK+ and Python libraries +CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -I/usr/include/python2.3/ -I. +LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0` + +# Build the shared object +#trayicon.so: trayicon.o eggtrayicon.o trayiconmodule.o +all: trayicon.o eggtrayicon.o trayiconmodule.o + $(CC) $(LDFLAGS) -shared $^ -o trayicon.so + + +# The path to the GTK+ python types +DEFS=`pkg-config --variable=defsdir pygtk-2.0` + +# Generate the C wrapper from the defs and our override file +trayicon.c: trayicon.defs trayicon.override + pygtk-codegen-2.0 --prefix trayicon \ + --register $(DEFS)/gdk-types.defs \ + --register $(DEFS)/gtk-types.defs \ + --override trayicon.override \ + trayicon.defs > $@ + +# A rule to clean the generated files +clean: + rm -f trayicon.so *.o trayicon.c *~ + +.PHONY: clean diff --git a/plugins/gtkgui/eggtrayicon.c b/plugins/gtkgui/eggtrayicon.c new file mode 100644 index 0000000000..65e4cdda09 --- /dev/null +++ b/plugins/gtkgui/eggtrayicon.c @@ -0,0 +1,344 @@ +/* -*- 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <string.h> +#include <gdk/gdkx.h> +#include "eggtrayicon.h" + +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + +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_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; + + gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK); +} + +static void +egg_tray_icon_class_init (EggTrayIconClass *klass) +{ + parent_class = g_type_class_peek_parent (klass); +} + +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 == DestroyNotify) + { + egg_tray_icon_update_manager_window (icon); + } + } + + return GDK_FILTER_CONTINUE; +} + +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; + +#if HAVE_GTK_MULTIHEAD + display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); +#else + display = gdk_display; +#endif + + 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; + +#if HAVE_GTK_MULTIHEAD + xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); +#else + xdisplay = gdk_display; +#endif + + if (icon->manager_window != None) + { + GdkWindow *gdkwin; + +#if HAVE_GTK_MULTIHEAD + gdkwin = gdk_window_lookup_for_display (display, + icon->manager_window); +#else + gdkwin = gdk_window_lookup (icon->manager_window); +#endif + + 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); + + XUngrabServer (xdisplay); + XFlush (xdisplay); + + if (icon->manager_window != None) + { + GdkWindow *gdkwin; + +#if HAVE_GTK_MULTIHEAD + gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), + icon->manager_window); +#else + gdkwin = gdk_window_lookup (icon->manager_window); +#endif + + 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); + } +} + +EggTrayIcon * +egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name); + +EggTrayIcon * +egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name) +{ + EggTrayIcon *icon; + char buffer[256]; + GdkWindow *root_window; + + g_return_val_if_fail (xscreen != NULL, NULL); + + icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL); + gtk_window_set_title (GTK_WINDOW (icon), name); + +#if HAVE_GTK_MULTIHEAD + gtk_plug_construct_for_display (GTK_PLUG (icon), + gdk_screen_get_display (screen), 0); +#else + gtk_plug_construct (GTK_PLUG (icon), 0); +#endif + + gtk_widget_realize (GTK_WIDGET (icon)); + + /* Now see if there's a manager window around */ + g_snprintf (buffer, sizeof (buffer), + "_NET_SYSTEM_TRAY_S%d", + XScreenNumberOfScreen (xscreen)); + + icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen), + buffer, False); + + icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen), + "MANAGER", False); + + icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen), + "_NET_SYSTEM_TRAY_OPCODE", False); + + egg_tray_icon_update_manager_window (icon); + +#if HAVE_GTK_MULTIHEAD + root_window = gdk_screen_get_root_window (screen); +#else + root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); +#endif + + /* Add a root window filter so that we get changes on MANAGER */ + gdk_window_add_filter (root_window, + egg_tray_icon_manager_filter, icon); + + return icon; +} + +#if HAVE_GTK_MULTIHEAD +EggTrayIcon * +egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) +{ + EggTrayIcon *icon; + char buffer[256]; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name); +} +#endif + +EggTrayIcon* +egg_tray_icon_new (const gchar *name) +{ + return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name); +} + +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; + +#if HAVE_GTK_MULTIHEAD + xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); +#else + xdisplay = gdk_display; +#endif + + 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); +} diff --git a/plugins/gtkgui/eggtrayicon.h b/plugins/gtkgui/eggtrayicon.h new file mode 100644 index 0000000000..724bc3da8b --- /dev/null +++ b/plugins/gtkgui/eggtrayicon.h @@ -0,0 +1,76 @@ +/* -*- 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; + Window manager_window; +}; + +struct _EggTrayIconClass +{ + GtkPlugClass parent_class; +}; + +GType egg_tray_icon_get_type (void); + +#if EGG_TRAY_ENABLE_MULTIHEAD +EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen *screen, + const gchar *name); +#endif + +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); + + + +G_END_DECLS + +#endif /* __EGG_TRAY_ICON_H__ */ diff --git a/plugins/gtkgui/gtkgui.glade b/plugins/gtkgui/gtkgui.glade index 50c98277a9..0688ab11d8 100644 --- a/plugins/gtkgui/gtkgui.glade +++ b/plugins/gtkgui/gtkgui.glade @@ -2,7 +2,6 @@ <!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> <glade-interface> -<requires lib="gnome"/> <widget class="GtkWindow" id="Gajim"> <property name="visible">True</property> @@ -10,8 +9,8 @@ <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_NONE</property> <property name="modal">False</property> - <property name="default_width">100</property> - <property name="default_height">300</property> + <property name="default_width">150</property> + <property name="default_height">400</property> <property name="resizable">True</property> <property name="destroy_with_parent">False</property> <property name="decorated">True</property> @@ -4062,7 +4061,7 @@ when NOT onlie</property> <property name="can_focus">True</property> <property name="editable">True</property> <property name="overwrite">False</property> - <property name="accepts_tab">True</property> + <property name="accepts_tab">False</property> <property name="justification">GTK_JUSTIFY_LEFT</property> <property name="wrap_mode">GTK_WRAP_WORD</property> <property name="cursor_visible">True</property> diff --git a/plugins/gtkgui/gtkgui.py b/plugins/gtkgui/gtkgui.py index bc175ec210..ac0ab7e485 100644 --- a/plugins/gtkgui/gtkgui.py +++ b/plugins/gtkgui/gtkgui.py @@ -21,6 +21,7 @@ import pygtk pygtk.require('2.0') import gtk from gtk import TRUE, FALSE +import trayicon import gtk.glade,gobject import os,string,time,Queue import common.optparser,common.sleepy @@ -102,6 +103,7 @@ class message_Window: if self.plugin.roster.pixbufs.has_key(self.user.show): self.plugin.roster.tree.get_model().set_value(i, 0, \ self.plugin.roster.pixbufs[self.user.show]) + self.plugin.set_systray() def on_msg_key_press_event(self, widget, event): """When a key is pressed : @@ -839,13 +841,15 @@ class roster_Window: def set_optionmenu(self): #table to change index in plugin.connected to index in optionmenu table = {0:6, 1:0, 2:1, 3:2, 4:3, 5:4} - mini = min(self.plugin.connected.values()) + maxi = max(self.plugin.connected.values()) optionmenu = self.xml.get_widget('optionmenu') #temporarily block signal in order not to send status that we show #in the optionmenu optionmenu.handler_block(self.id_signal_optionmenu) - optionmenu.set_history(table[mini]) + optionmenu.set_history(table[maxi]) optionmenu.handler_unblock(self.id_signal_optionmenu) + statuss = ['offline', 'online', 'away', 'xa', 'dnd', 'invisible'] + self.plugin.set_systray(statuss[maxi]) def on_status_changed(self, account, status): """the core tells us that our status has changed""" @@ -891,6 +895,7 @@ class roster_Window: self.plugin.queues[account][jid] = Queue.Queue(50) for i in self.get_user_iter(jid, account): model.set_value(i, 0, self.pixbufs['message']) + self.plugin.set_systray('message') tim = time.strftime("[%H:%M:%S]") self.plugin.queues[account][jid].put((msg, tim)) if path: @@ -1402,6 +1407,27 @@ class plugin: self.sleeper_state[account] = 3 return 1 + def set_systray_img(self, status): + if not self.roster.pixbufs.has_key(status): + return + pix = self.roster.pixbufs[status] + if isinstance(pix, gtk.gdk.PixbufAnimation): + self.img_tray.set_from_animation(pix) + else: + self.img_tray.set_from_pixbuf(pix) + + def set_systray(self, status=None): + if not status: + self.nb_msg -= 1 + if self.nb_msg == 0: + self.set_systray_img(self.status) + elif status == 'message': + self.nb_msg += 1 + self.set_systray_img('message') + else: + self.status = status + self.set_systray_img(status) + def __init__(self, quIN, quOUT): gtk.threads_init() gtk.threads_enter() @@ -1420,6 +1446,7 @@ class plugin: self.config = self.wait('CONFIG') self.send('ASK_CONFIG', None, ('GtkGui', 'accounts')) self.accounts = self.wait('CONFIG') + self.nb_msg = 0 self.windows = {'logs':{}} self.queues = {} self.connected = {} @@ -1440,6 +1467,13 @@ class plugin: gtk.timeout_add(100, self.read_queue) gtk.timeout_add(1000, self.read_sleepy) self.sleeper = None + t = trayicon.TrayIcon("Gajim") + tip = gtk.Tooltips() + tip.set_tip(t, 'Gajim') + self.img_tray = gtk.Image() + t.add(self.img_tray) + t.show_all() + self.set_systray('offline') gtk.main() gtk.threads_leave() diff --git a/plugins/gtkgui/trayicon.defs b/plugins/gtkgui/trayicon.defs new file mode 100644 index 0000000000..f61b1a2e73 --- /dev/null +++ b/plugins/gtkgui/trayicon.defs @@ -0,0 +1,58 @@ +;; -*- scheme -*- +; object definitions ... +(define-object TrayIcon + (in-module "Egg") + (parent "GtkPlug") + (c-name "EggTrayIcon") + (gtype-id "EGG_TYPE_TRAY_ICON") +) + +;; Enumerations and flags ... + + +;; From eggtrayicon.h + +(define-function egg_tray_icon_get_type + (c-name "egg_tray_icon_get_type") + (return-type "GType") +) + +;;(define-function egg_tray_icon_new_for_screen +;; (c-name "egg_tray_icon_new_for_screen") +;; (return-type "EggTrayIcon*") +;; (parameters +;; '("GdkScreen*" "screen") +;; '("const-gchar*" "name") +;; ) +;;) + +(define-function egg_tray_icon_new + (c-name "egg_tray_icon_new") + (is-constructor-of "EggTrayIcon") + (return-type "EggTrayIcon*") + (parameters + '("const-gchar*" "name") + ) +) + +(define-method send_message + (of-object "EggTrayIcon") + (c-name "egg_tray_icon_send_message") + (return-type "guint") + (parameters + '("gint" "timeout") + '("const-char*" "message") + '("gint" "len") + ) +) + +(define-method cancel_message + (of-object "EggTrayIcon") + (c-name "egg_tray_icon_cancel_message") + (return-type "none") + (parameters + '("guint" "id") + ) +) + + diff --git a/plugins/gtkgui/trayicon.override b/plugins/gtkgui/trayicon.override new file mode 100644 index 0000000000..979f523dcb --- /dev/null +++ b/plugins/gtkgui/trayicon.override @@ -0,0 +1,28 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +%% +headers +#include <Python.h> + +#include "pygobject.h" +#include "eggtrayicon.h" +%% +modulename trayicon +%% +import gtk.Plug as PyGtkPlug_Type +%% +ignore-glob + *_get_type +%% +override egg_tray_icon_send_message kwargs +static PyObject* +_wrap_egg_tray_icon_send_message(PyGObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = {"timeout", "message", NULL}; + int timeout, len, ret; + char *message; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "is#:TrayIcon.send_message", kwlist, &timeout, &message, &len)) + return NULL; + ret = egg_tray_icon_send_message(EGG_TRAY_ICON(self->obj), timeout, message, len); + return PyInt_FromLong(ret); +} diff --git a/plugins/gtkgui/trayiconmodule.c b/plugins/gtkgui/trayiconmodule.c new file mode 100644 index 0000000000..c2959a4854 --- /dev/null +++ b/plugins/gtkgui/trayiconmodule.c @@ -0,0 +1,25 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ + +/* include this first, before NO_IMPORT_PYGOBJECT is defined */ +#include <pygobject.h> + +void trayicon_register_classes (PyObject *d); + +extern PyMethodDef trayicon_functions[]; + +DL_EXPORT(void) +inittrayicon(void) +{ + PyObject *m, *d; + + init_pygobject (); + + m = Py_InitModule ("trayicon", trayicon_functions); + d = PyModule_GetDict (m); + + trayicon_register_classes (d); + + if (PyErr_Occurred ()) { + Py_FatalError ("can't initialise module trayicon :("); + } +} -- GitLab