Browse Source

Half-baked cleanup of the systray plugin.

Renamed from files and going to remove the tray widget layer.
Also added support for transparent tray icons, but this
is not fully working yet.
upstream/xfce4-panel-4.10.1
Nick Schermer 13 years ago
parent
commit
d148383963
  1. 43
      plugins/systray/Makefile.am
  2. 21
      plugins/systray/systray-dialog.glade
  3. 932
      plugins/systray/systray-manager.c
  4. 72
      plugins/systray/systray-manager.h
  5. 0
      plugins/systray/systray-marshal.list
  6. 582
      plugins/systray/systray.c
  7. 44
      plugins/systray/systray.h
  8. 491
      plugins/systray/xfce-tray-dialogs.c
  9. 25
      plugins/systray/xfce-tray-dialogs.h
  10. 889
      plugins/systray/xfce-tray-manager.c
  11. 76
      plugins/systray/xfce-tray-manager.h
  12. 497
      plugins/systray/xfce-tray-plugin.c
  13. 42
      plugins/systray/xfce-tray-plugin.h
  14. 847
      plugins/systray/xfce-tray-widget.c
  15. 69
      plugins/systray/xfce-tray-widget.h

43
plugins/systray/Makefile.am

@ -11,25 +11,24 @@ plugindir = \
plugin_LTLIBRARIES = \
libsystray.la
libsystray_built_sources = \
xfce-tray-marshal.c \
xfce-tray-marshal.h
systray-dialog_glade.h \
systray-marshal.c \
systray-marshal.h
libsystray_la_SOURCES = \
$(libsystray_built_sources) \
xfce-tray-dialogs.c \
xfce-tray-dialogs.h \
xfce-tray-manager.c \
xfce-tray-manager.h \
xfce-tray-plugin.c \
xfce-tray-plugin.h \
xfce-tray-widget.c \
xfce-tray-widget.h
systray.c \
systray.h \
systray-manager.c \
systray-manager.h
libsystray_la_CFLAGS = \
$(LIBX11_CFLAGS) \
$(GTK_CFLAGS) \
$(EXO_CFLAGS) \
$(XFCONF_CFLAGS) \
$(LIBXFCE4UTIL_CFLAGS) \
$(LIBXFCE4UI_CFLAGS) \
$(PLATFORM_CFLAGS)
@ -44,6 +43,8 @@ libsystray_la_LIBADD = \
$(top_builddir)/libxfce4panel/libxfce4panel.la \
$(LIBX11_LIBS) \
$(GTK_LIBS) \
$(EXO_LIBS) \
$(XFCONF_LIBS) \
$(LIBXFCE4UTIL_LIBS) \
$(LIBXFCE4UI_LIBS)
@ -63,12 +64,13 @@ desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
EXTRA_DIST = \
$(desktop_in_in_files) \
xfce-tray-marshal.list
systray-dialog.glade \
systray-marshal.list
DISTCLEANFILES = \
$(desktop_DATA) \
$(desktop_in_files)
#
# Rules to auto-generate built sources
#
@ -79,12 +81,15 @@ BUILT_SOURCES = \
DISTCLEANFILES += \
$(libsystray_built_sources)
xfce-tray-marshal.h: xfce-tray-marshal.list Makefile
glib-genmarshal --header --internal --prefix=_xfce_tray_marshal $< > $@
systray-marshal.h: systray-marshal.list Makefile
glib-genmarshal --header --internal --prefix=_systray_marshal $< > $@
systray-marshal.c: systray-marshal.list Makefile
echo "#include \"systray-marshal.h\"" > $@ \
&& glib-genmarshal --prefix=_systray_marshal --body $< >> $@
xfce-tray-marshal.c: xfce-tray-marshal.list Makefile
echo "#include \"xfce-tray-marshal.h\"" > $@ \
&& glib-genmarshal --prefix=_xfce_tray_marshal --body $< >> $@
systray-dialog_glade.h: systray-dialog.glade
exo-csource --static --strip-comments --strip-content --name=systray_dialog_glade $< >$@
endif
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:

21
plugins/systray/systray-dialog.glade

@ -42,7 +42,7 @@
<property name="xalign">0</property>
<property name="label" translatable="yes">_Number of rows:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">style-num-rows</property>
<property name="mnemonic_widget">rows</property>
</object>
<packing>
<property name="expand">False</property>
@ -50,9 +50,11 @@
</packing>
</child>
<child>
<object class="GtkSpinButton" id="style-num-rows">
<object class="GtkSpinButton" id="rows">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">none</property>
<property name="adjustment">rows-adjustment</property>
<property name="numeric">True</property>
</object>
<packing>
@ -66,7 +68,7 @@
</packing>
</child>
<child>
<object class="GtkCheckButton" id="style-show-frame">
<object class="GtkCheckButton" id="show-frame">
<property name="label" translatable="yes">Show _frame</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@ -103,12 +105,12 @@
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="top_padding">6</property>
<property name="left_padding">12</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">6</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
@ -116,6 +118,8 @@
<object class="GtkTreeView" id="applications-treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_clickable">False</property>
<property name="rules_hint">True</property>
</object>
</child>
</object>
@ -152,6 +156,8 @@
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
@ -168,4 +174,11 @@
<action-widget response="0">close-button</action-widget>
</action-widgets>
</object>
<object class="GtkAdjustment" id="rows-adjustment">
<property name="value">1</property>
<property name="lower">1</property>
<property name="upper">10</property>
<property name="step_increment">1</property>
<property name="page_increment">2</property>
</object>
</interface>

