Merge local changes.

This commit is contained in:
Stephan Erb 2009-11-24 16:04:58 +01:00
commit bcef68c8e2
31 changed files with 389 additions and 1399 deletions

View file

@ -1,9 +1,9 @@
CURRENT DEVELOPERS: CURRENT DEVELOPERS:
Alexander Cherniuk (ts33kr AT gmail.com)
Nikos Kouremenos (kourem AT gmail.com) Nikos Kouremenos (kourem AT gmail.com)
Yann Leboulanger (asterix AT lagaule.org) Yann Leboulanger (asterix AT lagaule.org)
Julien Pivotto (roidelapluie AT gmail.com) Julien Pivotto (roidelapluie AT gmail.com)
red-agent (hell.director AT gmail.com)
Jonathan Schleifer (js-gajim AT webkeks.org) Jonathan Schleifer (js-gajim AT webkeks.org)
Travis Shirk (travis AT pobox.com) Travis Shirk (travis AT pobox.com)
Brendan Taylor (whateley AT gmail.com) Brendan Taylor (whateley AT gmail.com)

View file

@ -50,7 +50,6 @@ MAINTAINERCLEANFILES = \
aclocal.m4 \ aclocal.m4 \
libtool \ libtool \
po/POTFILES.in \ po/POTFILES.in \
src/trayicon_la-eggtrayicon.loT \
m4/intltool.m4 m4/intltool.m4
MAINTAINERCLEANDIRS = \ MAINTAINERCLEANDIRS = \

View file

@ -16,7 +16,7 @@ Welcome to Gajim and thank you for trying out our client.
<h2>Runtime Requirements</h2> <h2>Runtime Requirements</h2>
<ul> <ul>
<li>python2.5 or higher</li> <li>python2.5 or higher</li>
<li>pygtk2.12 or higher</li> <li>pygtk2.16 or higher</li>
<li>python-libglade</li> <li>python-libglade</li>
<li>pysqlite2 (if you have python 2.5, you already have this)</li> <li>pysqlite2 (if you have python 2.5, you already have this)</li>
</ul> </ul>
@ -34,7 +34,6 @@ Gajim is a GTK+ app that loves GNOME. You can do 'make' so you don't require gno
<li>For zeroconf (bonjour), the "enable link-local messaging" checkbox, you need dbus-glib, python-avahi</li> <li>For zeroconf (bonjour), the "enable link-local messaging" checkbox, you need dbus-glib, python-avahi</li>
<li>dnsutils (or whatever package provides the nslookup binary) for SRV support</li> <li>dnsutils (or whatever package provides the nslookup binary) for SRV support</li>
<li>gtkspell and aspell-LANG where lang is your locale eg. en, fr etc</li> <li>gtkspell and aspell-LANG where lang is your locale eg. en, fr etc</li>
<li>GnomePythonExtras 2.10 or above (aka gnome-python-desktop) so you can avoid compiling trayicon and gtkspell</li>
<li>gnome-python-desktop (for GnomeKeyring support)</li> <li>gnome-python-desktop (for GnomeKeyring support)</li>
<li>notification-daemon or notify-python (and D-Bus) to get cooler popups</li> <li>notification-daemon or notify-python (and D-Bus) to get cooler popups</li>
<li>D-Bus running to have gajim-remote working. Some distributions split dbus-x11, which is needed for dbus to work with Gajim. Version >= 0.80 is required.</li> <li>D-Bus running to have gajim-remote working. Some distributions split dbus-x11, which is needed for dbus to work with Gajim. Version >= 0.80 is required.</li>
@ -53,8 +52,6 @@ the xml lib that *comes* with python and not pyxml or whatever.
<ul> <ul>
<li>python-dev</li> <li>python-dev</li>
<li>python-gtk2-dev</li> <li>python-gtk2-dev</li>
<li>libgtk2.0-dev aka. gtk2-devel</li>
<li>libgtkspell-dev (for the gtkspell module)</li>
<li>intltool (>= 0.40.1)</li> <li>intltool (>= 0.40.1)</li>
</ul> </ul>

View file

@ -39,7 +39,7 @@ AM_NLS
dnl **** dnl ****
dnl pygtk and gtk+ dnl pygtk and gtk+
dnl **** dnl ****
PKG_CHECK_MODULES([PYGTK], [gtk+-2.0 >= 2.12.0 pygtk-2.0 >= 2.12.0]) PKG_CHECK_MODULES([PYGTK], [gtk+-2.0 >= 2.16.0 pygtk-2.0 >= 2.16.0])
AC_SUBST(PYGTK_CFLAGS) AC_SUBST(PYGTK_CFLAGS)
AC_SUBST(PYGTK_LIBS) AC_SUBST(PYGTK_LIBS)
PYGTK_DEFS=`$PKG_CONFIG --variable=defsdir pygtk-2.0` PYGTK_DEFS=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
@ -50,15 +50,6 @@ if test "x$PYTHON" = "x:"; then
AC_MSG_ERROR([Python not found]) AC_MSG_ERROR([Python not found])
fi fi
dnl ****
dnl tray icon
dnl ****
AC_ARG_ENABLE(trayicon,
[ --disable-trayicon do not build trayicon module [default yes]],
enable_trayicon=$enableval, enable_trayicon=yes)
test "x$enable_trayicon" = "xyes" && have_trayicon=true || have_trayicon=false
AM_CONDITIONAL(BUILD_TRAYICON, $have_trayicon)
ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}" ACLOCAL_AMFLAGS="\${ACLOCAL_FLAGS}"
AC_SUBST(ACLOCAL_AMFLAGS) AC_SUBST(ACLOCAL_AMFLAGS)
@ -91,8 +82,3 @@ AC_CONFIG_FILES([
po/Makefile.in po/Makefile.in
]) ])
AC_OUTPUT AC_OUTPUT
echo "
*****************************
Build features:
trayicon ......... ${have_trayicon}
*****************************"

View file

@ -33,5 +33,4 @@ export datadir=@DATADIR@/gajim
PYTHON_EXEC=@PYTHON@ PYTHON_EXEC=@PYTHON@
cd ${datadir}/src cd ${datadir}/src
export PYTHONPATH="$PYTHONPATH:@LIBDIR@/gajim"
exec ${PYTHON_EXEC} -OO $APP.py "$@" exec ${PYTHON_EXEC} -OO $APP.py "$@"

View file

