diff -Nru indicator-systemtray-unity-0.2/config.h indicator-systemtray-unity-0.2.1/config.h --- indicator-systemtray-unity-0.2/config.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/config.h 2015-05-30 11:43:09.000000000 +0000 @@ -0,0 +1,67 @@ +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have a working `mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the `munmap' function. */ +#define HAVE_MUNMAP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* The left border of the window system tray. */ +#define LEFT_BOARD 5 + +/* Version number of package */ +#define VERSION "4.0.4" + diff -Nru indicator-systemtray-unity-0.2/debian/changelog indicator-systemtray-unity-0.2.1/debian/changelog --- indicator-systemtray-unity-0.2/debian/changelog 2015-04-29 20:06:36.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/debian/changelog 2015-06-03 19:30:04.000000000 +0000 @@ -1,3 +1,10 @@ +indicator-systemtray-unity (0.2.1-utopic0) utopic; urgency=medium + + * Added background settings. + * Small changes in the library "unity-misc". + + -- Gleb Golovachev Wed, 03 Jun 2015 03:03:03 +0500 + indicator-systemtray-unity (0.2-utopic0) utopic; urgency=medium * Fixed small bugs. diff -Nru indicator-systemtray-unity-0.2/debian/control indicator-systemtray-unity-0.2.1/debian/control --- indicator-systemtray-unity-0.2/debian/control 2015-04-29 19:40:31.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/debian/control 2015-06-03 11:59:37.000000000 +0000 @@ -4,8 +4,7 @@ Maintainer: Gleb Golovachev Build-Depends: debhelper (>= 7), libgtk-3-dev, - libindicator3-dev, - libunity-misc-dev + libindicator3-dev Standards-Version: 3.9.5 Homepage: https://launchpad.net/~fixnix/+archive/ubuntu/indicator-systemtray-unity diff -Nru indicator-systemtray-unity-0.2/debian/source/format indicator-systemtray-unity-0.2.1/debian/source/format --- indicator-systemtray-unity-0.2/debian/source/format 2015-04-29 19:40:31.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/debian/source/format 2015-06-03 19:24:35.000000000 +0000 @@ -1 +1 @@ -3.0 (native) +3.0 (quilt) diff -Nru indicator-systemtray-unity-0.2/fixedtip.c indicator-systemtray-unity-0.2.1/fixedtip.c --- indicator-systemtray-unity-0.2/fixedtip.c 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/fixedtip.c 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,277 @@ +/* Metacity fixed tooltip routine */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003-2006 Vincent Untz + * + * 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. + */ + +#include "fixedtip.h" + +/* Signals */ +enum +{ + CLICKED, + LAST_SIGNAL +}; + +static guint fixedtip_signals[LAST_SIGNAL] = { 0 }; + +struct _NaFixedTipPrivate +{ + GtkWidget *parent; + GtkWidget *label; + GtkOrientation orientation; +}; + +G_DEFINE_TYPE (NaFixedTip, na_fixed_tip, GTK_TYPE_WINDOW) + +static gboolean +button_press_handler (GtkWidget *fixedtip, + GdkEventButton *event, + gpointer data) +{ + if (event->button == 1 && event->type == GDK_BUTTON_PRESS) + g_signal_emit (fixedtip, fixedtip_signals[CLICKED], 0); + + return FALSE; +} + +static gboolean +na_fixed_tip_draw (GtkWidget *widget, cairo_t *cr) +{ + GtkStyleContext *context; + GtkStateFlags state; + int width, height; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + state = gtk_widget_get_state_flags (widget); + context = gtk_widget_get_style_context (widget); + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLTIP); + gtk_style_context_set_state (context, state); + + cairo_save (cr); + gtk_render_background (context, cr, + 0., 0., + (gdouble)width, + (gdouble)height); + cairo_restore (cr); + + gtk_style_context_restore (context); + + return FALSE; +} + +static void +na_fixed_tip_class_init (NaFixedTipClass *class) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + widget_class->draw = na_fixed_tip_draw; + + fixedtip_signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NaFixedTipClass, clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (class, sizeof (NaFixedTipPrivate)); +} + +/* Did you already see this code? Yes, it's gtk_tooltips_ force_window() ;-) */ +static void +na_fixed_tip_init (NaFixedTip *fixedtip) +{ + GtkWidget *label; + + fixedtip->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixedtip, NA_TYPE_FIXED_TIP, + NaFixedTipPrivate); + + gtk_window_set_type_hint (GTK_WINDOW (fixedtip), + GDK_WINDOW_TYPE_HINT_TOOLTIP); + + gtk_widget_set_app_paintable (GTK_WIDGET (fixedtip), TRUE); + gtk_window_set_resizable (GTK_WINDOW (fixedtip), FALSE); + gtk_widget_set_name (GTK_WIDGET (fixedtip), "gtk-tooltips"); + gtk_container_set_border_width (GTK_CONTAINER (fixedtip), 4); + + label = gtk_label_new (NULL); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (fixedtip), label); + fixedtip->priv->label = label; + + gtk_widget_add_events (GTK_WIDGET (fixedtip), GDK_BUTTON_PRESS_MASK); + + g_signal_connect (fixedtip, "button_press_event", + G_CALLBACK (button_press_handler), NULL); + + fixedtip->priv->orientation = GTK_ORIENTATION_HORIZONTAL; +} + +static void +na_fixed_tip_position (NaFixedTip *fixedtip) +{ + GdkScreen *screen; + GdkWindow *parent_window; + GtkRequisition req; + int root_x; + int root_y; + int parent_width; + int parent_height; + int screen_width; + int screen_height; + + screen = gtk_widget_get_screen (fixedtip->priv->parent); + parent_window = gtk_widget_get_window (fixedtip->priv->parent); + + gtk_window_set_screen (GTK_WINDOW (fixedtip), screen); + + gtk_widget_get_preferred_size (GTK_WIDGET (fixedtip), &req, NULL); + + gdk_window_get_origin (parent_window, &root_x, &root_y); + parent_width = gdk_window_get_width (parent_window); + parent_height = gdk_window_get_height (parent_window); + + screen_width = gdk_screen_get_width (screen); + screen_height = gdk_screen_get_height (screen); + + /* pad between panel and message window */ +#define PAD 5 + + if (fixedtip->priv->orientation == GTK_ORIENTATION_VERTICAL) + { + if (root_x <= screen_width / 2) + root_x += parent_width + PAD; + else + root_x -= req.width + PAD; + } + else + { + if (root_y <= screen_height / 2) + root_y += parent_height + PAD; + else + root_y -= req.height + PAD; + } + + /* Push onscreen */ + if ((root_x + req.width) > screen_width) + root_x = screen_width - req.width; + + if ((root_y + req.height) > screen_height) + root_y = screen_height - req.height; + + gtk_window_move (GTK_WINDOW (fixedtip), root_x, root_y); +} + +static void +na_fixed_tip_parent_size_allocated (GtkWidget *parent, + GtkAllocation *allocation, + NaFixedTip *fixedtip) +{ + na_fixed_tip_position (fixedtip); +} + +static void +na_fixed_tip_parent_screen_changed (GtkWidget *parent, + GdkScreen *new_screen, + NaFixedTip *fixedtip) +{ + na_fixed_tip_position (fixedtip); +} + +GtkWidget * +na_fixed_tip_new (GtkWidget *parent, + GtkOrientation orientation) +{ + NaFixedTip *fixedtip; + + g_return_val_if_fail (parent != NULL, NULL); + + fixedtip = g_object_new (NA_TYPE_FIXED_TIP, + "type", GTK_WINDOW_POPUP, + NULL); + + fixedtip->priv->parent = parent; + +#if 0 + //FIXME: would be nice to be able to get the toplevel for the tip, but this + //doesn't work + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (parent); + /* + if (toplevel && gtk_widget_is_toplevel (toplevel) && GTK_IS_WINDOW (toplevel)) + gtk_window_set_transient_for (GTK_WINDOW (fixedtip), GTK_WINDOW (toplevel)); + */ +#endif + + fixedtip->priv->orientation = orientation; + + //FIXME: would be nice to move the tip when the notification area moves + g_signal_connect_object (parent, "size-allocate", + G_CALLBACK (na_fixed_tip_parent_size_allocated), + fixedtip, 0); + g_signal_connect_object (parent, "screen-changed", + G_CALLBACK (na_fixed_tip_parent_screen_changed), + fixedtip, 0); + + na_fixed_tip_position (fixedtip); + + return GTK_WIDGET (fixedtip); +} + +void +na_fixed_tip_set_markup (GtkWidget *widget, + const char *markup_text) +{ + NaFixedTip *fixedtip; + + g_return_if_fail (NA_IS_FIXED_TIP (widget)); + + fixedtip = NA_FIXED_TIP (widget); + + gtk_label_set_markup (GTK_LABEL (fixedtip->priv->label), + markup_text); + + na_fixed_tip_position (fixedtip); +} + +void +na_fixed_tip_set_orientation (GtkWidget *widget, + GtkOrientation orientation) +{ + NaFixedTip *fixedtip; + + g_return_if_fail (NA_IS_FIXED_TIP (widget)); + + fixedtip = NA_FIXED_TIP (widget); + + if (orientation == fixedtip->priv->orientation) + return; + + fixedtip->priv->orientation = orientation; + + na_fixed_tip_position (fixedtip); +} diff -Nru indicator-systemtray-unity-0.2/fixedtip.h indicator-systemtray-unity-0.2.1/fixedtip.h --- indicator-systemtray-unity-0.2/fixedtip.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/fixedtip.h 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,68 @@ +/* Fixed tooltip routine */ + +/* + * Copyright (C) 2001 Havoc Pennington, 2002 Red Hat Inc. + * Copyright (C) 2003-2006 Vincent Untz + * + * 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 FIXED_TIP_H +#define FIXED_TIP_H + +#include + +G_BEGIN_DECLS + +#define NA_TYPE_FIXED_TIP (na_fixed_tip_get_type ()) +#define NA_FIXED_TIP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_FIXED_TIP, NaFixedTip)) +#define NA_FIXED_TIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_FIXED_TIP, NaFixedTipClass)) +#define NA_IS_FIXED_TIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_FIXED_TIP)) +#define NA_IS_FIXED_TIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_FIXED_TIP)) +#define NA_FIXED_TIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_FIXED_TIP, NaFixedTipClass)) + +typedef struct _NaFixedTip NaFixedTip; +typedef struct _NaFixedTipPrivate NaFixedTipPrivate; +typedef struct _NaFixedTipClass NaFixedTipClass; + +struct _NaFixedTip +{ + GtkWindow parent_instance; + + NaFixedTipPrivate *priv; +}; + +struct _NaFixedTipClass +{ + GtkWindowClass parent_class; + + void (* clicked) (NaFixedTip *fixedtip); +}; + +GType na_fixed_tip_get_type (void); + +GtkWidget *na_fixed_tip_new (GtkWidget *parent, + GtkOrientation orientation); + +void na_fixed_tip_set_markup (GtkWidget *widget, + const char *markup_text); + +void na_fixed_tip_set_orientation (GtkWidget *widget, + GtkOrientation orientation); + +G_END_DECLS + +#endif /* FIXED_TIP_H */ diff -Nru indicator-systemtray-unity-0.2/gnome-bg-slideshow.c indicator-systemtray-unity-0.2.1/gnome-bg-slideshow.c --- indicator-systemtray-unity-0.2/gnome-bg-slideshow.c 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/gnome-bg-slideshow.c 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,440 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- + +gnomebg.c: Object for the desktop background. + +Copyright (C) 2000 Eazel, Inc. +Copyright (C) 2007-2008 Red Hat, Inc. +Copyright (C) 2011 Canonical Ltd. + +This program 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 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library 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. + +Derived from eel-background.c and eel-gdk-pixbuf-extensions.c by +Darin Adler and Ramiro Estrugo + +Authors: Soren Sandmann + Gordon Allott + +*/ + +/* Basically ripped apart gnome-bg so i can get access to the slideshow + * data, so i can sync with gnome-bg's transitions without using gnome-bg's + * transitions + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "gnome-bg-slideshow.h" + + + + +static double +now (void) +{ + GTimeVal tv; + + g_get_current_time (&tv); + + return (double)tv.tv_sec + (tv.tv_usec / 1000000.0); +} + +Slide * +get_current_slide (SlideShow *show, + double *alpha) +{ + double delta = fmod (now() - show->start_time, show->total_duration); + GList *list; + double elapsed; + int i; + + if (delta < 0) + delta += show->total_duration; + + elapsed = 0; + i = 0; + for (list = show->slides->head; list != NULL; list = list->next) { + Slide *slide = list->data; + + if (elapsed + slide->duration > delta) { + if (alpha) + *alpha = (delta - elapsed) / (double)slide->duration; + return slide; + } + + i++; + elapsed += slide->duration; + } + + /* this should never happen since we have slides and we should always + * find a current slide for the elapsed time since beginning -- we're + * looping with fmod() */ + g_assert_not_reached (); + + return NULL; +} + + +double +get_slide_timeout (Slide *slide) +{ + double timeout; + if (slide->fixed) { + timeout = slide->duration; + } else { + /* Maybe the number of steps should be configurable? */ + + /* In the worst case we will do a fade from 0 to 256, which mean + * we will never use more than 255 steps, however in most cases + * the first and last value are similar and users can't percieve + * changes in pixel values as small as 1/255th. So, lets not waste + * CPU cycles on transitioning to often. + * + * 64 steps is enough for each step to be just detectable in a 16bit + * color mode in the worst case, so we'll use this as an approximation + * of whats detectable. + */ + timeout = slide->duration / 64.0; + } + return timeout; +} + +static gboolean stack_is (SlideShow *parser, const char *s1, ...); + +/* Parser for fading background */ +static void +handle_start_element (GMarkupParseContext *context, + const gchar *name, + const gchar **attr_names, + const gchar **attr_values, + gpointer user_data, + GError **err) +{ + SlideShow *parser = user_data; + gint i; + + if (strcmp (name, "static") == 0 || strcmp (name, "transition") == 0) { + Slide *slide = g_new0 (Slide, 1); + + if (strcmp (name, "static") == 0) + slide->fixed = TRUE; + + g_queue_push_tail (parser->slides, slide); + } + else if (strcmp (name, "size") == 0) { + Slide *slide = parser->slides->tail->data; + FileSize *size = g_new0 (FileSize, 1); + for (i = 0; attr_names[i]; i++) { + if (strcmp (attr_names[i], "width") == 0) + size->width = atoi (attr_values[i]); + else if (strcmp (attr_names[i], "height") == 0) + size->height = atoi (attr_values[i]); + } + if (parser->stack->tail && + (strcmp (parser->stack->tail->data, "file") == 0 || + strcmp (parser->stack->tail->data, "from") == 0)) { + slide->file1 = g_slist_prepend (slide->file1, size); + } + else if (parser->stack->tail && + strcmp (parser->stack->tail->data, "to") == 0) { + slide->file2 = g_slist_prepend (slide->file2, size); + } + } + g_queue_push_tail (parser->stack, g_strdup (name)); +} + +static void +handle_end_element (GMarkupParseContext *context, + const gchar *name, + gpointer user_data, + GError **err) +{ + SlideShow *parser = user_data; + + g_free (g_queue_pop_tail (parser->stack)); +} + +static gboolean +stack_is (SlideShow *parser, + const char *s1, + ...) +{ + GList *stack = NULL; + const char *s; + GList *l1, *l2; + va_list args; + + stack = g_list_prepend (stack, (gpointer)s1); + + va_start (args, s1); + + s = va_arg (args, const char *); + while (s) { + stack = g_list_prepend (stack, (gpointer)s); + s = va_arg (args, const char *); + } + + l1 = stack; + l2 = parser->stack->head; + + while (l1 && l2) { + if (strcmp (l1->data, l2->data) != 0) { + g_list_free (stack); + return FALSE; + } + + l1 = l1->next; + l2 = l2->next; + } + + g_list_free (stack); + + return (!l1 && !l2); +} + +static int +parse_int (const char *text) +{ + return strtol (text, NULL, 0); +} + +static void +handle_text (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **err) +{ + SlideShow *parser = user_data; + Slide *slide = parser->slides->tail? parser->slides->tail->data : NULL; + FileSize *fs; + gint i; + + if (stack_is (parser, "year", "starttime", "background", NULL)) { + parser->start_tm.tm_year = parse_int (text) - 1900; + } + else if (stack_is (parser, "month", "starttime", "background", NULL)) { + parser->start_tm.tm_mon = parse_int (text) - 1; + } + else if (stack_is (parser, "day", "starttime", "background", NULL)) { + parser->start_tm.tm_mday = parse_int (text); + } + else if (stack_is (parser, "hour", "starttime", "background", NULL)) { + parser->start_tm.tm_hour = parse_int (text) - 1; + } + else if (stack_is (parser, "minute", "starttime", "background", NULL)) { + parser->start_tm.tm_min = parse_int (text); + } + else if (stack_is (parser, "second", "starttime", "background", NULL)) { + parser->start_tm.tm_sec = parse_int (text); + } + else if (stack_is (parser, "duration", "static", "background", NULL) || + stack_is (parser, "duration", "transition", "background", NULL)) { + slide->duration = g_strtod (text, NULL); + parser->total_duration += slide->duration; + } + else if (stack_is (parser, "file", "static", "background", NULL) || + stack_is (parser, "from", "transition", "background", NULL)) { + for (i = 0; text[i]; i++) { + if (!g_ascii_isspace (text[i])) + break; + } + if (text[i] == 0) + return; + fs = g_new (FileSize, 1); + fs->width = -1; + fs->height = -1; + fs->file = g_strdup (text); + slide->file1 = g_slist_prepend (slide->file1, fs); + if (slide->file1->next != NULL) + parser->has_multiple_sizes = TRUE; + } + else if (stack_is (parser, "size", "file", "static", "background", NULL) || + stack_is (parser, "size", "from", "transition", "background", NULL)) { + fs = slide->file1->data; + fs->file = g_strdup (text); + if (slide->file1->next != NULL) + parser->has_multiple_sizes = TRUE; + } + else if (stack_is (parser, "to", "transition", "background", NULL)) { + for (i = 0; text[i]; i++) { + if (!g_ascii_isspace (text[i])) + break; + } + if (text[i] == 0) + return; + fs = g_new (FileSize, 1); + fs->width = -1; + fs->height = -1; + fs->file = g_strdup (text); + slide->file2 = g_slist_prepend (slide->file2, fs); + if (slide->file2->next != NULL) + parser->has_multiple_sizes = TRUE; + } + else if (stack_is (parser, "size", "to", "transition", "background", NULL)) { + fs = slide->file2->data; + fs->file = g_strdup (text); + if (slide->file2->next != NULL) + parser->has_multiple_sizes = TRUE; + } +} + +SlideShow * +slideshow_ref (SlideShow *show) +{ + show->ref_count++; + return show; +} + +void +slideshow_unref (SlideShow *show) +{ + GList *list; + GSList *slist; + FileSize *size; + + show->ref_count--; + if (show->ref_count > 0) + return; + + for (list = show->slides->head; list != NULL; list = list->next) { + Slide *slide = list->data; + + for (slist = slide->file1; slist != NULL; slist = slist->next) { + size = slist->data; + g_free (size->file); + g_free (size); + } + g_slist_free (slide->file1); + + for (slist = slide->file2; slist != NULL; slist = slist->next) { + size = slist->data; + g_free (size->file); + g_free (size); + } + g_slist_free (slide->file2); + + g_free (slide); + } + + g_queue_free (show->slides); + + g_list_foreach (show->stack->head, (GFunc) g_free, NULL); + g_queue_free (show->stack); + + g_free (show); +} + +static void +threadsafe_localtime (time_t threadsafe_time, struct tm *tm) +{ + struct tm *res; + + G_LOCK_DEFINE_STATIC (localtime_mutex); + + G_LOCK (localtime_mutex); + + res = localtime (&threadsafe_time); + if (tm) { + *tm = *res; + } + + G_UNLOCK (localtime_mutex); +} + +SlideShow * +read_slideshow_file (const char *filename, + GError **err) +{ + GMarkupParser parser = { + handle_start_element, + handle_end_element, + handle_text, + NULL, /* passthrough */ + NULL, /* error */ + }; + + GFile *file; + char *contents = NULL; + gsize len; + SlideShow *show = NULL; + GMarkupParseContext *context = NULL; + time_t t; + + if (!filename) + return NULL; + + file = g_file_new_for_path (filename); + if (!g_file_load_contents (file, NULL, &contents, &len, NULL, NULL)) { + g_object_unref (file); + return NULL; + } + g_object_unref (file); + + show = g_new0 (SlideShow, 1); + show->ref_count = 1; + threadsafe_localtime ((time_t)0, &show->start_tm); + show->stack = g_queue_new (); + show->slides = g_queue_new (); + + context = g_markup_parse_context_new (&parser, 0, show, NULL); + + if (!g_markup_parse_context_parse (context, contents, len, err)) { + slideshow_unref (show); + show = NULL; + } + + + if (show) { + if (!g_markup_parse_context_end_parse (context, err)) { + slideshow_unref (show); + show = NULL; + } + } + + g_markup_parse_context_free (context); + + if (show) { + int show_len; + + t = mktime (&show->start_tm); + + show->start_time = (double)t; + + show_len = g_queue_get_length (show->slides); + + /* no slides, that's not a slideshow */ + if (show_len == 0) { + slideshow_unref (show); + show = NULL; + /* one slide, there's no transition */ + } else if (show_len == 1) { + Slide *slide = show->slides->head->data; + slide->duration = G_MAXUINT; + } + } + + g_free (contents); + + return show; +} diff -Nru indicator-systemtray-unity-0.2/gnome-bg-slideshow.h indicator-systemtray-unity-0.2.1/gnome-bg-slideshow.h --- indicator-systemtray-unity-0.2/gnome-bg-slideshow.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/gnome-bg-slideshow.h 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,76 @@ +/* gnome-bg.h - + + Copyright 2007, Red Hat, Inc. + + This file is part of the Gnome Library. + + The Gnome 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. + + The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Soren Sandmann +*/ + +#ifndef __GNOME_BG_SLIDESHOW__ +#define __GNOME_BG_SLIDESHOW__ + +#include + +G_BEGIN_DECLS +typedef struct _SlideShow SlideShow; +typedef struct _Slide Slide; +typedef struct _FileSize FileSize; + +struct _FileSize +{ + gint width; + gint height; + + char *file; +}; +struct _Slide +{ + double duration; /* in seconds */ + gboolean fixed; + + GSList *file1; + GSList *file2; /* NULL if fixed is TRUE */ +}; + +struct _SlideShow +{ + gint ref_count; + double start_time; + double total_duration; + + GQueue *slides; + + gboolean has_multiple_sizes; + + /* used during parsing */ + struct tm start_tm; + GQueue *stack; +}; + +Slide *get_current_slide (SlideShow *show, + double *alpha); +SlideShow *read_slideshow_file (const char *filename, + GError **err); +SlideShow *slideshow_ref (SlideShow *show); +void slideshow_unref (SlideShow *show); + + +G_END_DECLS + +#endif diff -Nru indicator-systemtray-unity-0.2/indicator-systemtray.c indicator-systemtray-unity-0.2.1/indicator-systemtray.c --- indicator-systemtray-unity-0.2/indicator-systemtray.c 2015-04-29 19:40:31.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/indicator-systemtray.c 2015-06-03 07:13:43.000000000 +0000 @@ -14,14 +14,19 @@ with this program. If not, see . */ +#include "config.h" /* Indicator Stuff */ #include #include //#include -//#include -//#include -#include +//#include "na-tray-manager.h" +//#include "na-tray-child.h" +#include "na-tray.h" +#include + +#define GETTEXT_PACKAGE "indicator-systemtray-unity" +#define LOCALEDIR "/usr/share/locale" #define INDICATOR_SYSTEMTRAY_TYPE (indicator_systemtray_get_type ()) #define INDICATOR_SYSTEMTRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SYSTEMTRAY_TYPE, IndicatorSystemtray)) @@ -59,25 +64,43 @@ gboolean hide_menu_is_active; GtkImage *image; GtkMenu *menu; + GtkWidget *settings_item; + GtkWidget *static_show_item; + GtkWidget *floating_show_item; gchar *accessible_desc; - + GtkWidget *fixed; + gboolean show_background_static; + gchar *bg_static; + gchar *bg_static_stroke; + gboolean show_background_floating; + gchar *bg_floating; + gchar *bg_floating_stroke; GSettings *settings; }; #define INDICATOR_SYSTEMTRAY_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SYSTEMTRAY_TYPE, IndicatorSystemtrayPrivate)) -#define SYSTEMTRAY_SCHEMA "net.launchpad.indicator.systemtray" -#define SYSTEMTRAY_KEY_DISABLE_INDICATOR "disable-indicator" -#define SYSTEMTRAY_KEY_IS_FIRST_TIME "started-the-first-time" -#define SYSTEMTRAY_KEY_TRAY_IS_STATIC "tray-is-static" -#define SYSTEMTRAY_KEY_STATIC_X "static-x" -#define SYSTEMTRAY_KEY_STATIC_Y "static-y" +#define SYSTEMTRAY_SCHEMA "net.launchpad.indicator.systemtray" +#define SYSTEMTRAY_KEY_DISABLE_INDICATOR "disable-indicator" +#define SYSTEMTRAY_KEY_IS_FIRST_TIME "started-the-first-time" +#define SYSTEMTRAY_KEY_TRAY_IS_STATIC "tray-is-static" +#define SYSTEMTRAY_KEY_STATIC_X "static-x" +#define SYSTEMTRAY_KEY_STATIC_Y "static-y" + +#define SYSTEMTRAY_KEY_STATIC_SHOW_BG "show-background-static" +#define SYSTEMTRAY_KEY_STATIC_BG "rgba-static" +#define SYSTEMTRAY_KEY_STATIC_BG_STROKE "rgba-static-stroke" + +#define SYSTEMTRAY_KEY_FLOATING_SHOW_BG "show-background-floating" +#define SYSTEMTRAY_KEY_FLOATING_BG "rgba-floating" +#define SYSTEMTRAY_KEY_FLOATING_BG_STROKE "rgba-floating-stroke" + +#define SYSTEMTRAY_ICON_WIDTH 23 +#define SYSTEMTRAY_TRAY_TOP 24 +#define SYSTEMTRAY_TRAY_HEIGHT 24 -#define SYSTEMTRAY_ICON_WIDTH 23 -#define SYSTEMTRAY_TRAY_TOP 24 - -#define INDICATOR_ICON_SYSTEMTRAY "indicator-systemtray-unity" +#define INDICATOR_ICON_SYSTEMTRAY "indicator-systemtray-unity" GType indicator_systemtray_get_type(void); @@ -98,17 +121,30 @@ static void update_position_tray(gpointer user_data); static void update_indicator_visibility(IndicatorSystemtray *self); static void mouse_get_position(gint *x, gint *y); +static gboolean parse_rgb_value(const gchar *str, gchar **endp, gdouble *number); +static gboolean rgba_parse(GdkRGBA *rgba, const gchar *spec); +static gchar *rgba_to_string(const GdkRGBA *rgba, gdouble format); +static gboolean color_chooser(GdkRGBA *color, const gchar *title); + /* Callbacks */ static void menu_visible_notify_cb(GtkWidget *menu, GParamSpec *pspec, gpointer user_data); static gboolean on_window_expose (GtkWidget *window, cairo_t *cr, gpointer user_data); static gint width_of_tray(gpointer user_data); static gboolean filter_tray_cb(NaTray* tray, NaTrayChild* icon, gpointer user_data); static void on_tray_icon_removed(NaTrayManager* manager, NaTrayChild* removed, gpointer user_data); +static void static_color_bg_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data); +static void static_color_bg_stroke_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data); +static void static_color_bg_reset_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data); +static void floating_color_bg_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data); +static void floating_color_bg_stroke_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data); +static void floating_color_bg_reset_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data); +static void static_show_item_toggled(GtkCheckMenuItem *menu_item, gpointer user_data); +static void floating_show_item_toggled(GtkCheckMenuItem *menu_item, gpointer user_data); static void setting_changed_cb(GSettings *settings, gchar *key, gpointer user_data); static void set_position_menu(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data); +static gboolean show_tray(gpointer user_data); static gboolean hide_tray(gpointer user_data); static gboolean hide_menu(gpointer user_data); -static void setting_changed_cb(GSettings *settings, gchar *key, gpointer user_data); /* Indicator Module Config */ INDICATOR_SET_VERSION @@ -138,6 +174,9 @@ static void indicator_systemtray_init(IndicatorSystemtray *self) { self->priv = INDICATOR_SYSTEMTRAY_GET_PRIVATE(self); + bindtextdomain( GETTEXT_PACKAGE, LOCALEDIR ); + textdomain( GETTEXT_PACKAGE ); + self->priv->menu = NULL; self->priv->image = NULL; self->priv->count_tray_icon = 0; @@ -170,16 +209,72 @@ g_settings_set_int(self->priv->settings, SYSTEMTRAY_KEY_STATIC_Y, self->priv->static_y); } + self->priv->show_background_static = g_settings_get_boolean(self->priv->settings, SYSTEMTRAY_KEY_STATIC_SHOW_BG); + self->priv->bg_static = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG); + self->priv->bg_static_stroke = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG_STROKE); + self->priv->show_background_floating = g_settings_get_boolean(self->priv->settings, SYSTEMTRAY_KEY_FLOATING_SHOW_BG); + self->priv->bg_floating = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG); + self->priv->bg_floating_stroke = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG_STROKE); + self->priv->hide_tray_is_active = FALSE; self->priv->hide_menu_is_active = FALSE; + self->priv->menu = GTK_MENU( gtk_menu_new() ); + self->priv->settings_item = gtk_menu_item_new_with_label( _("Settings") ); + gtk_menu_shell_append( GTK_MENU_SHELL(self->priv->menu), self->priv->settings_item ); + GtkWidget *settings_sub = gtk_menu_new(); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(self->priv->settings_item), settings_sub ); +//--- + GtkWidget *background_item = gtk_menu_item_new_with_label( _("Background") ); + gtk_menu_shell_append( GTK_MENU_SHELL(settings_sub), background_item ); + GtkWidget *background_sub = gtk_menu_new(); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(background_item), background_sub ); +//---- + GtkWidget *static_item = gtk_menu_item_new_with_label( _("Static") ); + gtk_menu_shell_append( GTK_MENU_SHELL(background_sub), static_item ); + GtkWidget *static_sub = gtk_menu_new(); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(static_item), static_sub ); +//----- + GtkWidget *static_color_bg_item = gtk_menu_item_new_with_label( _("Color") ); + gtk_menu_shell_append( GTK_MENU_SHELL(static_sub), static_color_bg_item ); + g_signal_connect( G_OBJECT(static_color_bg_item), "activate", G_CALLBACK(static_color_bg_item_activate), self ); + GtkWidget *static_color_bg_stroke_item = gtk_menu_item_new_with_label( _("Stroke") ); + gtk_menu_shell_append( GTK_MENU_SHELL(static_sub), static_color_bg_stroke_item ); + g_signal_connect( G_OBJECT(static_color_bg_stroke_item), "activate", G_CALLBACK(static_color_bg_stroke_item_activate), self ); + self->priv->static_show_item = gtk_check_menu_item_new_with_label( _("Show") ); + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(self->priv->static_show_item), self->priv->show_background_static ); + gtk_menu_shell_append( GTK_MENU_SHELL(static_sub), self->priv->static_show_item ); + g_signal_connect( G_OBJECT(self->priv->static_show_item), "toggled", G_CALLBACK(static_show_item_toggled), self ); + GtkWidget *static_color_bg_reset_item = gtk_menu_item_new_with_label( _("Reset") ); + gtk_menu_shell_append( GTK_MENU_SHELL(static_sub), static_color_bg_reset_item ); + g_signal_connect( G_OBJECT(static_color_bg_reset_item), "activate", G_CALLBACK(static_color_bg_reset_item_activate), self ); +//---- + GtkWidget *floating_item = gtk_menu_item_new_with_label( _("Floating") ); + gtk_menu_shell_append( GTK_MENU_SHELL(background_sub), floating_item ); + GtkWidget *floating_sub = gtk_menu_new(); + gtk_menu_item_set_submenu( GTK_MENU_ITEM(floating_item), floating_sub ); +//----- + GtkWidget *floating_color_bg_item = gtk_menu_item_new_with_label( _("Color") ); + gtk_menu_shell_append( GTK_MENU_SHELL(floating_sub), floating_color_bg_item ); + g_signal_connect( G_OBJECT(floating_color_bg_item), "activate", G_CALLBACK(floating_color_bg_item_activate), self ); + GtkWidget *floating_color_bg_stroke_item = gtk_menu_item_new_with_label( _("Stroke") ); + gtk_menu_shell_append( GTK_MENU_SHELL(floating_sub), floating_color_bg_stroke_item ); + g_signal_connect( G_OBJECT(floating_color_bg_stroke_item), "activate", G_CALLBACK(floating_color_bg_stroke_item_activate), self ); + self->priv->floating_show_item = gtk_check_menu_item_new_with_label( _("Show") ); + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(self->priv->floating_show_item), self->priv->show_background_floating ); + gtk_menu_shell_append( GTK_MENU_SHELL(floating_sub), self->priv->floating_show_item ); + g_signal_connect( G_OBJECT(self->priv->floating_show_item), "toggled", G_CALLBACK(floating_show_item_toggled), self ); + GtkWidget *floating_color_bg_reset_item = gtk_menu_item_new_with_label( _("Reset") ); + gtk_menu_shell_append( GTK_MENU_SHELL(floating_sub), floating_color_bg_reset_item ); + g_signal_connect( G_OBJECT(floating_color_bg_reset_item), "activate", G_CALLBACK(floating_color_bg_reset_item_activate), self ); + self->priv->window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_window_set_type_hint( GTK_WINDOW (self->priv->window), GDK_WINDOW_TYPE_HINT_DOCK ); gtk_window_set_has_resize_grip( GTK_WINDOW (self->priv->window), FALSE ); gtk_window_set_keep_above( GTK_WINDOW (self->priv->window), TRUE ); gtk_window_set_skip_pager_hint( GTK_WINDOW (self->priv->window), TRUE ); gtk_window_set_skip_taskbar_hint( GTK_WINDOW (self->priv->window), TRUE ); - gtk_window_set_gravity(GTK_WINDOW(self->priv->window), GDK_GRAVITY_NORTH_EAST); + gtk_window_set_gravity( GTK_WINDOW(self->priv->window), GDK_GRAVITY_NORTH_EAST ); gtk_widget_set_name( self->priv->window, "UnityPanelApplet" ); gtk_widget_set_visual( self->priv->window, gdk_screen_get_rgba_visual(gdk_screen_get_default()) ); gtk_widget_realize( self->priv->window ); @@ -189,12 +284,26 @@ self->priv->tray = na_tray_new_for_screen( gdk_screen_get_default(), GTK_ORIENTATION_HORIZONTAL, (NaTrayFilterCallback)filter_tray_cb, self ); g_signal_connect( na_tray_get_manager(self->priv->tray), "tray_icon_removed", G_CALLBACK(on_tray_icon_removed), self ); - gtk_container_add( GTK_CONTAINER(self->priv->window), GTK_WIDGET(self->priv->tray) ); + GtkWidget *fixed; + fixed = gtk_fixed_new (); + self->priv->fixed = fixed; + gtk_container_add (GTK_CONTAINER (self->priv->window), self->priv->fixed); + gtk_widget_show (self->priv->fixed); + gtk_fixed_put (GTK_FIXED (self->priv->fixed), GTK_WIDGET(self->priv->tray), LEFT_BOARD, 0); + gtk_widget_show( GTK_WIDGET(self->priv->tray) ); gtk_widget_show_all( self->priv->window ); + gtk_widget_show_all( GTK_WIDGET(self->priv->menu) ); + if (self->priv->tray_is_static) { + gtk_widget_show( self->priv->settings_item ); + } + else { + gtk_widget_hide( self->priv->settings_item ); + } gtk_widget_hide( self->priv->window ); g_signal_connect( self->priv->menu, "notify::visible", G_CALLBACK(menu_visible_notify_cb), self ); - gtk_window_resize( GTK_WINDOW(self->priv->window), 1, 24 ); + gtk_widget_set_size_request( GTK_WIDGET(self->priv->tray), 1, SYSTEMTRAY_TRAY_HEIGHT ); + gtk_window_resize( GTK_WINDOW(self->priv->window), 1, SYSTEMTRAY_TRAY_HEIGHT ); } } @@ -248,7 +357,7 @@ static GtkMenu *get_menu(IndicatorObject *io) { IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( io ); - return GTK_MENU( self->priv->menu ); + return self->priv->menu; } static const gchar *get_accessible_desc(IndicatorObject *io) { @@ -274,6 +383,83 @@ g_settings_set_boolean( self->priv->settings, SYSTEMTRAY_KEY_TRAY_IS_STATIC, self->priv->tray_is_static ); } +static gboolean color_chooser(GdkRGBA *color, const gchar *title) { + GtkWidget *colorseldlg; + gint response_id; + gboolean response_check = FALSE; + colorseldlg = gtk_color_chooser_dialog_new( title, NULL ); + gtk_color_chooser_set_rgba( GTK_COLOR_CHOOSER (colorseldlg), color ); + + response_id = gtk_dialog_run( GTK_DIALOG(colorseldlg) ); + if(response_id == GTK_RESPONSE_OK) { + gtk_color_chooser_get_rgba( GTK_COLOR_CHOOSER(colorseldlg), color ); + response_check = TRUE; + } + + gtk_widget_destroy( colorseldlg ); + return response_check; +} + +static void static_color_bg_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + GdkRGBA color; + rgba_parse( &color, self->priv->bg_static ); + if(color_chooser(&color, _("Color"))) { + g_settings_set_string( self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG, rgba_to_string(&color, 255) ); + } +} + +static void static_color_bg_stroke_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + GdkRGBA color; + rgba_parse( &color, self->priv->bg_static_stroke ); + if(color_chooser(&color, _("Stroke"))) { + g_settings_set_string( self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG_STROKE, rgba_to_string(&color, 255) ); + } +} + +static void static_color_bg_reset_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + g_settings_reset( self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG ); + g_settings_reset( self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG_STROKE ); + g_settings_reset( self->priv->settings, SYSTEMTRAY_KEY_STATIC_SHOW_BG ); +} + +static void floating_color_bg_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + GdkRGBA color; + rgba_parse( &color, self->priv->bg_floating ); + if(color_chooser(&color, _("Color"))) { + g_settings_set_string( self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG, rgba_to_string(&color, 255) ); + } +} + +static void floating_color_bg_stroke_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + GdkRGBA color; + rgba_parse( &color, self->priv->bg_floating_stroke ); + if(color_chooser(&color, _("Stroke"))) { + g_settings_set_string( self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG_STROKE, rgba_to_string(&color, 255) ); + } +} + +static void floating_color_bg_reset_item_activate(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + g_settings_reset( self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG ); + g_settings_reset( self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG_STROKE ); + g_settings_reset( self->priv->settings, SYSTEMTRAY_KEY_FLOATING_SHOW_BG ); +} + +static void static_show_item_toggled(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + g_settings_set_boolean( self->priv->settings, SYSTEMTRAY_KEY_STATIC_SHOW_BG, gtk_check_menu_item_get_active( menu_item ) ); +} + +static void floating_show_item_toggled(GtkCheckMenuItem *menu_item, gpointer user_data) { + IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + g_settings_set_boolean( self->priv->settings, SYSTEMTRAY_KEY_FLOATING_SHOW_BG, gtk_check_menu_item_get_active( menu_item ) ); +} + /** * setting_changed_cb: * @settings: the GSettings object @@ -299,8 +485,13 @@ if (self->priv->tray_is_static) { gtk_widget_show( self->priv->window ); gtk_window_move( GTK_WINDOW(self->priv->window), self->priv->static_x, self->priv->static_y ); + gtk_widget_show( self->priv->settings_item ); + } + else { + gtk_widget_hide( self->priv->window ); + gtk_widget_hide( self->priv->settings_item ); } - else gtk_widget_hide( self->priv->window ); + gtk_widget_queue_draw( self->priv->window ); } else if (g_strcmp0(key, SYSTEMTRAY_KEY_STATIC_X) == 0) { self->priv->static_x = g_settings_get_int(self->priv->settings, SYSTEMTRAY_KEY_STATIC_X); @@ -312,24 +503,235 @@ if (self->priv->tray_is_static) gtk_window_move( GTK_WINDOW(self->priv->window), self->priv->static_x, self->priv->static_y ); } + else if (g_strcmp0(key, SYSTEMTRAY_KEY_STATIC_SHOW_BG) == 0) { + self->priv->show_background_static = g_settings_get_boolean(self->priv->settings, SYSTEMTRAY_KEY_STATIC_SHOW_BG); + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(self->priv->static_show_item)) != self->priv->show_background_static) + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(self->priv->static_show_item), self->priv->show_background_static ); + gtk_widget_queue_draw( self->priv->window ); + } + else if (g_strcmp0(key, SYSTEMTRAY_KEY_STATIC_BG) == 0) { + self->priv->bg_static = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG); + gtk_widget_queue_draw( self->priv->window ); + } + else if (g_strcmp0(key, SYSTEMTRAY_KEY_STATIC_BG_STROKE) == 0) { + self->priv->bg_static_stroke = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_STATIC_BG_STROKE); + gtk_widget_queue_draw( self->priv->window ); + } + else if (g_strcmp0(key, SYSTEMTRAY_KEY_FLOATING_SHOW_BG) == 0) { + self->priv->show_background_floating = g_settings_get_boolean(self->priv->settings, SYSTEMTRAY_KEY_FLOATING_SHOW_BG); + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(self->priv->floating_show_item)) != self->priv->show_background_floating) + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(self->priv->floating_show_item), self->priv->show_background_floating ); + gtk_widget_queue_draw( self->priv->window ); + } + else if (g_strcmp0(key, SYSTEMTRAY_KEY_FLOATING_BG) == 0) { + self->priv->bg_floating = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG); + gtk_widget_queue_draw( self->priv->window ); + } + else if (g_strcmp0(key, SYSTEMTRAY_KEY_FLOATING_BG_STROKE) == 0) { + self->priv->bg_floating_stroke = g_settings_get_string(self->priv->settings, SYSTEMTRAY_KEY_FLOATING_BG_STROKE); + if (gtk_widget_is_visible(self->priv->window)) + gtk_widget_queue_draw( self->priv->window ); + } +} + +#define SKIP_WHITESPACES(s) while (*(s) == ' ') (s)++; + +static gboolean parse_rgb_value (const gchar *str, gchar **endp, gdouble *number) +{ + const char *p; + + *number = g_ascii_strtod (str, endp); + + if (*endp == str) + return FALSE; + + p = *endp; + + SKIP_WHITESPACES (p); + + if (*p == '%') + { + *endp = (char *)(p + 1); + *number = CLAMP(*number / 100., 0., 1.); + } + else + { + *number = CLAMP(*number / 255., 0., 1.); + } + + return TRUE; +} + +static gboolean rgba_parse (GdkRGBA *rgba, const gchar *spec) +{ + gboolean has_alpha; + gdouble r, g, b, a; + gchar *str = (gchar *) spec; + + g_return_val_if_fail (spec != NULL, FALSE); + + + if(g_ascii_strncasecmp (str, "rgba", 4) == 0) + { + has_alpha = TRUE; + str += 4; + } + else if (g_ascii_strncasecmp (str, "rgb", 3) == 0) + { + has_alpha = FALSE; + a = 1; + str += 3; + } + else + { + PangoColor pango_color; + + /* Resort on PangoColor for rgb.txt color + * map and '#' prefixed colors + */ + if (pango_color_parse (&pango_color, str)) + { + if (rgba) + { + rgba->red = pango_color.red / 65535.; + rgba->green = pango_color.green / 65535.; + rgba->blue = pango_color.blue / 65535.; + rgba->alpha = 1; + } + + return TRUE; + } + else + return FALSE; + } + + SKIP_WHITESPACES (str); + + if (*str != '(') + return FALSE; + + str++; + + /* Parse red */ + SKIP_WHITESPACES (str); + if (!parse_rgb_value (str, &str, &r)) + return FALSE; + SKIP_WHITESPACES (str); + + if (*str != ',') + return FALSE; + + str++; + + /* Parse green */ + SKIP_WHITESPACES (str); + if (!parse_rgb_value (str, &str, &g)) + return FALSE; + SKIP_WHITESPACES (str); + + if (*str != ',') + return FALSE; + + str++; + + /* Parse blue */ + SKIP_WHITESPACES (str); + if (!parse_rgb_value (str, &str, &b)) + return FALSE; + SKIP_WHITESPACES (str); + + if (has_alpha) + { + if (*str != ',') + return FALSE; + + str++; + + SKIP_WHITESPACES (str); + if (!parse_rgb_value (str, &str, &a)) + return FALSE; + SKIP_WHITESPACES (str); + } + + if (*str != ')') + return FALSE; + + str++; + + SKIP_WHITESPACES (str); + + if (*str != '\0') + return FALSE; + + if (rgba) + { + rgba->red = CLAMP (r, 0, 1); + rgba->green = CLAMP (g, 0, 1); + rgba->blue = CLAMP (b, 0, 1); + rgba->alpha = CLAMP (a, 0, 1); + } + + return TRUE; +} + +#undef SKIP_WHITESPACES + +gchar * rgba_to_string (const GdkRGBA *rgba, gdouble format) { + return g_strdup_printf ("rgba(%d,%d,%d,%d)", + (int)(rgba->red * format), + (int)(rgba->green * format), + (int)(rgba->blue * format), + (int)(rgba->alpha * format)); } static gboolean on_window_expose (GtkWidget *window, cairo_t *cr, gpointer user_data) { IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); + GdkRGBA bg; + GdkRGBA bg_stroke; + gboolean check_bground = FALSE; + gboolean check_bground_stroke = FALSE; GtkAllocation alloc; - + gtk_widget_get_allocation( window, &alloc ); - + cairo_set_operator( cr, CAIRO_OPERATOR_CLEAR ); cairo_paint( cr ); - cairo_set_operator( cr, CAIRO_OPERATOR_OVER ); - cairo_set_source_rgba( cr, 0.0f, 0.0f, 0.0f, 0.0f ); - cairo_rectangle( cr, 0, 0, alloc.width, alloc.height ); - cairo_fill( cr ); + cairo_set_operator( cr, CAIRO_OPERATOR_OVER ); + if(self->priv->tray_is_static) { + if(self->priv->show_background_static) { + check_bground = rgba_parse( &bg, self->priv->bg_static ); + check_bground_stroke = rgba_parse( &bg_stroke, self->priv->bg_static_stroke ); + } + else { + check_bground = rgba_parse( &bg, "rgba(0,0,0,0)" ); + check_bground_stroke = rgba_parse( &bg_stroke, "rgba(0,0,0,0)" ); + } + } + else { + if(self->priv->show_background_floating) { + check_bground = rgba_parse( &bg, self->priv->bg_floating ); + check_bground_stroke = rgba_parse( &bg_stroke, self->priv->bg_floating_stroke ); + } + else { + check_bground = rgba_parse( &bg, "rgba(0,0,0,0)" ); + check_bground_stroke = rgba_parse( &bg_stroke, "rgba(0,0,0,0)" ); + } + } + if(check_bground) { + cairo_set_source_rgba( cr, bg.red, bg.green, bg.blue, bg.alpha ); + cairo_rectangle( cr, 0, 0, alloc.width, alloc.height ); + cairo_fill( cr ); + } + if(check_bground_stroke) { + cairo_set_line_width( cr, 0.3 ); + cairo_set_source_rgba( cr, bg_stroke.red, bg_stroke.green, bg_stroke.blue, bg_stroke.alpha ); + cairo_rectangle( cr, 0.25, 0.25, alloc.width-0.65, alloc.height-0.45 ); + cairo_stroke( cr ); + } gtk_container_propagate_draw( GTK_CONTAINER(window), gtk_bin_get_child(GTK_BIN(window)), cr ); - + update_position_tray( self ); if (self->priv->tray_is_static && self->priv->count_tray_icon == 0 && gtk_widget_is_visible(self->priv->window)) { @@ -342,14 +744,18 @@ static gint width_of_tray(gpointer user_data) { IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); - return self->priv->count_tray_icon * SYSTEMTRAY_ICON_WIDTH; + return self->priv->count_tray_icon * SYSTEMTRAY_ICON_WIDTH + 4; } static gboolean filter_tray_cb(NaTray* tray, NaTrayChild* icon, gpointer user_data) { IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); - self->priv->count_tray_icon++; - gtk_window_resize( GTK_WINDOW(self->priv->window), width_of_tray(self), 24 ); + if (na_tray_child_has_alpha(icon)) + na_tray_child_set_composited(icon, TRUE); + + self->priv->count_tray_icon++; + gtk_widget_set_size_request( GTK_WIDGET(self->priv->tray), width_of_tray(self), SYSTEMTRAY_TRAY_HEIGHT ); + gtk_window_resize( GTK_WINDOW(self->priv->window), width_of_tray(self), SYSTEMTRAY_TRAY_HEIGHT ); if (self->priv->count_tray_icon > 0 && self->priv->hide_indicator) { self->priv->hide_indicator = FALSE; update_indicator_visibility( self ); @@ -363,7 +769,8 @@ static void on_tray_icon_removed(NaTrayManager* manager, NaTrayChild* removed, gpointer user_data) { IndicatorSystemtray *self = INDICATOR_SYSTEMTRAY( user_data ); self->priv->count_tray_icon--; - gtk_window_resize( GTK_WINDOW(self->priv->window), width_of_tray(self), 24 ); + gtk_widget_set_size_request( GTK_WIDGET(self->priv->tray), width_of_tray(self), SYSTEMTRAY_TRAY_HEIGHT ); + gtk_window_resize( GTK_WINDOW(self->priv->window), width_of_tray(self), SYSTEMTRAY_TRAY_HEIGHT ); if (self->priv->count_tray_icon == 0) { self->priv->hide_indicator = TRUE; update_indicator_visibility( self ); @@ -383,7 +790,7 @@ g_settings_set_int(self->priv->settings, SYSTEMTRAY_KEY_STATIC_Y, self->priv->static_y); } else { - self->priv->x = self->priv->x + (width_of_tray(self)/2) + 18; + self->priv->x = self->priv->x + (width_of_tray(self)/2) + 19; self->priv->y = SYSTEMTRAY_TRAY_TOP; if (self->priv->x > w_s) self->priv->x = w_s; @@ -416,12 +823,12 @@ gboolean visible; g_object_get( G_OBJECT(self->priv->menu), "visible", &visible, NULL ); if (visible) { - gtk_menu_reposition( GTK_MENU(self->priv->menu) ); + gtk_menu_reposition( self->priv->menu ); GtkWidget *top_widget = gtk_widget_get_toplevel( GTK_WIDGET(self->priv->menu) ); GtkWindow *top_win = GTK_WINDOW( top_widget ); gtk_window_get_position( top_win, &self->priv->x, &self->priv->y ); update_position_tray( self ); - gtk_menu_popup( GTK_MENU(self->priv->menu), NULL, NULL, (GtkMenuPositionFunc)set_position_menu, self, 0, gtk_get_current_event_time() ); + gtk_menu_popup( self->priv->menu, NULL, NULL, (GtkMenuPositionFunc)set_position_menu, self, 0, gtk_get_current_event_time() ); gtk_widget_show( self->priv->window ); gtk_window_move( GTK_WINDOW(self->priv->window), self->priv->x, self->priv->y/*+1*/ ); if (y > 24) return FALSE; Binary files /tmp/qClOQsS048/indicator-systemtray-unity-0.2/indicator-systemtray-unity.png and /tmp/lNK7LSVqjS/indicator-systemtray-unity-0.2.1/indicator-systemtray-unity.png differ diff -Nru indicator-systemtray-unity-0.2/Makefile indicator-systemtray-unity-0.2.1/Makefile --- indicator-systemtray-unity-0.2/Makefile 2015-04-29 19:54:21.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/Makefile 2015-06-03 17:05:28.000000000 +0000 @@ -1,13 +1,36 @@ -CC=gcc --shared -fPIC -CFLAGS=-g -Wall -Wfatal-errors -std=c99 $(shell pkg-config --cflags --libs gtk+-3.0 indicator3-0.4 unity-misc) +CC=gcc --shared -fPIC -Wall +CFLAGS=-Wfatal-errors $(shell pkg-config --cflags --libs gtk+-3.0) +CFLAGS_IND=-Wfatal-errors $(shell pkg-config --cflags --libs gtk+-3.0 indicator3-0.4) +CFLAGS_MAIN=-Wfatal-errors -std=c99 $(shell pkg-config --cflags --libs gtk+-3.0 x11) -lm -all: libsystemtray.so +all : libsystemtray.so clean -libsystemtray.so: indicator-systemtray.c - $(CC) $< $(CFLAGS) -o $@ +libsystemtray.so : indicator-systemtray.o fixedtip.o gnome-bg-slideshow.o na-marshal.o na-tray.o na-tray-child.o na-tray-manager.o + $(CC) -o $@ $^ $(CFLAGS_MAIN) -clean: - rm -f *.o libsystemtray.so +indicator-systemtray.o : indicator-systemtray.c + $(CC) -c $< $(CFLAGS_IND) + +fixedtip.o : fixedtip.c + $(CC) -c $< $(CFLAGS) + +gnome-bg-slideshow.o : gnome-bg-slideshow.c + $(CC) -c $< $(CFLAGS) + +na-marshal.o : na-marshal.c + $(CC) -c $< $(CFLAGS) + +na-tray.o : na-tray.c + $(CC) -c $< $(CFLAGS) + +na-tray-child.o : na-tray-child.c + $(CC) -c $< $(CFLAGS) + +na-tray-manager.o : na-tray-manager.c + $(CC) -c $< $(CFLAGS) + +clean : + rm -f *.o fixedtip gnome-bg-slideshow na-marshal na-tray na-tray-child na-tray-manager install: install -Dm 644 libsystemtray.so $(DESTDIR)/usr/lib/indicators3/7/libsystemtray.so @@ -15,6 +38,7 @@ install -Dm 644 resources/UNITY_PANEL_TRAY_DISABLE.sh $(DESTDIR)/etc/profile.d/UNITY_PANEL_TRAY_DISABLE.sh install -Dm 644 resources/net.launchpad.indicator.systemtray.gschema.xml $(DESTDIR)/usr/share/glib-2.0/schemas/net.launchpad.indicator.systemtray.gschema.xml #glib-compile-schemas $(DESTDIR)/usr/share/glib-2.0/schemas/ + bash potomo.sh $(DESTDIR)/usr/share/locale uninstall: rm $(DESTDIR)/usr/lib/indicators3/7/libsystemtray.so diff -Nru indicator-systemtray-unity-0.2/na-marshal.c indicator-systemtray-unity-0.2.1/na-marshal.c --- indicator-systemtray-unity-0.2/na-marshal.c 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-marshal.c 2015-01-28 12:16:34.000000000 +0000 @@ -0,0 +1,166 @@ + +#include + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_schar (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#define g_marshal_value_peek_variant(v) g_value_get_variant (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* VOID:OBJECT,OBJECT (./na-marshal.list:1) */ +void +_na_marshal_VOID__OBJECT_OBJECT (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_OBJECT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_object (param_values + 2), + data2); +} + +/* VOID:OBJECT,STRING,LONG,LONG (./na-marshal.list:2) */ +void +_na_marshal_VOID__OBJECT_STRING_LONG_LONG (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_STRING_LONG_LONG) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + glong arg_3, + glong arg_4, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_STRING_LONG_LONG callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 5); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_STRING_LONG_LONG) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_long (param_values + 3), + g_marshal_value_peek_long (param_values + 4), + data2); +} + +/* VOID:OBJECT,LONG (./na-marshal.list:3) */ +void +_na_marshal_VOID__OBJECT_LONG (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_LONG) (gpointer data1, + gpointer arg_1, + glong arg_2, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_LONG callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_LONG) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_long (param_values + 2), + data2); +} + diff -Nru indicator-systemtray-unity-0.2/na-marshal.h indicator-systemtray-unity-0.2.1/na-marshal.h --- indicator-systemtray-unity-0.2/na-marshal.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-marshal.h 2015-01-28 12:16:34.000000000 +0000 @@ -0,0 +1,36 @@ + +#ifndef ___na_marshal_MARSHAL_H__ +#define ___na_marshal_MARSHAL_H__ + +#include + +G_BEGIN_DECLS + +/* VOID:OBJECT,OBJECT (./na-marshal.list:1) */ +extern void _na_marshal_VOID__OBJECT_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,STRING,LONG,LONG (./na-marshal.list:2) */ +extern void _na_marshal_VOID__OBJECT_STRING_LONG_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,LONG (./na-marshal.list:3) */ +extern void _na_marshal_VOID__OBJECT_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +G_END_DECLS + +#endif /* ___na_marshal_MARSHAL_H__ */ + diff -Nru indicator-systemtray-unity-0.2/na-tray.c indicator-systemtray-unity-0.2.1/na-tray.c --- indicator-systemtray-unity-0.2/na-tray.c 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-tray.c 2015-05-30 11:43:58.000000000 +0000 @@ -0,0 +1,886 @@ +/* + * Copyright (C) 2002 Red Hat, Inc. + * Copyright (C) 2003-2006 Vincent Untz + * Copyright (C) 2007 Christian Persch + * + * 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. + */ + +#include "config.h" +#include + +#include + +#include "fixedtip.h" + +#include "na-tray.h" + +#define ICON_SPACING 1 +#define MIN_BOX_SIZE 3 + +typedef struct +{ + NaTrayManager *tray_manager; + GSList *all_trays; + GHashTable *icon_table; + GHashTable *tip_table; +} TraysScreen; + +struct _NaTrayPrivate +{ + GdkScreen *screen; + TraysScreen *trays_screen; + + GtkWidget *box; + GtkWidget *frame; + + guint idle_redraw_id; + + GtkOrientation orientation; + + NaTrayFilterCallback cb; + gpointer data; +}; + +typedef struct +{ + char *text; + glong id; + glong timeout; +} IconTipBuffer; + +typedef struct +{ + NaTray *tray; /* tray containing the tray icon */ + GtkWidget *icon; /* tray icon sending the message */ + GtkWidget *fixedtip; + guint source_id; + glong id; /* id of the current message */ + GSList *buffer; /* buffered messages */ +} IconTip; + +enum +{ + PROP_0, + PROP_ORIENTATION, + PROP_SCREEN +}; + +static gboolean initialized = FALSE; +static TraysScreen *trays_screens = NULL; + +static void icon_tip_show_next (IconTip *icontip); + +/* NaTray */ + +G_DEFINE_TYPE (NaTray, na_tray, GTK_TYPE_BIN) + +static NaTray * +get_tray (TraysScreen *trays_screen) +{ + if (trays_screen->all_trays == NULL) + return NULL; + + return trays_screen->all_trays->data; +} + +const char *ordered_roles[] = { + "keyboard", + "volume", + "bluetooth", + "network", + "battery", + NULL +}; + +const char *wmclass_roles[] = { + "Bluetooth-applet", "bluetooth", + "Gnome-volume-control-applet", "volume", + "Nm-applet", "network", + "Gnome-power-manager", "battery", + "keyboard", "keyboard", + NULL, +}; + +static const char * +find_role (const char *wmclass) +{ + int i; + + for (i = 0; wmclass_roles[i]; i += 2) + { + if (strcmp (wmclass, wmclass_roles[i]) == 0) + return wmclass_roles[i + 1]; + } + + return NULL; +} + +static int +find_role_position (const char *role) +{ + int i; + + for (i = 0; ordered_roles[i]; i++) + { + if (strcmp (role, ordered_roles[i]) == 0) + break; + } + + return i + 1; +} + +static int +find_icon_position (NaTray *tray, + GtkWidget *icon) +{ + NaTrayPrivate *priv; + int position; + char *class_a; + const char *role; + int role_position; + GList *l, *children; + + /* We insert the icons with a known roles in a specific order (the one + * defined by ordered_roles), and all other icons at the beginning of the box + * (left in LTR). */ + + priv = tray->priv; + position = 0; + + class_a = NULL; + na_tray_child_get_wm_class (NA_TRAY_CHILD (icon), NULL, &class_a); + if (!class_a) + return position; + + role = find_role (class_a); + g_free (class_a); + if (!role) + return position; + + role_position = find_role_position (role); + g_object_set_data (G_OBJECT (icon), "role-position", GINT_TO_POINTER (role_position)); + + children = gtk_container_get_children (GTK_CONTAINER (priv->box)); + for (l = g_list_last (children); l; l = l->prev) + { + GtkWidget *child = l->data; + int rp; + + rp = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "role-position")); + if (rp == 0 || rp < role_position) + { + position = g_list_index (children, child) + 1; + break; + } + } + g_list_free (children); + + /* should never happen, but it doesn't hurt to be on the safe side */ + if (position < 0) + position = 0; + + return position; +} + +static void +tray_added (NaTrayManager *manager, + GtkWidget *icon, + TraysScreen *trays_screen) +{ + NaTray *tray; + NaTrayPrivate *priv; + int position; + + tray = get_tray (trays_screen); + if (tray == NULL) + return; + + priv = tray->priv; + + g_assert (priv->trays_screen == trays_screen); + + if (priv->cb && !priv->cb (tray, icon, priv->data)) + { + return; + } + + g_hash_table_insert (trays_screen->icon_table, icon, tray); + + position = find_icon_position (tray, icon); + gtk_box_pack_start (GTK_BOX (priv->box), icon, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (priv->box), icon, position); + + gtk_widget_show (icon); +} + +static void +tray_removed (NaTrayManager *manager, + GtkWidget *icon, + TraysScreen *trays_screen) +{ + NaTray *tray; + NaTrayPrivate *priv; + + tray = g_hash_table_lookup (trays_screen->icon_table, icon); + if (tray == NULL) + return; + + priv = tray->priv; + + g_assert (tray->priv->trays_screen == trays_screen); + + gtk_container_remove (GTK_CONTAINER (priv->box), icon); + + g_hash_table_remove (trays_screen->icon_table, icon); + /* this will also destroy the tip associated to this icon */ + g_hash_table_remove (trays_screen->tip_table, icon); +} + +static void +icon_tip_buffer_free (gpointer data, + gpointer userdata) +{ + IconTipBuffer *buffer; + + buffer = data; + + g_free (buffer->text); + buffer->text = NULL; + + g_free (buffer); +} + +static void +icon_tip_free (gpointer data) +{ + IconTip *icontip; + + if (data == NULL) + return; + + icontip = data; + + if (icontip->fixedtip != NULL) + gtk_widget_destroy (GTK_WIDGET (icontip->fixedtip)); + icontip->fixedtip = NULL; + + if (icontip->source_id != 0) + g_source_remove (icontip->source_id); + icontip->source_id = 0; + + if (icontip->buffer != NULL) + { + g_slist_foreach (icontip->buffer, icon_tip_buffer_free, NULL); + g_slist_free (icontip->buffer); + } + icontip->buffer = NULL; + + g_free (icontip); +} + +static int +icon_tip_buffer_compare (gconstpointer a, + gconstpointer b) +{ + const IconTipBuffer *buffer_a = a; + const IconTipBuffer *buffer_b = b; + + if (buffer_a == NULL || buffer_b == NULL) + return !(buffer_a == buffer_b); + + return buffer_a->id - buffer_b->id; +} + +static void +icon_tip_show_next_clicked (GtkWidget *widget, + gpointer data) +{ + icon_tip_show_next ((IconTip *) data); +} + +static gboolean +icon_tip_show_next_timeout (gpointer data) +{ + IconTip *icontip = (IconTip *) data; + + icon_tip_show_next (icontip); + + return FALSE; +} + +static void +icon_tip_show_next (IconTip *icontip) +{ + IconTipBuffer *buffer; + + if (icontip->buffer == NULL) + { + /* this will also destroy the tip window */ + g_hash_table_remove (icontip->tray->priv->trays_screen->tip_table, + icontip->icon); + return; + } + + if (icontip->source_id != 0) + g_source_remove (icontip->source_id); + icontip->source_id = 0; + + buffer = icontip->buffer->data; + icontip->buffer = g_slist_remove (icontip->buffer, buffer); + + if (icontip->fixedtip == NULL) + { + icontip->fixedtip = na_fixed_tip_new (icontip->icon, + na_tray_get_orientation (icontip->tray)); + + g_signal_connect (icontip->fixedtip, "clicked", + G_CALLBACK (icon_tip_show_next_clicked), icontip); + } + + na_fixed_tip_set_markup (icontip->fixedtip, buffer->text); + + if (!gtk_widget_get_mapped (icontip->fixedtip)) + gtk_widget_show (icontip->fixedtip); + + icontip->id = buffer->id; + + if (buffer->timeout > 0) + icontip->source_id = g_timeout_add_seconds (buffer->timeout, + icon_tip_show_next_timeout, + icontip); + + icon_tip_buffer_free (buffer, NULL); +} + +static void +message_sent (NaTrayManager *manager, + GtkWidget *icon, + const char *text, + glong id, + glong timeout, + TraysScreen *trays_screen) +{ + IconTip *icontip; + IconTipBuffer find_buffer; + IconTipBuffer *buffer; + gboolean show_now; + + icontip = g_hash_table_lookup (trays_screen->tip_table, icon); + + find_buffer.id = id; + if (icontip && + (icontip->id == id || + g_slist_find_custom (icontip->buffer, &find_buffer, + icon_tip_buffer_compare) != NULL)) + /* we already have this message, so ignore it */ + /* FIXME: in an ideal world, we'd remember all the past ids and ignore them + * too */ + return; + + show_now = FALSE; + + if (icontip == NULL) + { + NaTray *tray; + + tray = g_hash_table_lookup (trays_screen->icon_table, icon); + if (tray == NULL) + { + /* We don't know about the icon sending the message, so ignore it. + * But this should never happen since NaTrayManager shouldn't send + * us the message if there's no socket for it. */ + g_critical ("Ignoring a message sent by a tray icon " + "we don't know: \"%s\".\n", text); + return; + } + + icontip = g_new0 (IconTip, 1); + icontip->tray = tray; + icontip->icon = icon; + + g_hash_table_insert (trays_screen->tip_table, icon, icontip); + + show_now = TRUE; + } + + buffer = g_new0 (IconTipBuffer, 1); + + buffer->text = g_strdup (text); + buffer->id = id; + buffer->timeout = timeout; + + icontip->buffer = g_slist_append (icontip->buffer, buffer); + + if (show_now) + icon_tip_show_next (icontip); +} + +static void +message_cancelled (NaTrayManager *manager, + GtkWidget *icon, + glong id, + TraysScreen *trays_screen) +{ + IconTip *icontip; + IconTipBuffer find_buffer; + GSList *cancel_buffer_l; + IconTipBuffer *cancel_buffer; + + icontip = g_hash_table_lookup (trays_screen->tip_table, icon); + if (icontip == NULL) + return; + + if (icontip->id == id) + { + icon_tip_show_next (icontip); + return; + } + + find_buffer.id = id; + cancel_buffer_l = g_slist_find_custom (icontip->buffer, &find_buffer, + icon_tip_buffer_compare); + if (cancel_buffer_l == NULL) + return; + + cancel_buffer = cancel_buffer_l->data; + icon_tip_buffer_free (cancel_buffer, NULL); + + icontip->buffer = g_slist_remove_link (icontip->buffer, cancel_buffer_l); + g_slist_free_1 (cancel_buffer_l); +} + +static void +update_orientation_for_messages (gpointer key, + gpointer value, + gpointer data) +{ + NaTray *tray; + IconTip *icontip; + + if (value == NULL) + return; + + icontip = value; + tray = data; + if (icontip->tray != tray) + return; + + if (icontip->fixedtip) + na_fixed_tip_set_orientation (icontip->fixedtip, tray->priv->orientation); +} + +static void +update_size_and_orientation (NaTray *tray) +{ + NaTrayPrivate *priv = tray->priv; + + gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), priv->orientation); + + /* This only happens when setting the property during object construction */ + if (!priv->trays_screen) + return; + + g_hash_table_foreach (priv->trays_screen->tip_table, + update_orientation_for_messages, tray); + + if (get_tray (priv->trays_screen) == tray) + na_tray_manager_set_orientation (priv->trays_screen->tray_manager, + priv->orientation); + + /* note, you want this larger if the frame has non-NONE relief by default. */ + switch (priv->orientation) + { + case GTK_ORIENTATION_VERTICAL: + /* Give box a min size so the frame doesn't look dumb */ + gtk_widget_set_size_request (priv->box, MIN_BOX_SIZE, -1); + break; + case GTK_ORIENTATION_HORIZONTAL: + gtk_widget_set_size_request (priv->box, -1, MIN_BOX_SIZE); + break; + } +} + +/* Children with alpha channels have been set to be composited by calling + * gdk_window_set_composited(). We need to paint these children ourselves. + */ +static void +na_tray_draw_icon (GtkWidget *widget, + gpointer data) +{ + cairo_t *cr = (cairo_t *) data; + + if (na_tray_child_has_alpha (NA_TRAY_CHILD (widget))) + { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + + cairo_save (cr); + gdk_cairo_set_source_window (cr, + gtk_widget_get_window (widget), + allocation.x-LEFT_BOARD, + allocation.y); + cairo_rectangle (cr, allocation.x-LEFT_BOARD, allocation.y, allocation.width, allocation.height); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + } +} + +static void +na_tray_draw_box (GtkWidget *box, + cairo_t *cr) +{ + gtk_container_foreach (GTK_CONTAINER (box), na_tray_draw_icon, cr); +} + +static void +na_tray_init (NaTray *tray) +{ + NaTrayPrivate *priv; + + priv = tray->priv = G_TYPE_INSTANCE_GET_PRIVATE (tray, NA_TYPE_TRAY, NaTrayPrivate); + + priv->screen = NULL; + priv->orientation = GTK_ORIENTATION_HORIZONTAL; + + priv->frame = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); + gtk_container_add (GTK_CONTAINER (tray), priv->frame); + gtk_widget_show (priv->frame); + + priv->box = gtk_box_new (priv->orientation, ICON_SPACING); + g_signal_connect (priv->box, "draw", + G_CALLBACK (na_tray_draw_box), NULL); + gtk_container_add (GTK_CONTAINER (priv->frame), priv->box); + gtk_widget_show (priv->box); +} + +static GObject * +na_tray_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + NaTray *tray; + NaTrayPrivate *priv; + int screen_number; + + object = G_OBJECT_CLASS (na_tray_parent_class)->constructor (type, + n_construct_properties, + construct_params); + tray = NA_TRAY (object); + priv = tray->priv; + + g_assert (priv->screen != NULL); + + if (!initialized) + { + GdkDisplay *display; + int n_screens; + + display = gdk_display_get_default (); + n_screens = gdk_display_get_n_screens (display); + trays_screens = g_new0 (TraysScreen, n_screens); + initialized = TRUE; + } + + screen_number = gdk_screen_get_number (priv->screen); + + if (trays_screens [screen_number].tray_manager == NULL) + { + NaTrayManager *tray_manager; + + tray_manager = na_tray_manager_new (); + + if (na_tray_manager_manage_screen (tray_manager, priv->screen)) + { + trays_screens [screen_number].tray_manager = tray_manager; + + g_signal_connect (tray_manager, "tray_icon_added", + G_CALLBACK (tray_added), + &trays_screens [screen_number]); + g_signal_connect (tray_manager, "tray_icon_removed", + G_CALLBACK (tray_removed), + &trays_screens [screen_number]); + g_signal_connect (tray_manager, "message_sent", + G_CALLBACK (message_sent), + &trays_screens [screen_number]); + g_signal_connect (tray_manager, "message_cancelled", + G_CALLBACK (message_cancelled), + &trays_screens [screen_number]); + + trays_screens [screen_number].icon_table = g_hash_table_new (NULL, + NULL); + trays_screens [screen_number].tip_table = g_hash_table_new_full ( + NULL, + NULL, + NULL, + icon_tip_free); + } + else + { + g_printerr ("System tray didn't get the system tray manager selection for screen %d\n", + screen_number); + g_object_unref (tray_manager); + } + } + + priv->trays_screen = &trays_screens [screen_number]; + trays_screens [screen_number].all_trays = g_slist_append (trays_screens [screen_number].all_trays, + tray); + + update_size_and_orientation (tray); + + return object; +} + +static void +na_tray_dispose (GObject *object) +{ + NaTray *tray = NA_TRAY (object); + NaTrayPrivate *priv = tray->priv; + TraysScreen *trays_screen = priv->trays_screen; + + if (trays_screen != NULL) + { + trays_screen->all_trays = g_slist_remove (trays_screen->all_trays, tray); + + if (trays_screen->all_trays == NULL) + { + /* Make sure we drop the manager selection */ + g_object_unref (trays_screen->tray_manager); + trays_screen->tray_manager = NULL; + + g_hash_table_destroy (trays_screen->icon_table); + trays_screen->icon_table = NULL; + + g_hash_table_destroy (trays_screen->tip_table); + trays_screen->tip_table = NULL; + } + else + { + NaTray *new_tray; + + new_tray = get_tray (trays_screen); + if (new_tray != NULL) + na_tray_manager_set_orientation (trays_screen->tray_manager, + na_tray_get_orientation (new_tray)); + } + } + + priv->trays_screen = NULL; + + if (priv->idle_redraw_id != 0) + { + g_source_remove (priv->idle_redraw_id); + priv->idle_redraw_id = 0; + } + + G_OBJECT_CLASS (na_tray_parent_class)->dispose (object); +} + +static void +na_tray_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NaTray *tray = NA_TRAY (object); + NaTrayPrivate *priv = tray->priv; + + switch (prop_id) + { + case PROP_ORIENTATION: + na_tray_set_orientation (tray, g_value_get_enum (value)); + break; + case PROP_SCREEN: + priv->screen = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +na_tray_get_preferred_width (GtkWidget *widget, + gint *minimal_width, + gint *natural_width) +{ + gtk_widget_get_preferred_width (gtk_bin_get_child (GTK_BIN (widget)), + minimal_width, + natural_width); +} + +static void +na_tray_get_preferred_height (GtkWidget *widget, + gint *minimal_height, + gint *natural_height) +{ + gtk_widget_get_preferred_height (gtk_bin_get_child (GTK_BIN (widget)), + minimal_height, + natural_height); +} + +static void +na_tray_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + gtk_widget_size_allocate (gtk_bin_get_child (GTK_BIN (widget)), allocation); + gtk_widget_set_allocation (widget, allocation); +} + +static void +na_tray_class_init (NaTrayClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gobject_class->constructor = na_tray_constructor; + gobject_class->set_property = na_tray_set_property; + gobject_class->dispose = na_tray_dispose; + widget_class->get_preferred_width = na_tray_get_preferred_width; + widget_class->get_preferred_height = na_tray_get_preferred_height; + widget_class->size_allocate = na_tray_size_allocate; + + g_object_class_install_property + (gobject_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", "orientation", "orientation", + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property + (gobject_class, + PROP_SCREEN, + g_param_spec_object ("screen", "screen", "screen", + GDK_TYPE_SCREEN, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); + + g_type_class_add_private (gobject_class, sizeof (NaTrayPrivate)); +} + +NaTray * +na_tray_new_for_screen (GdkScreen *screen, + GtkOrientation orientation, + NaTrayFilterCallback cb, + gpointer data) +{ + NaTray *tray; + + tray = g_object_new (NA_TYPE_TRAY, + "screen", screen, + "orientation", orientation, + NULL); + + tray->priv->cb = cb; + tray->priv->data = data; + + return tray; +} + +void +na_tray_set_orientation (NaTray *tray, + GtkOrientation orientation) +{ + NaTrayPrivate *priv = tray->priv; + + if (orientation == priv->orientation) + return; + + priv->orientation = orientation; + + update_size_and_orientation (tray); +} + +GtkOrientation +na_tray_get_orientation (NaTray *tray) +{ + return tray->priv->orientation; +} + +static gboolean +idle_redraw_cb (NaTray *tray) +{ + NaTrayPrivate *priv = tray->priv; + + gtk_container_foreach (GTK_CONTAINER (priv->box), (GtkCallback)na_tray_child_force_redraw, tray); + + priv->idle_redraw_id = 0; + + return FALSE; +} + +void +na_tray_set_padding (NaTray *tray, + gint padding) +{ + NaTrayPrivate *priv = tray->priv; + + if (get_tray (priv->trays_screen) == tray) + na_tray_manager_set_padding (priv->trays_screen->tray_manager, padding); +} + +void +na_tray_set_icon_size (NaTray *tray, + gint size) +{ + NaTrayPrivate *priv = tray->priv; + + if (get_tray (priv->trays_screen) == tray) + na_tray_manager_set_icon_size (priv->trays_screen->tray_manager, size); +} + +void +na_tray_set_colors (NaTray *tray, + GdkColor *fg, + GdkColor *error, + GdkColor *warning, + GdkColor *success) +{ + NaTrayPrivate *priv = tray->priv; + + if (get_tray (priv->trays_screen) == tray) + na_tray_manager_set_colors (priv->trays_screen->tray_manager, fg, error, warning, success); +} + +void +na_tray_force_redraw (NaTray *tray) +{ + NaTrayPrivate *priv = tray->priv; + + /* Force the icons to redraw their backgrounds. + */ + if (priv->idle_redraw_id == 0) + priv->idle_redraw_id = g_idle_add ((GSourceFunc) idle_redraw_cb, tray); +} + +NaTrayManager * +na_tray_get_manager (NaTray *tray) +{ + return trays_screens [gdk_screen_get_number (tray->priv->screen)].tray_manager; +} + diff -Nru indicator-systemtray-unity-0.2/na-tray-child.c indicator-systemtray-unity-0.2.1/na-tray-child.c --- indicator-systemtray-unity-0.2/na-tray-child.c 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-tray-child.c 2015-05-21 15:17:23.000000000 +0000 @@ -0,0 +1,540 @@ +/* na-tray-child.c + * Copyright (C) 2002 Anders Carlsson + * Copyright (C) 2003-2006 Vincent Untz + * Copyright (C) 2008 Red Hat, Inc. + * + * 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 "config.h" +#include + +#include "na-tray-child.h" + +#include +#include +#include + +G_DEFINE_TYPE (NaTrayChild, na_tray_child, GTK_TYPE_SOCKET) + +static void +na_tray_child_finalize (GObject *object) +{ + G_OBJECT_CLASS (na_tray_child_parent_class)->finalize (object); +} + +static void +na_tray_child_realize (GtkWidget *widget) +{ + NaTrayChild *child = NA_TRAY_CHILD (widget); + GdkVisual *visual = gtk_widget_get_visual (widget); + GdkWindow *window; + + GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget); + + window = gtk_widget_get_window (widget); + + if (child->has_alpha) + { + /* We have real transparency with an ARGB visual and the Composite + * extension. */ + + /* Set a transparent background */ + cairo_pattern_t *transparent = cairo_pattern_create_rgba (0, 0, 0, 0); + gdk_window_set_background_pattern (window, transparent); + gdk_window_set_composited (window, TRUE); + cairo_pattern_destroy (transparent); + + child->parent_relative_bg = FALSE; + } + else if (visual == gdk_window_get_visual (gdk_window_get_parent (window))) + { + /* Otherwise, if the visual matches the visual of the parent window, we + * can use a parent-relative background and fake transparency. */ + gdk_window_set_background_pattern (window, NULL); + + child->parent_relative_bg = TRUE; + } + else + { + /* Nothing to do; the icon will sit on top of an ugly gray box */ + child->parent_relative_bg = FALSE; + } + + gdk_window_set_composited (window, child->composited); + + gtk_widget_set_app_paintable (GTK_WIDGET (child), + child->parent_relative_bg || child->has_alpha); + + /* Double-buffering will interfere with the parent-relative-background fake + * transparency, since the double-buffer code doesn't know how to fill in the + * background of the double-buffer correctly. + */ + gtk_widget_set_double_buffered (GTK_WIDGET (child), + child->parent_relative_bg); +} + +static void +na_tray_child_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + /* The default handler resets the background according to the new style. + * We either use a transparent background or a parent-relative background + * and ignore the style background. So, just don't chain up. + */ +} + +#if 0 +/* This is adapted from code that was commented out in na-tray-manager.c; the + * code in na-tray-manager.c wouldn't have worked reliably, this will. So maybe + * it can be reenabled. On other hand, things seem to be working fine without + * it. + * + * If reenabling, you need to hook it up in na_tray_child_class_init(). + */ +static void +na_tray_child_size_request (GtkWidget *widget, + GtkRequisition *request) +{ + GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_request (widget, request); + + /* + * Make sure the icons have a meaningful size .. + */ + if ((request->width < 16) || (request->height < 16)) + { + gint nw = MAX (24, request->width); + gint nh = MAX (24, request->height); + g_warning ("Tray icon has requested a size of (%ix%i), resizing to (%ix%i)", + req.width, req.height, nw, nh); + request->width = nw; + request->height = nh; + } +} +#endif + +static void +na_tray_child_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + NaTrayChild *child = NA_TRAY_CHILD (widget); + GtkAllocation widget_allocation; + gboolean moved, resized; + + gtk_widget_get_allocation (widget, &widget_allocation); + + moved = (allocation->x != widget_allocation.x || + allocation->y != widget_allocation.y); + resized = (allocation->width != widget_allocation.width || + allocation->height != widget_allocation.height); + + /* When we are allocating the widget while mapped we need special handling + * for both real and fake transparency. + * + * Real transparency: we need to invalidate and trigger a redraw of the old + * and new areas. (GDK really should handle this for us, but doesn't as of + * GTK+-2.14) + * + * Fake transparency: if the widget moved, we need to force the contents to + * be redrawn with the new offset for the parent-relative background. + */ + if ((moved || resized) && gtk_widget_get_mapped (widget)) + { + if (na_tray_child_has_alpha (child)) + gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)), + &widget_allocation, FALSE); + } + + GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_allocate (widget, + allocation); + + if ((moved || resized) && gtk_widget_get_mapped (widget)) + { + if (na_tray_child_has_alpha (NA_TRAY_CHILD (widget))) + gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)), + &widget_allocation, FALSE); + else if (moved && child->parent_relative_bg) + na_tray_child_force_redraw (child); + } +} + +/* The plug window should completely occupy the area of the child, so we won't + * get a draw event. But in case we do (the plug unmaps itself, say), this + * draw handler draws with real or fake transparency. + */ +static gboolean +na_tray_child_draw (GtkWidget *widget, + cairo_t *cr) +{ + NaTrayChild *child = NA_TRAY_CHILD (widget); + + if (na_tray_child_has_alpha (child)) + { + /* Clear to transparent */ + cairo_set_source_rgba (cr, 0, 0, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + } + else if (child->parent_relative_bg) + { + GdkWindow *window; + cairo_surface_t *target; + GdkRectangle clip_rect; + + window = gtk_widget_get_window (widget); + target = cairo_get_group_target (cr); + + gdk_cairo_get_clip_rectangle (cr, &clip_rect); + + /* Clear to parent-relative pixmap + * We need to use direct X access here because GDK doesn't know about + * the parent relative pixmap. */ + cairo_surface_flush (target); + + XClearArea (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + clip_rect.x, clip_rect.y, + clip_rect.width, clip_rect.height, + False); + cairo_surface_mark_dirty_rectangle (target, + clip_rect.x, clip_rect.y, + clip_rect.width, clip_rect.height); + } + + return FALSE; +} + +static void +na_tray_child_get_preferred_width (GtkWidget* widget, gint *mwidth, gint *nwidth) +{ + *mwidth = *nwidth = 22; +} + +static void +na_tray_child_get_preferred_height (GtkWidget *widget, gint *mheight, gint *nheight) +{ + *mheight = *nheight = 22; +} + +static void +na_tray_child_init (NaTrayChild *child) +{ +} + +static void +na_tray_child_class_init (NaTrayChildClass *klass) +{ + GObjectClass *gobject_class; + GtkWidgetClass *widget_class; + + gobject_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + + gobject_class->finalize = na_tray_child_finalize; + widget_class->style_set = na_tray_child_style_set; + widget_class->realize = na_tray_child_realize; + widget_class->size_allocate = na_tray_child_size_allocate; + widget_class->draw = na_tray_child_draw; + widget_class->get_preferred_width = na_tray_child_get_preferred_width; + widget_class->get_preferred_height = na_tray_child_get_preferred_height; +} + +GtkWidget * +na_tray_child_new (GdkScreen *screen, + Window icon_window) +{ + XWindowAttributes window_attributes; + Display *xdisplay; + NaTrayChild *child; + GdkVisual *visual; + gboolean visual_has_alpha; + int red_prec, green_prec, blue_prec, depth; + int result; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + g_return_val_if_fail (icon_window != None, NULL); + + xdisplay = GDK_SCREEN_XDISPLAY (screen); + + /* We need to determine the visual of the window we are embedding and create + * the socket in the same visual. + */ + + gdk_error_trap_push (); + result = XGetWindowAttributes (xdisplay, icon_window, + &window_attributes); + gdk_error_trap_pop_ignored (); + + if (!result) /* Window already gone */ + return NULL; + + visual = gdk_x11_screen_lookup_visual (screen, + window_attributes.visual->visualid); + if (!visual) /* Icon window is on another screen? */ + return NULL; + + child = g_object_new (NA_TYPE_TRAY_CHILD, NULL); + child->icon_window = icon_window; + + gtk_widget_set_visual (GTK_WIDGET (child), visual); + + /* We have alpha if the visual has something other than red, green, + * and blue */ + gdk_visual_get_red_pixel_details (visual, NULL, NULL, &red_prec); + gdk_visual_get_green_pixel_details (visual, NULL, NULL, &green_prec); + gdk_visual_get_blue_pixel_details (visual, NULL, NULL, &blue_prec); + depth = gdk_visual_get_depth (visual); + + visual_has_alpha = red_prec + blue_prec + green_prec < depth; + child->has_alpha = (visual_has_alpha && + gdk_display_supports_composite (gdk_screen_get_display (screen))); + + child->composited = child->has_alpha; + + return GTK_WIDGET (child); +} + +char * +na_tray_child_get_title (NaTrayChild *child) +{ + char *retval = NULL; + GdkDisplay *display; + Atom utf8_string, atom, type; + int result; + int format; + gulong nitems; + gulong bytes_after; + gchar *val; + + g_return_val_if_fail (NA_IS_TRAY_CHILD (child), NULL); + + display = gtk_widget_get_display (GTK_WIDGET (child)); + + utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"); + atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"); + + gdk_error_trap_push (); + + result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), + child->icon_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; +} + +/** + * na_tray_child_has_alpha; + * @child: a #NaTrayChild + * + * Checks if the child has an ARGB visual and real alpha transparence. + * (as opposed to faked alpha transparency with an parent-relative + * background) + * + * Return value: %TRUE if the child has an alpha transparency + */ +gboolean +na_tray_child_has_alpha (NaTrayChild *child) +{ + g_return_val_if_fail (NA_IS_TRAY_CHILD (child), FALSE); + + return child->has_alpha; +} + +/** + * na_tray_child_set_composited; + * @child: a #NaTrayChild + * @composited: %TRUE if the child's window should be redirected + * + * Sets whether the #GdkWindow of the child should be set redirected + * using gdk_window_set_composited(). By default this is based off of + * na_tray_child_has_alpha(), but it may be useful to override it in + * certain circumstances; for example, if the #NaTrayChild is added + * to a parent window and that parent window is composited against the + * background. + */ +void +na_tray_child_set_composited (NaTrayChild *child, + gboolean composited) +{ + g_return_if_fail (NA_IS_TRAY_CHILD (child)); + + if (child->composited == composited) + return; + + child->composited = composited; + if (gtk_widget_get_realized (GTK_WIDGET (child))) + gdk_window_set_composited (gtk_widget_get_window (GTK_WIDGET (child)), + composited); +} + +/* If we are faking transparency with a window-relative background, force a + * redraw of the icon. This should be called if the background changes or if + * the child is shifted with respect to the background. + */ +void +na_tray_child_force_redraw (NaTrayChild *child) +{ + GtkWidget *widget = GTK_WIDGET (child); + + if (gtk_widget_get_mapped (widget) && child->parent_relative_bg) + { +#if 1 + /* Sending an ExposeEvent might cause redraw problems if the + * icon is expecting the server to clear-to-background before + * the redraw. It should be ok for GtkStatusIcon or EggTrayIcon. + */ + Display *xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)); + XEvent xev; + GdkWindow *plug_window; + GtkAllocation allocation; + + plug_window = gtk_socket_get_plug_window (GTK_SOCKET (child)); + gtk_widget_get_allocation (widget, &allocation); + + xev.xexpose.type = Expose; + xev.xexpose.window = GDK_WINDOW_XID (plug_window); + xev.xexpose.x = 0; + xev.xexpose.y = 0; + xev.xexpose.width = allocation.width; + xev.xexpose.height = allocation.height; + xev.xexpose.count = 0; + + gdk_error_trap_push (); + XSendEvent (xdisplay, + xev.xexpose.window, + False, ExposureMask, + &xev); + gdk_error_trap_pop_ignored (); +#else + /* Hiding and showing is the safe way to do it, but can result in more + * flickering. + */ + gdk_window_hide (widget->window); + gdk_window_show (widget->window); +#endif + } +} + +/* from libwnck/xutils.c, comes as LGPLv2+ */ +static char * +latin1_to_utf8 (const char *latin1) +{ + GString *str; + const char *p; + + str = g_string_new (NULL); + + p = latin1; + while (*p) + { + g_string_append_unichar (str, (gunichar) *p); + ++p; + } + + return g_string_free (str, FALSE); +} + +/* derived from libwnck/xutils.c, comes as LGPLv2+ */ +static void +_get_wmclass (Display *xdisplay, + Window xwindow, + char **res_class, + char **res_name) +{ + XClassHint ch; + + ch.res_name = NULL; + ch.res_class = NULL; + + gdk_error_trap_push (); + XGetClassHint (xdisplay, xwindow, &ch); + gdk_error_trap_pop_ignored (); + + if (res_class) + *res_class = NULL; + + if (res_name) + *res_name = NULL; + + if (ch.res_name) + { + if (res_name) + *res_name = latin1_to_utf8 (ch.res_name); + + XFree (ch.res_name); + } + + if (ch.res_class) + { + if (res_class) + *res_class = latin1_to_utf8 (ch.res_class); + + XFree (ch.res_class); + } +} + +/** + * na_tray_child_get_wm_class; + * @child: a #NaTrayChild + * @res_name: return location for a string containing the application name of + * @child, or %NULL + * @res_class: return location for a string containing the application class of + * @child, or %NULL + * + * Fetches the resource associated with @child. + */ +void +na_tray_child_get_wm_class (NaTrayChild *child, + char **res_name, + char **res_class) +{ + GdkDisplay *display; + + g_return_if_fail (NA_IS_TRAY_CHILD (child)); + + display = gtk_widget_get_display (GTK_WIDGET (child)); + + _get_wmclass (GDK_DISPLAY_XDISPLAY (display), + child->icon_window, + res_class, + res_name); +} diff -Nru indicator-systemtray-unity-0.2/na-tray-child.h indicator-systemtray-unity-0.2.1/na-tray-child.h --- indicator-systemtray-unity-0.2/na-tray-child.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-tray-child.h 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* na-tray-child.h + * Copyright (C) 2002 Anders Carlsson + * Copyright (C) 2003-2006 Vincent Untz + * Copyright (C) 2008 Red Hat, Inc. + * + * 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 __NA_TRAY_CHILD_H__ +#define __NA_TRAY_CHILD_H__ + +#include +#include + +G_BEGIN_DECLS + +#define NA_TYPE_TRAY_CHILD (na_tray_child_get_type ()) +#define NA_TRAY_CHILD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_CHILD, NaTrayChild)) +#define NA_TRAY_CHILD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_CHILD, NaTrayChildClass)) +#define NA_IS_TRAY_CHILD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_CHILD)) +#define NA_IS_TRAY_CHILD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_CHILD)) +#define NA_TRAY_CHILD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_CHILD, NaTrayChildClass)) + +typedef struct _NaTrayChild NaTrayChild; +typedef struct _NaTrayChildClass NaTrayChildClass; +typedef struct _NaTrayChildChild NaTrayChildChild; + +struct _NaTrayChild +{ + GtkSocket parent_instance; + Window icon_window; + guint has_alpha : 1; + guint composited : 1; + guint parent_relative_bg : 1; +}; + +struct _NaTrayChildClass +{ + GtkSocketClass parent_class; +}; + +GType na_tray_child_get_type (void); + +GtkWidget *na_tray_child_new (GdkScreen *screen, + Window icon_window); +char *na_tray_child_get_title (NaTrayChild *child); +gboolean na_tray_child_has_alpha (NaTrayChild *child); +void na_tray_child_set_composited (NaTrayChild *child, + gboolean composited); +void na_tray_child_force_redraw (NaTrayChild *child); +void na_tray_child_get_wm_class (NaTrayChild *child, + char **res_name, + char **res_class); + +G_END_DECLS + +#endif /* __NA_TRAY_CHILD_H__ */ diff -Nru indicator-systemtray-unity-0.2/na-tray.h indicator-systemtray-unity-0.2.1/na-tray.h --- indicator-systemtray-unity-0.2/na-tray.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-tray.h 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* na-tray-tray.h + * Copyright (C) 2002 Anders Carlsson + * Copyright (C) 2003-2006 Vincent Untz + * + * 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. + * + * Used to be: eggtraytray.h + */ + +#ifndef __NA_TRAY_H__ +#define __NA_TRAY_H__ + +#ifdef GDK_WINDOWING_X11 +#include +#endif +#include + +#include "na-tray-manager.h" + +G_BEGIN_DECLS + +#define NA_TYPE_TRAY (na_tray_get_type ()) +#define NA_TRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY, NaTray)) +#define NA_TRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY, NaTrayClass)) +#define NA_IS_TRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY)) +#define NA_IS_TRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY)) +#define NA_TRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY, NaTrayClass)) + +typedef struct _NaTray NaTray; +typedef struct _NaTrayPrivate NaTrayPrivate; +typedef struct _NaTrayClass NaTrayClass; + +typedef gboolean (*NaTrayFilterCallback) (NaTray *tray, GtkWidget *icon, gpointer data); + +struct _NaTray +{ + GtkBin parent_instance; + + NaTrayPrivate *priv; +}; + +struct _NaTrayClass +{ + GtkBinClass parent_class; +}; + +GType na_tray_get_type (void); +NaTray *na_tray_new_for_screen (GdkScreen *screen, + GtkOrientation orientation, + NaTrayFilterCallback cb, + gpointer data); +void na_tray_set_orientation (NaTray *tray, + GtkOrientation orientation); +GtkOrientation na_tray_get_orientation (NaTray *tray); +void na_tray_set_padding (NaTray *tray, + gint padding); +void na_tray_set_icon_size (NaTray *tray, + gint icon_size); +void na_tray_set_colors (NaTray *tray, + GdkColor *fg, + GdkColor *error, + GdkColor *warning, + GdkColor *success); +void na_tray_force_redraw (NaTray *tray); + +NaTrayManager * na_tray_get_manager (NaTray *tray); + +G_END_DECLS + +#endif /* __NA_TRAY_H__ */ diff -Nru indicator-systemtray-unity-0.2/na-tray-manager.c indicator-systemtray-unity-0.2.1/na-tray-manager.c --- indicator-systemtray-unity-0.2/na-tray-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-tray-manager.c 2015-05-21 15:16:47.000000000 +0000 @@ -0,0 +1,990 @@ +/* na-tray-manager.c + * Copyright (C) 2002 Anders Carlsson + * Copyright (C) 2003-2006 Vincent Untz + * + * 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. + * + * Used to be: eggtraymanager.c + */ + +#include "config.h" +#include +#include + +#include "na-tray-manager.h" + +#if defined (GDK_WINDOWING_X11) +#include +#include +#elif defined (GDK_WINDOWING_WIN32) +#include +#endif +#include + +#include "na-marshal.h" + +/* 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; + char *str; +#ifdef GDK_WINDOWING_X11 + Window window; +#endif +} PendingMessage; + +static guint manager_signals[LAST_SIGNAL]; + +#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 + +#ifdef GDK_WINDOWING_X11 +static gboolean na_tray_manager_check_running_screen_x11 (GdkScreen *screen); +#endif + +static void na_tray_manager_finalize (GObject *object); +static void na_tray_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void na_tray_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void na_tray_manager_unmanage (NaTrayManager *manager); + +G_DEFINE_TYPE (NaTrayManager, na_tray_manager, G_TYPE_OBJECT) + +static void +na_tray_manager_init (NaTrayManager *manager) +{ + manager->invisible = NULL; + manager->socket_table = g_hash_table_new (NULL, NULL); + + manager->padding = 0; + manager->icon_size = 0; + + manager->fg.red = 0; + manager->fg.green = 0; + manager->fg.blue = 0; + + manager->error.red = 0xffff; + manager->error.green = 0; + manager->error.blue = 0; + + manager->warning.red = 0xffff; + manager->warning.green = 0xffff; + manager->warning.blue = 0; + + manager->success.red = 0; + manager->success.green = 0xffff; + manager->success.blue = 0; +} + +static void +na_tray_manager_class_init (NaTrayManagerClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *)klass; + + gobject_class->finalize = na_tray_manager_finalize; + gobject_class->set_property = na_tray_manager_set_property; + gobject_class->get_property = na_tray_manager_get_property; + + g_object_class_install_property (gobject_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + "orientation", + "orientation", + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); + + manager_signals[TRAY_ICON_ADDED] = + g_signal_new ("tray_icon_added", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NaTrayManagerClass, 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 (NaTrayManagerClass, 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 (NaTrayManagerClass, message_sent), + NULL, NULL, + _na_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 (NaTrayManagerClass, message_cancelled), + NULL, NULL, + _na_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 (NaTrayManagerClass, lost_selection), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + +#if defined (GDK_WINDOWING_X11) + /* Nothing */ +#elif defined (GDK_WINDOWING_WIN32) + g_warning ("Port NaTrayManager to Win32"); +#else + g_warning ("Port NaTrayManager to this GTK+ backend"); +#endif +} + +static void +na_tray_manager_finalize (GObject *object) +{ + NaTrayManager *manager; + + manager = NA_TRAY_MANAGER (object); + + na_tray_manager_unmanage (manager); + + g_list_free (manager->messages); + g_hash_table_destroy (manager->socket_table); + + G_OBJECT_CLASS (na_tray_manager_parent_class)->finalize (object); +} + +static void +na_tray_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NaTrayManager *manager = NA_TRAY_MANAGER (object); + + switch (prop_id) + { + case PROP_ORIENTATION: + na_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 +na_tray_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NaTrayManager *manager = NA_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; + } +} + +NaTrayManager * +na_tray_manager_new (void) +{ + NaTrayManager *manager; + + manager = g_object_new (NA_TYPE_TRAY_MANAGER, NULL); + + return manager; +} + +#ifdef GDK_WINDOWING_X11 + +static gboolean +na_tray_manager_plug_removed (GtkSocket *socket, + NaTrayManager *manager) +{ + NaTrayChild *child = NA_TRAY_CHILD (socket); + + g_hash_table_remove (manager->socket_table, + GINT_TO_POINTER (child->icon_window)); + g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child); + + /* This destroys the socket. */ + return FALSE; +} + +static void +na_tray_manager_handle_dock_request (NaTrayManager *manager, + XClientMessageEvent *xevent) +{ + Window icon_window = xevent->data.l[2]; + GtkWidget *child; + + if (g_hash_table_lookup (manager->socket_table, + GINT_TO_POINTER (icon_window))) + { + /* We already got this notification earlier, ignore this one */ + return; + } + + child = na_tray_child_new (manager->screen, icon_window); + if (child == NULL) /* already gone or other error */ + return; + + g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0, + child); + + /* If the child wasn't attached, then destroy it */ + + if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child)))) + { + gtk_widget_destroy (child); + return; + } + + g_signal_connect (child, "plug_removed", + G_CALLBACK (na_tray_manager_plug_removed), manager); + + gtk_socket_add_id (GTK_SOCKET (child), icon_window); + + if (!gtk_socket_get_plug_window (GTK_SOCKET (child))) + { + /* Embedding failed, we won't get a plug-removed signal */ + /* This signal destroys the socket */ + g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child); + return; + } + + g_hash_table_insert (manager->socket_table, + GINT_TO_POINTER (icon_window), child); + gtk_widget_show (child); +} + +static void +pending_message_free (PendingMessage *message) +{ + g_free (message->str); + g_free (message); +} + +static void +na_tray_manager_handle_message_data (NaTrayManager *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); + + pending_message_free (msg); + manager->messages = g_list_remove_link (manager->messages, p); + g_list_free_1 (p); + } + + break; + } + } +} + +static void +na_tray_manager_handle_begin_message (NaTrayManager *manager, + XClientMessageEvent *xevent) +{ + GtkSocket *socket; + GList *p; + PendingMessage *msg; + long timeout; + long len; + long id; + + socket = g_hash_table_lookup (manager->socket_table, + GINT_TO_POINTER (xevent->window)); + /* we don't know about this tray icon, so ignore the message */ + if (!socket) + return; + + timeout = xevent->data.l[2]; + len = xevent->data.l[3]; + id = xevent->data.l[4]; + + /* Check if the same message is already in the queue and remove it if so */ + for (p = manager->messages; p; p = p->next) + { + PendingMessage *pmsg = p->data; + + if (xevent->window == pmsg->window && + id == pmsg->id) + { + /* Hmm, we found it, now remove it */ + pending_message_free (pmsg); + manager->messages = g_list_remove_link (manager->messages, p); + g_list_free_1 (p); + break; + } + } + + if (len == 0) + { + g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0, + socket, "", id, timeout); + } + else + { + /* Now add the new message to the queue */ + msg = g_new0 (PendingMessage, 1); + msg->window = xevent->window; + msg->timeout = timeout; + msg->len = len; + msg->id = id; + 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 +na_tray_manager_handle_cancel_message (NaTrayManager *manager, + XClientMessageEvent *xevent) +{ + GList *p; + GtkSocket *socket; + long id; + + id = xevent->data.l[2]; + + /* Check if the message is 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 && + id == msg->id) + { + pending_message_free (msg); + manager->messages = g_list_remove_link (manager->messages, p); + g_list_free_1 (p); + break; + } + } + + 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 +na_tray_manager_window_filter (GdkXEvent *xev, + GdkEvent *event, + gpointer data) +{ + XEvent *xevent = (GdkXEvent *)xev; + NaTrayManager *manager = data; + + if (xevent->type == ClientMessage) + { + /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_REQUEST_DOCK */ + if (xevent->xclient.message_type == manager->opcode_atom && + xevent->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) + { + na_tray_manager_handle_dock_request (manager, + (XClientMessageEvent *) xevent); + return GDK_FILTER_REMOVE; + } + /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_BEGIN_MESSAGE */ + else if (xevent->xclient.message_type == manager->opcode_atom && + xevent->xclient.data.l[1] == SYSTEM_TRAY_BEGIN_MESSAGE) + { + na_tray_manager_handle_begin_message (manager, + (XClientMessageEvent *) event); + return GDK_FILTER_REMOVE; + } + /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_CANCEL_MESSAGE */ + else if (xevent->xclient.message_type == manager->opcode_atom && + xevent->xclient.data.l[1] == SYSTEM_TRAY_CANCEL_MESSAGE) + { + na_tray_manager_handle_cancel_message (manager, + (XClientMessageEvent *) event); + return GDK_FILTER_REMOVE; + } + /* _NET_SYSTEM_TRAY_MESSAGE_DATA */ + else if (xevent->xclient.message_type == manager->message_data_atom) + { + na_tray_manager_handle_message_data (manager, + (XClientMessageEvent *) event); + return GDK_FILTER_REMOVE; + } + } + else if (xevent->type == SelectionClear) + { + g_signal_emit (manager, manager_signals[LOST_SELECTION], 0); + na_tray_manager_unmanage (manager); + } + + return GDK_FILTER_CONTINUE; +} + +#if 0 +//FIXME investigate why this doesn't work +static gboolean +na_tray_manager_selection_clear_event (GtkWidget *widget, + GdkEventSelection *event, + NaTrayManager *manager) +{ + g_signal_emit (manager, manager_signals[LOST_SELECTION], 0); + na_tray_manager_unmanage (manager); + + return FALSE; +} +#endif +#endif + +static void +na_tray_manager_unmanage (NaTrayManager *manager) +{ +#ifdef GDK_WINDOWING_X11 + GdkDisplay *display; + guint32 timestamp; + GtkWidget *invisible; + GdkWindow *window; + + if (manager->invisible == NULL) + return; + + invisible = manager->invisible; + window = gtk_widget_get_window (invisible); + + g_assert (GTK_IS_INVISIBLE (invisible)); + g_assert (gtk_widget_get_realized (invisible)); + g_assert (GDK_IS_WINDOW (window)); + + display = gtk_widget_get_display (invisible); + + if (gdk_selection_owner_get_for_display (display, manager->selection_atom) == + window) + { + timestamp = gdk_x11_get_server_time (window); + gdk_selection_owner_set_for_display (display, + NULL, + manager->selection_atom, + timestamp, + TRUE); + } + + gdk_window_remove_filter (window, + na_tray_manager_window_filter, manager); + + manager->invisible = NULL; /* prior to destroy for reentrancy paranoia */ + gtk_widget_destroy (invisible); + g_object_unref (G_OBJECT (invisible)); +#endif +} + +static void +na_tray_manager_set_orientation_property (NaTrayManager *manager) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *window; + GdkDisplay *display; + Atom orientation_atom; + gulong data[1]; + + g_return_if_fail (manager->invisible != NULL); + window = gtk_widget_get_window (manager->invisible); + g_return_if_fail (window != NULL); + + display = gtk_widget_get_display (manager->invisible); + orientation_atom = gdk_x11_get_xatom_by_name_for_display (display, + "_NET_SYSTEM_TRAY_ORIENTATION"); + + data[0] = manager->orientation == GTK_ORIENTATION_HORIZONTAL ? + SYSTEM_TRAY_ORIENTATION_HORZ : + SYSTEM_TRAY_ORIENTATION_VERT; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + orientation_atom, + XA_CARDINAL, 32, + PropModeReplace, + (guchar *) &data, 1); +#endif +} + +static void +na_tray_manager_set_visual_property (NaTrayManager *manager) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *window; + GdkDisplay *display; + Visual *xvisual; + Atom visual_atom; + gulong data[1]; + + g_return_if_fail (manager->invisible != NULL); + window = gtk_widget_get_window (manager->invisible); + g_return_if_fail (window != NULL); + + /* The visual property is a hint to the tray icons as to what visual they + * should use for their windows. If the X server has RGBA colormaps, then + * we tell the tray icons to use a RGBA colormap and we'll composite the + * icon onto its parents with real transparency. Otherwise, we just tell + * the icon to use our colormap, and we'll do some hacks with parent + * relative backgrounds to simulate transparency. + */ + + display = gtk_widget_get_display (manager->invisible); + visual_atom = gdk_x11_get_xatom_by_name_for_display (display, + "_NET_SYSTEM_TRAY_VISUAL"); + + if (gdk_screen_get_rgba_visual (manager->screen) != NULL && + gdk_display_supports_composite (display)) + xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (manager->screen)); + else + { + /* We actually want the visual of the tray where the icons will + * be embedded. In almost all cases, this will be the same as the visual + * of the screen. + */ + xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (manager->screen)); + } + + data[0] = XVisualIDFromVisual (xvisual); + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + visual_atom, + XA_VISUALID, 32, + PropModeReplace, + (guchar *) &data, 1); +#endif +} + +static void +na_tray_manager_set_padding_property (NaTrayManager *manager) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *window; + GdkDisplay *display; + Atom atom; + gulong data[1]; + + g_return_if_fail (manager->invisible != NULL); + window = gtk_widget_get_window (manager->invisible); + g_return_if_fail (window != NULL); + + display = gtk_widget_get_display (manager->invisible); + atom = gdk_x11_get_xatom_by_name_for_display (display, + "_NET_SYSTEM_TRAY_PADDING"); + + data[0] = manager->padding; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + atom, + XA_CARDINAL, 32, + PropModeReplace, + (guchar *) &data, 1); +#endif +} + +static void +na_tray_manager_set_icon_size_property (NaTrayManager *manager) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *window; + GdkDisplay *display; + Atom atom; + gulong data[1]; + + g_return_if_fail (manager->invisible != NULL); + window = gtk_widget_get_window (manager->invisible); + g_return_if_fail (window != NULL); + + display = gtk_widget_get_display (manager->invisible); + atom = gdk_x11_get_xatom_by_name_for_display (display, + "_NET_SYSTEM_TRAY_ICON_SIZE"); + + data[0] = manager->icon_size; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + atom, + XA_CARDINAL, 32, + PropModeReplace, + (guchar *) &data, 1); +#endif +} + +static void +na_tray_manager_set_colors_property (NaTrayManager *manager) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *window; + GdkDisplay *display; + Atom atom; + gulong data[12]; + + g_return_if_fail (manager->invisible != NULL); + window = gtk_widget_get_window (manager->invisible); + g_return_if_fail (window != NULL); + + display = gtk_widget_get_display (manager->invisible); + atom = gdk_x11_get_xatom_by_name_for_display (display, + "_NET_SYSTEM_TRAY_COLORS"); + + data[0] = manager->fg.red; + data[1] = manager->fg.green; + data[2] = manager->fg.blue; + data[3] = manager->error.red; + data[4] = manager->error.green; + data[5] = manager->error.blue; + data[6] = manager->warning.red; + data[7] = manager->warning.green; + data[8] = manager->warning.blue; + data[9] = manager->success.red; + data[10] = manager->success.green; + data[11] = manager->success.blue; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + atom, + XA_CARDINAL, 32, + PropModeReplace, + (guchar *) &data, 12); +#endif +} + +#ifdef GDK_WINDOWING_X11 + +static gboolean +na_tray_manager_manage_screen_x11 (NaTrayManager *manager, + GdkScreen *screen) +{ + GdkDisplay *display; + Screen *xscreen; + GtkWidget *invisible; + GdkWindow *window; + char *selection_atom_name; + guint32 timestamp; + + g_return_val_if_fail (NA_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 (na_tray_manager_check_running_screen_x11 (screen)) + return FALSE; +#endif + + manager->screen = screen; + + display = gdk_screen_get_display (screen); + xscreen = GDK_SCREEN_XSCREEN (screen); + + 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", + gdk_screen_get_number (screen)); + manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE); + g_free (selection_atom_name); + + manager->invisible = invisible; + g_object_ref (G_OBJECT (manager->invisible)); + + na_tray_manager_set_orientation_property (manager); + na_tray_manager_set_visual_property (manager); + na_tray_manager_set_padding_property (manager); + na_tray_manager_set_icon_size_property (manager); + na_tray_manager_set_colors_property (manager); + + window = gtk_widget_get_window (invisible); + + timestamp = gdk_x11_get_server_time (window); + + /* Check if we could set the selection owner successfully */ + if (gdk_selection_owner_set_for_display (display, + window, + manager->selection_atom, + timestamp, + TRUE)) + { + XClientMessageEvent xev; + GdkAtom opcode_atom; + GdkAtom message_data_atom; + + xev.type = ClientMessage; + xev.window = RootWindowOfScreen (xscreen); + xev.message_type = gdk_x11_get_xatom_by_name_for_display (display, + "MANAGER"); + + xev.format = 32; + xev.data.l[0] = timestamp; + xev.data.l[1] = gdk_x11_atom_to_xatom_for_display (display, + manager->selection_atom); + xev.data.l[2] = GDK_WINDOW_XID (window); + xev.data.l[3] = 0; /* manager specific data */ + xev.data.l[4] = 0; /* manager specific data */ + + XSendEvent (GDK_DISPLAY_XDISPLAY (display), + RootWindowOfScreen (xscreen), + False, StructureNotifyMask, (XEvent *)&xev); + + opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE); + manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display, + opcode_atom); + + message_data_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_MESSAGE_DATA", + FALSE); + manager->message_data_atom = gdk_x11_atom_to_xatom_for_display (display, + message_data_atom); + + /* Add a window filter */ +#if 0 + /* This is for when we lose the selection of _NET_SYSTEM_TRAY_Sx */ + g_signal_connect (invisible, "selection-clear-event", + G_CALLBACK (na_tray_manager_selection_clear_event), + manager); +#endif + gdk_window_add_filter (window, + na_tray_manager_window_filter, manager); + return TRUE; + } + else + { + gtk_widget_destroy (invisible); + g_object_unref (invisible); + manager->invisible = NULL; + + manager->screen = NULL; + + return FALSE; + } +} + +#endif + +gboolean +na_tray_manager_manage_screen (NaTrayManager *manager, + GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (manager->screen == NULL, FALSE); + +#ifdef GDK_WINDOWING_X11 + return na_tray_manager_manage_screen_x11 (manager, screen); +#else + return FALSE; +#endif +} + +#ifdef GDK_WINDOWING_X11 + +static gboolean +na_tray_manager_check_running_screen_x11 (GdkScreen *screen) +{ + GdkDisplay *display; + Atom selection_atom; + char *selection_atom_name; + + display = gdk_screen_get_display (screen); + selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", + gdk_screen_get_number (screen)); + selection_atom = gdk_x11_get_xatom_by_name_for_display (display, + selection_atom_name); + g_free (selection_atom_name); + + if (XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), + selection_atom) != None) + return TRUE; + else + return FALSE; +} + +#endif + +gboolean +na_tray_manager_check_running (GdkScreen *screen) +{ + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + +#ifdef GDK_WINDOWING_X11 + return na_tray_manager_check_running_screen_x11 (screen); +#else + return FALSE; +#endif +} + +void +na_tray_manager_set_orientation (NaTrayManager *manager, + GtkOrientation orientation) +{ + g_return_if_fail (NA_IS_TRAY_MANAGER (manager)); + + if (manager->orientation != orientation) + { + manager->orientation = orientation; + + na_tray_manager_set_orientation_property (manager); + + g_object_notify (G_OBJECT (manager), "orientation"); + } +} + +void +na_tray_manager_set_padding (NaTrayManager *manager, + gint padding) +{ + g_return_if_fail (NA_IS_TRAY_MANAGER (manager)); + + if (manager->padding != padding) + { + manager->padding = padding; + + na_tray_manager_set_padding_property (manager); + } +} + +void +na_tray_manager_set_icon_size (NaTrayManager *manager, + gint icon_size) +{ + g_return_if_fail (NA_IS_TRAY_MANAGER (manager)); + + if (manager->icon_size != icon_size) + { + manager->icon_size = icon_size; + + na_tray_manager_set_icon_size_property (manager); + } +} + +void +na_tray_manager_set_colors (NaTrayManager *manager, + GdkColor *fg, + GdkColor *error, + GdkColor *warning, + GdkColor *success) +{ + g_return_if_fail (NA_IS_TRAY_MANAGER (manager)); + + if (!gdk_color_equal (&manager->fg, fg) || + !gdk_color_equal (&manager->error, error) || + !gdk_color_equal (&manager->warning, warning) || + !gdk_color_equal (&manager->success, success)) + { + manager->fg = *fg; + manager->error = *error; + manager->warning = *warning; + manager->success = *success; + + na_tray_manager_set_colors_property (manager); + } +} + +GtkOrientation +na_tray_manager_get_orientation (NaTrayManager *manager) +{ + g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), GTK_ORIENTATION_HORIZONTAL); + + return manager->orientation; +} diff -Nru indicator-systemtray-unity-0.2/na-tray-manager.h indicator-systemtray-unity-0.2.1/na-tray-manager.h --- indicator-systemtray-unity-0.2/na-tray-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/na-tray-manager.h 2014-01-15 12:04:34.000000000 +0000 @@ -0,0 +1,114 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* na-tray-manager.h + * Copyright (C) 2002 Anders Carlsson + * Copyright (C) 2003-2006 Vincent Untz + * + * 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. + * + * Used to be: eggtraymanager.h + */ + +#ifndef __NA_TRAY_MANAGER_H__ +#define __NA_TRAY_MANAGER_H__ + +#ifdef GDK_WINDOWING_X11 +#include +#endif +#include + +#include "na-tray-child.h" + +G_BEGIN_DECLS + +#define NA_TYPE_TRAY_MANAGER (na_tray_manager_get_type ()) +#define NA_TRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_MANAGER, NaTrayManager)) +#define NA_TRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_MANAGER, NaTrayManagerClass)) +#define NA_IS_TRAY_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_MANAGER)) +#define NA_IS_TRAY_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_MANAGER)) +#define NA_TRAY_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_MANAGER, NaTrayManagerClass)) + +typedef struct _NaTrayManager NaTrayManager; +typedef struct _NaTrayManagerClass NaTrayManagerClass; + +struct _NaTrayManager +{ + GObject parent_instance; + +#ifdef GDK_WINDOWING_X11 + GdkAtom selection_atom; + Atom opcode_atom; + Atom message_data_atom; +#endif + + GtkWidget *invisible; + GdkScreen *screen; + GtkOrientation orientation; + gint padding; + gint icon_size; + GdkColor fg; + GdkColor error; + GdkColor warning; + GdkColor success; + + GList *messages; + GHashTable *socket_table; +}; + +struct _NaTrayManagerClass +{ + GObjectClass parent_class; + + void (* tray_icon_added) (NaTrayManager *manager, + NaTrayChild *child); + void (* tray_icon_removed) (NaTrayManager *manager, + NaTrayChild *child); + + void (* message_sent) (NaTrayManager *manager, + NaTrayChild *child, + const gchar *message, + glong id, + glong timeout); + + void (* message_cancelled) (NaTrayManager *manager, + NaTrayChild *child, + glong id); + + void (* lost_selection) (NaTrayManager *manager); +}; + +GType na_tray_manager_get_type (void); + +gboolean na_tray_manager_check_running (GdkScreen *screen); +NaTrayManager *na_tray_manager_new (void); +gboolean na_tray_manager_manage_screen (NaTrayManager *manager, + GdkScreen *screen); +void na_tray_manager_set_orientation (NaTrayManager *manager, + GtkOrientation orientation); +GtkOrientation na_tray_manager_get_orientation (NaTrayManager *manager); +void na_tray_manager_set_padding (NaTrayManager *manager, + gint padding); +void na_tray_manager_set_icon_size (NaTrayManager *manager, + gint padding); +void na_tray_manager_set_colors (NaTrayManager *manager, + GdkColor *fg, + GdkColor *error, + GdkColor *warning, + GdkColor *success); + + +G_END_DECLS + +#endif /* __NA_TRAY_MANAGER_H__ */ diff -Nru indicator-systemtray-unity-0.2/po/ar.po indicator-systemtray-unity-0.2.1/po/ar.po --- indicator-systemtray-unity-0.2/po/ar.po 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/po/ar.po 2015-06-03 06:45:22.000000000 +0000 @@ -0,0 +1,52 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: indicator-systemtray-unity 0.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-03 11:42+0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator-systemtray.c:223 +msgid "Settings" +msgstr "الإعدادات" + +#: indicator-systemtray.c:228 +msgid "Background" +msgstr "" + +#: indicator-systemtray.c:233 +msgid "Static" +msgstr "" + +#: indicator-systemtray.c:238 indicator-systemtray.c:257 +#: indicator-systemtray.c:407 indicator-systemtray.c:432 +msgid "Color" +msgstr "" + +#: indicator-systemtray.c:241 indicator-systemtray.c:260 +#: indicator-systemtray.c:416 indicator-systemtray.c:441 +msgid "Stroke" +msgstr "" + +#: indicator-systemtray.c:244 indicator-systemtray.c:263 +msgid "Show" +msgstr "" + +#: indicator-systemtray.c:248 indicator-systemtray.c:267 +msgid "Reset" +msgstr "" + +#: indicator-systemtray.c:252 +msgid "Floating" +msgstr "" diff -Nru indicator-systemtray-unity-0.2/po/de.po indicator-systemtray-unity-0.2.1/po/de.po --- indicator-systemtray-unity-0.2/po/de.po 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/po/de.po 2015-06-03 07:03:43.000000000 +0000 @@ -0,0 +1,52 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: indicator-systemtray-unity 0.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-03 11:42+0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator-systemtray.c:223 +msgid "Settings" +msgstr "Einstellungen" + +#: indicator-systemtray.c:228 +msgid "Background" +msgstr "Hintergrund" + +#: indicator-systemtray.c:233 +msgid "Static" +msgstr "Statische" + +#: indicator-systemtray.c:238 indicator-systemtray.c:257 +#: indicator-systemtray.c:407 indicator-systemtray.c:432 +msgid "Color" +msgstr "Farbe" + +#: indicator-systemtray.c:241 indicator-systemtray.c:260 +#: indicator-systemtray.c:416 indicator-systemtray.c:441 +msgid "Stroke" +msgstr "Kontur" + +#: indicator-systemtray.c:244 indicator-systemtray.c:263 +msgid "Show" +msgstr "Zeigen" + +#: indicator-systemtray.c:248 indicator-systemtray.c:267 +msgid "Reset" +msgstr "Zurücksetzen" + +#: indicator-systemtray.c:252 +msgid "Floating" +msgstr "Schwimmende" diff -Nru indicator-systemtray-unity-0.2/po/fr.po indicator-systemtray-unity-0.2.1/po/fr.po --- indicator-systemtray-unity-0.2/po/fr.po 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/po/fr.po 2015-06-03 07:11:40.000000000 +0000 @@ -0,0 +1,52 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: indicator-systemtray-unity 0.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-03 11:42+0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator-systemtray.c:223 +msgid "Settings" +msgstr "Paramètres" + +#: indicator-systemtray.c:228 +msgid "Background" +msgstr "Arrière-plan" + +#: indicator-systemtray.c:233 +msgid "Static" +msgstr "Statique" + +#: indicator-systemtray.c:238 indicator-systemtray.c:257 +#: indicator-systemtray.c:407 indicator-systemtray.c:432 +msgid "Color" +msgstr "Couleur" + +#: indicator-systemtray.c:241 indicator-systemtray.c:260 +#: indicator-systemtray.c:416 indicator-systemtray.c:441 +msgid "Stroke" +msgstr "Contour" + +#: indicator-systemtray.c:244 indicator-systemtray.c:263 +msgid "Show" +msgstr "Afficher" + +#: indicator-systemtray.c:248 indicator-systemtray.c:267 +msgid "Reset" +msgstr "Réinitialiser" + +#: indicator-systemtray.c:252 +msgid "Floating" +msgstr "Flottant" diff -Nru indicator-systemtray-unity-0.2/po/indicator-systemtray.pot indicator-systemtray-unity-0.2.1/po/indicator-systemtray.pot --- indicator-systemtray-unity-0.2/po/indicator-systemtray.pot 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/po/indicator-systemtray.pot 2015-06-03 14:20:24.000000000 +0000 @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-03 19:20+0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator-systemtray.c:223 +msgid "Settings" +msgstr "" + +#: indicator-systemtray.c:228 +msgid "Background" +msgstr "" + +#: indicator-systemtray.c:233 +msgid "Static" +msgstr "" + +#: indicator-systemtray.c:238 indicator-systemtray.c:257 +#: indicator-systemtray.c:407 indicator-systemtray.c:432 +msgid "Color" +msgstr "" + +#: indicator-systemtray.c:241 indicator-systemtray.c:260 +#: indicator-systemtray.c:416 indicator-systemtray.c:441 +msgid "Stroke" +msgstr "" + +#: indicator-systemtray.c:244 indicator-systemtray.c:263 +msgid "Show" +msgstr "" + +#: indicator-systemtray.c:248 indicator-systemtray.c:267 +msgid "Reset" +msgstr "" + +#: indicator-systemtray.c:252 +msgid "Floating" +msgstr "" + diff -Nru indicator-systemtray-unity-0.2/po/ru.po indicator-systemtray-unity-0.2.1/po/ru.po --- indicator-systemtray-unity-0.2/po/ru.po 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/po/ru.po 2015-06-03 06:56:22.000000000 +0000 @@ -0,0 +1,52 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: indicator-systemtray-unity 0.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-03 11:42+0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Gleb Golovachev \n" +"Language-Team: LANGUAGE \n" +"Language: Russian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator-systemtray.c:223 +msgid "Settings" +msgstr "Настройки" + +#: indicator-systemtray.c:228 +msgid "Background" +msgstr "Фон" + +#: indicator-systemtray.c:233 +msgid "Static" +msgstr "Статический" + +#: indicator-systemtray.c:238 indicator-systemtray.c:257 +#: indicator-systemtray.c:407 indicator-systemtray.c:432 +msgid "Color" +msgstr "Цвет" + +#: indicator-systemtray.c:241 indicator-systemtray.c:260 +#: indicator-systemtray.c:416 indicator-systemtray.c:441 +msgid "Stroke" +msgstr "Обводка" + +#: indicator-systemtray.c:244 indicator-systemtray.c:263 +msgid "Show" +msgstr "Показать" + +#: indicator-systemtray.c:248 indicator-systemtray.c:267 +msgid "Reset" +msgstr "Сброс" + +#: indicator-systemtray.c:252 +msgid "Floating" +msgstr "Плавающий" diff -Nru indicator-systemtray-unity-0.2/po/uk.po indicator-systemtray-unity-0.2.1/po/uk.po --- indicator-systemtray-unity-0.2/po/uk.po 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/po/uk.po 2015-06-03 06:59:42.000000000 +0000 @@ -0,0 +1,52 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: indicator-systemtray-unity 0.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-06-03 11:42+0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator-systemtray.c:223 +msgid "Settings" +msgstr "Параметри" + +#: indicator-systemtray.c:228 +msgid "Background" +msgstr "Фон" + +#: indicator-systemtray.c:233 +msgid "Static" +msgstr "Статичний" + +#: indicator-systemtray.c:238 indicator-systemtray.c:257 +#: indicator-systemtray.c:407 indicator-systemtray.c:432 +msgid "Color" +msgstr "Колір" + +#: indicator-systemtray.c:241 indicator-systemtray.c:260 +#: indicator-systemtray.c:416 indicator-systemtray.c:441 +msgid "Stroke" +msgstr "Обведення" + +#: indicator-systemtray.c:244 indicator-systemtray.c:263 +msgid "Show" +msgstr "Показати" + +#: indicator-systemtray.c:248 indicator-systemtray.c:267 +msgid "Reset" +msgstr "Скидання" + +#: indicator-systemtray.c:252 +msgid "Floating" +msgstr "Плаваючий" diff -Nru indicator-systemtray-unity-0.2/potomo.sh indicator-systemtray-unity-0.2.1/potomo.sh --- indicator-systemtray-unity-0.2/potomo.sh 1970-01-01 00:00:00.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/potomo.sh 2015-06-03 06:38:50.000000000 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +xgettext -k_ indicator-systemtray.c -o indicator-systemtray.pot +echo >>indicator-systemtray.pot +cp indicator-systemtray.pot ./po/indicator-systemtray.pot +cd po +f=`find -name \*.po` +for po_file in $f +do +echo "Processing ${po_file}" +po_file=`echo ${po_file} | sed -e 's/.\///'` +lang=`echo ${po_file} | sed -e 's/.po$//'` +echo ${po_file} +echo ${lang} +msgmerge -U ${lang}.po indicator-systemtray.pot +if [ "$@" == "" ]; +then +mo_dir=usr/share/locale/${lang}/LC_MESSAGES +else +mo_dir=$@/${lang}/LC_MESSAGES +fi +mkdir -p ${mo_dir} +msgfmt ${lang}.po -o ${mo_dir}/indicator-systemtray-unity.mo +done +cd .. diff -Nru indicator-systemtray-unity-0.2/README.md indicator-systemtray-unity-0.2.1/README.md --- indicator-systemtray-unity-0.2/README.md 2015-04-29 19:40:31.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/README.md 2015-05-01 10:09:54.000000000 +0000 @@ -12,20 +12,22 @@ cd indicator-systemtray-unity make sudo make install - -re-login ``` +re-login + Deb ----- ``` sudo apt-get install fakeroot dpkg-dev +``` delete line ( glib-compile-schemas $(DESTDIR)/usr/share/glib-2.0/schemas/ ) in Makefile +``` dpkg-buildpackage -rfakeroot -b - ``` + PPA ----- @@ -35,12 +37,16 @@ sudo apt-get install indicator-systemtray-unity ``` +To remove this package (with its configuration files!!!): +``` +sudo apt-get --purge remove indicator-systemtray-unity +``` Settings ----- To change the mode position: press the middle mouse button on the indicator. -The horizontal position can be changed: scrolling over the indicator. +The horizontal position can be changed: scrolling the mouse over the indicator. Settings can be changed in gsettings:/net/launchpad/indicator/systemtray (use dconf-editor). diff -Nru indicator-systemtray-unity-0.2/resources/net.launchpad.indicator.systemtray.gschema.xml indicator-systemtray-unity-0.2.1/resources/net.launchpad.indicator.systemtray.gschema.xml --- indicator-systemtray-unity-0.2/resources/net.launchpad.indicator.systemtray.gschema.xml 2015-04-29 19:40:31.000000000 +0000 +++ indicator-systemtray-unity-0.2.1/resources/net.launchpad.indicator.systemtray.gschema.xml 2015-06-01 18:15:25.000000000 +0000 @@ -26,5 +26,35 @@ Position Y Position Y when in mode "show always". + + true + Show the background for static Systemtray + To display a background value must be TRUE. + + + 'rgba(153,153,153,200)' + Static. Color + The color of the Systemtray background. (0 - 255,...) + + + '#000000' + Static. Stroke. Color + The color of the Systemtray background. (0 - 255,...) + + + true + Show the background for floating Systemtray + To display a background value must be TRUE. + + + 'rgba(153,153,153,200)' + Static. Color + The color of the Systemtray background. (0 - 255,...) + + + '#000000' + Static. Stroke. Color + The color of the Systemtray background. (0 - 255,...) +