932
plugins/systray/systray-manager.c

@ -0,0 +1,932 @@
/* $Id$ */
/*
* Copyright (c) 2002 Anders Carlsson <andersca@gnu.org>
* Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org>
* Copyright (c) 2003-2004 Olivier Fourdan <fourdan@xfce.org>
* Copyright (c) 2003-2006 Vincent Untz
* Copyright (c) 2007-2009 Nick Schermer <nick@xfce.org>
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <libxfce4panel/libxfce4panel.h>
#include <libxfce4util/libxfce4util.h>
#include "systray-manager.h"
#include "systray-marshal.h"
#define XFCE_SYSTRAY_MANAGER_REQUEST_DOCK 0
#define XFCE_SYSTRAY_MANAGER_BEGIN_MESSAGE 1
#define XFCE_SYSTRAY_MANAGER_CANCEL_MESSAGE 2
#define XFCE_SYSTRAY_MANAGER_ORIENTATION_HORIZONTAL 0
#define XFCE_SYSTRAY_MANAGER_ORIENTATION_VERTICAL 1
static void systray_manager_finalize (GObject *object);
static void systray_manager_remove_socket (gpointer key,
gpointer value,
gpointer user_data);
static GdkFilterReturn systray_manager_window_filter (GdkXEvent *xev,
GdkEvent *event,
gpointer user_data);
static GdkFilterReturn systray_manager_handle_client_message_opcode (GdkXEvent *xevent,
GdkEvent *event,
gpointer user_data);
static GdkFilterReturn systray_manager_handle_client_message_message_data (GdkXEvent *xevent,
GdkEvent *event,
gpointer user_data);
static void systray_manager_handle_begin_message (SystrayManager *manager,
XClientMessageEvent *xevent);
static void systray_manager_handle_cancel_message (SystrayManager *manager,
XClientMessageEvent *xevent);
static void systray_manager_handle_dock_request (SystrayManager *manager,
XClientMessageEvent *xevent);
static gboolean systray_manager_handle_undock_request (GtkSocket *socket,
gpointer user_data);
static void systray_manager_set_visual (SystrayManager *manager);
static void systray_manager_message_free (SystrayMessage *message);
static void systray_manager_message_remove_from_list (SystrayManager *manager,
XClientMessageEvent *xevent);
enum
{
ICON_ADDED,
ICON_REMOVED,
MESSAGE_SENT,
MESSAGE_CANCELLED,
LOST_SELECTION,
LAST_SIGNAL
};
struct _SystrayManagerClass
{
GObjectClass __parent__;
};
struct _SystrayManager
{
GObject __parent__;
/* invisible window */
GtkWidget *invisible;
/* list of client sockets */
GHashTable *sockets;
/* orientation of the tray */
GtkOrientation orientation;
/* list of pending messages */
GSList *messages;
/* _net_system_tray_opcode atom */
Atom opcode_atom;
/* _net_system_tray_s%d atom */
GdkAtom selection_atom;
};
struct _SystrayMessage
{
/* message string */
gchar *string;
/* message id */
glong id;
/* x11 window */
Window window;
/* numb3rs */
glong length;
glong remaining_length;
glong timeout;
};
static guint systray_manager_signals[LAST_SIGNAL];
static GQuark xwindow_quark = 0;
XFCE_PANEL_DEFINE_TYPE (SystrayManager, systray_manager, G_TYPE_OBJECT)
static void
systray_manager_class_init (SystrayManagerClass *klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = systray_manager_finalize;
systray_manager_signals[ICON_ADDED] =
g_signal_new (I_("icon-added"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
GTK_TYPE_SOCKET);
systray_manager_signals[ICON_REMOVED] =
g_signal_new (I_("icon-removed"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
GTK_TYPE_SOCKET);
systray_manager_signals[MESSAGE_SENT] =
g_signal_new (I_("message-sent"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_systray_marshal_VOID__OBJECT_STRING_LONG_LONG,
G_TYPE_NONE, 4,
GTK_TYPE_SOCKET,
G_TYPE_STRING,
G_TYPE_LONG,
G_TYPE_LONG);
systray_manager_signals[MESSAGE_CANCELLED] =
g_signal_new (I_("message-cancelled"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_systray_marshal_VOID__OBJECT_LONG,
G_TYPE_NONE, 2,
GTK_TYPE_SOCKET,
G_TYPE_LONG);
systray_manager_signals[LOST_SELECTION] =
g_signal_new (I_("lost-selection"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/* initialize quark */
xwindow_quark = g_quark_from_static_string ("systray-manager-xwindow");
}
static void
systray_manager_init (SystrayManager *manager)
{
/* initialize */
manager->invisible = NULL;
manager->orientation = GTK_ORIENTATION_HORIZONTAL;
manager->messages = NULL;
/* create new sockets table */
manager->sockets = g_hash_table_new (NULL, NULL);
}
GQuark
systray_manager_error_quark (void)
{
static GQuark q = 0;
if (q == 0)
q = g_quark_from_static_string ("systray-manager-error-quark");
return q;
}
static void
systray_manager_finalize (GObject *object)
{
SystrayManager *manager = XFCE_SYSTRAY_MANAGER (object);
/* destroy the hash table */
g_hash_table_destroy (manager->sockets);
if (manager->messages)
{
/* cleanup all pending messages */
g_slist_foreach (manager->messages,
(GFunc) systray_manager_message_free, NULL);
/* free the list */
g_slist_free (manager->messages);
}
G_OBJECT_CLASS (systray_manager_parent_class)->finalize (object);
}
SystrayManager *
systray_manager_new (void)
{
return g_object_new (XFCE_TYPE_SYSTRAY_MANAGER, NULL);
}
gboolean
systray_manager_check_running (GdkScreen *screen)
{
gchar *selection_name;
GdkDisplay *display;
Atom selection_atom;
panel_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
/* get the display */
display = gdk_screen_get_display (screen);
/* create the selection atom name */
selection_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
gdk_screen_get_number (screen));
/* get the atom */
selection_atom = gdk_x11_get_xatom_by_name_for_display (display,
selection_name);
/* cleanup */
g_free (selection_name);
/* return result */
return (XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), selection_atom) != None);
}
gboolean
systray_manager_register (SystrayManager *manager,
GdkScreen *screen,
GError **error)
{
GdkDisplay *display;
gchar *selection_name;
gboolean succeed;
gint screen_number;
GtkWidget *invisible;
guint32 timestamp;
GdkAtom opcode_atom;
XClientMessageEvent xevent;
Window root_window;
panel_return_val_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager), FALSE);
panel_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
panel_return_val_if_fail (error == NULL || *error == NULL, FALSE);
/* create invisible window */
invisible = gtk_invisible_new_for_screen (screen);
gtk_widget_realize (invisible);
/* let the invisible window monitor property and configuration changes */
gtk_widget_add_events (invisible, GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK);
/* get the screen number */
screen_number = gdk_screen_get_number (screen);
/* create the selection atom name */
selection_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", screen_number);
/* get the selection atom */
manager->selection_atom = gdk_atom_intern (selection_name, FALSE);
/* cleanup */
g_free (selection_name);
/* get the display */
display = gdk_screen_get_display (screen);
/* set the invisible window and take a reference */
manager->invisible = g_object_ref (G_OBJECT (invisible));
/* set the visial property for transparent tray icons */
if (gtk_check_version (2, 16, 0) == NULL)
systray_manager_set_visual (manager);
/* get the current x server time stamp */
timestamp = gdk_x11_get_server_time (invisible->window);
/* try to become the selection owner of this display */
succeed = gdk_selection_owner_set_for_display (display, invisible->window,
manager->selection_atom,
timestamp, TRUE);
if (G_LIKELY (succeed))
{
/* get the root window */
root_window = RootWindowOfScreen (GDK_SCREEN_XSCREEN (screen));
/* send a message to x11 that we're going to handle this display */
xevent.type = ClientMessage;
xevent.window = root_window;
xevent.message_type = gdk_x11_get_xatom_by_name_for_display (display, "MANAGER");
xevent.format = 32;
xevent.data.l[0] = timestamp;
xevent.data.l[1] = gdk_x11_atom_to_xatom_for_display (display,
manager->selection_atom);
xevent.data.l[2] = GDK_WINDOW_XWINDOW (invisible->window);
xevent.data.l[3] = 0;
xevent.data.l[4] = 0;
/* send the message */
XSendEvent (GDK_DISPLAY_XDISPLAY (display), root_window,
False, StructureNotifyMask, (XEvent *)&xevent);
/* system_tray_request_dock and selectionclear */
gdk_window_add_filter (invisible->window, systray_manager_window_filter, manager);
/* get the opcode atom (for both gdk and x11) */
opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE);
manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display, opcode_atom);
/* system_tray_begin_message and system_tray_cancel_message */
gdk_display_add_client_message_filter (display,
opcode_atom, systray_manager_handle_client_message_opcode, manager);
/* _net_system_tray_message_data */
gdk_display_add_client_message_filter (display,
gdk_atom_intern ("_NET_SYSTEM_TRAY_MESSAGE_DATA", FALSE),
systray_manager_handle_client_message_message_data, manager);
}
else
{
/* release the invisible */
g_object_unref (G_OBJECT (manager->invisible));
manager->invisible = NULL;
/* desktroy the invisible window */
gtk_widget_destroy (invisible);
/* set an error */
g_set_error (error, XFCE_SYSTRAY_MANAGER_ERROR,
XFCE_SYSTRAY_MANAGER_ERROR_SELECTION_FAILED,
_("Failed to acquire manager selection for screen %d"),
screen_number);
}
return succeed;
}
static void
systray_manager_remove_socket (gpointer key,
gpointer value,
gpointer user_data)
{
SystrayManager *manager = XFCE_SYSTRAY_MANAGER (user_data);
GtkSocket *socket = GTK_SOCKET (value);
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
panel_return_if_fail (GTK_IS_SOCKET (socket));
/* properly undock from the tray */
g_signal_emit (manager, systray_manager_signals[ICON_REMOVED], 0, socket);
}
void
systray_manager_unregister (SystrayManager *manager)
{
GdkDisplay *display;
GtkWidget *invisible = manager->invisible;
GdkWindow *owner;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
/* leave when there is no invisible window */
if (invisible == NULL)
return;
panel_return_if_fail (GTK_IS_INVISIBLE (invisible));
panel_return_if_fail (GTK_WIDGET_REALIZED (invisible));
panel_return_if_fail (GDK_IS_WINDOW (invisible->window));
/* get the display of the invisible window */
display = gtk_widget_get_display (invisible);
/* remove our handling of the selection if we're the owner */
owner = gdk_selection_owner_get_for_display (display, manager->selection_atom);
if (owner == invisible->window)
{
/* reset the selection owner */
gdk_selection_owner_set_for_display (display,
NULL,
manager->selection_atom,
gdk_x11_get_server_time (invisible->window),
TRUE);
}
/* remove window filter */
gdk_window_remove_filter (invisible->window, systray_manager_window_filter, manager);
/* remove all sockets from the hash table */
g_hash_table_foreach (manager->sockets, systray_manager_remove_socket, manager);
/* destroy and unref the invisible window */
manager->invisible = NULL;
gtk_widget_destroy (invisible);
g_object_unref (G_OBJECT (invisible));
}
static GdkFilterReturn
systray_manager_window_filter (GdkXEvent *xev,
GdkEvent *event,
gpointer user_data)
{
XEvent *xevent = (XEvent *)xev;
SystrayManager *manager = XFCE_SYSTRAY_MANAGER (user_data);
panel_return_val_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager), GDK_FILTER_CONTINUE);
if (xevent->type == ClientMessage)
{
if (xevent->xclient.message_type == manager->opcode_atom
&& xevent->xclient.data.l[1] == XFCE_SYSTRAY_MANAGER_REQUEST_DOCK)
{
/* dock a tray icon */
systray_manager_handle_dock_request (manager, (XClientMessageEvent *) xevent);
return GDK_FILTER_REMOVE;
}
}
else if (xevent->type == SelectionClear)
{
/* emit the signal */
g_signal_emit (manager, systray_manager_signals[LOST_SELECTION], 0);
/* unregister the manager */
systray_manager_unregister (manager);
}
return GDK_FILTER_CONTINUE;
}
static GdkFilterReturn
systray_manager_handle_client_message_opcode (GdkXEvent *xevent,
GdkEvent *event,
gpointer user_data)
{
XClientMessageEvent *xev;
SystrayManager *manager = XFCE_SYSTRAY_MANAGER (user_data);
panel_return_val_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager), GDK_FILTER_REMOVE);
/* cast to x11 event */
xev = (XClientMessageEvent *) xevent;
switch (xev->data.l[1])
{
case XFCE_SYSTRAY_MANAGER_REQUEST_DOCK:
/* handled in systray_manager_window_filter () */
break;
case XFCE_SYSTRAY_MANAGER_BEGIN_MESSAGE:
systray_manager_handle_begin_message (manager, xev);
return GDK_FILTER_REMOVE;
case XFCE_SYSTRAY_MANAGER_CANCEL_MESSAGE:
systray_manager_handle_cancel_message (manager, xev);
return GDK_FILTER_REMOVE;
default:
break;
}
return GDK_FILTER_CONTINUE;
}
static GdkFilterReturn
systray_manager_handle_client_message_message_data (GdkXEvent *xevent,
GdkEvent *event,
gpointer user_data)
{
XClientMessageEvent *xev = xevent;
SystrayManager *manager = XFCE_SYSTRAY_MANAGER (user_data);
GSList *li;
SystrayMessage *message;
glong length;
GtkSocket *socket;
panel_return_val_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager), GDK_FILTER_REMOVE);
/* try to find the pending message in the list */
for (li = manager->messages; li != NULL; li = li->next)
{
message = li->data;
if (xev->window == message->window)
{
/* copy the data of this message */
length = MIN (message->remaining_length, 20);
memcpy ((message->string + message->length - message->remaining_length), &xev->data, length);
message->remaining_length -= length;
/* check if we have the complete message */
if (message->remaining_length == 0)
{
/* try to get the socket from the known tray icons */
socket = g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (message->window));
if (G_LIKELY (socket))
{
/* known socket, send the signal */
g_signal_emit (manager, systray_manager_signals[MESSAGE_SENT], 0,
socket, message->string, message->id, message->timeout);
}
/* delete the message from the list */
manager->messages = g_slist_delete_link (manager->messages, li);
/* free the message */
systray_manager_message_free (message);
}
/* stop searching */
break;
}
}
return GDK_FILTER_REMOVE;
}
static void
systray_manager_handle_begin_message (SystrayManager *manager,
XClientMessageEvent *xevent)
{
GtkSocket *socket;
SystrayMessage *message;
glong length, timeout, id;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
/* try to find the window in the list of known tray icons */
socket = g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (xevent->window));
/* unkown tray icon: ignore the message */
if (G_UNLIKELY (socket == NULL))
return;
/* remove the same message from the list */
systray_manager_message_remove_from_list (manager, xevent);
/* get some message information */
timeout = xevent->data.l[2];
length = xevent->data.l[3];
id = xevent->data.l[4];
if (length == 0)
{
/* directly emit empty messages */
g_signal_emit (manager, systray_manager_signals[MESSAGE_SENT], 0,
socket, "", id, timeout);
}
else
{
/* create new structure */
message = g_slice_new0 (SystrayMessage);
/* set message data */
message->window = xevent->window;
message->timeout = timeout;
message->length = length;
message->id = id;
message->remaining_length = length;
message->string = g_malloc (length + 1);
message->string[length] = '\0';
/* add this message to the list of pending messages */
manager->messages = g_slist_prepend (manager->messages, message);
}
}
static void
systray_manager_handle_cancel_message (SystrayManager *manager,
XClientMessageEvent *xevent)
{
GtkSocket *socket;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
/* remove the same message from the list */
systray_manager_message_remove_from_list (manager, xevent);
/* try to find the window in the list of known tray icons */
socket = g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (xevent->window));
if (G_LIKELY (socket))
{
/* emit the cancelled signal */
g_signal_emit (manager, systray_manager_signals[MESSAGE_CANCELLED], 0,
socket, xevent->data.l[2]);
}
}
static void
systray_manager_handle_dock_request (SystrayManager *manager,
XClientMessageEvent *xevent)
{
GtkWidget *socket;
Window *xwindow;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
/* check if we already have this notification */
if (g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (xevent->data.l[2])))
return;
/* create a new socket */
socket = gtk_socket_new ();
/* allocate and set the xwindow */
xwindow = g_new (Window, 1);
*xwindow = xevent->data.l[2];
/* connect the xwindow data to the socket */
g_object_set_qdata_full (G_OBJECT (socket), xwindow_quark, xwindow, g_free);
/* add the icon to the tray */
g_signal_emit (manager, systray_manager_signals[ICON_ADDED], 0, socket);
/* check if the widget has been attached. if the widget has no
toplevel window, we cannot set the socket id. */
if (G_LIKELY (GTK_IS_WINDOW (gtk_widget_get_toplevel (socket))))
{
/* signal to monitor if the client is removed from the socket */
g_signal_connect (G_OBJECT (socket), "plug-removed",
G_CALLBACK (systray_manager_handle_undock_request), manager);
/* register the xembed client window id for this socket */
gtk_socket_add_id (GTK_SOCKET (socket), *xwindow);
/* add the socket to the list of known sockets */
g_hash_table_insert (manager->sockets, GUINT_TO_POINTER (*xwindow), socket);
}
else
{
/* warning */
g_warning ("No parent window set, destroying socket");
/* not attached successfully, destroy it */
gtk_widget_destroy (socket);
}
}
static gboolean
systray_manager_handle_undock_request (GtkSocket *socket,
gpointer user_data)
{
SystrayManager *manager = XFCE_SYSTRAY_MANAGER (user_data);
Window *xwindow;
panel_return_val_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager), FALSE);
/* emit signal that the socket will be removed */
g_signal_emit (manager, systray_manager_signals[ICON_REMOVED], 0, socket);
/* get the xwindow */
xwindow = g_object_get_qdata (G_OBJECT (socket), xwindow_quark);
/* remove the socket from the list */
g_hash_table_remove (manager->sockets, GUINT_TO_POINTER (*xwindow));
/* unset object data */
g_object_set_qdata (G_OBJECT (socket), xwindow_quark, NULL);
/* destroy the socket */
return FALSE;
}
static void
systray_manager_set_visual (SystrayManager *manager)
{
GdkDisplay *display;
Visual *xvisual;
Atom visual_atom;
gulong data[1];
GdkColormap *colormap;
GdkScreen *screen;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
panel_return_if_fail (GTK_IS_INVISIBLE (manager->invisible));
panel_return_if_fail (GDK_IS_WINDOW (manager->invisible->window));
/* get invisible display and screen */
display = gtk_widget_get_display (manager->invisible);
screen = gtk_invisible_get_screen (GTK_INVISIBLE (manager->invisible));
/* get the xatom for the visual property */
visual_atom = gdk_x11_get_xatom_by_name_for_display (display,
"_NET_SYSTEM_TRAY_VISUAL");
if (gtk_widget_is_composited (manager->invisible)
&& gdk_screen_get_rgba_visual (screen) != NULL
&& gdk_display_supports_composite (display))
{
/* get the rgba visual */
xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (screen));
}
else
{
/* use the default visual for the screen */
colormap = gdk_screen_get_default_colormap (screen);
xvisual = GDK_VISUAL_XVISUAL (gdk_colormap_get_visual (colormap));
}
data[0] = XVisualIDFromVisual (xvisual);
XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
GDK_WINDOW_XWINDOW (manager->invisible->window),
visual_atom,
XA_VISUALID, 32,
PropModeReplace,
(guchar *) &data, 1);
}
void
systray_manager_set_orientation (SystrayManager *manager,
GtkOrientation orientation)
{
GdkDisplay *display;
Atom orientation_atom;
gulong data[1];
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
panel_return_if_fail (GTK_IS_INVISIBLE (manager->invisible));
panel_return_if_fail (GDK_IS_WINDOW (manager->invisible->window));
if (G_LIKELY (manager->orientation != orientation))
{
/* set the new orientation */
manager->orientation = orientation;
/* get invisible display */
display = gtk_widget_get_display (manager->invisible);
/* get the xatom for the orientation property */
orientation_atom = gdk_x11_get_xatom_by_name_for_display (display,
"_NET_XFCE_SYSTRAY_MANAGER_ORIENTATION");
/* set the data we're going to send to x */
data[0] = (manager->orientation == GTK_ORIENTATION_HORIZONTAL ?
XFCE_SYSTRAY_MANAGER_ORIENTATION_HORIZONTAL
: XFCE_SYSTRAY_MANAGER_ORIENTATION_VERTICAL);
/* change the x property */
XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
GDK_WINDOW_XWINDOW (manager->invisible->window),
orientation_atom,
XA_CARDINAL, 32,
PropModeReplace,
(guchar *) &data, 1);
}
}
gchar *
systray_manager_get_application_name (GtkWidget *socket)
{
gchar *name = NULL;
GdkDisplay *display;
gint succeed;
XTextProperty xprop;
Window *xwindow;
/* get the xwindow */
xwindow = g_object_get_qdata (G_OBJECT (socket), xwindow_quark);
if (G_LIKELY (xwindow != NULL))
{
/* get the display of the socket */
display = gtk_widget_get_display (socket);
/* avoid exiting the application on X errors */
gdk_error_trap_push ();
/* try to get the wm name (this is more relaiable with qt applications) */
succeed = XGetWMName (GDK_DISPLAY_XDISPLAY (display), *xwindow, &xprop);
/* check if everything went fine */
if (G_LIKELY (gdk_error_trap_pop () == 0 && succeed >= Success))
{
/* check the xprop content */
if (G_LIKELY (xprop.value && xprop.nitems > 0))
{
/* get the lowercase name if it's utf-8 valid */
if (G_LIKELY (g_utf8_validate ((const gchar *) xprop.value, xprop.nitems, NULL)))
name = g_utf8_strdown ((const gchar *) xprop.value, xprop.nitems);
/* cleanup */
XFree (xprop.value);
}
}
}
return name;
}
/**
* tray messages
**/
static void
systray_manager_message_free (SystrayMessage *message)
{
/* cleanup */
g_free (message->string);
/* remove slice */
g_slice_free (SystrayMessage, message);
}
static void
systray_manager_message_remove_from_list (SystrayManager *manager,
XClientMessageEvent *xevent)
{
GSList *li;
SystrayMessage *message;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
/* seach for the same message in the list of pending messages */
for (li = manager->messages; li != NULL; li = li->next)
{
message = li->data;
/* check if this is the same message */
if (xevent->window == message->window && xevent->data.l[4] == message->id)
{
/* delete the message from the list */
manager->messages = g_slist_delete_link (manager->messages, li);
/* free the message */
systray_manager_message_free (message);
break;
}
}
}