@ -1,31 +1,7 @@
CLEANFILES = \
trayicon.c
INCLUDES = \ INCLUDES = \
$(PYTHON_INCLUDES) $(PYTHON_INCLUDES)
export MACOSX_DEPLOYMENT_TARGET=10.4 export MACOSX_DEPLOYMENT_TARGET=10.4
if BUILD_TRAYICON
trayiconlib_LTLIBRARIES = trayicon.la
trayiconlibdir = $(pkglibdir)
trayicon_la_LIBADD = $(PYGTK_LIBS)
trayicon_la_SOURCES = \
eggtrayicon.c \
trayiconmodule.c
nodist_trayicon_la_SOURCES = \
trayicon.c
trayicon_la_LDFLAGS = \
-module -avoid-version
trayicon_la_CFLAGS = $(PYGTK_CFLAGS)
trayicon.c:
pygtk-codegen-2.0 --prefix trayicon \
--register $(PYGTK_DEFS)/gdk-types.defs \
--register $(PYGTK_DEFS)/gtk-types.defs \
--override $(srcdir)/trayicon.override \
$(srcdir)/trayicon.defs > $@
endif
gajimsrcdir = $(pkgdatadir)/src gajimsrcdir = $(pkgdatadir)/src
gajimsrc_PYTHON = $(srcdir)/*.py gajimsrc_PYTHON = $(srcdir)/*.py
@ -56,12 +32,7 @@ EXTRA_DIST = $(gajimsrc_PYTHON) \
$(gajimsrc2_PYTHON) \ $(gajimsrc2_PYTHON) \
$(gajimsrc3_PYTHON) \ $(gajimsrc3_PYTHON) \
$(gajimsrc4_PYTHON) \ $(gajimsrc4_PYTHON) \
$(gajimsrc5_PYTHON) \ $(gajimsrc5_PYTHON)
eggtrayicon.c \
trayiconmodule.c \
eggtrayicon.h \
trayicon.defs \
trayicon.override
dist-hook: dist-hook:
rm -f $(distdir)/ipython_view.py rm -f $(distdir)/ipython_view.py

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1,4 +1,4 @@
# Copyright (C) 2009 red-agent <hell.director@gmail.com> # Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by

View file

@ -1737,7 +1737,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
# wrong answer # wrong answer
return return
tzo = qp.getTag('tzo').getData() tzo = qp.getTag('tzo').getData()
if tzo == 'Z': if tzo.lower() == 'z':
tzo = '0:0' tzo = '0:0'
tzoh, tzom = tzo.split(':') tzoh, tzom = tzo.split(':')
utc_time = qp.getTag('utc').getData() utc_time = qp.getTag('utc').getData()
@ -1862,7 +1862,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
log.warn('Invalid JID: %s, ignoring it' % item.getAttr('jid')) log.warn('Invalid JID: %s, ignoring it' % item.getAttr('jid'))
continue continue
name = item.getAttr('name') name = item.getAttr('name')
contact = gajim.contact.get_contact(self.name, jid) contact = gajim.contacts.get_contact(self.name, jid)
groups = [] groups = []
same_groups = True same_groups = True
for group in item.getTags('group'): for group in item.getTags('group'):

View file

@ -297,8 +297,6 @@ class PreferencesWindow:
systray_combobox.set_active(1) systray_combobox.set_active(1)
else: else:
systray_combobox.set_active(2) systray_combobox.set_active(2)
if not gajim.interface.systray_capabilities:
systray_combobox.set_sensitive(False)
# sounds # sounds
if gajim.config.get('sounds_on'): if gajim.config.get('sounds_on'):

View file

@ -3080,6 +3080,8 @@ class PrivacyListWindow:
self.global_rules = {} self.global_rules = {}
self.list_of_groups = {} self.list_of_groups = {}
self.max_order = 0
# Default Edit Values # Default Edit Values
self.edit_rule_type = 'jid' self.edit_rule_type = 'jid'
self.allow_deny = 'allow' self.allow_deny = 'allow'
@ -3175,6 +3177,8 @@ class PrivacyListWindow:
else: else:
text_item = _('Order: %(order)s, action: %(action)s') % \ text_item = _('Order: %(order)s, action: %(action)s') % \
{'order': rule['order'], 'action': rule['action']} {'order': rule['order'], 'action': rule['action']}
if int(rule['order']) > self.max_order:
self.max_order = int(rule['order'])
self.global_rules[text_item] = rule self.global_rules[text_item] = rule
self.list_of_rules_combobox.append_text(text_item) self.list_of_rules_combobox.append_text(text_item)
if len(rules) == 0: if len(rules) == 0:
@ -3322,7 +3326,7 @@ class PrivacyListWindow:
self.edit_view_status_checkbutton.set_active(False) self.edit_view_status_checkbutton.set_active(False)
self.edit_send_status_checkbutton.set_active(False) self.edit_send_status_checkbutton.set_active(False)
self.edit_all_checkbutton.set_active(False) self.edit_all_checkbutton.set_active(False)
self.edit_order_spinbutton.set_value(1) self.edit_order_spinbutton.set_value(self.max_order + 1)
self.edit_type_group_combobox.set_active(0) self.edit_type_group_combobox.set_active(0)
self.edit_type_subscription_combobox.set_active(0) self.edit_type_subscription_combobox.set_active(0)
self.add_edit_rule_label.set_label( self.add_edit_rule_label.set_label(
@ -3365,6 +3369,8 @@ class PrivacyListWindow:
def on_save_rule_button_clicked(self, widget): def on_save_rule_button_clicked(self, widget):
tags=[] tags=[]
current_tags = self.get_current_tags() current_tags = self.get_current_tags()
if int(current_tags['order']) > self.max_order:
self.max_order = int(current_tags['order'])
if self.active_rule == '': if self.active_rule == '':
tags.append(current_tags) tags.append(current_tags)

View file

@ -1,584 +0,0 @@
/* 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 <glib/gi18n.h>
#include <libintl.h>
#include "eggtrayicon.h"
#include <gdkconfig.h>
#if defined (GDK_WINDOWING_X11)
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#elif defined (GDK_WINDOWING_WIN32)
#include <gdk/gdkwin32.h>
#endif
#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_add (GtkContainer *container, GtkWidget *widget);
static void egg_tray_icon_realize (GtkWidget *widget);
static void egg_tray_icon_unrealize (GtkWidget *widget);
#ifdef GDK_WINDOWING_X11
static void egg_tray_icon_update_manager_window (EggTrayIcon *icon,
gboolean dock_if_realized);
static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon);
#endif
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;
GtkContainerClass *container_class = (GtkContainerClass *)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;
container_class->add = egg_tray_icon_add;
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));
#if defined (GDK_WINDOWING_X11)
/* Nothing */
#elif defined (GDK_WINDOWING_WIN32)
g_warning ("Port eggtrayicon to Win32");
#else
g_warning ("Port eggtrayicon to this GTK+ backend");
#endif
}
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;
}
}
#ifdef GDK_WINDOWING_X11
static Display *
egg_tray_icon_get_x_display(EggTrayIcon *icon)
{
Display *xdisplay = NULL;
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (icon));
if (!GDK_IS_DISPLAY (display))
display = gdk_display_get_default ();
xdisplay = GDK_DISPLAY_XDISPLAY (display);
return xdisplay;
}
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 = egg_tray_icon_get_x_display(icon);
if (xdisplay == NULL)
return;
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, TRUE);
}
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_manager_window_destroyed (icon);
}
}
return GDK_FILTER_CONTINUE;
}
#endif
static void
egg_tray_icon_unrealize (GtkWidget *widget)
{
#ifdef GDK_WINDOWING_X11
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);
#endif
}
#ifdef GDK_WINDOWING_X11
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 = egg_tray_icon_get_x_display(icon);
if (display == NULL)
return;
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,
gboolean dock_if_realized)
{
Display *xdisplay;
if (icon->manager_window != None)
return;
xdisplay = egg_tray_icon_get_x_display(icon);
if (xdisplay == NULL)
return;
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);
if (dock_if_realized && GTK_WIDGET_REALIZED (icon))
egg_tray_icon_send_dock_request (icon);
egg_tray_icon_get_orientation_property (icon);
}
}
static gboolean
transparent_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
gdk_window_clear_area (widget->window, event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
static void
make_transparent_again (GtkWidget *widget, GtkStyle *previous_style,
gpointer user_data)
{
gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
}
static void
make_transparent (GtkWidget *widget, gpointer user_data)
{
if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget))
return;
gtk_widget_set_app_paintable (widget, TRUE);
gtk_widget_set_double_buffered (widget, FALSE);
gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
g_signal_connect (widget, "expose_event",
G_CALLBACK (transparent_expose_event), NULL);
g_signal_connect_after (widget, "style_set",
G_CALLBACK (make_transparent_again), NULL);
}
static void
egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon)
{
GdkWindow *gdkwin;
g_return_if_fail (icon->manager_window != None);
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);
icon->manager_window = None;
egg_tray_icon_update_manager_window (icon, TRUE);
}
#endif
static void
egg_tray_icon_realize (GtkWidget *widget)
{
#ifdef GDK_WINDOWING_X11
EggTrayIcon *icon = EGG_TRAY_ICON (widget);
GdkScreen *screen;
Display *xdisplay;
char buffer[256];
GdkWindow *root_window;
if (GTK_WIDGET_CLASS (parent_class)->realize)
GTK_WIDGET_CLASS (parent_class)->realize (widget);
make_transparent (widget, NULL);
xdisplay = egg_tray_icon_get_x_display(icon);
if (xdisplay == NULL)
return;
screen = gtk_widget_get_screen (widget);
/* 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, FALSE);
egg_tray_icon_send_dock_request (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);
#endif
}
static void
egg_tray_icon_add (GtkContainer *container, GtkWidget *widget)
{
g_signal_connect (widget, "realize",
G_CALLBACK (make_transparent), NULL);
GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
}
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);
#ifdef GDK_WINDOWING_X11
if (icon->manager_window == None)
return 0;
#endif
if (len < 0)
len = strlen (message);
stamp = icon->stamp++;
#ifdef GDK_WINDOWING_X11
/* 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 = egg_tray_icon_get_x_display(icon);
if (xdisplay == NULL)
return 0;
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 ();
#endif
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);
#ifdef GDK_WINDOWING_X11
egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
(Window)gtk_plug_get_id (GTK_PLUG (icon)),
id, 0, 0);
#endif
}
GtkOrientation
egg_tray_icon_get_orientation (EggTrayIcon *icon)
{
g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
return icon->orientation;
}

View file

@ -1,80 +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>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
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;
#ifdef GDK_WINDOWING_X11
Atom selection_atom;
Atom manager_atom;
Atom system_tray_opcode_atom;
Atom orientation_atom;
Window manager_window;
#endif
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__ */

View file

@ -83,10 +83,6 @@ class FeaturesWindow:
_('Passive popups notifying for new events.'), _('Passive popups notifying for new events.'),
_('Requires python-notify or instead python-dbus in conjunction with notification-daemon.'), _('Requires python-notify or instead python-dbus in conjunction with notification-daemon.'),
_('Feature not available under Windows.')), _('Feature not available under Windows.')),
_('Trayicon'): (self.trayicon_available,
_('A icon in systemtray reflecting the current presence.'),
_('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'),
_('Requires PyGTK >= 2.10.')),
_('Automatic status'): (self.idle_available, _('Automatic status'): (self.idle_available,
_('Ability to measure idle time, in order to set auto status.'), _('Ability to measure idle time, in order to set auto status.'),
_('Requires libxss library.'), _('Requires libxss library.'),
@ -240,15 +236,6 @@ class FeaturesWindow:
return False return False
return True return True
def trayicon_available(self):
if os.name == 'nt':
return True
try:
import systray
except Exception:
return False
return True
def idle_available(self): def idle_available(self):
from common import sleepy from common import sleepy
return sleepy.SUPPORTED return sleepy.SUPPORTED

View file

@ -29,6 +29,7 @@
import os import os
import time import time
import locale
import gtk import gtk
import pango import pango
import gobject import gobject
@ -394,9 +395,7 @@ class GroupchatControl(ChatControlBase):
nick1 = nick1.decode('utf-8') nick1 = nick1.decode('utf-8')
nick2 = nick2.decode('utf-8') nick2 = nick2.decode('utf-8')
if type1 == 'role': if type1 == 'role':
if nick1 < nick2: return locale.strcoll(nick1, nick2)
return -1
return 1
if type1 == 'contact': if type1 == 'contact':
gc_contact1 = gajim.contacts.get_gc_contact(self.account, gc_contact1 = gajim.contacts.get_gc_contact(self.account,
self.room_jid, nick1) self.room_jid, nick1)
@ -420,11 +419,7 @@ class GroupchatControl(ChatControlBase):
# We compare names # We compare names
name1 = gc_contact1.get_shown_name() name1 = gc_contact1.get_shown_name()
name2 = gc_contact2.get_shown_name() name2 = gc_contact2.get_shown_name()
if name1.lower() < name2.lower(): return locale.strcoll(name1.lower(), name2.lower())
return -1
if name2.lower() < name1.lower():
return 1
return 0
def on_msg_textview_populate_popup(self, textview, menu): def on_msg_textview_populate_popup(self, textview, menu):
'''we override the default context menu and we prepend Clear '''we override the default context menu and we prepend Clear

View file

@ -3122,7 +3122,7 @@ class Interface:
gajim.ipython_window = window gajim.ipython_window = window
def run(self): def run(self):
if self.systray_capabilities and gajim.config.get('trayicon') != 'never': if gajim.config.get('trayicon') != 'never':
self.show_systray() self.show_systray()
self.roster = roster_window.RosterWindow() self.roster = roster_window.RosterWindow()
@ -3357,21 +3357,9 @@ class Interface:
gtkgui_helpers.make_jabber_state_images() gtkgui_helpers.make_jabber_state_images()
self.systray_enabled = False self.systray_enabled = False
self.systray_capabilities = False
if (os.name == 'nt'): import statusicon
import statusicon self.systray = statusicon.StatusIcon()
self.systray = statusicon.StatusIcon()
self.systray_capabilities = True
else: # use ours, not GTK+ one
# [FIXME: remove this when we migrate to 2.10 and we can do
# cool tooltips somehow and (not dying to keep) animation]
import systray
self.systray_capabilities = systray.HAS_SYSTRAY_CAPABILITIES
if self.systray_capabilities:
self.systray = systray.Systray()
else:
gajim.config.set('trayicon', 'never')
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'gajim.png') path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'gajim.png')
pix = gtk.gdk.pixbuf_new_from_file(path_to_file) pix = gtk.gdk.pixbuf_new_from_file(path_to_file)

