Re-add rating.
[gmpc.git] / src / tray-icon2.c
blob9eeb9a7ed38d09263f2adc5133f32384bacf6a8b
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * AppIndicator Support added 2011 by Moritz Molch <mail@moritzmolch.de>
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.
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.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <gtk/gtk.h>
23 #include <libmpd/libmpd.h>
24 #include <string.h>
25 #include <config.h>
26 #include "main.h"
27 #include "playlist3.h"
28 #include "preferences.h"
29 #include "gmpc-extras.h"
30 #include "gmpc-metaimage.h"
31 #include "misc.h"
32 #include "tray-icon2.h"
33 #include "internal-plugins.h"
35 #define LOG_DOMAIN "TrayIcon"
36 /* name of config field */
37 #define TRAY_ICON2_ID "tray-icon2"
39 #ifdef HAVE_APP_INDICATOR
40 #include <libappindicator/app-indicator.h>
41 AppIndicator *indicator;
42 #endif
44 GtkStatusIcon *tray_icon2_gsi = NULL;
46 static gchar *current_song_checksum = NULL;
48 static void tray_icon2_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata);
49 static void tray_icon2_connection_changed(MpdObj * mi, int connect, void *user_data);
50 static void tray_icon2_create_tooltip_real(int position);
51 static gboolean tray_icon2_tooltip_destroy(void);
52 static void tray_icon2_init(void);
53 static void tray_icon2_update_menu_widget(GtkWidget *menu);
55 /**
56 * Tooltip
58 GtkWidget *tray_icon2_tooltip = NULL;
59 GtkWidget *tray_icon2_tooltip_pb = NULL;
60 guint tray_icon2_tooltip_timeout = 0;
61 enum
63 TI2_AT_TOOLTIP,
64 TI2_AT_UPPER_LEFT,
65 TI2_AT_UPPER_RIGHT,
66 TI2_AT_LOWER_LEFT,
67 TI2_AT_LOWER_RIGHT,
68 TI2_AT_NUM_OPTIONS
70 /**
71 * Preferences
73 static GtkBuilder *tray_icon2_preferences_xml = NULL;
74 void popup_timeout_changed(void);
75 void popup_width_changed(void);
76 void popup_position_changed(GtkComboBox * om);
77 void popup_enable_toggled(GtkToggleButton * but);
78 void tray_enable_toggled(GtkToggleButton * but);
79 void tray_icon2_preferences_pm_combo_changed(GtkComboBox * cm, gpointer data);
80 /**
81 * Tray icon
84 gboolean tray_icon2_get_available(void)
86 #ifdef HAVE_APP_INDICATOR
87 if ((indicator) && (app_indicator_get_status(indicator) != APP_INDICATOR_STATUS_PASSIVE))
88 return TRUE;
90 #endif
91 if (tray_icon2_gsi)
93 if (gtk_status_icon_is_embedded(tray_icon2_gsi) && gtk_status_icon_get_visible(tray_icon2_gsi))
95 return TRUE;
99 return FALSE;
104 * click on the tray icon
106 static void tray_icon2_activate(GtkStatusIcon * gsi, gpointer user_data)
108 pl3_toggle_hidden();
110 #ifdef HAVE_APP_INDICATOR
111 tray_icon2_update_menu();
112 #endif
117 * Right mouse press on tray icon
120 static void tray_icon2_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data)
122 int state = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
123 mpd_player_seek(connection, (int)seek_time);
124 if (tray_icon2_tooltip_timeout)
126 g_source_remove(tray_icon2_tooltip_timeout);
128 tray_icon2_tooltip_timeout = g_timeout_add_seconds(state * 2, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
132 static void tray_icon2_update_menu_widget(GtkWidget *menu)
134 GtkWidget *item;
136 item = gtk_check_menu_item_new_with_mnemonic(_("Sho_w GMPC"));
137 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), !playlist3_window_is_hidden());
138 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
139 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_toggle_hidden), NULL);
141 item = gtk_separator_menu_item_new();
142 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
144 if (mpd_check_connected(connection))
146 if (mpd_server_check_command_allowed(connection, "play"))
148 if (mpd_player_get_state(connection) == MPD_STATUS_STATE_PLAY)
150 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PAUSE, NULL);
151 } else
153 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PLAY, NULL);
155 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
156 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(play_song), NULL);
158 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_STOP, NULL);
159 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
160 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(stop_song), NULL);
162 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_NEXT, NULL);
163 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
164 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(next_song), NULL);
166 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS, NULL);
167 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
168 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(prev_song), NULL);
170 } else
172 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL);
173 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
174 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(connect_to_mpd), NULL);
177 item = gtk_separator_menu_item_new();
178 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
180 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
181 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
182 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(main_quit), NULL);
183 gtk_widget_show_all(menu);
187 void tray_icon2_update_menu(void)
189 #ifdef HAVE_APP_INDICATOR
190 if (indicator != NULL) {
191 GtkWidget *menu;
192 if (app_indicator_get_menu(indicator) != NULL)
194 menu = (GtkWidget*)app_indicator_get_menu(indicator);
195 gtk_widget_destroy(menu);
198 menu = gtk_menu_new();
199 app_indicator_set_menu(indicator, GTK_MENU(menu));
200 tray_icon2_update_menu_widget(menu);
202 #endif
205 static void tray_icon2_populate_menu(GtkStatusIcon * gsi, guint button, guint activate_time, gpointer user_data)
207 GtkWidget *menu = gtk_menu_new();
208 tray_icon2_update_menu_widget(menu);
209 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, gtk_status_icon_position_menu, gsi, button, activate_time);
213 static void tray_icon2_embedded_changed(GtkStatusIcon * icon, GParamSpec * arg1, gpointer data)
215 if (!gtk_status_icon_is_embedded(icon))
217 /* the widget isn't embedded anymore */
218 create_playlist3();
224 * Initialize the tray icon
226 static int tray_icon2_button_press_event(gpointer tray, GdkEventButton * event, gpointer data)
228 if (event->button == 2)
230 play_song();
231 } else
233 return FALSE;
236 return TRUE;
240 static int tray_icon2_button_scroll_event(gpointer tray, GdkEventScroll * event, gpointer data)
242 if (event->direction == GDK_SCROLL_UP)
244 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
245 mpd_status_set_volume(connection, mpd_status_get_volume(connection) + cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
246 } else if (event->direction == GDK_SCROLL_DOWN)
248 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
249 mpd_status_set_volume(connection, mpd_status_get_volume(connection) - cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
250 } else if (event->direction == GDK_SCROLL_LEFT)
252 prev_song();
253 } else if (event->direction == GDK_SCROLL_RIGHT)
255 next_song();
257 return TRUE;
260 #ifdef HAVE_APP_INDICATOR
261 static int tray_icon2_button_scroll_event_appindicator(AppIndicator *this_indicator, gint steps, guint direction, gpointer userdata)
263 if (direction == GDK_SCROLL_UP)
265 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
266 mpd_status_set_volume(connection, mpd_status_get_volume(connection) + cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
267 } else if (direction == GDK_SCROLL_DOWN)
269 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
270 mpd_status_set_volume(connection, mpd_status_get_volume(connection) - cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
271 } else if (direction == GDK_SCROLL_LEFT)
273 prev_song();
274 } else if (direction == GDK_SCROLL_RIGHT)
276 next_song();
278 return TRUE;
280 #endif
283 static void tray_icon2_init(void)
286 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", TRUE))
288 #ifndef HAVE_APP_INDICATOR
289 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "use_appindicator", FALSE);
290 #endif
292 #ifdef HAVE_APP_INDICATOR
293 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR))
295 GtkMenu *indicator_menu = GTK_MENU(gtk_menu_new());
296 indicator = app_indicator_new ("gmpc", "gmpc-tray-disconnected", APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
297 app_indicator_set_icon_theme_path(indicator, PIXMAP_PATH);
298 app_indicator_set_menu (indicator, GTK_MENU (indicator_menu));
299 tray_icon2_update_menu();
301 app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE);
302 g_signal_connect(G_OBJECT(indicator), "scroll-event", G_CALLBACK(tray_icon2_button_scroll_event_appindicator), NULL);
304 } else {
305 #endif
306 tray_icon2_gsi = gtk_status_icon_new_from_icon_name("gmpc-tray-disconnected");
307 #if GTK_CHECK_VERSION(2,15,0)
308 gtk_status_icon_set_has_tooltip(GTK_STATUS_ICON(tray_icon2_gsi), TRUE);
309 #endif
311 /* connect the (sparse) signals */
312 g_signal_connect(G_OBJECT(tray_icon2_gsi), "popup-menu", G_CALLBACK(tray_icon2_populate_menu), NULL);
313 g_signal_connect(G_OBJECT(tray_icon2_gsi), "activate", G_CALLBACK(tray_icon2_activate), NULL);
314 g_signal_connect(G_OBJECT(tray_icon2_gsi), "notify::embedded", G_CALLBACK(tray_icon2_embedded_changed), NULL);
315 if (gtk_check_version(2, 15, 0) == NULL)
317 g_signal_connect(G_OBJECT(tray_icon2_gsi), "button-press-event", G_CALLBACK(tray_icon2_button_press_event), NULL);
318 g_signal_connect(G_OBJECT(tray_icon2_gsi), "scroll-event", G_CALLBACK(tray_icon2_button_scroll_event), NULL);
319 /*g_signal_connect(G_OBJECT(tray_icon2_gsi), "query-tooltip", G_CALLBACK(tray_icon2_tooltip_query), NULL);*/
321 #ifdef HAVE_APP_INDICATOR
323 #endif // HAVE_APP_INDICATOR
325 /* Make sure the icons are up2date */
326 tray_icon2_connection_changed(connection, mpd_check_connected(connection), NULL);
332 * Destroy and cleanup
334 static void tray_icon2_destroy(void)
336 #ifdef HAVE_APP_INDICATOR
337 if (indicator) {
338 gtk_widget_destroy(GTK_WIDGET(app_indicator_get_menu(indicator)));
339 g_object_unref(indicator);
340 indicator = NULL;
342 #endif
343 if (tray_icon2_gsi)
345 g_object_unref(tray_icon2_gsi);
346 tray_icon2_gsi = NULL;
349 /* free the currnet song checksum */
350 if (current_song_checksum)
352 g_free(current_song_checksum);
353 current_song_checksum = NULL;
359 * Get enabled
361 static gboolean tray_icon2_get_enabled(void)
363 return cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", TRUE);
368 * Set Disabled
370 static void tray_icon2_set_enabled(int enabled)
372 #ifndef HAVE_APP_INDICATOR
373 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "use_appindicator", FALSE);
374 #endif
376 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "enable", enabled);
377 #ifdef HAVE_APP_INDICATOR
378 if ((enabled) && (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR)))
380 if (!indicator)
382 tray_icon2_init();
383 tray_icon2_status_changed(connection, MPD_CST_SONGID, NULL);
384 } else
386 app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE);
388 } else
390 if (indicator)
392 app_indicator_set_status(indicator, APP_INDICATOR_STATUS_PASSIVE);
395 #endif
397 if ((enabled) && (!cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR)))
399 if (!tray_icon2_gsi)
401 tray_icon2_init();
402 tray_icon2_status_changed(connection, MPD_CST_SONGID, NULL);
403 } else
405 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon2_gsi), TRUE);
407 } else
409 if (tray_icon2_gsi)
411 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon2_gsi), FALSE);
418 * TOOLTIP
420 static gboolean has_buttons = FALSE;
421 static GtkWidget *play_button = NULL;
423 static gboolean tray_icon2_tooltip_destroy(void)
425 tray_icon2_tooltip_pb = NULL;
426 gtk_widget_destroy(tray_icon2_tooltip);
427 tray_icon2_tooltip = NULL;
428 /* remove timeout, this is for when it doesn't get called from inside the timeout */
429 if (tray_icon2_tooltip_timeout)
431 g_source_remove(tray_icon2_tooltip_timeout);
433 tray_icon2_tooltip_timeout = 0;
434 has_buttons = FALSE;
435 /* remove the timeout */
436 return FALSE;
440 static gboolean tray_icon2_tooltip_button_press_event(GtkWidget * box, GdkEventButton * event, GtkWidget * vbox)
442 if ((event == NULL || event->button == 3) && !has_buttons)
444 GtkWidget *hbox, *button;
445 int state = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
446 if (tray_icon2_tooltip_timeout)
448 g_source_remove(tray_icon2_tooltip_timeout);
450 tray_icon2_tooltip_timeout = g_timeout_add_seconds(state * 2, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
452 has_buttons = TRUE;
454 hbox = gtk_hbox_new(TRUE, 6);
455 /* prev */
456 button = gtk_button_new();
457 gtk_button_set_image(GTK_BUTTON(button),
458 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS, GTK_ICON_SIZE_BUTTON));
459 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
460 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(prev_song), NULL);
461 /* stop */
462 button = gtk_button_new();
463 gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_BUTTON));
464 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
465 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(stop_song), NULL);
466 /* pause/play */
467 state = mpd_player_get_state(connection);
468 if (state != MPD_PLAYER_PLAY)
470 play_button = button = gtk_button_new();
471 gtk_button_set_image(GTK_BUTTON(button),
472 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
473 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
474 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(play_song), NULL);
475 } else
477 play_button = button = gtk_button_new();
478 gtk_button_set_image(GTK_BUTTON(button),
479 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON));
481 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
482 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(play_song), NULL);
484 /* next */
485 button = gtk_button_new();
486 gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_MEDIA_NEXT, GTK_ICON_SIZE_BUTTON));
488 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
489 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(next_song), NULL);
491 gtk_widget_show_all(hbox);
492 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
494 return TRUE;
496 tray_icon2_tooltip_destroy();
497 return TRUE;
501 static gboolean popup_enter_notify_event(GtkWidget * event, GdkEventCrossing * eventc, gpointer data)
503 if (tray_icon2_tooltip_timeout)
505 g_source_remove(tray_icon2_tooltip_timeout);
507 tray_icon2_tooltip_timeout = 0;
508 return FALSE;
512 static gboolean popup_leave_notify_event(GtkWidget * event, GdkEventCrossing * eventc, gpointer data)
514 int tooltip_timeout = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
515 tray_icon2_tooltip_timeout = g_timeout_add_seconds(tooltip_timeout, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
516 return FALSE;
520 static void tray_icon2_create_tooltip_real(int position)
522 int x = 0, y = 0, monitor;
523 GdkScreen *screen;
524 GtkWidget *pl3_win = playlist3_get_window();
525 GtkWidget *hbox = NULL;
526 GtkWidget *vbox = NULL;
527 GtkWidget *label = NULL;
528 GtkWidget *event = NULL;
529 GtkWidget *coverimg = NULL;
530 GtkStyleContext *sc;
531 mpd_Song *song = NULL;
532 int tooltip_timeout = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
533 int state = 0;
534 int x_offset = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "x-offset", 0);
535 int y_offset = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "y-offset", 0);
536 int tooltip_width = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-width", 300);
538 song = mpd_playlist_get_current_song(connection);
540 * if the tooltip still exists destroy it...
542 if (tray_icon2_tooltip)
544 /* Do a check to avoid ugly redraws */
545 mpd_Song *song2 = g_object_get_data(G_OBJECT(tray_icon2_tooltip), "song");
546 if (song2 && song)
548 if (song->file && song2->file && strcmp(song2->file, song->file) == 0)
550 if (tray_icon2_tooltip_timeout)
552 g_source_remove(tray_icon2_tooltip_timeout);
554 tray_icon2_tooltip_timeout =
555 g_timeout_add_seconds(tooltip_timeout, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
556 return;
559 if (tray_icon2_tooltip_timeout)
561 g_source_remove(tray_icon2_tooltip_timeout);
562 tray_icon2_tooltip_timeout = 0;
564 tray_icon2_tooltip_pb = NULL;
565 gtk_widget_destroy(tray_icon2_tooltip);
566 tray_icon2_tooltip = NULL;
567 //tray_icon2_tooltip_destroy();
569 /* If gmpc is fullscreen, don't show the tooltip */
570 if (pl3_window_is_fullscreen())
571 return;
573 * Creat the tootlip window
575 tray_icon2_tooltip = gtk_window_new(GTK_WINDOW_POPUP);
576 screen = gtk_window_get_screen(GTK_WINDOW(tray_icon2_tooltip));
578 if (gdk_screen_is_composited(screen))
580 GdkVisual *vs = gdk_screen_get_rgba_visual(screen);
581 if (vs)
582 gtk_widget_set_visual(tray_icon2_tooltip, vs);
583 gtk_window_set_opacity(GTK_WINDOW(tray_icon2_tooltip), 0.9);
586 sc = gtk_widget_get_style_context(tray_icon2_tooltip);
587 gtk_style_context_add_class(sc, GTK_STYLE_CLASS_TOOLTIP);
588 /* causes the border */
589 gtk_container_set_border_width(GTK_CONTAINER(tray_icon2_tooltip), 1);
590 gtk_window_set_default_size(GTK_WINDOW(tray_icon2_tooltip), tooltip_width, -1);
591 gtk_window_set_transient_for(GTK_WINDOW(tray_icon2_tooltip), GTK_WINDOW(pl3_win));
594 * Tooltip exists from 2 parts..
595 * ------------------
596 * | 1 | |
597 * | | 2 |
598 * ------------------
600 hbox = gtk_hbox_new(FALSE, 0);
601 gtk_container_add(GTK_CONTAINER(tray_icon2_tooltip), hbox);
605 * In first box we have image/coverart
606 * Re-use the gmpc-metaimage widget
608 if(cfg_get_single_value_as_int_with_default(config, "Interface", "hide-album-art", 0) == 0)
610 coverimg = (GtkWidget *)gmpc_metaimage_new_size(META_ALBUM_ART, 80);
611 gmpc_metaimage_set_squared(GMPC_METAIMAGE(coverimg), TRUE);
612 gmpc_metaimage_set_connection(GMPC_METAIMAGE(coverimg), connection);
613 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(coverimg), (char *)"gmpc");
615 * Force an update if mpd is playing
617 state = mpd_player_get_state(connection);
618 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
620 gmpc_metaimage_update_cover(GMPC_METAIMAGE(coverimg), connection, MPD_CST_SONGID, NULL);
621 } else
623 gmpc_metaimage_set_cover_na(GMPC_METAIMAGE(coverimg));
627 * Pack the widget in a eventbox so we can set background color
629 event = gtk_event_box_new();
630 gtk_widget_set_size_request(event, 86, 86);
631 // gtk_widget_modify_bg(GTK_WIDGET(event), GTK_STATE_NORMAL, &(pl3_win->style->bg[GTK_STATE_SELECTED]));
632 gtk_container_add(GTK_CONTAINER(event), coverimg);
633 gtk_box_pack_start(GTK_BOX(hbox), event, FALSE, TRUE, 0);
635 g_signal_connect(G_OBJECT(tray_icon2_tooltip), "enter-notify-event", G_CALLBACK(popup_enter_notify_event), NULL);
636 g_signal_connect(G_OBJECT(tray_icon2_tooltip), "leave-notify-event", G_CALLBACK(popup_leave_notify_event), NULL);
640 * Right (2) view
643 * Create white background label box
645 event = gtk_event_box_new();
646 vbox = gtk_vbox_new(FALSE, 0);
647 // gtk_widget_modify_bg(GTK_WIDGET(event), GTK_STATE_NORMAL, &(pl3_win->style->light[GTK_STATE_NORMAL]));
648 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
649 gtk_container_add(GTK_CONTAINER(event), vbox);
650 gtk_box_pack_start(GTK_BOX(hbox), event, TRUE, TRUE, 0);
652 if (!has_buttons)
654 g_signal_connect(G_OBJECT(hbox), "button-press-event", G_CALLBACK(tray_icon2_tooltip_button_press_event), vbox);
658 * If there is a song, show show song info
660 if (song)
662 int i;
663 char buffer[256];
664 int size_offset = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "size-offset", 1024);
665 size_offset = (size_offset < 100) ? 1024 : size_offset;
667 /** Artist label */
668 if (song->title || song->file || song->name)
670 gchar *test =
671 g_strdup_printf("<span size='%i' weight='bold'>[%%title%%|%%shortfile%%][ (%%name%%)]</span>",
672 14 * size_offset);
673 mpd_song_markup_escaped(buffer, 256, test, song);
674 q_free(test);
675 label = gtk_label_new("");
676 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
677 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
678 gtk_label_set_markup(GTK_LABEL(label), buffer);
679 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
681 if (song->artist)
683 gchar *test = g_strdup_printf("<span size='%i'>%%artist%%</span>", 10 * size_offset);
684 label = gtk_label_new("");
685 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
686 mpd_song_markup_escaped(buffer, 256, test, song);
687 q_free(test);
688 gtk_label_set_markup(GTK_LABEL(label), buffer);
689 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
691 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
693 if (song->album)
695 gchar *test = g_strdup_printf("<span size='%i'>%%album%%[ (%%year%%)]</span>", 8 * size_offset);
696 label = gtk_label_new("");
697 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
698 mpd_song_markup_escaped(buffer, 256, test, song);
699 q_free(test);
700 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
701 gtk_label_set_markup(GTK_LABEL(label), buffer);
702 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
704 tray_icon2_tooltip_pb = (GtkWidget *) gmpc_progress_new();
705 gmpc_progress_set_hide_text(GMPC_PROGRESS(tray_icon2_tooltip_pb), TRUE);
706 /* Update the progressbar */
707 gmpc_progress_set_time(GMPC_PROGRESS(tray_icon2_tooltip_pb),
708 mpd_status_get_total_song_time(connection),
709 mpd_status_get_elapsed_song_time(connection));
711 g_signal_connect(G_OBJECT(tray_icon2_tooltip_pb), "seek-event", G_CALLBACK(tray_icon2_seek_event), NULL);
713 // gtk_widget_modify_bg(GTK_WIDGET(tray_icon2_tooltip_pb), GTK_STATE_NORMAL,
714 // &(pl3_win->style->light[GTK_STATE_NORMAL]));
715 g_object_set_data_full(G_OBJECT(tray_icon2_tooltip), "song", mpd_songDup(song), (GDestroyNotify) mpd_freeSong);
716 gtk_box_pack_start(GTK_BOX(vbox), tray_icon2_tooltip_pb, TRUE, FALSE, 0);
718 i = mpd_player_get_next_song_id(connection);
719 if (i > 0)
721 mpd_Song *next_psong = mpd_playlist_get_song(connection, i);
722 if (next_psong)
724 gchar *test =
725 g_strdup_printf("<span size='%i'>%s: <i>[[%%title%% - &[%%artist%%]]|%%shortfile%%]</i></span>",
726 7 * size_offset, _("Next"));
727 label = gtk_label_new("");
728 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
729 mpd_song_markup_escaped(buffer, 256, test, next_psong);
730 q_free(test);
731 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
732 gtk_label_set_markup(GTK_LABEL(label), buffer);
733 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
734 mpd_freeSong(next_psong);
737 } else
739 gchar *value = g_markup_printf_escaped("<span size='large'>%s</span>", _("Gnome Music Player Client"));
740 label = gtk_label_new("");
741 gtk_label_set_markup(GTK_LABEL(label), value);
742 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
743 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
744 g_free(value);
747 * Position the popup
749 if (position == TI2_AT_TOOLTIP && tray_icon2_get_available())
752 GdkRectangle rect, rect2;
753 GtkOrientation orientation;
755 #ifdef HAVE_APP_INDICATOR
756 if (indicator != NULL) {
757 // there's no way to get the AppIndicator's position, so showing at tooltip is not possible
758 // choosing 50px above right corner
759 screen = gtk_widget_get_screen(pl3_win);
761 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
762 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
763 /** Set Y = window height - size; */
764 y = rect2.y + rect2.height - 50 - 95;
765 /** X =window width - width */
766 x = rect2.x + rect2.width - 5 - tooltip_width;
767 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
769 } else
770 #endif
772 if (gtk_status_icon_get_geometry(tray_icon2_gsi, &screen, &rect, &orientation))
774 monitor = gdk_screen_get_monitor_at_point(screen, rect.x, rect.y);
775 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
776 /* Get Y */
777 y = rect.y + rect.height + 5 - rect2.y + y_offset;
778 /* if the lower part falls off the screen, move it up */
779 if ((y + 95) > rect2.height)
781 y = rect.y - 95 - 5;
783 if (y < 0)
784 y = 0;
786 /* Get X */
787 x = rect.x - tooltip_width / 2 - rect2.x + x_offset;
788 if ((x + tooltip_width) > rect2.width)
790 if (orientation == GTK_ORIENTATION_VERTICAL)
792 x = rect2.width + -tooltip_width - rect.width - 5;
793 } else
795 x = rect2.width - tooltip_width;
798 if (x < 0)
800 if (orientation == GTK_ORIENTATION_VERTICAL)
802 x = rect.width + 5;
803 } else
805 x = 0;
808 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), rect2.x + x, rect2.y + y);
811 } else if (position == TI2_AT_UPPER_LEFT)
813 GdkRectangle rect2;
814 screen = gtk_widget_get_screen(pl3_win);
816 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
817 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
818 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), rect2.x + 5 + x_offset, rect2.y + 5 + y_offset);
819 } else if (position == TI2_AT_UPPER_RIGHT)
821 GdkRectangle rect2;
822 screen = gtk_widget_get_screen(pl3_win);
824 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
825 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
826 /** Set Y = 0; */
827 y = rect2.y + 5;
828 /** X is upper right - width */
829 x = rect2.x + rect2.width - 5 - tooltip_width;
830 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
831 } else if (position == TI2_AT_LOWER_LEFT)
833 GdkRectangle rect2;
834 screen = gtk_widget_get_screen(pl3_win);
836 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
837 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
838 /** Set Y = window height - size; */
839 y = rect2.y + rect2.height - 5 - 95;
840 /** X =5 */
841 x = rect2.x + 5;
842 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
843 } else
845 GdkRectangle rect2;
846 screen = gtk_widget_get_screen(pl3_win);
848 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
849 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
850 /** Set Y = window height - size; */
851 y = rect2.y + rect2.height - 5 - 95;
852 /** X =window width - width */
853 x = rect2.x + rect2.width - 5 - tooltip_width;
854 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
857 gtk_widget_show_all(tray_icon2_tooltip);
859 if (has_buttons)
861 has_buttons = FALSE;
862 tray_icon2_tooltip_button_press_event(hbox, NULL, vbox);
865 * Destroy it after 5 seconds
867 tray_icon2_tooltip_timeout = g_timeout_add_seconds(tooltip_timeout, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
871 void tray_icon2_create_tooltip(void)
873 int state = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-position", TI2_AT_TOOLTIP);
874 tray_icon2_create_tooltip_real(state);
878 static void tray_icon2_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata)
880 char buffer[256];
881 mpd_Song *song = mpd_playlist_get_current_song(connection);
882 if (what & (MPD_CST_SONGID) || what & MPD_CST_SONGPOS || what & MPD_CST_PLAYLIST)
885 * If enabled by user, show the tooltip.
886 * But only if playing or paused.
889 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "show-tooltip", TRUE))
891 int state = mpd_player_get_state(connection);
892 gchar *new_checksum;
893 new_checksum = mpd_song_checksum(song);
894 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
896 if (new_checksum == NULL || current_song_checksum == NULL
897 || strcmp(current_song_checksum, new_checksum))
898 tray_icon2_create_tooltip();
900 if (current_song_checksum)
902 g_free(current_song_checksum);
903 current_song_checksum = NULL;
905 current_song_checksum = new_checksum;
908 if (tray_icon2_gsi)
910 mpd_song_markup(buffer, 256, "[%name%: ][%title%|%shortfile%][ - %artist%]", song);
911 //gtk_status_icon_set_tooltip(tray_icon2_gsi,buffer);
915 /* update the progress bar if available */
916 if (what & MPD_CST_ELAPSED_TIME)
918 if (tray_icon2_tooltip && tray_icon2_tooltip_pb)
920 gmpc_progress_set_time(GMPC_PROGRESS(tray_icon2_tooltip_pb),
921 mpd_status_get_total_song_time(connection),
922 mpd_status_get_elapsed_song_time(connection));
926 #ifdef HAVE_APP_INDICATOR
927 if ((indicator == NULL) && (tray_icon2_gsi == NULL))
928 return;
930 if ((indicator != NULL) && (what & MPD_CST_STATE))
931 tray_icon2_update_menu();
933 #endif
935 if (what & MPD_CST_STATE)
937 int state = mpd_player_get_state(connection);
938 if (state == MPD_PLAYER_PLAY)
940 mpd_song_markup(buffer, 256, "[%name%: ][%title%|%shortfile%][ - %artist%]", song);
942 #ifdef HAVE_APP_INDICATOR
943 if (indicator != NULL)
944 app_indicator_set_icon_full(indicator, "gmpc-tray-play", "gmpc is playing");
945 #endif
946 if (tray_icon2_gsi != NULL)
947 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray-play");
949 //gtk_status_icon_set_tooltip(tray_icon2_gsi,buffer);
950 if (has_buttons)
952 gtk_button_set_image(GTK_BUTTON(play_button),
953 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON));
955 } else if (state == MPD_PLAYER_PAUSE)
957 #ifdef HAVE_APP_INDICATOR
958 if (indicator != NULL)
959 app_indicator_set_icon_full(indicator, "gmpc-tray-pause", "gmpc is pausing");
960 #endif
961 if (tray_icon2_gsi != NULL)
962 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray-pause");
964 //gtk_status_icon_set_tooltip(tray_icon2_gsi,_("Gnome Music Player Client"));
965 if (has_buttons)
967 gtk_button_set_image(GTK_BUTTON(play_button),
968 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
970 } else
972 #ifdef HAVE_APP_INDICATOR
973 if (indicator != NULL)
974 app_indicator_set_icon_full(indicator, "gmpc-tray", "gmpc is idling");
975 #endif
976 if (tray_icon2_gsi != NULL)
977 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray");
979 //gtk_status_icon_set_tooltip(tray_icon2_gsi,_("Gnome Music Player Client"));
980 if (has_buttons)
982 gtk_button_set_image(GTK_BUTTON(play_button),
983 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
991 * Show right icon when (dis)connected
993 static void tray_icon2_connection_changed(MpdObj * mi, int connect, void *user_data)
995 #ifdef HAVE_APP_INDICATOR
996 if ((indicator == NULL) && (tray_icon2_gsi == NULL))
997 return;
998 #endif
1000 if (connect)
1002 tray_icon2_status_changed(mi, MPD_CST_STATE, NULL);
1003 } else
1005 /* Set the disconnect image, and reset the GtkTooltip */
1006 #ifdef HAVE_APP_INDICATOR
1007 if (indicator != NULL) {
1008 app_indicator_set_icon_full(indicator, "gmpc-tray-disconnected", "gmpc is disconnected");
1009 tray_icon2_update_menu();
1011 #endif
1012 if (tray_icon2_gsi != NULL) {
1013 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray-disconnected");
1016 /* Destroy notification */
1017 if (tray_icon2_tooltip)
1018 tray_icon2_tooltip_destroy();
1022 gboolean trayicon2_have_appindicator_support( void )
1024 #ifdef HAVE_APP_INDICATOR
1025 return TRUE;
1026 #else
1027 return FALSE;
1028 #endif
1033 * PREFERENCES
1036 void tray_enable_toggled(GtkToggleButton * but)
1038 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "tray-icon.c: changing tray icon %i\n", gtk_toggle_button_get_active(but));
1039 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "enable", (int)gtk_toggle_button_get_active(but));
1041 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", 1))
1043 tray_icon2_set_enabled(TRUE);
1044 } else
1046 tray_icon2_set_enabled(FALSE);
1050 void trayicon2_toggle_use_appindicator(void)
1052 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "use_appindicator", !cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", TRUE));
1054 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", DEFAULT_TRAY_ICON_ENABLE))
1056 tray_icon2_set_enabled(FALSE);
1057 tray_icon2_set_enabled(TRUE);
1062 /* this sets all the settings in the notification area preferences correct */
1063 static void tray_update_settings(void)
1065 gtk_toggle_button_set_active((GtkToggleButton *)
1066 gtk_builder_get_object(tray_icon2_preferences_xml, "ck_tray_enable"),
1067 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable",
1068 DEFAULT_TRAY_ICON_ENABLE));
1072 void popup_enable_toggled(GtkToggleButton * but)
1074 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "show-tooltip", gtk_toggle_button_get_active(but));
1078 void popup_position_changed(GtkComboBox * om)
1080 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "tooltip-position", gtk_combo_box_get_active(om));
1084 void popup_timeout_changed(void)
1086 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "tooltip-timeout",
1087 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON
1088 (gtk_builder_get_object
1089 (tray_icon2_preferences_xml, "popup_timeout"))));
1092 void popup_width_changed(void)
1094 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "tooltip-width",
1095 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON
1096 (gtk_builder_get_object
1097 (tray_icon2_preferences_xml, "popup_width"))));
1100 static void update_popup_settings(void)
1102 gtk_toggle_button_set_active((GtkToggleButton *)
1103 gtk_builder_get_object(tray_icon2_preferences_xml, "ck_popup_enable"),
1104 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "show-tooltip", 1));
1105 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(tray_icon2_preferences_xml, "om_popup_position")),
1106 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-position", 0));
1107 gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(tray_icon2_preferences_xml, "popup_timeout")),
1108 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5));
1109 #ifdef HAVE_LIBNOTIFY
1110 gtk_toggle_button_set_active(
1111 GTK_TOGGLE_BUTTON(gtk_builder_get_object(tray_icon2_preferences_xml,"ck_libnotify_enable")),
1112 libnotify_plugin.get_enabled());
1114 #else
1115 gtk_widget_hide(gtk_builder_get_object(tray_icon2_preferences_xml, "frame_libnotify"));
1116 #endif
1120 static void tray_icon2_preferences_destroy(GtkWidget * container)
1122 if (tray_icon2_preferences_xml)
1124 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(tray_icon2_preferences_xml, "tray-pref-vbox");
1125 gtk_container_remove(GTK_CONTAINER(container), vbox);
1126 g_object_unref(tray_icon2_preferences_xml);
1127 tray_icon2_preferences_xml = NULL;
1132 void tray_icon2_preferences_pm_combo_changed(GtkComboBox * cm, gpointer data)
1134 int level = gtk_combo_box_get_active(cm);
1135 cfg_set_single_value_as_int(config, "Default", "min-error-level", level);
1138 void libnotify_enable_toggled(GtkCheckButton *button, gpointer data)
1140 #ifdef HAVE_LIBNOTIFY
1141 int state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1142 libnotify_plugin.set_enabled(state);
1143 #endif
1147 static void tray_icon2_preferences_construct(GtkWidget * container)
1149 gchar *path = gmpc_get_full_glade_path("preferences-trayicon.ui");
1150 tray_icon2_preferences_xml = gtk_builder_new();
1151 gtk_builder_add_from_file(tray_icon2_preferences_xml, path, NULL);
1152 q_free(path);
1154 if (tray_icon2_preferences_xml)
1156 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(tray_icon2_preferences_xml, "tray-pref-vbox");
1157 gtk_container_add(GTK_CONTAINER(container), vbox);
1158 tray_update_settings();
1159 update_popup_settings();
1160 gtk_builder_connect_signals(tray_icon2_preferences_xml, NULL);
1162 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(tray_icon2_preferences_xml, "pm-combo")),
1163 cfg_get_single_value_as_int_with_default(config, "Default", "min-error-level",
1164 ERROR_INFO));
1168 gmpcPrefPlugin tray_icon2_preferences =
1170 tray_icon2_preferences_construct,
1171 tray_icon2_preferences_destroy
1175 gmpcPlugin tray_icon2_plug =
1177 .name = N_("Notification"),
1178 .version = {0, 0, 0}
1180 .plugin_type = GMPC_INTERNALL,
1181 .init = tray_icon2_init,
1182 .destroy = tray_icon2_destroy,
1183 .mpd_status_changed = tray_icon2_status_changed,
1184 .mpd_connection_changed = tray_icon2_connection_changed,
1185 .set_enabled = NULL,
1186 .get_enabled = NULL,
1187 .pref = &tray_icon2_preferences