72
plugins/systray/systray-manager.h

@ -0,0 +1,72 @@
/* $Id$ */
/*
* Copyright (c) 2002 Anders Carlsson <andersca@gnu.org>
* Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org>
* Copyright (c) 2003-2004 Olivier Fourdan <fourdan@xfce.org>
* Copyright (c) 2003-2006 Vincent Untz
* Copyright (c) 2007-2009 Nick Schermer <nick@xfce.org>
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SYSTRAY_MANAGER_H__
#define __SYSTRAY_MANAGER_H__
#include <gtk/gtk.h>
typedef struct _SystrayManagerClass SystrayManagerClass;
typedef struct _SystrayManager SystrayManager;
typedef struct _SystrayMessage SystrayMessage;
#define XFCE_TYPE_SYSTRAY_MANAGER (systray_manager_get_type ())
#define XFCE_SYSTRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_SYSTRAY_MANAGER, SystrayManager))
#define XFCE_SYSTRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_SYSTRAY_MANAGER, SystrayManagerClass))
#define XFCE_IS_SYSTRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_SYSTRAY_MANAGER))
#define XFCE_IS_SYSTRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_SYSTRAY_MANAGER))
#define XFCE_SYSTRAY_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_SYSTRAY_MANAGER, SystrayManagerClass))
#define XFCE_SYSTRAY_MANAGER_ERROR (systray_manager_error_quark())
enum
{
XFCE_SYSTRAY_MANAGER_ERROR_SELECTION_FAILED
};
GType systray_manager_get_type (void) G_GNUC_CONST;
void systray_manager_register_type (GTypeModule *type_module);
GQuark systray_manager_error_quark (void);
SystrayManager *systray_manager_new (void) G_GNUC_MALLOC;
gboolean systray_manager_check_running (GdkScreen *screen);
gboolean systray_manager_register (SystrayManager *manager,
GdkScreen *screen,
GError **error);
void systray_manager_unregister (SystrayManager *manager);
void systray_manager_set_orientation (SystrayManager *manager,
GtkOrientation orientation);
gchar *systray_manager_get_application_name (GtkWidget *socket) G_GNUC_MALLOC;
#endif /* !__SYSTRAY_MANAGER_H__ */