View file

@ -38,6 +38,7 @@ import gobject
import os import os
import sys import sys
import time import time
import locale
import common.sleepy import common.sleepy
import history_window import history_window
@ -1558,9 +1559,7 @@ class RosterWindow:
account1 = account1.decode('utf-8') account1 = account1.decode('utf-8')
account2 = account2.decode('utf-8') account2 = account2.decode('utf-8')
if type1 == 'account': if type1 == 'account':
if account1 < account2: return locale.strcoll(account1, account2)
return -1
return 1
jid1 = model[iter1][C_JID].decode('utf-8') jid1 = model[iter1][C_JID].decode('utf-8')
jid2 = model[iter2][C_JID].decode('utf-8') jid2 = model[iter2][C_JID].decode('utf-8')
if type1 == 'contact': if type1 == 'contact':
@ -1607,20 +1606,23 @@ class RosterWindow:
elif show1 > show2: elif show1 > show2:
return 1 return 1
# We compare names # We compare names
if name1.lower() < name2.lower(): cmp_result = locale.strcoll(name1.lower(), name2.lower())
if cmp_result < 0:
return -1 return -1
if name2.lower() < name1.lower(): if cmp_result > 0:
return 1 return 1
if type1 == 'contact' and type2 == 'contact': if type1 == 'contact' and type2 == 'contact':
# We compare account names # We compare account names
if account1.lower() < account2.lower(): cmp_result = locale.strcoll(account1.lower(), account2.lower())
if cmp_result < 0:
return -1 return -1
if account2.lower() < account1.lower(): if cmp_result > 0:
return 1 return 1
# We compare jids # We compare jids
if jid1.lower() < jid2.lower(): cmp_result = locale.strcoll(jid1.lower(), jid2.lower())
if cmp_result < 0:
return -1 return -1
if jid2.lower() < jid1.lower(): if cmp_result > 0:
return 1 return 1
return 0 return 0
@ -5807,10 +5809,8 @@ class RosterWindow:
if gajim.config.get('show_roster_on_startup'): if gajim.config.get('show_roster_on_startup'):
self.window.show_all() self.window.show_all()
else: else:
if not gajim.config.get('trayicon') or not \ if gajim.config.get('trayicon') != 'always':
gajim.interface.systray_capabilities: # Without trayicon, user should see the roster!
# cannot happen via GUI, but I put this incase user touches
# config. without trayicon, he or she should see the roster!
self.window.show_all() self.window.show_all()
gajim.config.set('show_roster_on_startup', True) gajim.config.set('show_roster_on_startup', True)

