1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: tr-icon.c 13286 2012-04-16 18:42:26Z jordan $
11 */
12
13#include <glib/gi18n.h>
14#include <gtk/gtk.h>
15#ifdef HAVE_LIBAPPINDICATOR
16 #include <libappindicator/app-indicator.h>
17#endif
18#include <libtransmission/transmission.h>
19#include <libtransmission/utils.h>
20#include "actions.h"
21#include "tr-icon.h"
22#include "util.h"
23
24static GQuark
25get_core_quark( void )
26{
27    static GQuark quark = 0;
28    if( !quark ) quark = g_quark_from_static_string( "tr-core" );
29    return quark;
30}
31
32#define ICON_NAME "transmission"
33
34#ifdef HAVE_LIBAPPINDICATOR
35void
36gtr_icon_refresh( gpointer vindicator UNUSED )
37{
38}
39#else
40static void
41activated( GtkStatusIcon * self UNUSED, gpointer user_data UNUSED )
42{
43    gtr_action_activate( "toggle-main-window" );
44}
45
46static void
47popup( GtkStatusIcon *       self,
48       guint                 button,
49       guint                 when,
50       gpointer         data UNUSED )
51{
52    GtkWidget * w = gtr_action_get_widget( "/icon-popup" );
53
54    gtk_menu_popup ( GTK_MENU( w ), NULL, NULL,
55                     gtk_status_icon_position_menu,
56                     self, button, when );
57}
58
59void
60gtr_icon_refresh( gpointer vicon )
61{
62    double KBps;
63    double limit;
64    char up[64];
65    char upLimit[64];
66    char down[64];
67    char downLimit[64];
68    char tip[1024];
69    const char * idle = _( "Idle" );
70    GtkStatusIcon * icon = GTK_STATUS_ICON( vicon );
71    tr_session * session = gtr_core_session( g_object_get_qdata( G_OBJECT( icon ), get_core_quark( ) ) );
72
73    /* up */
74    KBps = tr_sessionGetRawSpeed_KBps( session, TR_UP );
75    if( KBps < 0.001 )
76        g_strlcpy( up, idle, sizeof( up ) );
77    else
78        tr_formatter_speed_KBps( up, KBps, sizeof( up ) );
79
80    /* up limit */
81    if( !tr_sessionGetActiveSpeedLimit_KBps( session, TR_UP, &limit ) )
82        *upLimit = '\0';
83    else {
84        char buf[64];
85        tr_formatter_speed_KBps( buf, limit, sizeof( buf ) );
86        g_snprintf( upLimit, sizeof( upLimit ), _( "(Limit: %s)" ), buf );
87    }
88
89    /* down */
90    KBps = tr_sessionGetRawSpeed_KBps( session, TR_DOWN );
91    if( KBps < 0.001 )
92        g_strlcpy( down, idle, sizeof( down ) );
93    else
94        tr_formatter_speed_KBps( down, KBps, sizeof( down ) );
95
96    /* down limit */
97    if( !tr_sessionGetActiveSpeedLimit_KBps( session, TR_DOWN, &limit ) )
98        *downLimit = '\0';
99    else {
100        char buf[64];
101        tr_formatter_speed_KBps( buf, limit, sizeof( buf ) );
102        g_snprintf( downLimit, sizeof( downLimit ), _( "(Limit: %s)" ), buf );
103    }
104
105    /* %1$s: current upload speed
106     * %2$s: current upload limit, if any
107     * %3$s: current download speed
108     * %4$s: current download limit, if any */
109    g_snprintf( tip, sizeof( tip ), _( "Transmission\nUp: %1$s %2$s\nDown: %3$s %4$s" ), up, upLimit, down, downLimit );
110
111    gtk_status_icon_set_tooltip_text( GTK_STATUS_ICON( icon ), tip );
112}
113#endif
114
115static const char *
116getIconName( void )
117{
118    const char * icon_name;
119
120    GtkIconTheme * theme = gtk_icon_theme_get_default( );
121
122    /* if the tray's icon is a 48x48 file, use it;
123     * otherwise, use the fallback builtin icon */
124    if( !gtk_icon_theme_has_icon( theme, TRAY_ICON ) )
125        icon_name = ICON_NAME;
126    else {
127        GtkIconInfo * icon_info = gtk_icon_theme_lookup_icon( theme, TRAY_ICON, 48, GTK_ICON_LOOKUP_USE_BUILTIN );
128        const gboolean icon_is_builtin = gtk_icon_info_get_filename ( icon_info ) == NULL;
129        gtk_icon_info_free ( icon_info );
130        icon_name = icon_is_builtin ? ICON_NAME : TRAY_ICON;
131    }
132
133    return icon_name;
134}
135
136gpointer
137gtr_icon_new( TrCore * core)
138{
139#ifdef HAVE_LIBAPPINDICATOR
140    GtkWidget * w;
141    const char * icon_name = getIconName( );
142    AppIndicator * indicator = app_indicator_new( ICON_NAME, icon_name, APP_INDICATOR_CATEGORY_SYSTEM_SERVICES );
143    app_indicator_set_status( indicator, APP_INDICATOR_STATUS_ACTIVE );
144    w = gtr_action_get_widget( "/icon-popup" );
145    app_indicator_set_menu( indicator, GTK_MENU ( w ) );
146    app_indicator_set_title( indicator, g_get_application_name( ) );
147    g_object_set_qdata( G_OBJECT( indicator ), get_core_quark( ), core );
148    return indicator;
149#else
150    const char * icon_name = getIconName( );
151    GtkStatusIcon * icon = gtk_status_icon_new_from_icon_name( icon_name );
152    g_signal_connect( icon, "activate", G_CALLBACK( activated ), NULL );
153    g_signal_connect( icon, "popup-menu", G_CALLBACK( popup ), NULL );
154    g_object_set_qdata( G_OBJECT( icon ), get_core_quark( ), core );
155    return icon;
156#endif
157}
158