0
plugins/systray/xfce-tray-marshal.list → plugins/systray/systray-marshal.list

582
plugins/systray/systray.c

@ -0,0 +1,582 @@
/* $Id$ */
/*
* Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org>
* Copyright (c) 2007-2009 Nick Schermer <nick@xfce.org>
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 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 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <libxfce4util/libxfce4util.h>
#include <libxfce4ui/libxfce4ui.h>
#include <common/panel-private.h>
#include <xfconf/xfconf.h>
#include <exo/exo.h>
#include "systray.h"
#include "systray-manager.h"
#include "systray-dialog_glade.h"
static void systray_plugin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void systray_plugin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void systray_plugin_construct (XfcePanelPlugin *panel_plugin);
static void systray_plugin_free_data (XfcePanelPlugin *panel_plugin);
static void systray_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin, gint screen_position);
static void systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin, GtkOrientation orientation);
static gboolean systray_plugin_size_changed (XfcePanelPlugin *panel_plugin, gint size);
static void systray_plugin_configure_plugin (XfcePanelPlugin *panel_plugin);
static void systray_plugin_reallocate (SystrayPlugin *plugin);
static void systray_plugin_icon_added (SystrayManager *manager, GtkWidget *icon, SystrayPlugin *plugin);
static void systray_plugin_icon_removed (SystrayManager *manager, GtkWidget *icon, SystrayPlugin *plugin);
static void systray_plugin_lost_selection (SystrayManager *manager, SystrayPlugin *plugin);
struct _SystrayPluginClass
{
XfcePanelPluginClass __parent__;
};
struct _SystrayPlugin
{
XfcePanelPlugin __parent__;
/* systray manager */
SystrayManager *manager;
/* xfconf channnel */
XfconfChannel *channel;
/* widgets */
GtkWidget *frame;
GtkWidget *fixed;
GtkWidget *button;
GSList *children;
guint show_hidden : 1;
/* settings */
guint rows;
guint show_frame : 1;
};
enum _SystrayChildState
{
CHILD_VISIBLE, /* always visible */
CHILD_AUTO_HIDE, /* hidden when tray is collapsed */
CHILD_DISABLED /* never show this icon */
};
struct _SystrayChild
{
/* the status icon */
GtkWidget *icon;
/* application name */
gchar *name;
/* child state */
SystrayChildState state;
};
enum
{
PROP_0,
PROP_ROWS,
PROP_SHOW_FRAME
};
/* define the plugin */
XFCE_PANEL_DEFINE_PLUGIN (SystrayPlugin, systray_plugin,
systray_manager_register_type)
static void
systray_plugin_class_init (SystrayPluginClass *klass)
{
XfcePanelPluginClass *plugin_class;
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = systray_plugin_get_property;
gobject_class->set_property = systray_plugin_set_property;
plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
plugin_class->construct = systray_plugin_construct;
plugin_class->free_data = systray_plugin_free_data;
plugin_class->size_changed = systray_plugin_size_changed;
plugin_class->screen_position_changed = systray_plugin_screen_position_changed;
plugin_class->configure_plugin = systray_plugin_configure_plugin;
plugin_class->orientation_changed = systray_plugin_orientation_changed;
g_object_class_install_property (gobject_class,
PROP_ROWS,
g_param_spec_uint ("rows",
NULL, NULL,
1, 10, 1,
EXO_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_SHOW_FRAME,
g_param_spec_boolean ("show-frame",
NULL, NULL,
FALSE,
EXO_PARAM_READWRITE));
}
static void
systray_plugin_init (SystrayPlugin *plugin)
{
plugin->manager = NULL;
plugin->rows = 1;
plugin->show_frame = FALSE;
/* initialize xfconf */
xfconf_init (NULL);
/* show configure */
xfce_panel_plugin_menu_show_configure (XFCE_PANEL_PLUGIN (plugin));
/* plugin widgets */
plugin->frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (plugin), plugin->frame);
gtk_frame_set_shadow_type (GTK_FRAME (plugin->frame), GTK_SHADOW_NONE);
gtk_widget_show (plugin->frame);
plugin->fixed = gtk_fixed_new ();
gtk_container_add (GTK_CONTAINER (plugin->frame), plugin->fixed);
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->fixed);
gtk_widget_show (plugin->fixed);
plugin->button = xfce_arrow_button_new (GTK_ARROW_NONE);
gtk_container_add (GTK_CONTAINER (plugin->fixed), plugin->button);
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
}
static void
systray_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (object);
switch (prop_id)
{
case PROP_ROWS:
g_value_set_uint (value, plugin->rows);
break;
case PROP_SHOW_FRAME:
g_value_set_boolean (value, plugin->show_frame);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
systray_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (object);
switch (prop_id)
{
case PROP_ROWS:
plugin->rows = g_value_get_uint (value);
systray_plugin_reallocate (plugin);
break;
case PROP_SHOW_FRAME:
plugin->show_frame = g_value_get_boolean (value);
/* set the frame shadow */
gtk_frame_set_shadow_type (GTK_FRAME (plugin->frame),
plugin->show_frame ? GTK_SHADOW_IN : GTK_SHADOW_NONE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
systray_plugin_screen_changed (GtkWidget *widget,
GdkScreen *previous_screen)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (widget);
GdkScreen *screen;
GError *error = NULL;
if (G_UNLIKELY (plugin->manager != NULL))
{
/* unregister from this screen */
systray_manager_unregister (plugin->manager);
g_object_unref (G_OBJECT (plugin->manager));
plugin->manager = NULL;
}
/* get the new screen */
screen = gtk_widget_get_screen (widget);
/* check if not another systray is running on this screen */
if (G_LIKELY (systray_manager_check_running (screen) == FALSE))
{
/* create a new manager and register this screen */
plugin->manager = systray_manager_new ();
/* hookup signals */
g_signal_connect (G_OBJECT (plugin->manager), "icon-added",
G_CALLBACK (systray_plugin_icon_added), plugin);
g_signal_connect (G_OBJECT (plugin->manager), "icon-removed",
G_CALLBACK (systray_plugin_icon_removed), plugin);
g_signal_connect (G_OBJECT (plugin->manager), "lost-selection",
G_CALLBACK (systray_plugin_lost_selection), plugin);
if (!systray_manager_register (plugin->manager, screen, &error))
{
/* TODO handle error and leave the plugin */
g_message ("Failed to register the systray manager %s", error->message);
g_error_free (error);
}
}
else
{
/* TODO, error and leave the plugin */
g_message ("already a notification area running");
}
}
static void
systray_plugin_construct (XfcePanelPlugin *panel_plugin)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
/* open the xfconf channel */
plugin->channel = xfce_panel_plugin_xfconf_channel_new (panel_plugin);
/* bind the properties */
xfconf_g_property_bind (plugin->channel, "/rows",
G_TYPE_UINT, plugin, "rows");
xfconf_g_property_bind (plugin->channel, "/show-frame",
G_TYPE_BOOLEAN, plugin, "show-frame");
/* monitor screen changes */
g_signal_connect (G_OBJECT (plugin), "screen-changed",
G_CALLBACK (systray_plugin_screen_changed), NULL);
/* initialize the screen */
systray_plugin_screen_changed (GTK_WIDGET (plugin), NULL);
}
static void
systray_plugin_free_data (XfcePanelPlugin *panel_plugin)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
/* disconnect screen changed signal */
g_signal_handlers_disconnect_by_func (G_OBJECT (plugin),
systray_plugin_screen_changed, NULL);
/* release the manager */
if (G_LIKELY (plugin->manager))
g_object_unref (G_OBJECT (plugin->manager));
/* release the xfconf channel */
if (G_LIKELY (plugin->channel))
g_object_unref (G_OBJECT (plugin->channel));
/* shutdown xfconf */
xfconf_shutdown ();
}
static void
systray_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin,
gint screen_position)
{
}
static void
systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin,
GtkOrientation orientation)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
/* send the new orientation to the manager */
if (G_LIKELY (plugin->manager != NULL))
systray_manager_set_orientation (plugin->manager, orientation);
}
static gboolean
systray_plugin_size_changed (XfcePanelPlugin *panel_plugin,
gint size)
{
panel_return_val_if_fail (XFCE_IS_SYSTRAY_PLUGIN (panel_plugin), FALSE);
if (xfce_panel_plugin_get_orientation (panel_plugin)
== GTK_ORIENTATION_HORIZONTAL)
gtk_widget_set_size_request (GTK_WIDGET (panel_plugin), -1, size);
else
gtk_widget_set_size_request (GTK_WIDGET (panel_plugin), size, -1);
/* reallocate all the children */
systray_plugin_reallocate (XFCE_SYSTRAY_PLUGIN (panel_plugin));
return TRUE;
}
static void
systray_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
GtkBuilder *builder;
GObject *dialog, *object;
/* fix gtk builder problem: "Invalid object type XfceTitledDialog" */
if (xfce_titled_dialog_get_type () == 0)
return;
builder = gtk_builder_new ();
if (gtk_builder_add_from_string (builder, systray_dialog_glade,
systray_dialog_glade_length, NULL))
{
dialog = gtk_builder_get_object (builder, "dialog");
g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, builder);
xfce_panel_plugin_take_window (panel_plugin, GTK_WINDOW (dialog));
xfce_panel_plugin_block_menu (panel_plugin);
g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify)
xfce_panel_plugin_unblock_menu, panel_plugin);
object = gtk_builder_get_object (builder, "close-button");
panel_return_if_fail (GTK_IS_WIDGET (object));
g_signal_connect_swapped (G_OBJECT (object), "clicked",
G_CALLBACK (gtk_widget_destroy), dialog);
object = gtk_builder_get_object (builder, "rows");
panel_return_if_fail (GTK_IS_WIDGET (object));
exo_mutual_binding_new (G_OBJECT (plugin), "rows",
G_OBJECT (object), "value");
object = gtk_builder_get_object (builder, "show-frame");
panel_return_if_fail (GTK_IS_WIDGET (object));
exo_mutual_binding_new (G_OBJECT (plugin), "show-frame",
G_OBJECT (object), "active");
gtk_widget_show (GTK_WIDGET (dialog));
}
else
{
/* release the builder */
g_object_unref (G_OBJECT (builder));
}
}
static void
systray_plugin_reallocate (SystrayPlugin *plugin)
{
GSList *li;
SystrayChild *child;
guint n;
gint x, y;
gint size;
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
/* get the icon size from the last allocation of the fixed widget */
size = xfce_panel_plugin_get_size (XFCE_PANEL_PLUGIN (plugin));
size = (size - 4) / plugin->rows;
if (size < 1)
size = 1;
for (li = plugin->children, n = 0; li != NULL; li = li->next)
{
child = li->data;
/* set the size request of the widget */
x = size * (n / plugin->rows);
y = size * (n % plugin->rows);
gtk_fixed_move (GTK_FIXED (plugin->fixed), child->icon, x, y);
gtk_widget_set_size_request (child->icon, size, size);
/* increase counter */
n++;
}
}
static gint
systray_plugin_child_compare (gconstpointer a,
gconstpointer b)
{
const SystrayChild *child_a = a;
const SystrayChild *child_b = b;
if (child_a->state == CHILD_DISABLED
|| child_b->state == CHILD_DISABLED)
return 0;
/* sort auto hide icons before visible ones */
if ((child_a->state == CHILD_AUTO_HIDE)
!= (child_b->state == CHILD_AUTO_HIDE))
return ((child_a->state == CHILD_AUTO_HIDE) ? -1 : 1);
if (!IS_STRING (child_a->name) || !IS_STRING (child_b->name))
{
if (IS_STRING (child_a->name) == IS_STRING (child_b->name))
return 0;
else
return !IS_STRING (child_a->name) ? -1 : 1;
}
/* sort by name */
return strcmp (child_a->name, child_b->name);
}