View file

@ -25,26 +25,62 @@
import sys import sys
import gtk import gtk
import systray import gobject
import os
import dialogs
import config
import tooltips
import gtkgui_helpers
import tooltips
from common import gajim from common import gajim
from common import helpers from common import helpers
from common import pep
class StatusIcon(systray.Systray): class StatusIcon:
'''Class for the notification area icon''' '''Class for the notification area icon'''
#NOTE: gtk api does NOT allow:
# leave, enter motion notify
# and can't do cool tooltips we use
def __init__(self): def __init__(self):
systray.Systray.__init__(self) self.single_message_handler_id = None
self.new_chat_handler_id = None
# click somewhere else does not popdown menu. workaround this.
self.added_hide_menuitem = False
self.status = 'offline'
self.xml = gtkgui_helpers.get_glade('systray_context_menu.glade')
self.systray_context_menu = self.xml.get_widget('systray_context_menu')
self.xml.signal_autoconnect(self)
self.popup_menus = []
self.status_icon = None self.status_icon = None
self.tooltip = tooltips.NotificationAreaTooltip()
def subscribe_events(self):
'''Register listeners to the events class'''
gajim.events.event_added_subscribe(self.on_event_added)
gajim.events.event_removed_subscribe(self.on_event_removed)
def unsubscribe_events(self):
'''Unregister listeners to the events class'''
gajim.events.event_added_unsubscribe(self.on_event_added)
gajim.events.event_removed_unsubscribe(self.on_event_removed)
def on_event_added(self, event):
'''Called when an event is added to the event list'''
if event.show_in_systray:
self.set_img()
def on_event_removed(self, event_list):
'''Called when one or more events are removed from the event list'''
self.set_img()
def show_icon(self): def show_icon(self):
if not self.status_icon: if not self.status_icon:
self.status_icon = gtk.StatusIcon() self.status_icon = gtk.StatusIcon()
self.status_icon.set_property('has-tooltip', True)
self.status_icon.connect('activate', self.on_status_icon_left_clicked) self.status_icon.connect('activate', self.on_status_icon_left_clicked)
self.status_icon.connect('popup-menu', self.status_icon.connect('popup-menu',
self.on_status_icon_right_clicked) self.on_status_icon_right_clicked)
self.status_icon.connect('query-tooltip',
self.on_status_icon_query_tooltip)
self.set_img() self.set_img()
self.status_icon.set_visible(True) self.status_icon.set_visible(True)
@ -53,6 +89,11 @@ class StatusIcon(systray.Systray):
def on_status_icon_right_clicked(self, widget, event_button, event_time): def on_status_icon_right_clicked(self, widget, event_button, event_time):
self.make_menu(event_button, event_time) self.make_menu(event_button, event_time)
def on_status_icon_query_tooltip(self, widget, x, y, keyboard_mode, tooltip):
self.tooltip.populate()
tooltip.set_custom(self.tooltip.hbox)
return True
def hide_icon(self): def hide_icon(self):
self.status_icon.set_visible(False) self.status_icon.set_visible(False)
self.unsubscribe_events() self.unsubscribe_events()
@ -64,8 +105,6 @@ class StatusIcon(systray.Systray):
'''apart from image, we also update tooltip text here''' '''apart from image, we also update tooltip text here'''
if not gajim.interface.systray_enabled: if not gajim.interface.systray_enabled:
return return
text = helpers.get_notification_icon_tooltip_text()
self.status_icon.set_tooltip(text)
if gajim.events.get_nb_systray_events(): if gajim.events.get_nb_systray_events():
state = 'event' state = 'event'
self.status_icon.set_blinking(True) self.status_icon.set_blinking(True)
@ -79,7 +118,304 @@ class StatusIcon(systray.Systray):
self.status_icon.set_from_pixbuf(image.get_pixbuf()) self.status_icon.set_from_pixbuf(image.get_pixbuf())
#FIXME: oops they forgot to support GIF animation? #FIXME: oops they forgot to support GIF animation?
#or they were lazy to get it to work under Windows! WTF! #or they were lazy to get it to work under Windows! WTF!
#elif image.get_storage_type() == gtk.IMAGE_ANIMATION: elif image.get_storage_type() == gtk.IMAGE_ANIMATION:
self.status_icon.set_from_pixbuf(
image.get_animation().get_static_image())
# self.img_tray.set_from_animation(image.get_animation()) # self.img_tray.set_from_animation(image.get_animation())
def change_status(self, global_status):
''' set tray image to 'global_status' '''
# change image and status, only if it is different
if global_status is not None and self.status != global_status:
self.status = global_status
self.set_img()
def start_chat(self, widget, account, jid):
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
if gajim.interface.msg_win_mgr.has_window(jid, account):
gajim.interface.msg_win_mgr.get_window(jid, account).set_active_tab(
jid, account)
elif contact:
gajim.interface.new_chat(contact, account)
gajim.interface.msg_win_mgr.get_window(jid, account).set_active_tab(
jid, account)
def on_single_message_menuitem_activate(self, widget, account):
dialogs.SingleMessageWindow(account, action='send')
def on_new_chat(self, widget, account):
dialogs.NewChatDialog(account)
def make_menu(self, event_button, event_time):
'''create chat with and new message (sub) menus/menuitems'''
for m in self.popup_menus:
m.destroy()
chat_with_menuitem = self.xml.get_widget('chat_with_menuitem')
single_message_menuitem = self.xml.get_widget(
'single_message_menuitem')
status_menuitem = self.xml.get_widget('status_menu')
join_gc_menuitem = self.xml.get_widget('join_gc_menuitem')
sounds_mute_menuitem = self.xml.get_widget('sounds_mute_menuitem')
if self.single_message_handler_id:
single_message_menuitem.handler_disconnect(
self.single_message_handler_id)
self.single_message_handler_id = None
if self.new_chat_handler_id:
chat_with_menuitem.disconnect(self.new_chat_handler_id)
self.new_chat_handler_id = None
sub_menu = gtk.Menu()
self.popup_menus.append(sub_menu)
status_menuitem.set_submenu(sub_menu)
gc_sub_menu = gtk.Menu() # gc is always a submenu
join_gc_menuitem.set_submenu(gc_sub_menu)
# We need our own set of status icons, let's make 'em!
iconset = gajim.config.get('iconset')
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
state_images = gtkgui_helpers.load_iconset(path)
if 'muc_active' in state_images:
join_gc_menuitem.set_image(state_images['muc_active'])
for show in ('online', 'chat', 'away', 'xa', 'dnd', 'invisible'):
uf_show = helpers.get_uf_show(show, use_mnemonic = True)
item = gtk.ImageMenuItem(uf_show)
item.set_image(state_images[show])
sub_menu.append(item)
item.connect('activate', self.on_show_menuitem_activate, show)
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
item = gtk.ImageMenuItem(_('_Change Status Message...'))
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'kbd_input.png')
img = gtk.Image()
img.set_from_file(path)
item.set_image(img)
sub_menu.append(item)
item.connect('activate', self.on_change_status_message_activate)
connected_accounts = gajim.get_number_of_connected_accounts()
if connected_accounts < 1:
item.set_sensitive(False)
connected_accounts_with_private_storage = 0
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
uf_show = helpers.get_uf_show('offline', use_mnemonic = True)
item = gtk.ImageMenuItem(uf_show)
item.set_image(state_images['offline'])
sub_menu.append(item)
item.connect('activate', self.on_show_menuitem_activate, 'offline')
iskey = connected_accounts > 0 and not (connected_accounts == 1 and
gajim.connections[gajim.connections.keys()[0]].is_zeroconf)
chat_with_menuitem.set_sensitive(iskey)
single_message_menuitem.set_sensitive(iskey)
join_gc_menuitem.set_sensitive(iskey)
accounts_list = sorted(gajim.contacts.get_accounts())
# items that get shown whether an account is zeroconf or not
if connected_accounts > 1: # 2 or more connections? make submenus
account_menu_for_chat_with = gtk.Menu()
chat_with_menuitem.set_submenu(account_menu_for_chat_with)
self.popup_menus.append(account_menu_for_chat_with)
for account in accounts_list:
if gajim.account_is_connected(account):
# for chat_with
item = gtk.MenuItem(_('using account %s') % account)
account_menu_for_chat_with.append(item)
item.connect('activate', self.on_new_chat, account)
elif connected_accounts == 1: # one account
# one account connected, no need to show 'as jid'
for account in gajim.connections:
if gajim.connections[account].connected > 1:
# for start chat
self.new_chat_handler_id = chat_with_menuitem.connect(
'activate', self.on_new_chat, account)
break # No other connected account
# menu items that don't apply to zeroconf connections
if connected_accounts == 1 or (connected_accounts == 2 and \
gajim.zeroconf_is_connected()):
# only one 'real' (non-zeroconf) account is connected, don't need
# submenus
for account in gajim.connections:
if gajim.account_is_connected(account) and \
not gajim.config.get_per('accounts', account, 'is_zeroconf'):
if gajim.connections[account].private_storage_supported:
connected_accounts_with_private_storage += 1
# for single message
single_message_menuitem.remove_submenu()
self.single_message_handler_id = single_message_menuitem.\
connect('activate',
self.on_single_message_menuitem_activate, account)
# join gc
gajim.interface.roster.add_bookmarks_list(gc_sub_menu,
account)
break # No other account connected
else:
# 2 or more 'real' accounts are connected, make submenus
account_menu_for_single_message = gtk.Menu()
single_message_menuitem.set_submenu(
account_menu_for_single_message)
self.popup_menus.append(account_menu_for_single_message)
for account in accounts_list:
if gajim.connections[account].is_zeroconf or \
not gajim.account_is_connected(account):
continue
if gajim.connections[account].private_storage_supported:
connected_accounts_with_private_storage += 1
# for single message
item = gtk.MenuItem(_('using account %s') % account)
item.connect('activate',
self.on_single_message_menuitem_activate, account)
account_menu_for_single_message.append(item)
# join gc
gc_item = gtk.MenuItem(_('using account %s') % account, False)
gc_sub_menu.append(gc_item)
gc_menuitem_menu = gtk.Menu()
gajim.interface.roster.add_bookmarks_list(gc_menuitem_menu,
account)
gc_item.set_submenu(gc_menuitem_menu)
gc_sub_menu.show_all()
newitem = gtk.SeparatorMenuItem() # separator
gc_sub_menu.append(newitem)
newitem = gtk.ImageMenuItem(_('_Manage Bookmarks...'))
img = gtk.image_new_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
newitem.set_image(img)
newitem.connect('activate',
gajim.interface.roster.on_manage_bookmarks_menuitem_activate)
gc_sub_menu.append(newitem)
if connected_accounts_with_private_storage == 0:
newitem.set_sensitive(False)
sounds_mute_menuitem.set_active(not gajim.config.get('sounds_on'))
if os.name == 'nt':
if self.added_hide_menuitem is False:
self.systray_context_menu.prepend(gtk.SeparatorMenuItem())
item = gtk.MenuItem(_('Hide this menu'))
self.systray_context_menu.prepend(item)
self.added_hide_menuitem = True
self.systray_context_menu.show_all()
self.systray_context_menu.popup(None, None, None, 0,
event_time)
def on_show_all_events_menuitem_activate(self, widget):
events = gajim.events.get_systray_events()
for account in events:
for jid in events[account]:
for event in events[account][jid]:
gajim.interface.handle_event(account, jid, event.type_)
def on_sounds_mute_menuitem_activate(self, widget):
gajim.config.set('sounds_on', not widget.get_active())
gajim.interface.save_config()
def on_show_roster_menuitem_activate(self, widget):
win = gajim.interface.roster.window
win.present()
def on_preferences_menuitem_activate(self, widget):
if 'preferences' in gajim.interface.instances:
gajim.interface.instances['preferences'].window.present()
else:
gajim.interface.instances['preferences'] = config.PreferencesWindow()
def on_quit_menuitem_activate(self, widget):
gajim.interface.roster.on_quit_request()
def on_left_click(self):
win = gajim.interface.roster.window
if len(gajim.events.get_systray_events()) == 0:
# No pending events, so toggle visible/hidden for roster window
if not win.iconify_initially and (win.get_property(
'has-toplevel-focus') or os.name == 'nt'):
# visible in ANY virtual desktop?
# we could be in another VD right now. eg vd2
# and we want to show it in vd2
if not gtkgui_helpers.possibly_move_window_in_current_desktop(win):
win.set_property('skip-taskbar-hint', False)
win.iconify() # else we hide it from VD that was visible in
win.set_property('skip-taskbar-hint', True)
else:
win.deiconify()
if not gajim.config.get('roster_window_skip_taskbar'):
win.set_property('skip-taskbar-hint', False)
win.present_with_time(gtk.get_current_event_time())
else:
self.handle_first_event()
def handle_first_event(self):
account, jid, event = gajim.events.get_first_systray_event()
if not event:
return
gajim.interface.handle_event(account, jid, event.type_)
def on_middle_click(self):
'''middle click raises window to have complete focus (fe. get kbd events)
but if already raised, it hides it'''
win = gajim.interface.roster.window
if win.is_active(): # is it fully raised? (eg does it receive kbd events?)
win.hide()
else:
win.present()
def on_clicked(self, widget, event):
self.on_tray_leave_notify_event(widget, None)
if event.type != gtk.gdk.BUTTON_PRESS:
return
if event.button == 1: # Left click
self.on_left_click()
elif event.button == 2: # middle click
self.on_middle_click()
elif event.button == 3: # right click
self.make_menu(event.button, event.time)
def on_show_menuitem_activate(self, widget, show):
# we all add some fake (we cannot select those nor have them as show)
# but this helps to align with roster's status_combobox index positions
l = ['online', 'chat', 'away', 'xa', 'dnd', 'invisible', 'SEPARATOR',
'CHANGE_STATUS_MSG_MENUITEM', 'SEPARATOR', 'offline']
index = l.index(show)
if not helpers.statuses_unified():
gajim.interface.roster.status_combobox.set_active(index + 2)
return
current = gajim.interface.roster.status_combobox.get_active()
if index != current:
gajim.interface.roster.status_combobox.set_active(index)
def on_change_status_message_activate(self, widget):
model = gajim.interface.roster.status_combobox.get_model()
active = gajim.interface.roster.status_combobox.get_active()
status = model[active][2].decode('utf-8')
def on_response(message, pep_dict):
if message is None: # None if user press Cancel
return
accounts = gajim.connections.keys()
for acct in accounts:
if not gajim.config.get_per('accounts', acct,
'sync_with_global_status'):
continue
show = gajim.SHOW_LIST[gajim.connections[acct].connected]
gajim.interface.roster.send_status(acct, show, message)
gajim.interface.roster.send_pep(acct, pep_dict)
dlg = dialogs.ChangeStatusMessageDialog(on_response, status)
dlg.dialog.present()
# vim: se ts=3: # vim: se ts=3:

