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.
23 #include <libmpd/libmpd.h>
27 #include "playlist3.h"
28 #include "preferences.h"
29 #include "gmpc-extras.h"
30 #include "gmpc-metaimage.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
;
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
);
58 GtkWidget
*tray_icon2_tooltip
= NULL
;
59 GtkWidget
*tray_icon2_tooltip_pb
= NULL
;
60 guint tray_icon2_tooltip_timeout
= 0;
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
);
83 gboolean
tray_icon2_get_available(void)
85 #ifdef HAVE_APP_INDICATOR
86 if ((indicator
) && (app_indicator_get_status(indicator
) != APP_INDICATOR_STATUS_PASSIVE
))
92 if (gtk_status_icon_is_embedded(tray_icon2_gsi
) && gtk_status_icon_get_visible(tray_icon2_gsi
))
103 * click on the tray icon
105 static void tray_icon2_activate(GtkStatusIcon
* gsi
, gpointer user_data
)
109 #ifdef HAVE_APP_INDICATOR
110 tray_icon2_update_menu();
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
)
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
);
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
);
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
) {
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
);
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 */
223 * Initialize the tray icon
225 static int tray_icon2_button_press_event(gpointer tray
, GdkEventButton
* event
, gpointer data
)
227 if (event
->button
== 2)
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
)
252 } else if (event
->direction
== GDK_SCROLL_RIGHT
)
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
)
273 } else if (direction
== GDK_SCROLL_RIGHT
)
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
);
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
);
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
);
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
337 gtk_widget_destroy(GTK_WIDGET(app_indicator_get_menu(indicator
)));
338 g_object_unref(indicator
);
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
;
360 static gboolean tray_icon2_get_enabled(void)
362 return cfg_get_single_value_as_int_with_default(config, TRAY_ICON2_ID, "enable", TRUE);
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
);
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
)))
382 tray_icon2_status_changed(connection
, MPD_CST_SONGID
, NULL
);
385 app_indicator_set_status(indicator
, APP_INDICATOR_STATUS_ACTIVE
);
391 app_indicator_set_status(indicator
, APP_INDICATOR_STATUS_PASSIVE
);
396 if ((enabled
) && (!cfg_get_single_value_as_int_with_default(config
, TRAY_ICON2_ID
, "use_appindicator", DEFAULT_TRAY_ICON_USE_APPINDICATOR
)))
401 tray_icon2_status_changed(connection
, MPD_CST_SONGID
, NULL
);
404 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon2_gsi
), TRUE
);
410 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon2_gsi
), FALSE
);
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;
434 /* remove the timeout */
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
);
453 hbox
= gtk_hbox_new(TRUE
, 6);
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
);
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
);
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
);
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
);
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);
495 tray_icon2_tooltip_destroy();
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;
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
);
519 static void tray_icon2_create_tooltip_real(int position
)
521 int x
= 0, y
= 0, monitor
;
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
;
530 mpd_Song
*song
= NULL
;
531 int tooltip_timeout
= cfg_get_single_value_as_int_with_default(config
, TRAY_ICON2_ID
, "tooltip-timeout", 5);
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");
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
);
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())
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
);
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..
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
);
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
);
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);
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
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
;
666 if (song
->title
|| song
->file
|| song
->name
)
669 g_strdup_printf("<span size='%i' weight='bold'>[%%title%%|%%shortfile%%][ (%%name%%)]</span>",
671 mpd_song_markup_escaped(buffer
, 256, test
, song
);
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);
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
);
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);
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
);
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
);
719 mpd_Song
*next_psong
= mpd_playlist_get_song(connection
, i
);
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
);
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
);
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);
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
);
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
);
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
)
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;
793 x
= rect2
.width
- 300;
798 if (orientation
== GTK_ORIENTATION_VERTICAL
)
806 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip
), rect2
.x
+ x
, rect2
.y
+ y
);
809 } else if (position
== TI2_AT_UPPER_LEFT
)
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
)
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
);
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
)
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;
840 gtk_window_move(GTK_WINDOW(tray_icon2_tooltip
), x
+ x_offset
, y
+ y_offset
);
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
);
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
)
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
);
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
;
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
))
928 if ((indicator
!= NULL
) && (what
& MPD_CST_STATE
))
929 tray_icon2_update_menu();
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");
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);
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");
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"));
965 gtk_button_set_image(GTK_BUTTON(play_button
),
966 gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY
, GTK_ICON_SIZE_BUTTON
));
970 #ifdef HAVE_APP_INDICATOR
971 if (indicator
!= NULL
)
972 app_indicator_set_icon_full(indicator
, "gmpc-tray", "gmpc is idling");
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"));
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
))
1000 tray_icon2_status_changed(mi
, MPD_CST_STATE
, NULL
);
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();
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
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
);
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());
1106 gtk_widget_hide(gtk_builder_get_object(tray_icon2_preferences_xml
, "frame_libnotify"));
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
);
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
);
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",
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