Gtk2-TrayManager-0.05/0000755000175200017520000000000010120147067014757 5ustar borupborup00000000000000Gtk2-TrayManager-0.05/eggmarshalers.list0000644000175200017520000000052310116415523020500 0ustar borupborup00000000000000VOID:OBJECT,OBJECT VOID:OBJECT,STRING,LONG,LONG VOID:OBJECT,LONG VOID:OBJECT,STRING,STRING VOID:UINT,UINT BOOLEAN:INT BOOLEAN:ENUM BOOLEAN:VOID OBJECT:VOID VOID:VOID VOID:INT,INT VOID:UINT,UINT VOID:BOOLEAN VOID:OBJECT,ENUM,BOXED VOID:BOXED BOOLEAN:BOOLEAN BOOLEAN:OBJECT,STRING,STRING BOOLEAN:ENUM,INT STRING:POINTER STRING:STRING,STRING Gtk2-TrayManager-0.05/egg-macros.h0000644000175200017520000000642310116431070017154 0ustar borupborup00000000000000/** * Useful macros. * * Author: * Darin Adler * * Copyright 2001 Ben Tea Spoons, Inc. */ #ifndef _EGG_MACROS_H_ #define _EGG_MACROS_H_ #include G_BEGIN_DECLS /* Macros for defining classes. Ideas taken from Nautilus and GOB. */ /* Define the boilerplate type stuff to reduce typos and code size. Defines * the get_type method and the parent_class static variable. */ #define EGG_BOILERPLATE(type, type_as_function, corba_type, \ parent_type, parent_type_macro, \ register_type_macro) \ static void type_as_function ## _class_init (type ## Class *klass); \ static void type_as_function ## _instance_init (type *object); \ static parent_type ## Class *parent_class = NULL; \ static void \ type_as_function ## _class_init_trampoline (gpointer klass, \ gpointer data) \ { \ parent_class = (parent_type ## Class *)g_type_class_ref ( \ parent_type_macro); \ type_as_function ## _class_init ((type ## Class *)klass); \ } \ GType \ type_as_function ## _get_type (void) \ { \ static GType object_type = 0; \ if (object_type == 0) { \ static const GTypeInfo object_info = { \ sizeof (type ## Class), \ NULL, /* base_init */ \ NULL, /* base_finalize */ \ type_as_function ## _class_init_trampoline, \ NULL, /* class_finalize */ \ NULL, /* class_data */ \ sizeof (type), \ 0, /* n_preallocs */ \ (GInstanceInitFunc) type_as_function ## _instance_init \ }; \ object_type = register_type_macro \ (type, type_as_function, corba_type, \ parent_type, parent_type_macro); \ } \ return object_type; \ } /* Just call the parent handler. This assumes that there is a variable * named parent_class that points to the (duh!) parent class. Note that * this macro is not to be used with things that return something, use * the _WITH_DEFAULT version for that */ #define EGG_CALL_PARENT(parent_class_cast, name, args) \ ((parent_class_cast(parent_class)->name != NULL) ? \ parent_class_cast(parent_class)->name args : (void)0) /* Same as above, but in case there is no implementation, it evaluates * to def_return */ #define EGG_CALL_PARENT_WITH_DEFAULT(parent_class_cast, \ name, args, def_return) \ ((parent_class_cast(parent_class)->name != NULL) ? \ parent_class_cast(parent_class)->name args : def_return) /* Call a virtual method */ #define EGG_CALL_VIRTUAL(object, get_class_cast, method, args) \ (get_class_cast (object)->method ? (* get_class_cast (object)->method) args : (void)0) /* Call a virtual method with default */ #define EGG_CALL_VIRTUAL_WITH_DEFAULT(object, get_class_cast, method, args, default) \ (get_class_cast (object)->method ? (* get_class_cast (object)->method) args : default) #define EGG_CLASS_BOILERPLATE(type, type_as_function, \ parent_type, parent_type_macro) \ EGG_BOILERPLATE(type, type_as_function, type, \ parent_type, parent_type_macro, \ EGG_REGISTER_TYPE) #define EGG_REGISTER_TYPE(type, type_as_function, corba_type, \ parent_type, parent_type_macro) \ g_type_register_static (parent_type_macro, #type, &object_info, 0) G_END_DECLS #endif /* _EGG_MACROS_H_ */ Gtk2-TrayManager-0.05/TrayManager.xs0000644000175200017520000000256110120065604017545 0ustar borupborup00000000000000#include "gtk2perl.h" #include "eggtraymanager.h" #include "traymanager-autogen.h" #define SvEggTrayManagerChild (EggTrayManagerChild*)SvGtkSocket #define newSVEggTrayManagerChild newSVGtkSocket MODULE = Gtk2::TrayManager PACKAGE = Gtk2::TrayManager PREFIX = egg_tray_manager_ ## gboolean egg_tray_manager_check_running (GdkScreen *screen) gboolean egg_tray_manager_check_running (class,screen) GdkScreen* screen C_ARGS: screen ## EggTrayManager *egg_tray_manager_new (void) EggTrayManager_noinc* egg_tray_manager_new (class) C_ARGS: ## gboolean egg_tray_manager_manage_screen (EggTrayManager *manager, GdkScreen *screen) gboolean egg_tray_manager_manage_screen (manager, screen) EggTrayManager *manager GdkScreen *screen ## char *egg_tray_manager_get_child_title (EggTrayManager *manager, EggTrayManagerChild *child) char * egg_tray_manager_get_child_title (manager, child) EggTrayManager* manager EggTrayManagerChild* child ## void egg_tray_manager_set_orientation (EggTrayManager *manager, GtkOrientation orientation) void egg_tray_manager_set_orientation (manager, orientation) EggTrayManager* manager GtkOrientation orientation ## GtkOrientation egg_tray_manager_get_orientation (EggTrayManager *manager) GtkOrientation egg_tray_manager_get_orientation (manager) EggTrayManager* manager BOOT: #include "register.xsh" #include "boot.xsh" Gtk2-TrayManager-0.05/maps0000644000175200017520000000022310103775361015644 0ustar borupborup00000000000000EGG_TYPE_TRAY_MANAGER EggTrayManager GObject Gtk2::TrayManager EGG_TYPE_TRAY_MANAGER_CHILD EggTrayManagerChild GObject Gtk2::TrayManager::Child Gtk2-TrayManager-0.05/MANIFEST0000644000175200017520000000036310120146674016115 0ustar borupborup00000000000000egg-macros.h egg-marshal.c eggintl.h eggmarshalers.list eggtraymanager.c eggtraymanager.h examples/trayclient.pl examples/trayserver.pl Makefile.PL MANIFEST This list of files maps META.yml README t/load.t TODO TrayManager.pm TrayManager.xs Gtk2-TrayManager-0.05/TODO0000644000175200017520000000003010120141366015434 0ustar borupborup00000000000000 - write better tests Gtk2-TrayManager-0.05/eggintl.h0000644000175200017520000000025610116431070016557 0ustar borupborup00000000000000#ifndef __EGG_INTL_H__ #define __EGG_INTL_H__ /* We don't support gettext yet, dunno if we should /Anders */ #define _(x) (x) #define N_(x) (x) #endif /* __EGG_INTL_H__ */ Gtk2-TrayManager-0.05/examples/0000755000175200017520000000000010120147067016575 5ustar borupborup00000000000000Gtk2-TrayManager-0.05/examples/trayclient.pl0000644000175200017520000000047410120137055021311 0ustar borupborup00000000000000#!/usr/bin/perl use Gtk2 -init; use Gtk2::TrayIcon; use strict; my $icon = Gtk2::TrayIcon->new('foo'); $icon->add(Gtk2::Image->new_from_stock('gtk-dialog-warning', 'menu')); $icon->show_all; Glib::Timeout->add(5000, sub { print "sending message\n"; $icon->send_message(5000, "hello, world!"); }); Gtk2->main; Gtk2-TrayManager-0.05/examples/trayserver.pl0000644000175200017520000000165110120137055021337 0ustar borupborup00000000000000#!/usr/bin/perl use Gtk2 -init; use Gtk2::TrayManager; use Data::Dumper; use strict; my $screen = Gtk2::Gdk::Screen->get_default; if (Gtk2::TrayManager->check_running($screen)) { print STDERR "A tray manager is already running, sorry!\n"; exit 256; } my $window = Gtk2::Window->new; $window->add(Gtk2::VBox->new); $window->set_resizable(0); my $tray = Gtk2::TrayManager->new; $tray->manage_screen($screen); $tray->set_orientation('vertical'); $tray->signal_connect('tray_icon_added', sub { $window->child->add($_[1]); $_[1]->show_all; }); $tray->signal_connect('tray_icon_removed', sub { $window->child->remove($_[1]); }); $tray->signal_connect('message_sent', sub { print "message_sent\n" . Dumper(\@_) }); $tray->signal_connect('message_cancelled', sub { print "message_cancelled\n" . Dumper(\@_) }); $tray->signal_connect('lost_selection', sub { print "lost_selection\n" . Dumper(\@_) }); $window->show_all; Gtk2->main; Gtk2-TrayManager-0.05/egg-marshal.c0000644000175200017520000000006610116431070017307 0ustar borupborup00000000000000#include "eggmarshalers.h" #include "eggmarshalers.c" Gtk2-TrayManager-0.05/META.yml0000644000175200017520000000053310120147067016231 0ustar borupborup00000000000000# http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: Gtk2-TrayManager version: 0.05 version_from: TrayManager.pm installdirs: site requires: Gtk2: 1.00 distribution_type: module generated_by: ExtUtils::MakeMaker version 6.17 Gtk2-TrayManager-0.05/eggtraymanager.h0000644000175200017520000000655010103775361020140 0ustar borupborup00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* eggtraymanager.h * Copyright (C) 2002 Anders Carlsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __EGG_TRAY_MANAGER_H__ #define __EGG_TRAY_MANAGER_H__ #include #include G_BEGIN_DECLS #define EGG_TYPE_TRAY_MANAGER (egg_tray_manager_get_type ()) #define EGG_TRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_MANAGER, EggTrayManager)) #define EGG_TRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_MANAGER, EggTrayManagerClass)) #define EGG_IS_TRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_MANAGER)) #define EGG_IS_TRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_MANAGER)) #define EGG_TRAY_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_MANAGER, EggTrayManagerClass)) typedef struct _EggTrayManager EggTrayManager; typedef struct _EggTrayManagerClass EggTrayManagerClass; typedef struct _EggTrayManagerChild EggTrayManagerChild; struct _EggTrayManager { GObject parent_instance; Atom opcode_atom; Atom selection_atom; Atom message_data_atom; Atom orientation_atom; GtkWidget *invisible; GdkScreen *screen; GtkOrientation orientation; GList *messages; GHashTable *socket_table; }; struct _EggTrayManagerClass { GObjectClass parent_class; void (* tray_icon_added) (EggTrayManager *manager, EggTrayManagerChild *child); void (* tray_icon_removed) (EggTrayManager *manager, EggTrayManagerChild *child); void (* message_sent) (EggTrayManager *manager, EggTrayManagerChild *child, const gchar *message, glong id, glong timeout); void (* message_cancelled) (EggTrayManager *manager, EggTrayManagerChild *child, glong id); void (* lost_selection) (EggTrayManager *manager); }; GType egg_tray_manager_get_type (void); gboolean egg_tray_manager_check_running (GdkScreen *screen); EggTrayManager *egg_tray_manager_new (void); gboolean egg_tray_manager_manage_screen (EggTrayManager *manager, GdkScreen *screen); char *egg_tray_manager_get_child_title (EggTrayManager *manager, EggTrayManagerChild *child); void egg_tray_manager_set_orientation (EggTrayManager *manager, GtkOrientation orientation); GtkOrientation egg_tray_manager_get_orientation (EggTrayManager *manager); G_END_DECLS #endif /* __EGG_TRAY_MANAGER_H__ */ Gtk2-TrayManager-0.05/t/0000755000175200017520000000000010120147067015222 5ustar borupborup00000000000000Gtk2-TrayManager-0.05/t/load.t0000644000175200017520000000040010117664617016333 0ustar borupborup00000000000000 use Gtk2::TestHelper tests => 3; BEGIN { use_ok( "Gtk2::TrayManager" ); } Gtk2->init; my $traymanager= Gtk2::TrayManager->new; isa_ok( $traymanager, "Glib::Object", '$traymanager' ); isa_ok( $traymanager, "Gtk2::TrayManager", '$traymanager' ); exit; Gtk2-TrayManager-0.05/TrayManager.pm0000644000175200017520000000756510120143566017544 0ustar borupborup00000000000000package Gtk2::TrayManager; use 5.008; use strict; use warnings; use Gtk2; require DynaLoader; our @ISA = qw(DynaLoader); our $VERSION = '0.05'; sub dl_load_flags { 0x01 } bootstrap Gtk2::TrayManager $VERSION; 1; __END__ =pod =for comment written by Gavin Brown =head1 NAME Gtk2::TrayManager - Perl bindings for EggTrayManager =head1 SYNOPSIS use Gtk2 -init; use Gtk2::TrayManager; my $screen = Gtk2::Gdk::Screen->get_default; if (Gtk2::TrayManager->check_running($screen)) { print STDERR "A tray manager is already running, sorry!\n"; exit 256; } my $tray = Gtk2::TrayManager->new; $tray->manage_screen($screen); $tray->set_orientation('vertical'); $tray->signal_connect('tray_icon_added', sub { # $_[1] is a Gtk2::Socket }); $tray->signal_connect('tray_icon_removed', sub { # $_[1] is a Gtk2::Socket }); =head1 ABSTRACT The EggTrayManager library is used internally by GNOME to implement the server-side of the Notification Area (or system tray) protocol. Gtk2::TrayManager allows you to create notification area applications using Gtk2-Perl. =head1 METHODS $running = Gtk2::TrayManager->check_running($screen); This method returns a boolean value indicating whether another program is already managing notifications for the given L. If this method returns a false value, then you should give way to the application that is already running. $tray = Gtk2::TrayManager->new; This creates a tray manager object. $tray->manage_screen($screen); This tells the tray to manage notifications for the L referenced by C<$screen>. $tray->set_orientation($orientation); This method tells the tray whether icons are to be arranged vertically or horizontally. C<$orientation> may be either 'C' or 'C'. $title = $tray->get_child_title($child); This method returns a string containing the title of the icon defined by C<$child>. =head1 SIGNALS =over =item C Emitted when a client plug (eg one created by L) wants to connect. For callbacks connected to this signal, C<@_> will have the form @_ = ( bless( {}, 'Gtk2::TrayManager' ), bless( {}, 'Gtk2::Socket' ) ); =item C Emitted when a client plug has disconnected. For callbacks connected to this signal, C<@_> will have the form @_ = ( bless( {}, 'Gtk2::TrayManager' ), bless( {}, 'Gtk2::Socket' ) ); =item C, C The Freedesktop.org specification includes support for "balloon messages", but these are not currently implemented in EggTrayManager. =item C As a rule, compliant applications should check to for an already running manager, and give way to it if it finds one. However, it is possible that your application might have its X selection forcibly removed; this signal is emitted if this should happen. =back =head1 SEE ALSO L, L, L and the System Tray spec at L. =head1 AUTHOR Christian Borup . Nagging and documentation by Gavin Brown =head1 COPYRIGHT AND LICENSE Copyright 2004 by the gtk2-perl team. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library 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 Library General Public License for more details. You should have received a copy of the GNU Library 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. =cut Gtk2-TrayManager-0.05/eggtraymanager.c0000644000175200017520000004477510103775361020146 0ustar borupborup00000000000000/* eggtraymanager.c * Copyright (C) 2002 Anders Carlsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include "eggtraymanager.h" #include #include #include #include #include #include "eggmarshalers.h" #ifndef EGG_COMPILATION #ifndef _ #define _(x) dgettext (GETTEXT_PACKAGE, x) #define N_(x) x #endif #else #define _(x) x #define N_(x) x #endif /* Signals */ enum { TRAY_ICON_ADDED, TRAY_ICON_REMOVED, MESSAGE_SENT, MESSAGE_CANCELLED, LOST_SELECTION, LAST_SIGNAL }; enum { PROP_0, PROP_ORIENTATION }; typedef struct { long id, len; long remaining_len; long timeout; Window window; char *str; } PendingMessage; static GObjectClass *parent_class = NULL; static guint manager_signals[LAST_SIGNAL] = { 0 }; #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 static gboolean egg_tray_manager_check_running_xscreen (Screen *xscreen); static void egg_tray_manager_init (EggTrayManager *manager); static void egg_tray_manager_class_init (EggTrayManagerClass *klass); static void egg_tray_manager_finalize (GObject *object); static void egg_tray_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void egg_tray_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void egg_tray_manager_unmanage (EggTrayManager *manager); GType egg_tray_manager_get_type (void) { static GType our_type = 0; if (our_type == 0) { static const GTypeInfo our_info = { sizeof (EggTrayManagerClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) egg_tray_manager_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (EggTrayManager), 0, /* n_preallocs */ (GInstanceInitFunc) egg_tray_manager_init }; our_type = g_type_register_static (G_TYPE_OBJECT, "EggTrayManager", &our_info, 0); } return our_type; } static void egg_tray_manager_init (EggTrayManager *manager) { manager->socket_table = g_hash_table_new (NULL, NULL); } static void egg_tray_manager_class_init (EggTrayManagerClass *klass) { GObjectClass *gobject_class; parent_class = g_type_class_peek_parent (klass); gobject_class = (GObjectClass *)klass; gobject_class->finalize = egg_tray_manager_finalize; gobject_class->set_property = egg_tray_manager_set_property; gobject_class->get_property = egg_tray_manager_get_property; 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_READWRITE | G_PARAM_CONSTRUCT)); manager_signals[TRAY_ICON_ADDED] = g_signal_new ("tray_icon_added", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTrayManagerClass, tray_icon_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_SOCKET); manager_signals[TRAY_ICON_REMOVED] = g_signal_new ("tray_icon_removed", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTrayManagerClass, tray_icon_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_SOCKET); manager_signals[MESSAGE_SENT] = g_signal_new ("message_sent", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTrayManagerClass, message_sent), NULL, NULL, _egg_marshal_VOID__OBJECT_STRING_LONG_LONG, G_TYPE_NONE, 4, GTK_TYPE_SOCKET, G_TYPE_STRING, G_TYPE_LONG, G_TYPE_LONG); manager_signals[MESSAGE_CANCELLED] = g_signal_new ("message_cancelled", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTrayManagerClass, message_cancelled), NULL, NULL, _egg_marshal_VOID__OBJECT_LONG, G_TYPE_NONE, 2, GTK_TYPE_SOCKET, G_TYPE_LONG); manager_signals[LOST_SELECTION] = g_signal_new ("lost_selection", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTrayManagerClass, lost_selection), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void egg_tray_manager_finalize (GObject *object) { EggTrayManager *manager; manager = EGG_TRAY_MANAGER (object); egg_tray_manager_unmanage (manager); G_OBJECT_CLASS (parent_class)->finalize (object); } static void egg_tray_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EggTrayManager *manager = EGG_TRAY_MANAGER (object); switch (prop_id) { case PROP_ORIENTATION: egg_tray_manager_set_orientation (manager, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void egg_tray_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EggTrayManager *manager = EGG_TRAY_MANAGER (object); switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum (value, manager->orientation); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } EggTrayManager * egg_tray_manager_new (void) { EggTrayManager *manager; manager = g_object_new (EGG_TYPE_TRAY_MANAGER, NULL); return manager; } static gboolean egg_tray_manager_plug_removed (GtkSocket *socket, EggTrayManager *manager) { Window *window; window = g_object_get_data (G_OBJECT (socket), "egg-tray-child-window"); g_hash_table_remove (manager->socket_table, GINT_TO_POINTER (*window)); g_object_set_data (G_OBJECT (socket), "egg-tray-child-window", NULL); g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, socket); /* This destroys the socket. */ return FALSE; } static void egg_tray_manager_handle_dock_request (EggTrayManager *manager, XClientMessageEvent *xevent) { GtkWidget *socket; Window *window; socket = gtk_socket_new (); /* We need to set the child window here * so that the client can call _get functions * in the signal handler */ window = g_new (Window, 1); *window = xevent->data.l[2]; g_object_set_data_full (G_OBJECT (socket), "egg-tray-child-window", window, g_free); g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0, socket); /* Add the socket only if it's been attached */ if (GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket)))) { g_signal_connect (socket, "plug_removed", G_CALLBACK (egg_tray_manager_plug_removed), manager); gtk_socket_add_id (GTK_SOCKET (socket), xevent->data.l[2]); g_hash_table_insert (manager->socket_table, GINT_TO_POINTER (xevent->data.l[2]), socket); } else gtk_widget_destroy (socket); } static void pending_message_free (PendingMessage *message) { g_free (message->str); g_free (message); } static void egg_tray_manager_handle_message_data (EggTrayManager *manager, XClientMessageEvent *xevent) { GList *p; int len; /* Try to see if we can find the * pending message in the list */ for (p = manager->messages; p; p = p->next) { PendingMessage *msg = p->data; if (xevent->window == msg->window) { /* Append the message */ len = MIN (msg->remaining_len, 20); memcpy ((msg->str + msg->len - msg->remaining_len), &xevent->data, len); msg->remaining_len -= len; if (msg->remaining_len == 0) { GtkSocket *socket; socket = g_hash_table_lookup (manager->socket_table, GINT_TO_POINTER (msg->window)); if (socket) { g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0, socket, msg->str, msg->id, msg->timeout); } manager->messages = g_list_remove_link (manager->messages, p); pending_message_free (msg); } return; } } } static void egg_tray_manager_handle_begin_message (EggTrayManager *manager, XClientMessageEvent *xevent) { GList *p; PendingMessage *msg; /* Check if the same message is * already in the queue and remove it if so */ for (p = manager->messages; p; p = p->next) { PendingMessage *msg = p->data; if (xevent->window == msg->window && xevent->data.l[4] == msg->id) { /* Hmm, we found it, now remove it */ pending_message_free (msg); manager->messages = g_list_remove_link (manager->messages, p); break; } } /* Now add the new message to the queue */ msg = g_new0 (PendingMessage, 1); msg->window = xevent->window; msg->timeout = xevent->data.l[2]; msg->len = xevent->data.l[3]; msg->id = xevent->data.l[4]; msg->remaining_len = msg->len; msg->str = g_malloc (msg->len + 1); msg->str[msg->len] = '\0'; manager->messages = g_list_prepend (manager->messages, msg); } static void egg_tray_manager_handle_cancel_message (EggTrayManager *manager, XClientMessageEvent *xevent) { GtkSocket *socket; socket = g_hash_table_lookup (manager->socket_table, GINT_TO_POINTER (xevent->window)); if (socket) { g_signal_emit (manager, manager_signals[MESSAGE_CANCELLED], 0, socket, xevent->data.l[2]); } } static GdkFilterReturn egg_tray_manager_handle_event (EggTrayManager *manager, XClientMessageEvent *xevent) { switch (xevent->data.l[1]) { case SYSTEM_TRAY_REQUEST_DOCK: egg_tray_manager_handle_dock_request (manager, xevent); return GDK_FILTER_REMOVE; case SYSTEM_TRAY_BEGIN_MESSAGE: egg_tray_manager_handle_begin_message (manager, xevent); return GDK_FILTER_REMOVE; case SYSTEM_TRAY_CANCEL_MESSAGE: egg_tray_manager_handle_cancel_message (manager, xevent); return GDK_FILTER_REMOVE; default: break; } return GDK_FILTER_CONTINUE; } static GdkFilterReturn egg_tray_manager_window_filter (GdkXEvent *xev, GdkEvent *event, gpointer data) { XEvent *xevent = (GdkXEvent *)xev; EggTrayManager *manager = data; if (xevent->type == ClientMessage) { if (xevent->xclient.message_type == manager->opcode_atom) { return egg_tray_manager_handle_event (manager, (XClientMessageEvent *)xevent); } else if (xevent->xclient.message_type == manager->message_data_atom) { egg_tray_manager_handle_message_data (manager, (XClientMessageEvent *)xevent); return GDK_FILTER_REMOVE; } } else if (xevent->type == SelectionClear) { g_signal_emit (manager, manager_signals[LOST_SELECTION], 0); egg_tray_manager_unmanage (manager); } return GDK_FILTER_CONTINUE; } static void egg_tray_manager_unmanage (EggTrayManager *manager) { Display *display; guint32 timestamp; GtkWidget *invisible; if (manager->invisible == NULL) return; invisible = manager->invisible; g_assert (GTK_IS_INVISIBLE (invisible)); g_assert (GTK_WIDGET_REALIZED (invisible)); g_assert (GDK_IS_WINDOW (invisible->window)); display = GDK_WINDOW_XDISPLAY (invisible->window); if (XGetSelectionOwner (display, manager->selection_atom) == GDK_WINDOW_XWINDOW (invisible->window)) { timestamp = gdk_x11_get_server_time (invisible->window); XSetSelectionOwner (display, manager->selection_atom, None, timestamp); } gdk_window_remove_filter (invisible->window, egg_tray_manager_window_filter, manager); manager->invisible = NULL; /* prior to destroy for reentrancy paranoia */ gtk_widget_destroy (invisible); g_object_unref (G_OBJECT (invisible)); } static void egg_tray_manager_set_orientation_property (EggTrayManager *manager) { gulong data[1]; if (!manager->invisible || !manager->invisible->window) return; g_assert (manager->orientation_atom != None); data[0] = manager->orientation == GTK_ORIENTATION_HORIZONTAL ? SYSTEM_TRAY_ORIENTATION_HORZ : SYSTEM_TRAY_ORIENTATION_VERT; XChangeProperty (GDK_WINDOW_XDISPLAY (manager->invisible->window), GDK_WINDOW_XWINDOW (manager->invisible->window), manager->orientation_atom, XA_CARDINAL, 32, PropModeReplace, (guchar *) &data, 1); } static gboolean egg_tray_manager_manage_xscreen (EggTrayManager *manager, Screen *xscreen) { GtkWidget *invisible; char *selection_atom_name; guint32 timestamp; GdkScreen *screen; g_return_val_if_fail (EGG_IS_TRAY_MANAGER (manager), FALSE); g_return_val_if_fail (manager->screen == NULL, FALSE); /* If there's already a manager running on the screen * we can't create another one. */ #if 0 if (egg_tray_manager_check_running_xscreen (xscreen)) return FALSE; #endif screen = gdk_display_get_screen (gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen)), XScreenNumberOfScreen (xscreen)); invisible = gtk_invisible_new_for_screen (screen); gtk_widget_realize (invisible); gtk_widget_add_events (invisible, GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK); selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen (xscreen)); manager->selection_atom = XInternAtom (DisplayOfScreen (xscreen), selection_atom_name, False); g_free (selection_atom_name); manager->orientation_atom = XInternAtom (DisplayOfScreen (xscreen), "_NET_SYSTEM_TRAY_ORIENTATION", FALSE); egg_tray_manager_set_orientation_property (manager); timestamp = gdk_x11_get_server_time (invisible->window); XSetSelectionOwner (DisplayOfScreen (xscreen), manager->selection_atom, GDK_WINDOW_XWINDOW (invisible->window), timestamp); /* Check if we were could set the selection owner successfully */ if (XGetSelectionOwner (DisplayOfScreen (xscreen), manager->selection_atom) == GDK_WINDOW_XWINDOW (invisible->window)) { XClientMessageEvent xev; xev.type = ClientMessage; xev.window = RootWindowOfScreen (xscreen); xev.message_type = XInternAtom (DisplayOfScreen (xscreen), "MANAGER", False); xev.format = 32; xev.data.l[0] = timestamp; xev.data.l[1] = manager->selection_atom; xev.data.l[2] = GDK_WINDOW_XWINDOW (invisible->window); xev.data.l[3] = 0; /* manager specific data */ xev.data.l[4] = 0; /* manager specific data */ XSendEvent (DisplayOfScreen (xscreen), RootWindowOfScreen (xscreen), False, StructureNotifyMask, (XEvent *)&xev); manager->invisible = invisible; g_object_ref (G_OBJECT (manager->invisible)); manager->opcode_atom = XInternAtom (DisplayOfScreen (xscreen), "_NET_SYSTEM_TRAY_OPCODE", False); manager->message_data_atom = XInternAtom (DisplayOfScreen (xscreen), "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); /* Add a window filter */ gdk_window_add_filter (invisible->window, egg_tray_manager_window_filter, manager); return TRUE; } else { gtk_widget_destroy (invisible); return FALSE; } } gboolean egg_tray_manager_manage_screen (EggTrayManager *manager, GdkScreen *screen) { g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); g_return_val_if_fail (manager->screen == NULL, FALSE); return egg_tray_manager_manage_xscreen (manager, GDK_SCREEN_XSCREEN (screen)); } static gboolean egg_tray_manager_check_running_xscreen (Screen *xscreen) { Atom selection_atom; char *selection_atom_name; selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", XScreenNumberOfScreen (xscreen)); selection_atom = XInternAtom (DisplayOfScreen (xscreen), selection_atom_name, False); g_free (selection_atom_name); if (XGetSelectionOwner (DisplayOfScreen (xscreen), selection_atom)) return TRUE; else return FALSE; } gboolean egg_tray_manager_check_running (GdkScreen *screen) { g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); return egg_tray_manager_check_running_xscreen (GDK_SCREEN_XSCREEN (screen)); } char * egg_tray_manager_get_child_title (EggTrayManager *manager, EggTrayManagerChild *child) { Window *child_window; Atom utf8_string, atom, type; int result; char *retval; int format; gulong nitems; gulong bytes_after; guchar *val; g_return_val_if_fail (EGG_IS_TRAY_MANAGER (manager), NULL); g_return_val_if_fail (GTK_IS_SOCKET (child), NULL); child_window = g_object_get_data (G_OBJECT (child), "egg-tray-child-window"); utf8_string = XInternAtom (GDK_DISPLAY (), "UTF8_STRING", False); atom = XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False); gdk_error_trap_push (); result = XGetWindowProperty (GDK_DISPLAY (), *child_window, atom, 0, G_MAXLONG, False, utf8_string, &type, &format, &nitems, &bytes_after, (guchar **)&val); if (gdk_error_trap_pop () || result != Success) return NULL; if (type != utf8_string || format != 8 || nitems == 0) { if (val) XFree (val); return NULL; } if (!g_utf8_validate (val, nitems, NULL)) { XFree (val); return NULL; } retval = g_strndup (val, nitems); XFree (val); return retval; } void egg_tray_manager_set_orientation (EggTrayManager *manager, GtkOrientation orientation) { g_return_if_fail (EGG_IS_TRAY_MANAGER (manager)); if (manager->orientation != orientation) { manager->orientation = orientation; egg_tray_manager_set_orientation_property (manager); g_object_notify (G_OBJECT (manager), "orientation"); } } GtkOrientation egg_tray_manager_get_orientation (EggTrayManager *manager) { g_return_val_if_fail (EGG_IS_TRAY_MANAGER (manager), GTK_ORIENTATION_HORIZONTAL); return manager->orientation; } Gtk2-TrayManager-0.05/Makefile.PL0000644000175200017520000000627710120141221016727 0ustar borupborup00000000000000 use 5.008; use ExtUtils::MakeMaker; use Cwd; use File::Spec; use ExtUtils::Depends; use ExtUtils::PkgConfig; use Gtk2::CodeGen; # minimum required version of dependancies we need to build our %build_reqs = ( 'perl-ExtUtils-Depends' => '0.1', 'perl-ExtUtils-PkgConfig' => '0.1', 'perl-Glib' => '1.00', 'perl-Gtk2' => '1.00', ); # Writing a fake Makefile ensures that CPAN will pick up the correct # dependencies and install them. unless (eval "use ExtUtils::Depends;" . "use ExtUtils::PkgConfig;" . "use Glib::MakeHelper;" . "use Gtk2::CodeGen;" # just seeing if Glib is available isn't enough, make sure # it's recent enough, too . "use Glib '$build_reqs{'perl-Glib'}';" . "use Gtk2 '$build_reqs{'perl-Gtk2'}';" . "1") { warn "$@\n"; WriteMakefile( PREREQ_FATAL => 1, PREREQ_PM => { Glib:: => $build_reqs{'perl-Glib'}, Gtk2:: => $build_reqs{'perl-Gtk2'}, ExtUtils::Depends:: => $build_reqs{'perl-ExtUtils-Depends'}, ExtUtils::PkgConfig:: => $build_reqs{'perl-ExtUtils-PkgConfig'}, }, ); exit 1; # not reached } mkdir 'build', 0777; my %pkgcfg = ExtUtils::PkgConfig->find ('gtk+-2.0'); Gtk2::CodeGen->parse_maps ('traymanager'); Gtk2::CodeGen->write_boot; my $genmarshal= `which glib-genmarshal`; unless($genmarshal) { print STDERR "glib-genmarshal needs to be installed\n"; exit 1; } chomp $genmarshal; print STDERR "writing build/eggmarshalers.h\n"; system("$genmarshal --prefix=_egg_marshal eggmarshalers.list --header > build/eggmarshalers.h"); print STDERR "writing build/eggmarshalers.c\n"; system("$genmarshal --prefix=_egg_marshal eggmarshalers.list --body > build/eggmarshalers.c"); $traymanager = ExtUtils::Depends->new ('Gtk2::TrayManager', 'Gtk2', 'Glib'); $traymanager->set_inc ($pkgcfg{cflags} . " -DEGG_COMPILATION"); $traymanager->set_libs ($pkgcfg{libs}); $traymanager->add_c(qw(egg-marshal.c eggtraymanager.c)); $traymanager->add_xs ("TrayManager.xs"); $traymanager->add_pm ('TrayManager.pm' => '$(INST_LIBDIR)/TrayManager.pm'); my $cwd = cwd(); $traymanager->add_typemaps (map {File::Spec->catfile($cwd,$_)} 'build/traymanager.typemap'); # $traymanager->install (qw(traymanager.h build/traymanager-autogen.h)); $traymanager->install (qw(build/traymanager-autogen.h)); $traymanager->save_config ('build/IFiles.pm'); WriteMakefile( NAME => 'Gtk2::TrayManager', VERSION_FROM => 'TrayManager.pm', # finds $VERSION # ABSTRACT_FROM => 'TrayManager.pm', # retrieve abstract from module XSPROTOARG => '-noprototypes', $traymanager->get_makefile_vars, PREREQ_PM => { Gtk2 => $build_reqs{'perl-Gtk2'}, }, ); package MY; use Cwd; sub postamble { return Glib::MakeHelper->postamble_clean () . Glib::MakeHelper->postamble_docs (@main::xs_files) . Glib::MakeHelper->postamble_rpms ( 'PERL_EXTUTILS_DEPENDS' => $build_reqs{'perl-ExtUtils-Depends'}, 'PERL_EXTUTILS_PKGCONFIG' => $build_reqs{'perl-ExtUtils-PkgConfig'}, 'PERL_GLIB' => $build_reqs{'perl-Glib'}, 'PERL_GTK' => $build_reqs{'perl-Gtk2'}, ); } package MAIN; Gtk2-TrayManager-0.05/README0000644000175200017520000000051210120141716015630 0ustar borupborup00000000000000 The EggTrayManager library is used internally by GNOME to implement the server-side of the Notification Area (or system tray) protocol. Gtk2::TrayManager allows you to create notification area applications using Gtk2-Perl. The module requires Gtk2 to be installed. But includes the code for eggtraymanager in the distribution.