View file

@ -1,459 +0,0 @@
# -*- coding:utf-8 -*-
## src/systray.py
##
## Copyright (C) 2003-2005 Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2005 Norman Rasmussen <norman AT rasmussen.co.za>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
## Travis Shirk <travis AT pobox.com>
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006 Stefan Bethge <stefan AT lanpartei.de>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
## Julien Pivotto <roidelapluie AT gmail.com>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
import gtk
import gobject
import os
import dialogs
import config
import tooltips
import gtkgui_helpers
from common import gajim
from common import helpers
from common import pep
HAS_SYSTRAY_CAPABILITIES = True
try:
import egg.trayicon as trayicon # gnomepythonextras trayicon
except Exception:
try:
import trayicon # our trayicon
except Exception:
gajim.log.debug('No trayicon module available')
HAS_SYSTRAY_CAPABILITIES = False
class Systray:
'''Class for icon in the notification area
This class is both base class (for statusicon.py) and normal class
for trayicon in GNU/Linux'''
def __init__(self):
self.single_message_handler_id = None
self.new_chat_handler_id = None
self.t = None
# click somewhere else does not popdown menu. workaround this.
self.added_hide_menuitem = False
self.img_tray = gtk.Image()
self.status = 'offline'
self.xml = gtkgui_helpers.get_glade('systray_context_menu.glade')
self.systray_context_menu = self.xml.get_widget('systray_context_menu')
self.xml.signal_autoconnect(self)
self.popup_menus = []
def subscribe_events(self):
'''Register listeners to the events class'''
gajim.events.event_added_subscribe(self.on_event_added)
gajim.events.event_removed_subscribe(self.on_event_removed)
def unsubscribe_events(self):
'''Unregister listeners to the events class'''
gajim.events.event_added_unsubscribe(self.on_event_added)
gajim.events.event_removed_unsubscribe(self.on_event_removed)
def on_event_added(self, event):
'''Called when an event is added to the event list'''
if event.show_in_systray:
self.set_img()
def on_event_removed(self, event_list):
'''Called when one or more events are removed from the event list'''
self.set_img()
def set_img(self):
if not gajim.interface.systray_enabled:
return
if gajim.events.get_nb_systray_events():
state = 'event'
else:
state = self.status
if state != 'event' and gajim.config.get('trayicon') == 'on_event':
self.t.hide()
else:
self.t.show()
image = gajim.interface.jabber_state_images['16'][state]
if image.get_storage_type() == gtk.IMAGE_ANIMATION:
self.img_tray.set_from_animation(image.get_animation())
elif image.get_storage_type() == gtk.IMAGE_PIXBUF:
self.img_tray.set_from_pixbuf(image.get_pixbuf())
def change_status(self, global_status):
''' set tray image to 'global_status' '''
# change image and status, only if it is different
if global_status is not None and self.status != global_status:
self.status = global_status
self.set_img()
def start_chat(self, widget, account, jid):
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
if gajim.interface.msg_win_mgr.has_window(jid, account):
gajim.interface.msg_win_mgr.get_window(jid, account).set_active_tab(
jid, account)
elif contact:
gajim.interface.new_chat(contact, account)
gajim.interface.msg_win_mgr.get_window(jid, account).set_active_tab(
jid, account)
def on_single_message_menuitem_activate(self, widget, account):
dialogs.SingleMessageWindow(account, action = 'send')
def on_new_chat(self, widget, account):
dialogs.NewChatDialog(account)
def make_menu(self, event_button, event_time):
'''create chat with and new message (sub) menus/menuitems'''
for m in self.popup_menus:
m.destroy()
chat_with_menuitem = self.xml.get_widget('chat_with_menuitem')
single_message_menuitem = self.xml.get_widget(
'single_message_menuitem')
status_menuitem = self.xml.get_widget('status_menu')
join_gc_menuitem = self.xml.get_widget('join_gc_menuitem')
sounds_mute_menuitem = self.xml.get_widget('sounds_mute_menuitem')
if self.single_message_handler_id:
single_message_menuitem.handler_disconnect(
self.single_message_handler_id)
self.single_message_handler_id = None
if self.new_chat_handler_id:
chat_with_menuitem.disconnect(self.new_chat_handler_id)
self.new_chat_handler_id = None
sub_menu = gtk.Menu()
self.popup_menus.append(sub_menu)
status_menuitem.set_submenu(sub_menu)
gc_sub_menu = gtk.Menu() # gc is always a submenu
join_gc_menuitem.set_submenu(gc_sub_menu)
# We need our own set of status icons, let's make 'em!
iconset = gajim.config.get('iconset')
path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
state_images = gtkgui_helpers.load_iconset(path)
if 'muc_active' in state_images:
join_gc_menuitem.set_image(state_images['muc_active'])
for show in ('online', 'chat', 'away', 'xa', 'dnd', 'invisible'):
uf_show = helpers.get_uf_show(show, use_mnemonic = True)
item = gtk.ImageMenuItem(uf_show)
item.set_image(state_images[show])
sub_menu.append(item)
item.connect('activate', self.on_show_menuitem_activate, show)
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
item = gtk.ImageMenuItem(_('_Change Status Message...'))
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'kbd_input.png')
img = gtk.Image()
img.set_from_file(path)
item.set_image(img)
sub_menu.append(item)
item.connect('activate', self.on_change_status_message_activate)
connected_accounts = gajim.get_number_of_connected_accounts()
if connected_accounts < 1:
item.set_sensitive(False)
connected_accounts_with_private_storage = 0
item = gtk.SeparatorMenuItem()
sub_menu.append(item)
uf_show = helpers.get_uf_show('offline', use_mnemonic = True)
item = gtk.ImageMenuItem(uf_show)
item.set_image(state_images['offline'])
sub_menu.append(item)
item.connect('activate', self.on_show_menuitem_activate, 'offline')
iskey = connected_accounts > 0 and not (connected_accounts == 1 and
gajim.connections[gajim.connections.keys()[0]].is_zeroconf)
chat_with_menuitem.set_sensitive(iskey)
single_message_menuitem.set_sensitive(iskey)
join_gc_menuitem.set_sensitive(iskey)
accounts_list = sorted(gajim.contacts.get_accounts())
# items that get shown whether an account is zeroconf or not
if connected_accounts > 1: # 2 or more connections? make submenus
account_menu_for_chat_with = gtk.Menu()
chat_with_menuitem.set_submenu(account_menu_for_chat_with)
self.popup_menus.append(account_menu_for_chat_with)
for account in accounts_list:
if gajim.account_is_connected(account):
# for chat_with
item = gtk.MenuItem(_('using account %s') % account)
account_menu_for_chat_with.append(item)
item.connect('activate', self.on_new_chat, account)
elif connected_accounts == 1: # one account
# one account connected, no need to show 'as jid'
for account in gajim.connections:
if gajim.connections[account].connected > 1:
# for start chat
self.new_chat_handler_id = chat_with_menuitem.connect(
'activate', self.on_new_chat, account)
break # No other connected account
# menu items that don't apply to zeroconf connections
if connected_accounts == 1 or (connected_accounts == 2 and \
gajim.zeroconf_is_connected()):
# only one 'real' (non-zeroconf) account is connected, don't need
# submenus
for account in gajim.connections:
if gajim.account_is_connected(account) and \
not gajim.config.get_per('accounts', account, 'is_zeroconf'):
if gajim.connections[account].private_storage_supported:
connected_accounts_with_private_storage += 1
# for single message
single_message_menuitem.remove_submenu()
self.single_message_handler_id = single_message_menuitem.\
connect('activate',
self.on_single_message_menuitem_activate, account)
# join gc
gajim.interface.roster.add_bookmarks_list(gc_sub_menu,
account)
break # No other account connected
else:
# 2 or more 'real' accounts are connected, make submenus
account_menu_for_single_message = gtk.Menu()
single_message_menuitem.set_submenu(
account_menu_for_single_message)
self.popup_menus.append(account_menu_for_single_message)
for account in accounts_list:
if gajim.connections[account].is_zeroconf or \
not gajim.account_is_connected(account):
continue
if gajim.connections[account].private_storage_supported:
connected_accounts_with_private_storage += 1
# for single message
item = gtk.MenuItem(_('using account %s') % account)
item.connect('activate',
self.on_single_message_menuitem_activate, account)
account_menu_for_single_message.append(item)
# join gc
gc_item = gtk.MenuItem(_('using account %s') % account, False)
gc_sub_menu.append(gc_item)
gc_menuitem_menu = gtk.Menu()
gajim.interface.roster.add_bookmarks_list(gc_menuitem_menu,
account)
gc_item.set_submenu(gc_menuitem_menu)
gc_sub_menu.show_all()
newitem = gtk.SeparatorMenuItem() # separator
gc_sub_menu.append(newitem)
newitem = gtk.ImageMenuItem(_('_Manage Bookmarks...'))
img = gtk.image_new_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
newitem.set_image(img)
newitem.connect('activate',
gajim.interface.roster.on_manage_bookmarks_menuitem_activate)
gc_sub_menu.append(newitem)
if connected_accounts_with_private_storage == 0:
newitem.set_sensitive(False)
sounds_mute_menuitem.set_active(not gajim.config.get('sounds_on'))
if os.name == 'nt':
if self.added_hide_menuitem is False:
self.systray_context_menu.prepend(gtk.SeparatorMenuItem())
item = gtk.MenuItem(_('Hide this menu'))
self.systray_context_menu.prepend(item)
self.added_hide_menuitem = True
self.systray_context_menu.show_all()
self.systray_context_menu.popup(None, None, None, 0,
event_time)
def on_show_all_events_menuitem_activate(self, widget):
events = gajim.events.get_systray_events()
for account in events:
for jid in events[account]:
for event in events[account][jid]:
gajim.interface.handle_event(account, jid, event.type_)
def on_sounds_mute_menuitem_activate(self, widget):
gajim.config.set('sounds_on', not widget.get_active())
gajim.interface.save_config()
def on_show_roster_menuitem_activate(self, widget):
win = gajim.interface.roster.window
win.present()
def on_preferences_menuitem_activate(self, widget):
if 'preferences' in gajim.interface.instances:
gajim.interface.instances['preferences'].window.present()
else:
gajim.interface.instances['preferences'] = config.PreferencesWindow()
def on_quit_menuitem_activate(self, widget):
gajim.interface.roster.on_quit_request()
def on_left_click(self):
win = gajim.interface.roster.window
if len(gajim.events.get_systray_events()) == 0:
# No pending events, so toggle visible/hidden for roster window
if not win.iconify_initially and (win.get_property(
'has-toplevel-focus') or os.name == 'nt'):
# visible in ANY virtual desktop?
# we could be in another VD right now. eg vd2
# and we want to show it in vd2
if not gtkgui_helpers.possibly_move_window_in_current_desktop(win):
win.set_property('skip-taskbar-hint', False)
win.iconify() # else we hide it from VD that was visible in
win.set_property('skip-taskbar-hint', True)
else:
win.deiconify()
if not gajim.config.get('roster_window_skip_taskbar'):
win.set_property('skip-taskbar-hint', False)
win.present_with_time(gtk.get_current_event_time())
else:
self.handle_first_event()
def handle_first_event(self):
account, jid, event = gajim.events.get_first_systray_event()
if not event:
return
gajim.interface.handle_event(account, jid, event.type_)
def on_middle_click(self):
'''middle click raises window to have complete focus (fe. get kbd events)
but if already raised, it hides it'''
win = gajim.interface.roster.window
if win.is_active(): # is it fully raised? (eg does it receive kbd events?)
win.hide()
else:
win.present()
def on_clicked(self, widget, event):
self.on_tray_leave_notify_event(widget, None)
if event.type != gtk.gdk.BUTTON_PRESS:
return
if event.button == 1: # Left click
self.on_left_click()
elif event.button == 2: # middle click
self.on_middle_click()
elif event.button == 3: # right click
self.make_menu(event.button, event.time)
def on_show_menuitem_activate(self, widget, show):
# we all add some fake (we cannot select those nor have them as show)
# but this helps to align with roster's status_combobox index positions
l = ['online', 'chat', 'away', 'xa', 'dnd', 'invisible', 'SEPARATOR',
'CHANGE_STATUS_MSG_MENUITEM', 'SEPARATOR', 'offline']
index = l.index(show)
if not helpers.statuses_unified():
gajim.interface.roster.status_combobox.set_active(index + 2)
return
current = gajim.interface.roster.status_combobox.get_active()
if index != current:
gajim.interface.roster.status_combobox.set_active(index)
def on_change_status_message_activate(self, widget):
model = gajim.interface.roster.status_combobox.get_model()
active = gajim.interface.roster.status_combobox.get_active()
status = model[active][2].decode('utf-8')
def on_response(message, pep_dict):
if message is None: # None if user press Cancel
return
accounts = gajim.connections.keys()
for acct in accounts:
if not gajim.config.get_per('accounts', acct,
'sync_with_global_status'):
continue
show = gajim.SHOW_LIST[gajim.connections[acct].connected]
gajim.interface.roster.send_status(acct, show, message)
gajim.interface.roster.send_pep(acct, pep_dict)
dlg = dialogs.ChangeStatusMessageDialog(on_response, status)
dlg.dialog.present()
def show_tooltip(self, widget):
position = widget.window.get_origin()
if self.tooltip.id == position:
size = widget.window.get_size()
self.tooltip.show_tooltip('', size[1], position[1])
def on_tray_motion_notify_event(self, widget, event):
position = widget.window.get_origin()
if self.tooltip.timeout > 0:
if self.tooltip.id != position:
self.tooltip.hide_tooltip()
if self.tooltip.timeout == 0 and \
self.tooltip.id != position:
self.tooltip.id = position
self.tooltip.timeout = gobject.timeout_add(500,
self.show_tooltip, widget)
def on_tray_leave_notify_event(self, widget, event):
position = widget.window.get_origin()
if self.tooltip.timeout > 0 and \
self.tooltip.id == position:
self.tooltip.hide_tooltip()
def on_tray_destroyed(self, widget):
'''re-add trayicon when systray is destroyed'''
self.t = None
if gajim.interface.systray_enabled:
self.show_icon()
def show_icon(self):
if not self.t:
self.t = trayicon.TrayIcon('Gajim')
self.t.connect('destroy', self.on_tray_destroyed)
eb = gtk.EventBox()
# avoid draw seperate bg color in some gtk themes
eb.set_visible_window(False)
eb.set_events(gtk.gdk.POINTER_MOTION_MASK)
eb.connect('button-press-event', self.on_clicked)
eb.connect('motion-notify-event', self.on_tray_motion_notify_event)
eb.connect('leave-notify-event', self.on_tray_leave_notify_event)
self.tooltip = tooltips.NotificationAreaTooltip()
self.img_tray = gtk.Image()
eb.add(self.img_tray)
self.t.add(eb)
self.set_img()
self.subscribe_events()
self.t.show_all()
def hide_icon(self):
if self.t:
self.t.destroy()
self.t = None
self.unsubscribe_events()
# vim: se ts=3:

