Remove sqlite3 build dep.
[gmpc.git] / src / tray-icon2.c
blob5db32e267c18f5d3bf87e96d571b5d0049de21c8
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_position_changed(GtkComboBox * om);
76 void popup_enable_toggled(GtkToggleButton * but);
77 void tray_enable_toggled(GtkToggleButton * but);
78 void tray_icon2_preferences_pm_combo_changed(GtkComboBox * cm, gpointer data);
79 /**
80 * Tray icon
83 gboolean tray_icon2_get_available(void)
85 #ifdef HAVE_APP_INDICATOR
86 if ((indicator) && (app_indicator_get_status(indicator) != APP_INDICATOR_STATUS_PASSIVE))
87 return TRUE;
89 #endif
90 if (tray_icon2_gsi)
92 if (gtk_status_icon_is_embedded(tray_icon2_gsi) && gtk_status_icon_get_visible(tray_icon2_gsi))
94 return TRUE;
98 return FALSE;
103 * click on the tray icon
105 static void tray_icon2_activate(GtkStatusIcon * gsi, gpointer user_data)
107 pl3_toggle_hidden();
109 #ifdef HAVE_APP_INDICATOR
110 tray_icon2_update_menu();
111 #endif
116 * Right mouse press on tray icon
119 static void tray_icon2_seek_event(GtkWidget * pb, guint seek_time, gpointer user_data)
121 int state = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
122 mpd_player_seek(connection, (int)seek_time);
123 if (tray_icon2_tooltip_timeout)
125 g_source_remove(tray_icon2_tooltip_timeout);
127 tray_icon2_tooltip_timeout = g_timeout_add_seconds(state * 2, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
131 static void tray_icon2_update_menu_widget(GtkWidget *menu)
133 GtkWidget *item;
135 item = gtk_check_menu_item_new_with_mnemonic(_("Sho_w GMPC"));
136 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), !playlist3_window_is_hidden());
137 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
138 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_toggle_hidden), NULL);
140 item = gtk_separator_menu_item_new();
141 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
143 if (mpd_check_connected(connection))
145 if (mpd_server_check_command_allowed(connection, "play"))
147 if (mpd_player_get_state(connection) == MPD_STATUS_STATE_PLAY)
149 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PAUSE, NULL);
150 } else
152 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PLAY, NULL);
154 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
155 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(play_song), NULL);
157 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_STOP, NULL);
158 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
159 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(stop_song), NULL);
161 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_NEXT, NULL);
162 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
163 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(next_song), NULL);
165 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS, NULL);
166 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
167 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(prev_song), NULL);
169 } else
171 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL);
172 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
173 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(connect_to_mpd), NULL);
176 item = gtk_separator_menu_item_new();
177 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
179 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
180 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
181 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(main_quit), NULL);
182 gtk_widget_show_all(menu);
186 void tray_icon2_update_menu(void)
188 #ifdef HAVE_APP_INDICATOR
189 if (indicator != NULL) {
190 GtkWidget *menu;
191 if (app_indicator_get_menu(indicator) != NULL)
193 menu = (GtkWidget*)app_indicator_get_menu(indicator);
194 gtk_widget_destroy(menu);
197 menu = gtk_menu_new();
198 app_indicator_set_menu(indicator, GTK_MENU(menu));
199 tray_icon2_update_menu_widget(menu);
201 #endif
204 static void tray_icon2_populate_menu(GtkStatusIcon * gsi, guint button, guint activate_time, gpointer user_data)
206 GtkWidget *menu = gtk_menu_new();
207 tray_icon2_update_menu_widget(menu);
208 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, gtk_status_icon_position_menu, gsi, button, activate_time);
212 static void tray_icon2_embedded_changed(GtkStatusIcon * icon, GParamSpec * arg1, gpointer data)
214 if (!gtk_status_icon_is_embedded(icon))
216 /* the widget isn't embedded anymore */
217 create_playlist3();
223 * Initialize the tray icon
225 static int tray_icon2_button_press_event(gpointer tray, GdkEventButton * event, gpointer data)
227 if (event->button == 2)
229 play_song();
230 } else
232 return FALSE;
235 return TRUE;
239 static int tray_icon2_button_scroll_event(gpointer tray, GdkEventScroll * event, gpointer data)
241 if (event->direction == GDK_SCROLL_UP)
243 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
244 mpd_status_set_volume(connection, mpd_status_get_volume(connection) + cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
245 } else if (event->direction == GDK_SCROLL_DOWN)
247 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
248 mpd_status_set_volume(connection, mpd_status_get_volume(connection) - cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
249 } else if (event->direction == GDK_SCROLL_LEFT)
251 prev_song();
252 } else if (event->direction == GDK_SCROLL_RIGHT)
254 next_song();
256 return TRUE;
259 #ifdef HAVE_APP_INDICATOR
260 static int tray_icon2_button_scroll_event_appindicator(AppIndicator *this_indicator, gint steps, guint direction, gpointer userdata)
262 if (direction == GDK_SCROLL_UP)
264 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
265 mpd_status_set_volume(connection, mpd_status_get_volume(connection) + cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
266 } else if (direction == GDK_SCROLL_DOWN)
268 if (mpd_server_check_command_allowed(connection, "volume") && mpd_status_get_volume(connection) >= 0)
269 mpd_status_set_volume(connection, mpd_status_get_volume(connection) - cfg_get_single_value_as_int_with_default(config, "Volume", "scroll-sensitivity", 5));
270 } else if (direction == GDK_SCROLL_LEFT)
272 prev_song();
273 } else if (direction == GDK_SCROLL_RIGHT)
275 next_song();
277 return TRUE;
279 #endif
282 static void tray_icon2_init(void)
285 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", TRUE))
287 #ifndef HAVE_APP_INDICATOR
288 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "use_appindicator", FALSE);
289 #endif
291 #ifdef HAVE_APP_INDICATOR
292 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR))
294 GtkMenu *indicator_menu = GTK_MENU(gtk_menu_new());
295 indicator = app_indicator_new ("gmpc", "gmpc-tray-disconnected", APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
296 app_indicator_set_icon_theme_path(indicator, PIXMAP_PATH);
297 app_indicator_set_menu (indicator, GTK_MENU (indicator_menu));
298 tray_icon2_update_menu();
300 app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE);
301 g_signal_connect(G_OBJECT(indicator), "scroll-event", G_CALLBACK(tray_icon2_button_scroll_event_appindicator), NULL);
303 } else {
304 #endif
305 tray_icon2_gsi = gtk_status_icon_new_from_icon_name("gmpc-tray-disconnected");
306 #if GTK_CHECK_VERSION(2,15,0)
307 gtk_status_icon_set_has_tooltip(GTK_STATUS_ICON(tray_icon2_gsi), TRUE);
308 #endif
310 /* connect the (sparse) signals */
311 g_signal_connect(G_OBJECT(tray_icon2_gsi), "popup-menu", G_CALLBACK(tray_icon2_populate_menu), NULL);
312 g_signal_connect(G_OBJECT(tray_icon2_gsi), "activate", G_CALLBACK(tray_icon2_activate), NULL);
313 g_signal_connect(G_OBJECT(tray_icon2_gsi), "notify::embedded", G_CALLBACK(tray_icon2_embedded_changed), NULL);
314 if (gtk_check_version(2, 15, 0) == NULL)
316 g_signal_connect(G_OBJECT(tray_icon2_gsi), "button-press-event", G_CALLBACK(tray_icon2_button_press_event), NULL);
317 g_signal_connect(G_OBJECT(tray_icon2_gsi), "scroll-event", G_CALLBACK(tray_icon2_button_scroll_event), NULL);
318 /*g_signal_connect(G_OBJECT(tray_icon2_gsi), "query-tooltip", G_CALLBACK(tray_icon2_tooltip_query), NULL);*/
320 #ifdef HAVE_APP_INDICATOR
322 #endif // HAVE_APP_INDICATOR
324 /* Make sure the icons are up2date */
325 tray_icon2_connection_changed(connection, mpd_check_connected(connection), NULL);
331 * Destroy and cleanup
333 static void tray_icon2_destroy(void)
335 #ifdef HAVE_APP_INDICATOR
336 if (indicator) {
337 gtk_widget_destroy(GTK_WIDGET(app_indicator_get_menu(indicator)));
338 g_object_unref(indicator);
339 indicator = NULL;
341 #endif
342 if (tray_icon2_gsi)
344 g_object_unref(tray_icon2_gsi);
345 tray_icon2_gsi = NULL;
348 /* free the currnet song checksum */
349 if (current_song_checksum)
351 g_free(current_song_checksum);
352 current_song_checksum = NULL;
358 * Get enabled
360 static gboolean tray_icon2_get_enabled(void)
362 return cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", TRUE);
367 * Set Disabled
369 static void tray_icon2_set_enabled(int enabled)
371 #ifndef HAVE_APP_INDICATOR
372 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "use_appindicator", FALSE);
373 #endif
375 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "enable", enabled);
376 #ifdef HAVE_APP_INDICATOR
377 if ((enabled) && (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR)))
379 if (!indicator)
381 tray_icon2_init();
382 tray_icon2_status_changed(connection, MPD_CST_SONGID, NULL);
383 } else
385 app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE);
387 } else
389 if (indicator)
391 app_indicator_set_status(indicator, APP_INDICATOR_STATUS_PASSIVE);
394 #endif
396 if ((enabled) && (!cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR)))
398 if (!tray_icon2_gsi)
400 tray_icon2_init();
401 tray_icon2_status_changed(connection, MPD_CST_SONGID, NULL);
402 } else
404 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon2_gsi), TRUE);
406 } else
408 if (tray_icon2_gsi)
410 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon2_gsi), FALSE);
417 * TOOLTIP
419 static gboolean has_buttons = FALSE;
420 static GtkWidget *play_button = NULL;
422 static gboolean tray_icon2_tooltip_destroy(void)
424 tray_icon2_tooltip_pb = NULL;
425 gtk_widget_destroy(tray_icon2_tooltip);
426 tray_icon2_tooltip = NULL;
427 /* remove timeout, this is for when it doesn't get called from inside the timeout */
428 if (tray_icon2_tooltip_timeout)
430 g_source_remove(tray_icon2_tooltip_timeout);
432 tray_icon2_tooltip_timeout = 0;
433 has_buttons = FALSE;
434 /* remove the timeout */
435 return FALSE;
439 static gboolean tray_icon2_tooltip_button_press_event(GtkWidget * box, GdkEventButton * event, GtkWidget * vbox)
441 if ((event == NULL || event->button == 3) && !has_buttons)
443 GtkWidget *hbox, *button;
444 int state = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
445 if (tray_icon2_tooltip_timeout)
447 g_source_remove(tray_icon2_tooltip_timeout);
449 tray_icon2_tooltip_timeout = g_timeout_add_seconds(state * 2, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
451 has_buttons = TRUE;
453 hbox = gtk_hbox_new(TRUE, 6);
454 /* prev */
455 button = gtk_button_new();
456 gtk_button_set_image(GTK_BUTTON(button),
457 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS, GTK_ICON_SIZE_BUTTON));
458 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
459 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(prev_song), NULL);
460 /* stop */
461 button = gtk_button_new();
462 gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP, GTK_ICON_SIZE_BUTTON));
463 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
464 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(stop_song), NULL);
465 /* pause/play */
466 state = mpd_player_get_state(connection);
467 if (state != MPD_PLAYER_PLAY)
469 play_button = button = gtk_button_new();
470 gtk_button_set_image(GTK_BUTTON(button),
471 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
472 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
473 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(play_song), NULL);
474 } else
476 play_button = button = gtk_button_new();
477 gtk_button_set_image(GTK_BUTTON(button),
478 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON));
480 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
481 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(play_song), NULL);
483 /* next */
484 button = gtk_button_new();
485 gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock(GTK_STOCK_MEDIA_NEXT, GTK_ICON_SIZE_BUTTON));
487 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
488 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(next_song), NULL);
490 gtk_widget_show_all(hbox);
491 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
493 return TRUE;
495 tray_icon2_tooltip_destroy();
496 return TRUE;
500 static gboolean popup_enter_notify_event(GtkWidget * event, GdkEventCrossing * eventc, gpointer data)
502 if (tray_icon2_tooltip_timeout)
504 g_source_remove(tray_icon2_tooltip_timeout);
506 tray_icon2_tooltip_timeout = 0;
507 return FALSE;
511 static gboolean popup_leave_notify_event(GtkWidget * event, GdkEventCrossing * eventc, gpointer data)
513 int tooltip_timeout = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
514 tray_icon2_tooltip_timeout = g_timeout_add_seconds(tooltip_timeout, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
515 return FALSE;
519 static void tray_icon2_create_tooltip_real(int position)
521 int x = 0, y = 0, monitor;
522 GdkScreen *screen;
523 GtkWidget *pl3_win = playlist3_get_window();
524 GtkWidget *hbox = NULL;
525 GtkWidget *vbox = NULL;
526 GtkWidget *label = NULL;
527 GtkWidget *event = NULL;
528 GtkWidget *coverimg = NULL;
529 GtkStyleContext *sc;
530 mpd_Song *song = NULL;
531 int tooltip_timeout = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5);
532 int state = 0;
533 int x_offset = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "x-offset", 0);
534 int y_offset = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "y-offset", 0);
536 song = mpd_playlist_get_current_song(connection);
538 * if the tooltip still exists destroy it...
540 if (tray_icon2_tooltip)
542 /* Do a check to avoid ugly redraws */
543 mpd_Song *song2 = g_object_get_data(G_OBJECT(tray_icon2_tooltip), "song");
544 if (song2 && song)
546 if (song->file && song2->file && strcmp(song2->file, song->file) == 0)
548 if (tray_icon2_tooltip_timeout)
550 g_source_remove(tray_icon2_tooltip_timeout);
552 tray_icon2_tooltip_timeout =
553 g_timeout_add_seconds(tooltip_timeout, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
554 return;
557 if (tray_icon2_tooltip_timeout)
559 g_source_remove(tray_icon2_tooltip_timeout);
560 tray_icon2_tooltip_timeout = 0;
562 tray_icon2_tooltip_pb = NULL;
563 gtk_widget_destroy(tray_icon2_tooltip);
564 tray_icon2_tooltip = NULL;
565 //tray_icon2_tooltip_destroy();
567 /* If gmpc is fullscreen, don't show the tooltip */
568 if (pl3_window_is_fullscreen())
569 return;
571 * Creat the tootlip window
573 tray_icon2_tooltip = gtk_window_new(GTK_WINDOW_POPUP);
574 screen = gtk_window_get_screen(GTK_WINDOW(tray_icon2_tooltip));
576 if (gdk_screen_is_composited(screen))
578 GdkVisual *vs = gdk_screen_get_rgba_visual(screen);
579 if (vs)
580 gtk_widget_set_visual(tray_icon2_tooltip, vs);
581 gtk_window_set_opacity(GTK_WINDOW(tray_icon2_tooltip), 0.9);
584 sc = gtk_widget_get_style_context(tray_icon2_tooltip);
585 gtk_style_context_add_class(sc, GTK_STYLE_CLASS_TOOLTIP);
586 /* causes the border */
587 gtk_container_set_border_width(GTK_CONTAINER(tray_icon2_tooltip), 1);
588 gtk_window_set_default_size(GTK_WINDOW(tray_icon2_tooltip), 300, -1);
589 gtk_window_set_transient_for(GTK_WINDOW(tray_icon2_tooltip), GTK_WINDOW(pl3_win));
592 * Tooltip exists from 2 parts..
593 * ------------------
594 * | 1 | |
595 * | | 2 |
596 * ------------------
598 hbox = gtk_hbox_new(FALSE, 0);
599 gtk_container_add(GTK_CONTAINER(tray_icon2_tooltip), hbox);
603 * In first box we have image/coverart
604 * Re-use the gmpc-metaimage widget
606 if(cfg_get_single_value_as_int_with_default(config, "Interface", "hide-album-art", 0) == 0)
608 coverimg = (GtkWidget *)gmpc_metaimage_new_size(META_ALBUM_ART, 80);
609 gmpc_metaimage_set_squared(GMPC_METAIMAGE(coverimg), TRUE);
610 gmpc_metaimage_set_connection(GMPC_METAIMAGE(coverimg), connection);
611 gmpc_metaimage_set_no_cover_icon(GMPC_METAIMAGE(coverimg), (char *)"gmpc");
613 * Force an update if mpd is playing
615 state = mpd_player_get_state(connection);
616 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
618 gmpc_metaimage_update_cover(GMPC_METAIMAGE(coverimg), connection, MPD_CST_SONGID, NULL);
619 } else
621 gmpc_metaimage_set_cover_na(GMPC_METAIMAGE(coverimg));
625 * Pack the widget in a eventbox so we can set background color
627 event = gtk_event_box_new();
628 gtk_widget_set_size_request(event, 86, 86);
629 // gtk_widget_modify_bg(GTK_WIDGET(event), GTK_STATE_NORMAL, &(pl3_win->style->bg[GTK_STATE_SELECTED]));
630 gtk_container_add(GTK_CONTAINER(event), coverimg);
631 gtk_box_pack_start(GTK_BOX(hbox), event, FALSE, TRUE, 0);
633 g_signal_connect(G_OBJECT(tray_icon2_tooltip), "enter-notify-event", G_CALLBACK(popup_enter_notify_event), NULL);
634 g_signal_connect(G_OBJECT(tray_icon2_tooltip), "leave-notify-event", G_CALLBACK(popup_leave_notify_event), NULL);
638 * Right (2) view
641 * Create white background label box
643 event = gtk_event_box_new();
644 vbox = gtk_vbox_new(FALSE, 0);
645 // gtk_widget_modify_bg(GTK_WIDGET(event), GTK_STATE_NORMAL, &(pl3_win->style->light[GTK_STATE_NORMAL]));
646 gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
647 gtk_container_add(GTK_CONTAINER(event), vbox);
648 gtk_box_pack_start(GTK_BOX(hbox), event, TRUE, TRUE, 0);
650 if (!has_buttons)
652 g_signal_connect(G_OBJECT(hbox), "button-press-event", G_CALLBACK(tray_icon2_tooltip_button_press_event), vbox);
656 * If there is a song, show show song info
658 if (song)
660 int i;
661 char buffer[256];
662 int size_offset = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "size-offset", 1024);
663 size_offset = (size_offset < 100) ? 1024 : size_offset;
665 /** Artist label */
666 if (song->title || song->file || song->name)
668 gchar *test =
669 g_strdup_printf("<span size='%i' weight='bold'>[%%title%%|%%shortfile%%][ (%%name%%)]</span>",
670 14 * size_offset);
671 mpd_song_markup_escaped(buffer, 256, test, song);
672 q_free(test);
673 label = gtk_label_new("");
674 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
675 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
676 gtk_label_set_markup(GTK_LABEL(label), buffer);
677 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
679 if (song->artist)
681 gchar *test = g_strdup_printf("<span size='%i'>%%artist%%</span>", 10 * size_offset);
682 label = gtk_label_new("");
683 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
684 mpd_song_markup_escaped(buffer, 256, test, song);
685 q_free(test);
686 gtk_label_set_markup(GTK_LABEL(label), buffer);
687 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
689 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
691 if (song->album)
693 gchar *test = g_strdup_printf("<span size='%i'>%%album%%[ (%%year%%)]</span>", 8 * size_offset);
694 label = gtk_label_new("");
695 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
696 mpd_song_markup_escaped(buffer, 256, test, song);
697 q_free(test);
698 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
699 gtk_label_set_markup(GTK_LABEL(label), buffer);
700 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
702 tray_icon2_tooltip_pb = (GtkWidget *) gmpc_progress_new();
703 gmpc_progress_set_hide_text(GMPC_PROGRESS(tray_icon2_tooltip_pb), TRUE);
704 /* Update the progressbar */
705 gmpc_progress_set_time(GMPC_PROGRESS(tray_icon2_tooltip_pb),
706 mpd_status_get_total_song_time(connection),
707 mpd_status_get_elapsed_song_time(connection));
709 g_signal_connect(G_OBJECT(tray_icon2_tooltip_pb), "seek-event", G_CALLBACK(tray_icon2_seek_event), NULL);
711 // gtk_widget_modify_bg(GTK_WIDGET(tray_icon2_tooltip_pb), GTK_STATE_NORMAL,
712 // &(pl3_win->style->light[GTK_STATE_NORMAL]));
713 g_object_set_data_full(G_OBJECT(tray_icon2_tooltip), "song", mpd_songDup(song), (GDestroyNotify) mpd_freeSong);
714 gtk_box_pack_start(GTK_BOX(vbox), tray_icon2_tooltip_pb, TRUE, FALSE, 0);
716 i = mpd_player_get_next_song_id(connection);
717 if (i > 0)
719 mpd_Song *next_psong = mpd_playlist_get_song(connection, i);
720 if (next_psong)
722 gchar *test =
723 g_strdup_printf("<span size='%i'>%s: <i>[[%%title%% - &[%%artist%%]]|%%shortfile%%]</i></span>",
724 7 * size_offset, _("Next"));
725 label = gtk_label_new("");
726 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
727 mpd_song_markup_escaped(buffer, 256, test, next_psong);
728 q_free(test);
729 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
730 gtk_label_set_markup(GTK_LABEL(label), buffer);
731 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
732 mpd_freeSong(next_psong);
735 } else
737 gchar *value = g_markup_printf_escaped("<span size='large'>%s</span>", _("Gnome Music Player Client"));
738 label = gtk_label_new("");
739 gtk_label_set_markup(GTK_LABEL(label), value);
740 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
741 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
742 g_free(value);
745 * Position the popup
747 if (position == TI2_AT_TOOLTIP && tray_icon2_get_available())
750 GdkRectangle rect, rect2;
751 GtkOrientation orientation;
753 #ifdef HAVE_APP_INDICATOR
754 if (indicator != NULL) {
755 // there's no way to get the AppIndicator's position, so showing at tooltip is not possible
756 // choosing 50px above right corner
757 screen = gtk_widget_get_screen(pl3_win);
759 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
760 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
761 /** Set Y = window height - size; */
762 y = rect2.y + rect2.height - 50 - 95;
763 /** X =window width - width */
764 x = rect2.x + rect2.width - 5 - 300;
765 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
767 } else
768 #endif
770 if (gtk_status_icon_get_geometry(tray_icon2_gsi, &screen, &rect, &orientation))
772 monitor = gdk_screen_get_monitor_at_point(screen, rect.x, rect.y);
773 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
774 /* Get Y */
775 y = rect.y + rect.height + 5 - rect2.y + y_offset;
776 /* if the lower part falls off the screen, move it up */
777 if ((y + 95) > rect2.height)
779 y = rect.y - 95 - 5;
781 if (y < 0)
782 y = 0;
784 /* Get X */
785 x = rect.x - 300 / 2 - rect2.x + x_offset;
786 if ((x + 300) > rect2.width)
788 if (orientation == GTK_ORIENTATION_VERTICAL)
790 x = rect2.width + -300 - rect.width - 5;
791 } else
793 x = rect2.width - 300;
796 if (x < 0)
798 if (orientation == GTK_ORIENTATION_VERTICAL)
800 x = rect.width + 5;
801 } else
803 x = 0;
806 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), rect2.x + x, rect2.y + y);
809 } else if (position == TI2_AT_UPPER_LEFT)
811 GdkRectangle rect2;
812 screen = gtk_widget_get_screen(pl3_win);
814 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
815 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
816 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), rect2.x + 5 + x_offset, rect2.y + 5 + y_offset);
817 } else if (position == TI2_AT_UPPER_RIGHT)
819 GdkRectangle rect2;
820 screen = gtk_widget_get_screen(pl3_win);
822 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
823 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
824 /** Set Y = 0; */
825 y = rect2.y + 5;
826 /** X is upper right - width */
827 x = rect2.x + rect2.width - 5 - 300;
828 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
829 } else if (position == TI2_AT_LOWER_LEFT)
831 GdkRectangle rect2;
832 screen = gtk_widget_get_screen(pl3_win);
834 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
835 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
836 /** Set Y = window height - size; */
837 y = rect2.y + rect2.height - 5 - 95;
838 /** X =5 */
839 x = rect2.x + 5;
840 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
841 } else
843 GdkRectangle rect2;
844 screen = gtk_widget_get_screen(pl3_win);
846 monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(pl3_win));
847 gdk_screen_get_monitor_geometry(screen, monitor, &rect2);
848 /** Set Y = window height - size; */
849 y = rect2.y + rect2.height - 5 - 95;
850 /** X =window width - width */
851 x = rect2.x + rect2.width - 5 - 300;
852 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip), x + x_offset, y + y_offset);
855 gtk_widget_show_all(tray_icon2_tooltip);
857 if (has_buttons)
859 has_buttons = FALSE;
860 tray_icon2_tooltip_button_press_event(hbox, NULL, vbox);
863 * Destroy it after 5 seconds
865 tray_icon2_tooltip_timeout = g_timeout_add_seconds(tooltip_timeout, (GSourceFunc) tray_icon2_tooltip_destroy, NULL);
869 void tray_icon2_create_tooltip(void)
871 int state = cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-position", TI2_AT_TOOLTIP);
872 tray_icon2_create_tooltip_real(state);
876 static void tray_icon2_status_changed(MpdObj * mi, ChangedStatusType what, void *userdata)
878 char buffer[256];
879 mpd_Song *song = mpd_playlist_get_current_song(connection);
880 if (what & (MPD_CST_SONGID) || what & MPD_CST_SONGPOS || what & MPD_CST_PLAYLIST)
883 * If enabled by user, show the tooltip.
884 * But only if playing or paused.
887 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "show-tooltip", TRUE))
889 int state = mpd_player_get_state(connection);
890 gchar *new_checksum;
891 new_checksum = mpd_song_checksum(song);
892 if (state == MPD_PLAYER_PLAY || state == MPD_PLAYER_PAUSE)
894 if (new_checksum == NULL || current_song_checksum == NULL
895 || strcmp(current_song_checksum, new_checksum))
896 tray_icon2_create_tooltip();
898 if (current_song_checksum)
900 g_free(current_song_checksum);
901 current_song_checksum = NULL;
903 current_song_checksum = new_checksum;
906 if (tray_icon2_gsi)
908 mpd_song_markup(buffer, 256, "[%name%: ][%title%|%shortfile%][ - %artist%]", song);
909 //gtk_status_icon_set_tooltip(tray_icon2_gsi,buffer);
913 /* update the progress bar if available */
914 if (what & MPD_CST_ELAPSED_TIME)
916 if (tray_icon2_tooltip && tray_icon2_tooltip_pb)
918 gmpc_progress_set_time(GMPC_PROGRESS(tray_icon2_tooltip_pb),
919 mpd_status_get_total_song_time(connection),
920 mpd_status_get_elapsed_song_time(connection));
924 #ifdef HAVE_APP_INDICATOR
925 if ((indicator == NULL) && (tray_icon2_gsi == NULL))
926 return;
928 if ((indicator != NULL) && (what & MPD_CST_STATE))
929 tray_icon2_update_menu();
931 #endif
933 if (what & MPD_CST_STATE)
935 int state = mpd_player_get_state(connection);
936 if (state == MPD_PLAYER_PLAY)
938 mpd_song_markup(buffer, 256, "[%name%: ][%title%|%shortfile%][ - %artist%]", song);
940 #ifdef HAVE_APP_INDICATOR
941 if (indicator != NULL)
942 app_indicator_set_icon_full(indicator, "gmpc-tray-play", "gmpc is playing");
943 #endif
944 if (tray_icon2_gsi != NULL)
945 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray-play");
947 //gtk_status_icon_set_tooltip(tray_icon2_gsi,buffer);
948 if (has_buttons)
950 gtk_button_set_image(GTK_BUTTON(play_button),
951 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_BUTTON));
953 } else if (state == MPD_PLAYER_PAUSE)
955 #ifdef HAVE_APP_INDICATOR
956 if (indicator != NULL)
957 app_indicator_set_icon_full(indicator, "gmpc-tray-pause", "gmpc is pausing");
958 #endif
959 if (tray_icon2_gsi != NULL)
960 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray-pause");
962 //gtk_status_icon_set_tooltip(tray_icon2_gsi,_("Gnome Music Player Client"));
963 if (has_buttons)
965 gtk_button_set_image(GTK_BUTTON(play_button),
966 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
968 } else
970 #ifdef HAVE_APP_INDICATOR
971 if (indicator != NULL)
972 app_indicator_set_icon_full(indicator, "gmpc-tray", "gmpc is idling");
973 #endif
974 if (tray_icon2_gsi != NULL)
975 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray");
977 //gtk_status_icon_set_tooltip(tray_icon2_gsi,_("Gnome Music Player Client"));
978 if (has_buttons)
980 gtk_button_set_image(GTK_BUTTON(play_button),
981 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
989 * Show right icon when (dis)connected
991 static void tray_icon2_connection_changed(MpdObj * mi, int connect, void *user_data)
993 #ifdef HAVE_APP_INDICATOR
994 if ((indicator == NULL) && (tray_icon2_gsi == NULL))
995 return;
996 #endif
998 if (connect)
1000 tray_icon2_status_changed(mi, MPD_CST_STATE, NULL);
1001 } else
1003 /* Set the disconnect image, and reset the GtkTooltip */
1004 #ifdef HAVE_APP_INDICATOR
1005 if (indicator != NULL) {
1006 app_indicator_set_icon_full(indicator, "gmpc-tray-disconnected", "gmpc is disconnected");
1007 tray_icon2_update_menu();
1009 #endif
1010 if (tray_icon2_gsi != NULL) {
1011 gtk_status_icon_set_from_icon_name(tray_icon2_gsi, "gmpc-tray-disconnected");
1014 /* Destroy notification */
1015 if (tray_icon2_tooltip)
1016 tray_icon2_tooltip_destroy();
1020 gboolean trayicon2_have_appindicator_support( void )
1022 #ifdef HAVE_APP_INDICATOR
1023 return TRUE;
1024 #else
1025 return FALSE;
1026 #endif
1031 * PREFERENCES
1034 void tray_enable_toggled(GtkToggleButton * but)
1036 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "tray-icon.c: changing tray icon %i\n", gtk_toggle_button_get_active(but));
1037 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "enable", (int)gtk_toggle_button_get_active(but));
1039 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", 1))
1041 tray_icon2_set_enabled(TRUE);
1042 } else
1044 tray_icon2_set_enabled(FALSE);
1048 void trayicon2_toggle_use_appindicator(void)
1050 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));
1052 if (cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", DEFAULT_TRAY_ICON_ENABLE))
1054 tray_icon2_set_enabled(FALSE);
1055 tray_icon2_set_enabled(TRUE);
1060 /* this sets all the settings in the notification area preferences correct */
1061 static void tray_update_settings(void)
1063 gtk_toggle_button_set_active((GtkToggleButton *)
1064 gtk_builder_get_object(tray_icon2_preferences_xml, "ck_tray_enable"),
1065 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable",
1066 DEFAULT_TRAY_ICON_ENABLE));
1070 void popup_enable_toggled(GtkToggleButton * but)
1072 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "show-tooltip", gtk_toggle_button_get_active(but));
1076 void popup_position_changed(GtkComboBox * om)
1078 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "tooltip-position", gtk_combo_box_get_active(om));
1082 void popup_timeout_changed(void)
1084 cfg_set_single_value_as_int(config, TRAY_ICON2_ID, "tooltip-timeout",
1085 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON
1086 (gtk_builder_get_object
1087 (tray_icon2_preferences_xml, "popup_timeout"))));
1091 static void update_popup_settings(void)
1093 gtk_toggle_button_set_active((GtkToggleButton *)
1094 gtk_builder_get_object(tray_icon2_preferences_xml, "ck_popup_enable"),
1095 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "show-tooltip", 1));
1096 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(tray_icon2_preferences_xml, "om_popup_position")),
1097 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-position", 0));
1098 gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(tray_icon2_preferences_xml, "popup_timeout")),
1099 cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "tooltip-timeout", 5));
1100 #ifdef HAVE_LIBNOTIFY
1101 gtk_toggle_button_set_active(
1102 GTK_TOGGLE_BUTTON(gtk_builder_get_object(tray_icon2_preferences_xml,"ck_libnotify_enable")),
1103 libnotify_plugin.get_enabled());
1105 #else
1106 gtk_widget_hide(gtk_builder_get_object(tray_icon2_preferences_xml, "frame_libnotify"));
1107 #endif
1111 static void tray_icon2_preferences_destroy(GtkWidget * container)
1113 if (tray_icon2_preferences_xml)
1115 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(tray_icon2_preferences_xml, "tray-pref-vbox");
1116 gtk_container_remove(GTK_CONTAINER(container), vbox);
1117 g_object_unref(tray_icon2_preferences_xml);
1118 tray_icon2_preferences_xml = NULL;
1123 void tray_icon2_preferences_pm_combo_changed(GtkComboBox * cm, gpointer data)
1125 int level = gtk_combo_box_get_active(cm);
1126 cfg_set_single_value_as_int(config, "Default", "min-error-level", level);
1129 void libnotify_enable_toggled(GtkCheckButton *button, gpointer data)
1131 #ifdef HAVE_LIBNOTIFY
1132 int state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1133 libnotify_plugin.set_enabled(state);
1134 #endif
1138 static void tray_icon2_preferences_construct(GtkWidget * container)
1140 gchar *path = gmpc_get_full_glade_path("preferences-trayicon.ui");
1141 tray_icon2_preferences_xml = gtk_builder_new();
1142 gtk_builder_add_from_file(tray_icon2_preferences_xml, path, NULL);
1143 q_free(path);
1145 if (tray_icon2_preferences_xml)
1147 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(tray_icon2_preferences_xml, "tray-pref-vbox");
1148 gtk_container_add(GTK_CONTAINER(container), vbox);
1149 tray_update_settings();
1150 update_popup_settings();
1151 gtk_builder_connect_signals(tray_icon2_preferences_xml, NULL);
1153 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(tray_icon2_preferences_xml, "pm-combo")),
1154 cfg_get_single_value_as_int_with_default(config, "Default", "min-error-level",
1155 ERROR_INFO));
1159 gmpcPrefPlugin tray_icon2_preferences =
1161 tray_icon2_preferences_construct,
1162 tray_icon2_preferences_destroy
1166 gmpcPlugin tray_icon2_plug =
1168 .name = N_("Notification"),
1169 .version = {0, 0, 0}
1171 .plugin_type = GMPC_INTERNALL,
1172 .init = tray_icon2_init,
1173 .destroy = tray_icon2_destroy,
1174 .mpd_status_changed = tray_icon2_status_changed,
1175 .mpd_connection_changed = tray_icon2_connection_changed,
1176 .set_enabled = NULL,
1177 .get_enabled = NULL,
1178 .pref = &tray_icon2_preferences