You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1014 lines
32 KiB
1014 lines
32 KiB
/*
|
|
* Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org>
|
|
* Copyright (c) 2007-2010 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 Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <libxfce4util/libxfce4util.h>
|
|
#include <libxfce4ui/libxfce4ui.h>
|
|
#include <common/panel-private.h>
|
|
#include <common/panel-xfconf.h>
|
|
#include <common/panel-utils.h>
|
|
#include <common/panel-debug.h>
|
|
#include <exo/exo.h>
|
|
|
|
#include "systray.h"
|
|
#include "systray-box.h"
|
|
#include "systray-socket.h"
|
|
#include "systray-manager.h"
|
|
#include "systray-dialog_ui.h"
|
|
|
|
#define ICON_SIZE (22)
|
|
#define BUTTON_SIZE (16)
|
|
#define FRAME_SPACING (1)
|
|
|
|
|
|
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_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_box_expose_event (GtkWidget *box,
|
|
GdkEventExpose *event);
|
|
static void systray_plugin_button_toggled (GtkWidget *button,
|
|
SystrayPlugin *plugin);
|
|
static void systray_plugin_button_set_arrow (SystrayPlugin *plugin);
|
|
static void systray_plugin_names_collect_visible (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data);
|
|
static void systray_plugin_names_collect_hidden (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data);
|
|
static gboolean systray_plugin_names_remove (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data);
|
|
static void systray_plugin_names_update (SystrayPlugin *plugin);
|
|
static gboolean systray_plugin_names_get_hidden (SystrayPlugin *plugin,
|
|
const gchar *name);
|
|
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);
|
|
static void systray_plugin_dialog_add_application_names (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data);
|
|
static void systray_plugin_dialog_hidden_toggled (GtkCellRendererToggle *renderer,
|
|
const gchar *path_string,
|
|
SystrayPlugin *plugin);
|
|
static void systray_plugin_dialog_clear_clicked (GtkWidget *button,
|
|
SystrayPlugin *plugin);
|
|
|
|
|
|
|
|
struct _SystrayPluginClass
|
|
{
|
|
XfcePanelPluginClass __parent__;
|
|
};
|
|
|
|
struct _SystrayPlugin
|
|
{
|
|
XfcePanelPlugin __parent__;
|
|
|
|
/* systray manager */
|
|
SystrayManager *manager;
|
|
|
|
guint idle_startup;
|
|
|
|
/* widgets */
|
|
GtkWidget *frame;
|
|
GtkWidget *hvbox;
|
|
GtkWidget *box;
|
|
GtkWidget *button;
|
|
|
|
/* settings */
|
|
guint show_frame : 1;
|
|
GHashTable *names;
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_SIZE_MAX,
|
|
PROP_SHOW_FRAME,
|
|
PROP_NAMES_HIDDEN,
|
|
PROP_NAMES_VISIBLE
|
|
};
|
|
|
|
enum
|
|
{
|
|
COLUMN_PIXBUF,
|
|
COLUMN_TITLE,
|
|
COLUMN_HIDDEN,
|
|
COLUMN_INTERNAL_NAME
|
|
};
|
|
|
|
|
|
|
|
/* define the plugin */
|
|
XFCE_PANEL_DEFINE_PLUGIN (SystrayPlugin, systray_plugin,
|
|
systray_box_register_type,
|
|
systray_manager_register_type,
|
|
systray_socket_register_type)
|
|
|
|
|
|
|
|
/* known applications to improve the icon and name */
|
|
static const gchar *known_applications[][3] =
|
|
{
|
|
/* application name, icon-name, understandable name */
|
|
{ "networkmanager applet", "network-workgroup", "Network Manager Applet" },
|
|
{ "thunar", "Thunar", "Thunar Progress Dialog" },
|
|
{ "workrave", NULL, "Workrave" },
|
|
{ "workrave tray icon", NULL, "Workrave Applet" },
|
|
{ "audacious2", "audacious", "Audacious" },
|
|
{ "wicd-client.py", "wicd-gtk", "Wicd" },
|
|
};
|
|
|
|
|
|
|
|
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->configure_plugin = systray_plugin_configure_plugin;
|
|
plugin_class->orientation_changed = systray_plugin_orientation_changed;
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SIZE_MAX,
|
|
g_param_spec_uint ("size-max",
|
|
NULL, NULL,
|
|
SIZE_MAX_MIN,
|
|
SIZE_MAX_MAX,
|
|
SIZE_MAX_DEFAULT,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SHOW_FRAME,
|
|
g_param_spec_boolean ("show-frame",
|
|
NULL, NULL,
|
|
TRUE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_NAMES_HIDDEN,
|
|
g_param_spec_boxed ("names-hidden",
|
|
NULL, NULL,
|
|
PANEL_PROPERTIES_TYPE_VALUE_ARRAY,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_NAMES_VISIBLE,
|
|
g_param_spec_boxed ("names-visible",
|
|
NULL, NULL,
|
|
PANEL_PROPERTIES_TYPE_VALUE_ARRAY,
|
|
EXO_PARAM_READWRITE));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_init (SystrayPlugin *plugin)
|
|
{
|
|
plugin->manager = NULL;
|
|
plugin->show_frame = TRUE;
|
|
plugin->idle_startup = 0;
|
|
plugin->names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
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_ETCHED_IN);
|
|
gtk_widget_show (plugin->frame);
|
|
|
|
plugin->hvbox = xfce_hvbox_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 2);
|
|
gtk_container_add (GTK_CONTAINER (plugin->frame), plugin->hvbox);
|
|
gtk_widget_show (plugin->hvbox);
|
|
|
|
plugin->box = systray_box_new ();
|
|
gtk_box_pack_start (GTK_BOX (plugin->hvbox), plugin->box, TRUE, TRUE, 0);
|
|
g_signal_connect (G_OBJECT (plugin->box), "expose-event",
|
|
G_CALLBACK (systray_plugin_box_expose_event), NULL);
|
|
gtk_container_set_border_width (GTK_CONTAINER (plugin->box), FRAME_SPACING);
|
|
gtk_widget_show (plugin->box);
|
|
|
|
plugin->button = xfce_arrow_button_new (GTK_ARROW_RIGHT);
|
|
gtk_box_pack_start (GTK_BOX (plugin->hvbox), plugin->button, FALSE, FALSE, 0);
|
|
g_signal_connect (G_OBJECT (plugin->button), "toggled",
|
|
G_CALLBACK (systray_plugin_button_toggled), plugin);
|
|
gtk_button_set_relief (GTK_BUTTON (plugin->button), GTK_RELIEF_NONE);
|
|
exo_binding_new (G_OBJECT (plugin->box), "has-hidden", G_OBJECT (plugin->button), "visible");
|
|
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);
|
|
GPtrArray *array;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_SIZE_MAX:
|
|
g_value_set_uint (value,
|
|
systray_box_get_size_max (XFCE_SYSTRAY_BOX (plugin->box)));
|
|
break;
|
|
|
|
case PROP_SHOW_FRAME:
|
|
g_value_set_boolean (value, plugin->show_frame);
|
|
break;
|
|
|
|
case PROP_NAMES_VISIBLE:
|
|
array = g_ptr_array_new ();
|
|
g_hash_table_foreach (plugin->names, systray_plugin_names_collect_visible, array);
|
|
g_value_set_boxed (value, array);
|
|
xfconf_array_free (array);
|
|
break;
|
|
|
|
case PROP_NAMES_HIDDEN:
|
|
array = g_ptr_array_new ();
|
|
g_hash_table_foreach (plugin->names, systray_plugin_names_collect_hidden, array);
|
|
g_value_set_boxed (value, array);
|
|
xfconf_array_free (array);
|
|
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);
|
|
gboolean show_frame;
|
|
gboolean hidden = TRUE;
|
|
GPtrArray *array;
|
|
const GValue *tmp;
|
|
gchar *name;
|
|
guint i;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_SIZE_MAX:
|
|
systray_box_set_size_max (XFCE_SYSTRAY_BOX (plugin->box),
|
|
g_value_get_uint (value));
|
|
break;
|
|
|
|
case PROP_SHOW_FRAME:
|
|
show_frame = g_value_get_boolean (value);
|
|
if (plugin->show_frame != show_frame)
|
|
{
|
|
plugin->show_frame = show_frame;
|
|
gtk_frame_set_shadow_type (GTK_FRAME (plugin->frame),
|
|
show_frame ? GTK_SHADOW_ETCHED_IN : GTK_SHADOW_NONE);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (plugin->box),
|
|
plugin->show_frame ? FRAME_SPACING : 0);
|
|
}
|
|
break;
|
|
|
|
case PROP_NAMES_VISIBLE:
|
|
hidden = FALSE;
|
|
/* fall-though */
|
|
|
|
case PROP_NAMES_HIDDEN:
|
|
/* remove old names with this state */
|
|
g_hash_table_foreach_remove (plugin->names,
|
|
systray_plugin_names_remove,
|
|
GUINT_TO_POINTER (hidden));
|
|
|
|
/* add new values */
|
|
array = g_value_get_boxed (value);
|
|
if (G_LIKELY (array != NULL))
|
|
{
|
|
for (i = 0; i < array->len; i++)
|
|
{
|
|
tmp = g_ptr_array_index (array, i);
|
|
panel_assert (G_VALUE_HOLDS_STRING (tmp));
|
|
name = g_value_dup_string (tmp);
|
|
g_hash_table_replace (plugin->names, name, GUINT_TO_POINTER (hidden));
|
|
}
|
|
}
|
|
|
|
/* update icons in the box */
|
|
systray_plugin_names_update (plugin);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
systray_plugin_screen_changed_idle (gpointer user_data)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (user_data);
|
|
GdkScreen *screen;
|
|
GError *error = NULL;
|
|
|
|
/* create a new manager and register this screen */
|
|
plugin->manager = systray_manager_new ();
|
|
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);
|
|
|
|
/* try to register the systray */
|
|
screen = gtk_widget_get_screen (GTK_WIDGET (plugin));
|
|
if (systray_manager_register (plugin->manager, screen, &error))
|
|
{
|
|
/* send the plugin orientation */
|
|
systray_plugin_orientation_changed (XFCE_PANEL_PLUGIN (plugin),
|
|
xfce_panel_plugin_get_orientation (XFCE_PANEL_PLUGIN (plugin)));
|
|
}
|
|
else
|
|
{
|
|
xfce_dialog_show_error (NULL, error, _("Unable to start the notification area"));
|
|
g_error_free (error);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_screen_changed_idle_destroyed (gpointer user_data)
|
|
{
|
|
XFCE_SYSTRAY_PLUGIN (user_data)->idle_startup = 0;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_screen_changed (GtkWidget *widget,
|
|
GdkScreen *previous_screen)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (widget);
|
|
|
|
if (G_UNLIKELY (plugin->manager != NULL))
|
|
{
|
|
/* unregister this screen screen */
|
|
systray_manager_unregister (plugin->manager);
|
|
g_object_unref (G_OBJECT (plugin->manager));
|
|
plugin->manager = NULL;
|
|
}
|
|
|
|
/* schedule a delayed startup */
|
|
if (plugin->idle_startup == 0)
|
|
plugin->idle_startup = g_idle_add_full (G_PRIORITY_LOW, systray_plugin_screen_changed_idle,
|
|
plugin, systray_plugin_screen_changed_idle_destroyed);
|
|
}
|
|
|
|
|
|
static void
|
|
systray_plugin_composited_changed (GtkWidget *widget)
|
|
{
|
|
/* restart the manager to add the sockets again */
|
|
systray_plugin_screen_changed (widget, gtk_widget_get_screen (widget));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_construct (XfcePanelPlugin *panel_plugin)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
|
|
const PanelProperty properties[] =
|
|
{
|
|
{ "size-max", G_TYPE_UINT },
|
|
{ "show-frame", G_TYPE_BOOLEAN },
|
|
{ "names-visible", PANEL_PROPERTIES_TYPE_VALUE_ARRAY },
|
|
{ "names-hidden", PANEL_PROPERTIES_TYPE_VALUE_ARRAY },
|
|
{ NULL }
|
|
};
|
|
|
|
xfce_panel_plugin_menu_show_configure (XFCE_PANEL_PLUGIN (plugin));
|
|
|
|
panel_properties_bind (NULL, G_OBJECT (plugin),
|
|
xfce_panel_plugin_get_property_base (panel_plugin),
|
|
properties, FALSE);
|
|
|
|
/* monitor screen changes */
|
|
g_signal_connect (G_OBJECT (plugin), "screen-changed",
|
|
G_CALLBACK (systray_plugin_screen_changed), NULL);
|
|
systray_plugin_screen_changed (GTK_WIDGET (plugin), NULL);
|
|
|
|
/* restart internally if compositing changed */
|
|
g_signal_connect (G_OBJECT (plugin), "composited-changed",
|
|
G_CALLBACK (systray_plugin_composited_changed), NULL);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_free_data (XfcePanelPlugin *panel_plugin)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
|
|
|
|
/* stop pending idle startup */
|
|
if (plugin->idle_startup != 0)
|
|
g_source_remove (plugin->idle_startup);
|
|
|
|
/* disconnect screen changed signal */
|
|
g_signal_handlers_disconnect_by_func (G_OBJECT (plugin),
|
|
systray_plugin_screen_changed, NULL);
|
|
|
|
g_hash_table_destroy (plugin->names);
|
|
|
|
if (G_LIKELY (plugin->manager != NULL))
|
|
{
|
|
systray_manager_unregister (plugin->manager);
|
|
g_object_unref (G_OBJECT (plugin->manager));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin,
|
|
GtkOrientation orientation)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
|
|
|
|
xfce_hvbox_set_orientation (XFCE_HVBOX (plugin->hvbox), orientation);
|
|
systray_box_set_orientation (XFCE_SYSTRAY_BOX (plugin->box), orientation);
|
|
|
|
if (G_LIKELY (plugin->manager != NULL))
|
|
systray_manager_set_orientation (plugin->manager, orientation);
|
|
|
|
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
|
gtk_widget_set_size_request (plugin->button, BUTTON_SIZE, -1);
|
|
else
|
|
gtk_widget_set_size_request (plugin->button, -1, BUTTON_SIZE);
|
|
|
|
systray_plugin_button_set_arrow (plugin);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
systray_plugin_size_changed (XfcePanelPlugin *panel_plugin,
|
|
gint size)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
|
|
GtkWidget *frame = plugin->frame;
|
|
gint border = 0;
|
|
|
|
/* set the frame border */
|
|
if (plugin->show_frame && size > 26)
|
|
border = 1;
|
|
gtk_container_set_border_width (GTK_CONTAINER (frame), border);
|
|
|
|
/* because the allocated size, used in size_requested is always 1 step
|
|
* behind the allocated size when resizing and during startup, we
|
|
* correct the maximum size set by the user with the size the panel
|
|
* will most likely allocated */
|
|
border += MAX (frame->style->xthickness, frame->style->ythickness);
|
|
systray_box_set_size_alloc (XFCE_SYSTRAY_BOX (plugin->box), size - 2 * border);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
|
|
GtkBuilder *builder;
|
|
GObject *dialog, *object, *store;
|
|
|
|
/* setup the dialog */
|
|
PANEL_UTILS_LINK_4UI
|
|
builder = panel_utils_builder_new (panel_plugin, systray_dialog_ui,
|
|
systray_dialog_ui_length, &dialog);
|
|
if (G_UNLIKELY (builder == NULL))
|
|
return;
|
|
|
|
object = gtk_builder_get_object (builder, "size-max");
|
|
panel_return_if_fail (GTK_IS_WIDGET (object));
|
|
exo_mutual_binding_new (G_OBJECT (plugin), "size-max",
|
|
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");
|
|
|
|
store = gtk_builder_get_object (builder, "applications-store");
|
|
panel_return_if_fail (GTK_IS_LIST_STORE (store));
|
|
g_hash_table_foreach (plugin->names,
|
|
systray_plugin_dialog_add_application_names, store);
|
|
g_object_set_data (G_OBJECT (plugin), "applications-store", store);
|
|
|
|
object = gtk_builder_get_object (builder, "hidden-toggle");
|
|
panel_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (object));
|
|
g_signal_connect (G_OBJECT (object), "toggled",
|
|
G_CALLBACK (systray_plugin_dialog_hidden_toggled), plugin);
|
|
|
|
object = gtk_builder_get_object (builder, "applications-clear");
|
|
panel_return_if_fail (GTK_IS_BUTTON (object));
|
|
g_signal_connect (G_OBJECT (object), "clicked",
|
|
G_CALLBACK (systray_plugin_dialog_clear_clicked), plugin);
|
|
|
|
gtk_widget_show (GTK_WIDGET (dialog));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_box_expose_event_icon (GtkWidget *child,
|
|
gpointer user_data)
|
|
{
|
|
cairo_t *cr = user_data;
|
|
GtkAllocation *alloc;
|
|
|
|
if (systray_socket_is_composited (XFCE_SYSTRAY_SOCKET (child)))
|
|
{
|
|
alloc = &child->allocation;
|
|
|
|
/* skip hidden (see offscreen in box widget) icons */
|
|
if (alloc->x > 0 && alloc->y > 0)
|
|
{
|
|
gdk_cairo_set_source_pixmap (cr, gtk_widget_get_window (child),
|
|
alloc->x, alloc->y);
|
|
cairo_paint (cr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_box_expose_event (GtkWidget *box,
|
|
GdkEventExpose *event)
|
|
{
|
|
cairo_t *cr;
|
|
|
|
if (!gtk_widget_is_composited (box))
|
|
return;
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window (box));
|
|
if (G_LIKELY (cr != NULL))
|
|
{
|
|
gdk_cairo_rectangle (cr, &event->area);
|
|
cairo_clip (cr);
|
|
|
|
/* separately draw all the composed tray icons after gtk
|
|
* handled the expose event */
|
|
gtk_container_foreach (GTK_CONTAINER (box),
|
|
systray_plugin_box_expose_event_icon, cr);
|
|
|
|
cairo_destroy (cr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_button_toggled (GtkWidget *button,
|
|
SystrayPlugin *plugin)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
|
|
panel_return_if_fail (plugin->button == button);
|
|
|
|
systray_box_set_show_hidden (XFCE_SYSTRAY_BOX (plugin->box),
|
|
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
|
|
systray_plugin_button_set_arrow (plugin);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_button_set_arrow (SystrayPlugin *plugin)
|
|
{
|
|
GtkArrowType arrow_type;
|
|
gboolean show_hidden;
|
|
GtkOrientation orientation;
|
|
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
|
|
show_hidden = systray_box_get_show_hidden (XFCE_SYSTRAY_BOX (plugin->box));
|
|
orientation = xfce_panel_plugin_get_orientation (XFCE_PANEL_PLUGIN (plugin));
|
|
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
|
arrow_type = show_hidden ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT;
|
|
else
|
|
arrow_type = show_hidden ? GTK_ARROW_UP : GTK_ARROW_DOWN;
|
|
|
|
xfce_arrow_button_set_arrow_type (XFCE_ARROW_BUTTON (plugin->button), arrow_type);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_collect (GPtrArray *array,
|
|
const gchar *name)
|
|
{
|
|
GValue *tmp;
|
|
|
|
tmp = g_new0 (GValue, 1);
|
|
g_value_init (tmp, G_TYPE_STRING);
|
|
g_value_set_string (tmp, name);
|
|
g_ptr_array_add (array, tmp);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_collect_visible (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data)
|
|
{
|
|
/* add all the visible names */
|
|
if (!GPOINTER_TO_UINT (value))
|
|
systray_plugin_names_collect (user_data, key);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_collect_hidden (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data)
|
|
{
|
|
/* add all the hidden names */
|
|
if (GPOINTER_TO_UINT (value))
|
|
systray_plugin_names_collect (user_data, key);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
systray_plugin_names_remove (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data)
|
|
{
|
|
return GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (user_data);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_update_icon (GtkWidget *icon,
|
|
gpointer data)
|
|
{
|
|
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (data);
|
|
SystraySocket *socket = XFCE_SYSTRAY_SOCKET (icon);
|
|
const gchar *name;
|
|
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (icon));
|
|
|
|
name = systray_socket_get_name (socket);
|
|
systray_socket_set_hidden (socket,
|
|
systray_plugin_names_get_hidden (plugin, name));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_update (SystrayPlugin *plugin)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
|
|
gtk_container_foreach (GTK_CONTAINER (plugin->box),
|
|
systray_plugin_names_update_icon, plugin);
|
|
systray_box_update (XFCE_SYSTRAY_BOX (plugin->box));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_set_hidden (SystrayPlugin *plugin,
|
|
const gchar *name,
|
|
gboolean hidden)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (!exo_str_is_empty (name));
|
|
|
|
g_hash_table_replace (plugin->names, g_strdup (name),
|
|
GUINT_TO_POINTER (hidden ? 1 : 0));
|
|
|
|
systray_plugin_names_update (plugin);
|
|
|
|
g_object_notify (G_OBJECT (plugin), "names-visible");
|
|
g_object_notify (G_OBJECT (plugin), "names-hidden");
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
systray_plugin_names_get_hidden (SystrayPlugin *plugin,
|
|
const gchar *name)
|
|
{
|
|
gpointer p;
|
|
|
|
if (exo_str_is_empty (name))
|
|
return FALSE;
|
|
|
|
/* lookup the name in the table */
|
|
p = g_hash_table_lookup (plugin->names, name);
|
|
if (G_UNLIKELY (p == NULL))
|
|
{
|
|
/* add the new name */
|
|
g_hash_table_insert (plugin->names, g_strdup (name), GUINT_TO_POINTER (0));
|
|
g_object_notify (G_OBJECT (plugin), "names-visible");
|
|
|
|
/* do not hide the icon */
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return (GPOINTER_TO_UINT (p) == 1 ? TRUE : FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_names_clear (SystrayPlugin *plugin)
|
|
{
|
|
g_hash_table_remove_all (plugin->names);
|
|
|
|
g_object_notify (G_OBJECT (plugin), "names-hidden");
|
|
g_object_notify (G_OBJECT (plugin), "names-visible");
|
|
|
|
systray_plugin_names_update (plugin);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_icon_added (SystrayManager *manager,
|
|
GtkWidget *icon,
|
|
SystrayPlugin *plugin)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (icon));
|
|
panel_return_if_fail (plugin->manager == manager);
|
|
panel_return_if_fail (GTK_IS_WIDGET (icon));
|
|
|
|
systray_plugin_names_update_icon (icon, plugin);
|
|
gtk_container_add (GTK_CONTAINER (plugin->box), icon);
|
|
gtk_widget_show (icon);
|
|
|
|
panel_debug_filtered (PANEL_DEBUG_SYSTRAY, "added %s[%p] icon",
|
|
systray_socket_get_name (XFCE_SYSTRAY_SOCKET (icon)), icon);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_icon_removed (SystrayManager *manager,
|
|
GtkWidget *icon,
|
|
SystrayPlugin *plugin)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (plugin->manager == manager);
|
|
panel_return_if_fail (GTK_IS_WIDGET (icon));
|
|
|
|
/* remove the icon from the box */
|
|
gtk_container_remove (GTK_CONTAINER (plugin->box), icon);
|
|
|
|
panel_debug_filtered (PANEL_DEBUG_SYSTRAY, "removed %s[%p] icon",
|
|
systray_socket_get_name (XFCE_SYSTRAY_SOCKET (icon)), icon);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_lost_selection (SystrayManager *manager,
|
|
SystrayPlugin *plugin)
|
|
{
|
|
GError error;
|
|
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (plugin->manager == manager);
|
|
|
|
/* create fake error and show it */
|
|
error.message = _("Most likely another widget took over the function "
|
|
"of a notification area. This area will be unused.");
|
|
xfce_dialog_show_error (NULL, &error, _("The notification area lost selection"));
|
|
}
|
|
|
|
|
|
|
|
static gchar *
|
|
systray_plugin_dialog_camel_case (const gchar *text)
|
|
{
|
|
const gchar *t;
|
|
gboolean upper = TRUE;
|
|
gunichar c;
|
|
GString *result;
|
|
|
|
panel_return_val_if_fail (!exo_str_is_empty (text), NULL);
|
|
|
|
/* allocate a new string for the result */
|
|
result = g_string_sized_new (32);
|
|
|
|
/* convert the input text */
|
|
for (t = text; *t != '\0'; t = g_utf8_next_char (t))
|
|
{
|
|
/* check the next char */
|
|
c = g_utf8_get_char (t);
|
|
if (g_unichar_isspace (c))
|
|
{
|
|
upper = TRUE;
|
|
}
|
|
else if (upper)
|
|
{
|
|
c = g_unichar_toupper (c);
|
|
upper = FALSE;
|
|
}
|
|
else
|
|
{
|
|
c = g_unichar_tolower (c);
|
|
}
|
|
|
|
/* append the char to the result */
|
|
g_string_append_unichar (result, c);
|
|
}
|
|
|
|
return g_string_free (result, FALSE);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_dialog_add_application_names (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data)
|
|
{
|
|
GtkListStore *store = GTK_LIST_STORE (user_data);
|
|
const gchar *name = key;
|
|
gboolean hidden = GPOINTER_TO_UINT (value);
|
|
const gchar *title = NULL;
|
|
gchar *camelcase = NULL;
|
|
const gchar *icon_name = name;
|
|
GdkPixbuf *pixbuf;
|
|
guint i;
|
|
GtkTreeIter iter;
|
|
|
|
panel_return_if_fail (GTK_IS_LIST_STORE (store));
|
|
panel_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
|
|
|
|
/* skip invalid names */
|
|
if (exo_str_is_empty (name))
|
|
return;
|
|
|
|
/* check if we have a better name for the application */
|
|
for (i = 0; i < G_N_ELEMENTS (known_applications); i++)
|
|
{
|
|
if (strcmp (name, known_applications[i][0]) == 0)
|
|
{
|
|
icon_name = known_applications[i][1];
|
|
title = known_applications[i][2];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* create fallback title if the application was not found */
|
|
if (title == NULL)
|
|
{
|
|
camelcase = systray_plugin_dialog_camel_case (name);
|
|
title = camelcase;
|
|
}
|
|
|
|
/* try to load the icon name */
|
|
if (G_LIKELY (icon_name != NULL))
|
|
pixbuf = xfce_panel_pixbuf_from_source (icon_name, NULL, ICON_SIZE);
|
|
else
|
|
pixbuf = NULL;
|
|
|
|
/* insert in the store */
|
|
gtk_list_store_append (store, &iter);
|
|
gtk_list_store_set (store, &iter,
|
|
COLUMN_PIXBUF, pixbuf,
|
|
COLUMN_TITLE, title,
|
|
COLUMN_HIDDEN, hidden,
|
|
COLUMN_INTERNAL_NAME, name,
|
|
-1);
|
|
|
|
g_free (camelcase);
|
|
if (pixbuf != NULL)
|
|
g_object_unref (G_OBJECT (pixbuf));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_dialog_hidden_toggled (GtkCellRendererToggle *renderer,
|
|
const gchar *path_string,
|
|
SystrayPlugin *plugin)
|
|
{
|
|
GtkTreeIter iter;
|
|
gboolean hidden;
|
|
GtkTreeModel *model;
|
|
gchar *name;
|
|
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (plugin->box));
|
|
|
|
model = g_object_get_data (G_OBJECT (plugin), "applications-store");
|
|
panel_return_if_fail (GTK_IS_LIST_STORE (model));
|
|
if (gtk_tree_model_get_iter_from_string (model, &iter, path_string))
|
|
{
|
|
gtk_tree_model_get (model, &iter,
|
|
COLUMN_HIDDEN, &hidden,
|
|
COLUMN_INTERNAL_NAME, &name, -1);
|
|
|
|
/* insert value (we need to update it) */
|
|
hidden = !hidden;
|
|
|
|
/* update box and store with new state */
|
|
systray_plugin_names_set_hidden (plugin, name, hidden);
|
|
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2, hidden, -1);
|
|
|
|
g_free (name);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
systray_plugin_dialog_clear_clicked (GtkWidget *button,
|
|
SystrayPlugin *plugin)
|
|
{
|
|
GtkListStore *store;
|
|
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
|
|
panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (plugin->box));
|
|
|
|
if (xfce_dialog_confirm (GTK_WINDOW (gtk_widget_get_toplevel (button)),
|
|
GTK_STOCK_CLEAR, NULL, NULL,
|
|
_("Are you sure you want to clear the list of "
|
|
"known applications?")))
|
|
{
|
|
store = g_object_get_data (G_OBJECT (plugin), "applications-store");
|
|
panel_return_if_fail (GTK_IS_LIST_STORE (store));
|
|
gtk_list_store_clear (store);
|
|
|
|
systray_plugin_names_clear (plugin);
|
|
}
|
|
}
|
|
|