View file

@ -269,7 +269,7 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
for line in acct['event_lines']: for line in acct['event_lines']:
self.add_text_row(' ' + line, 1) self.add_text_row(' ' + line, 1)
def populate(self, data): def populate(self, data=''):
self.create_window() self.create_window()
self.create_table() self.create_table()
@ -280,7 +280,7 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
self.table.set_property('column-spacing', 1) self.table.set_property('column-spacing', 1)
self.hbox.add(self.table) self.hbox.add(self.table)
self.win.add(self.hbox) self.hbox.show_all()
class GCTooltip(BaseTooltip): class GCTooltip(BaseTooltip):
''' Tooltip that is shown in the GC treeview ''' ''' Tooltip that is shown in the GC treeview '''

View file

@ -1,59 +0,0 @@
;; -*- 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")
)
)

View file

@ -1,47 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4 -*-
* src/trayicon.override
*
* Copyright (C) 2004-2005 Yann Leboulanger <asterix AT lagaule.org>
*
* This file is part of Gajim.
*
* Gajim 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; version 3 only.
*
* Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
*/
%%
headers
#include <Python.h>
#include "pygobject.h"
#include "eggtrayicon.h"
%%
modulename trayicon
%%
import gtk.Plug as PyGtkPlug_Type
import gtk.gdk.Screen as PyGdkScreen_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);
}

View file

@ -1,43 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4 -*-
* src/trayiconmodule.c
*
* Copyright (C) 2004-2005 Yann Leboulanger <asterix AT lagaule.org>
*
* This file is part of Gajim.
*
* Gajim 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; version 3 only.
*
* Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
*/
/* 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 :(");
}
}