~ubuntu-branches/ubuntu/vivid/liferea/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/gtk-status-icon.patch/src/ui/ui_tray.c

  • Committer: Package Import Robot
  • Author(s): bojo42
  • Date: 2012-03-29 14:17:21 UTC
  • mfrom: (1.3.9) (3.2.5 sid)
  • Revision ID: package-import@ubuntu.com-20120329141721-tbfopcrc5797wxt7
Tags: 1.8.3-0.1ubuntu1
* New upstream release (LP: #290666, #371754, #741543, #716688)
* Merge from Debian unstable (LP: #935147), remaining changes:
* debian/patches:
  - drop gtk-status-icon.patch & notification-append as in upstream
  - drop fix_systray_behavior as mostly upstreamed and rest seems unused
  - 01_ubuntu_feedlists: update & rename, move planets to "Open Source"  
  - add_X-Ubuntu-Gettext-Domain: rebase
  - libunity.patch: rebase, apply before indicator patch (liferea_shell.c)
  - libindicate_increase_version.patch: exclude from libindicate.patch
  - deactivate libindicate.patch, seems partly upstreamed and needs rework
* debian/control: libindicate-dev, libindicate-gtk-dev & libunity-dev
* debian/liferea.indicate & liferea.install: ship indicator desktop file
* debian/rules: enable libindicate

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * @file ui_tray.c tray icon handling
3
 
 * 
4
 
 * Copyright (C) 2003-2009 Lars Lindner <lars.lindner@gmail.com>
5
 
 * Copyright (C) 2004 Christophe Barbe <christophe.barbe@ufies.org>
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or modify
8
 
 * it under the terms of the GNU General Public License as published by
9
 
 * the Free Software Foundation; either version 2 of the License, or
10
 
 * (at your option) any later version.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 
 */
21
 
 
22
 
#ifdef HAVE_CONFIG_H
23
 
#  include <config.h>
24
 
#endif
25
 
 
26
 
#include <math.h>
27
 
#include <string.h>
28
 
#include <gtk/gtk.h>
29
 
#include <gdk/gdk.h>
30
 
 
31
 
#include "common.h"
32
 
#include "conf.h"
33
 
#include "eggtrayicon.h"
34
 
#include "feedlist.h"
35
 
#include "net.h"
36
 
#include "ui/liferea_shell.h"
37
 
#include "ui/ui_common.h"
38
 
#include "ui/ui_popup.h"
39
 
#include "ui/ui_tray.h"
40
 
 
41
 
// FIXME: determine this from Pango or Cairo somehow...
42
 
#define FONT_CHAR_WIDTH 6
43
 
#define FONT_CHAR_HEIGHT 8
44
 
 
45
 
#define TRAY_ICON_WIDTH 16
46
 
#define TRAY_ICON_HEIGHT 16
47
 
 
48
 
static struct trayIcon_priv {
49
 
        int             trayCount;              /**< reference counter */
50
 
        GdkPixbuf       *currentIcon;           /**< currently displayed icon */
51
 
        
52
 
        EggTrayIcon     *widget;                /**< the tray icon widget */
53
 
        GtkWidget       *image;                 /**< render widget in the notification area */
54
 
        GtkWidget       *alignment;
55
 
        GtkWidget       *eventBox;
56
 
} *trayIcon_priv = NULL;
57
 
 
58
 
static void ui_tray_install(void);
59
 
 
60
 
static void
61
 
ui_tray_tooltip_set (const gchar *message)
62
 
{
63
 
        gtk_widget_set_tooltip_text(GTK_WIDGET(trayIcon_priv->eventBox), message);
64
 
}
65
 
 
66
 
static void ui_tray_expose_cb() {
67
 
        cairo_t         *c;
68
 
        gchar           *str;
69
 
        guint           newItems;
70
 
        GtkRequisition  requisition;
71
 
        
72
 
        gtk_widget_size_request(GTK_WIDGET(trayIcon_priv->widget), &requisition);
73
 
        
74
 
        /* We expect currentIcon to be a 16x16 image and we will 
75
 
           render a colored area with height 10 in the middle of 
76
 
           the image with 8pt text inside */
77
 
 
78
 
        gdk_draw_pixbuf(GDK_DRAWABLE(trayIcon_priv->image->window), 
79
 
                        NULL, trayIcon_priv->currentIcon, 0, 0, 
80
 
                        (requisition.width > TRAY_ICON_WIDTH)?(requisition.width - TRAY_ICON_WIDTH)/2 - 1:0, 
81
 
                        (requisition.height > TRAY_ICON_HEIGHT)?(requisition.height - TRAY_ICON_HEIGHT)/2 - 1:0, 
82
 
                        gdk_pixbuf_get_width(trayIcon_priv->currentIcon), 
83
 
                        gdk_pixbuf_get_height(trayIcon_priv->currentIcon),
84
 
                        GDK_RGB_DITHER_NONE, 0, 0);
85
 
        
86
 
        if(!conf_get_bool_value(SHOW_NEW_COUNT_IN_TRAY))
87
 
                return;
88
 
        
89
 
        newItems = feedlist_get_new_item_count();
90
 
        if(newItems > 0) {
91
 
                guint textWidth, textStart;
92
 
                str = g_strdup_printf("%d", newItems);
93
 
                textWidth = strlen(str) * FONT_CHAR_WIDTH;
94
 
                
95
 
                if(textWidth + 2 > TRAY_ICON_WIDTH)
96
 
                        textStart = 1;
97
 
                else
98
 
                        textStart = TRAY_ICON_WIDTH/2 - textWidth/2;
99
 
 
100
 
                c = gdk_cairo_create(trayIcon_priv->image->window);
101
 
                cairo_rectangle(c, textStart - 1, 3, textWidth + 1, FONT_CHAR_HEIGHT + 2);
102
 
                cairo_set_source_rgb(c, 1, 0.50, 0.10); // orange
103
 
                cairo_fill(c);
104
 
 
105
 
                cairo_set_source_rgb(c, 1, 1, 1);               
106
 
                cairo_move_to(c, textStart - 1, 3 + FONT_CHAR_HEIGHT);
107
 
                cairo_select_font_face(c, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
108
 
                cairo_set_font_size(c, FONT_CHAR_HEIGHT + 2);
109
 
                cairo_show_text(c, str);
110
 
                cairo_destroy(c);
111
 
 
112
 
                g_free(str);
113
 
        }
114
 
}
115
 
 
116
 
static void
117
 
ui_tray_icon_set (gint newItems, GdkPixbuf *icon)
118
 
{
119
 
        guint   width;
120
 
 
121
 
        g_assert (trayIcon_priv->widget);
122
 
 
123
 
        /* Having two code branches here to have real transparency
124
 
           at least with new count disabled... */
125
 
        if (conf_get_bool_value (SHOW_NEW_COUNT_IN_TRAY)) {     
126
 
                width = ((guint) log10 (newItems) + 1) * FONT_CHAR_WIDTH;
127
 
                width += 2; /* number color border */
128
 
                width += 2; /* tray icon padding */;
129
 
                if (width < 16)
130
 
                        width = 16;
131
 
 
132
 
                trayIcon_priv->currentIcon = icon;
133
 
 
134
 
                if (trayIcon_priv->image)
135
 
                        gtk_widget_destroy (trayIcon_priv->image);
136
 
 
137
 
                if (trayIcon_priv->alignment)
138
 
                        gtk_widget_destroy (trayIcon_priv->alignment);
139
 
 
140
 
                trayIcon_priv->alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
141
 
                trayIcon_priv->image = gtk_drawing_area_new ();
142
 
                gtk_widget_set_size_request (trayIcon_priv->image, width, 16);
143
 
                g_signal_connect (G_OBJECT (trayIcon_priv->image), "expose_event",  
144
 
                                  G_CALLBACK (ui_tray_expose_cb), NULL);
145
 
 
146
 
                gtk_container_add (GTK_CONTAINER (trayIcon_priv->eventBox), trayIcon_priv->alignment);
147
 
                gtk_container_add (GTK_CONTAINER (trayIcon_priv->alignment), trayIcon_priv->image);
148
 
                gtk_widget_show_all (GTK_WIDGET(trayIcon_priv->widget));
149
 
        } else {
150
 
                /* Skip loading icon if already displayed. */
151
 
                if (icon == trayIcon_priv->currentIcon)
152
 
                        return;
153
 
                trayIcon_priv->currentIcon = icon;
154
 
 
155
 
                if (trayIcon_priv->image)
156
 
                        gtk_widget_destroy (trayIcon_priv->image);
157
 
 
158
 
                if (trayIcon_priv->alignment) {
159
 
                        gtk_widget_destroy (trayIcon_priv->alignment);
160
 
                        trayIcon_priv->alignment = NULL;
161
 
                }
162
 
 
163
 
                trayIcon_priv->alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
164
 
                trayIcon_priv->image = gtk_image_new_from_pixbuf (icon);
165
 
                gtk_container_add (GTK_CONTAINER (trayIcon_priv->eventBox), trayIcon_priv->alignment);
166
 
                gtk_container_add (GTK_CONTAINER (trayIcon_priv->alignment), trayIcon_priv->image);
167
 
                gtk_widget_show_all (GTK_WIDGET (trayIcon_priv->widget));
168
 
        }
169
 
}
170
 
 
171
 
void
172
 
ui_tray_update (void)
173
 
{
174
 
        gint    newItems, unreadItems;
175
 
        gchar   *msg, *tmp;
176
 
        
177
 
        if (!trayIcon_priv)
178
 
                return;
179
 
 
180
 
        newItems = feedlist_get_new_item_count ();
181
 
        unreadItems = feedlist_get_unread_item_count ();
182
 
                
183
 
        if (newItems != 0) {
184
 
                if (network_is_online ())
185
 
                        ui_tray_icon_set (newItems, icons[ICON_AVAILABLE]);
186
 
                else
187
 
                        ui_tray_icon_set (newItems, icons[ICON_AVAILABLE_OFFLINE]);
188
 
                        
189
 
                msg = g_strdup_printf (ngettext ("%d new item", "%d new items", newItems), newItems);
190
 
        } else {
191
 
                if (network_is_online ())
192
 
                        ui_tray_icon_set (newItems, icons[ICON_EMPTY]);
193
 
                else
194
 
                        ui_tray_icon_set (newItems, icons[ICON_EMPTY_OFFLINE]);
195
 
                        
196
 
                msg = g_strdup (_("No new items"));
197
 
        }
198
 
 
199
 
        if (unreadItems != 0)
200
 
                tmp = g_strdup_printf (ngettext("%s\n%d unread item", "%s\n%d unread items", unreadItems), msg, unreadItems);
201
 
        else
202
 
                tmp = g_strdup_printf (_("%s\nNo unread items"), msg);
203
 
 
204
 
        ui_tray_tooltip_set (tmp);
205
 
        g_free (tmp);
206
 
        g_free (msg);
207
 
}
208
 
 
209
 
/* a click on the systray icon should show the program window
210
 
   if invisible or hide it if visible */
211
 
static void
212
 
tray_icon_pressed (GtkWidget *button, GdkEventButton *event, EggTrayIcon *icon)
213
 
{
214
 
        if ((event->type == GDK_2BUTTON_PRESS) || (event->type == GDK_3BUTTON_PRESS))
215
 
                return;  /* ignore double and triple clicks */
216
 
 
217
 
        switch (event->button) {
218
 
                case 1:
219
 
                        liferea_shell_toggle_visibility ();
220
 
                        break;
221
 
                case 3:
222
 
                        ui_popup_systray_menu (event->button, event->time);
223
 
                        break;
224
 
        }
225
 
}
226
 
 
227
 
static gboolean ui_tray_create_cb() {
228
 
 
229
 
        ui_tray_install();
230
 
        
231
 
        return FALSE; /* for when we're called by the glib idle handler */
232
 
}
233
 
 
234
 
 
235
 
static void
236
 
ui_tray_embedded_cb(GtkWidget *widget, void *data)
237
 
{
238
 
        /* Nothing to do */
239
 
}
240
 
 
241
 
 
242
 
static void ui_tray_destroyed_cb(GtkWidget *widget, void *data) {
243
 
 
244
 
        g_object_unref(G_OBJECT(trayIcon_priv->widget));
245
 
        g_free(trayIcon_priv);
246
 
        trayIcon_priv = NULL;
247
 
        
248
 
        if (0 == ui_tray_get_count ())
249
 
                liferea_shell_present ();
250
 
        
251
 
        /* And make it re-appear when the notification area reappears */
252
 
        g_idle_add(ui_tray_create_cb, NULL);
253
 
        
254
 
}
255
 
 
256
 
static void ui_tray_install(void) {
257
 
 
258
 
        g_assert(!trayIcon_priv);
259
 
        trayIcon_priv = g_new0(struct trayIcon_priv, 1);
260
 
 
261
 
        trayIcon_priv->widget = egg_tray_icon_new(PACKAGE);
262
 
        trayIcon_priv->eventBox = gtk_event_box_new();
263
 
        
264
 
        g_signal_connect(trayIcon_priv->eventBox, "button_press_event",
265
 
                         G_CALLBACK(tray_icon_pressed), trayIcon_priv->widget);
266
 
        g_signal_connect(G_OBJECT(trayIcon_priv->widget), "embedded",
267
 
                         G_CALLBACK(ui_tray_embedded_cb), NULL);
268
 
        g_signal_connect(G_OBJECT(trayIcon_priv->widget), "destroy",
269
 
                         G_CALLBACK(ui_tray_destroyed_cb), NULL);
270
 
        
271
 
        liferea_shell_setup_URL_receiver (trayIcon_priv->eventBox);
272
 
        
273
 
        gtk_container_add(GTK_CONTAINER(trayIcon_priv->widget), trayIcon_priv->eventBox);
274
 
        g_object_ref(G_OBJECT(trayIcon_priv->widget));
275
 
        
276
 
        ui_tray_update();
277
 
        trayIcon_priv->trayCount++;
278
 
}
279
 
 
280
 
static void ui_tray_remove(void) {
281
 
 
282
 
        g_assert(trayIcon_priv->widget);
283
 
        
284
 
        g_signal_handlers_disconnect_by_func(G_OBJECT(trayIcon_priv->widget),
285
 
                                             G_CALLBACK(ui_tray_destroyed_cb), NULL);
286
 
        gtk_widget_destroy(trayIcon_priv->image);
287
 
        g_object_unref(G_OBJECT(trayIcon_priv->widget));
288
 
        gtk_object_destroy(GTK_OBJECT(trayIcon_priv->widget));
289
 
        g_free(trayIcon_priv);
290
 
        trayIcon_priv = NULL;
291
 
 
292
 
        if (0 == ui_tray_get_count ())
293
 
                liferea_shell_present ();
294
 
}
295
 
 
296
 
void ui_tray_enable(gboolean enabled) {
297
 
 
298
 
        if(enabled) {
299
 
                if(!trayIcon_priv)
300
 
                        ui_tray_install();
301
 
        } else {
302
 
                if(trayIcon_priv)
303
 
                        ui_tray_remove();
304
 
        }
305
 
}
306
 
 
307
 
guint
308
 
ui_tray_get_count(void)
309
 
{
310
 
        return trayIcon_priv?trayIcon_priv->trayCount:0;
311
 
}
312
 
 
313
 
gboolean ui_tray_get_origin(gint *x, gint *y) {
314
 
 
315
 
        if(!trayIcon_priv)
316
 
                return FALSE;
317
 
 
318
 
        gdk_window_get_origin(GTK_WIDGET(trayIcon_priv->widget)->window, x, y); 
319
 
        return TRUE;
320
 
}
321
 
 
322
 
void ui_tray_size_request(GtkRequisition *requisition) {
323
 
 
324
 
        if(!trayIcon_priv)
325
 
                return;
326
 
 
327
 
        gtk_widget_size_request(GTK_WIDGET(trayIcon_priv->widget), requisition);
328
 
}