/* XMMS STATUS PLUGIN - Status Docklet Plugin for XMMS * Copyright (C) 2000,2001,2002,2003 Ian Campbell. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public Licensse as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "xmms-status-plugin.h" #include "eggtrayicon.h" const gchar *plugin_name = "Status Docklet Plugin " VERSION; const gchar *plugin_window_title = "xmms-status-plugin"; GeneralPlugin *get_gplugin_info(void); static void init(void); static void cleanup(void); static gint timeout_callback (gpointer data); static gint button_press_callback (GtkWidget *widget, GdkEventButton *event); static gint xmms_remote_function_callback (GtkWidget *widget, gpointer data); static void drag_data_received_callback (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time); static void toggle_main_window (void); static void toggle_playlist_window (void); static void toggle_equalizer_window (void); static void toggle_all_windows(void); #ifdef HAVE_XMMS_REMOTE_PLAYLIST_DELETE static void remove_current_song (void); #endif static void add_song_to_playlist(void); static void add_menu_item(GtkWidget *menu, const gchar *name, GtkSignalFunc callback, gpointer data); static void setup_legacy_docklet_properties(GdkWindow *window); extern GtkWidget *util_create_filebrowser(gboolean clear_pl_on_ok); static GtkWidget *status_docklet = NULL; static GtkWidget *status_image = NULL; static GtkTooltips *status_tooltips = NULL; static GtkWidget *status_popup = NULL; static guint timeout_tag = -1; static GtkTargetEntry drop_types[] = { { "text/plain", 0, 1 }, }; static gchar playlist_was_shown; static gchar eq_was_shown; GeneralPlugin status_plugin = { NULL, /* handle - filled by xmms */ NULL, /* filename - filled by xmms */ -1, /* Session */ "Status Docklet Plugin " VERSION, /* Description */ init, status_docklet_about, status_docklet_configure, /* Configure */ cleanup }; GeneralPlugin *get_gplugin_info(void) { return (&status_plugin); } /* This function sets up the window manager hints. KDE1 and GNOME use the KWM_DOCKWINDOW property, while KDE2 uses _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR. */ static void setup_legacy_docklet_properties(GdkWindow *window) { glong data[1]; GdkAtom kwm_dockwindow_atom; GdkAtom kde_net_system_tray_window_for_atom; kwm_dockwindow_atom = gdk_atom_intern("KWM_DOCKWINDOW", FALSE); kde_net_system_tray_window_for_atom = gdk_atom_intern("_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", FALSE); /* This is the old KDE 1.0 and GNOME 1.2 way... */ data[0] = TRUE; gdk_property_change(window, kwm_dockwindow_atom, kwm_dockwindow_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *)&data, 1); /* This is needed to support KDE 2.0 */ /* can be set to zero or the root win I think */ data[0] = 0; gdk_property_change(window, kde_net_system_tray_window_for_atom, XA_WINDOW, 32, GDK_PROP_MODE_REPLACE, (guchar *)&data, 1); } /* * Detect if we are using the legacy docklet interface or the new XEMBED (freedesktop.org) protocol. */ static void detect_tray_version(void) { ConfigFile *cfgfile; /* TODO: Actually detect */ /* For now default to freedesktop.org Notification Tray support */ status_docklet_config.freedesktop_docklet_support = TRUE; cfgfile = xmms_cfg_open_default_file(); if (cfgfile) { gboolean value_found; value_found = xmms_cfg_read_boolean (cfgfile, "status_docklet", "freedesktop_docklet", &status_docklet_config.freedesktop_docklet_support); xmms_cfg_free(cfgfile); } } static void init(void) { GtkWidget *sub_menu; GtkWidget *sub_menu_item; detect_tray_version(); if ( !status_docklet_config.freedesktop_docklet_support ) { status_docklet = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(status_docklet), plugin_window_title); gtk_window_set_wmclass(GTK_WINDOW(status_docklet), "XMMS_StatusDocklet", "xmms"); gtk_widget_set_usize(GTK_WIDGET(status_docklet), 22, 22); } else { status_docklet = GTK_WIDGET(egg_tray_icon_new(plugin_window_title)); } gtk_widget_realize (GTK_WIDGET(status_docklet)); gtk_signal_connect(GTK_OBJECT(status_docklet), "drag_data_received", GTK_SIGNAL_FUNC(drag_data_received_callback), NULL); gtk_drag_dest_set(GTK_WIDGET(status_docklet), GTK_DEST_DEFAULT_ALL, drop_types, 1, GDK_ACTION_COPY); gtk_widget_add_events(GTK_WIDGET(status_docklet), GDK_BUTTON_PRESS_MASK); gtk_signal_connect(GTK_OBJECT(status_docklet), "button_press_event", GTK_SIGNAL_FUNC(button_press_callback), NULL); gtk_signal_connect(GTK_OBJECT(status_docklet), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &status_docklet); status_image = status_docklet_image_new(); gtk_container_add(GTK_CONTAINER(status_docklet), status_image); gtk_signal_connect(GTK_OBJECT(status_image), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &status_image); gtk_widget_show(status_image); status_tooltips = gtk_tooltips_new(); gtk_tooltips_enable(GTK_TOOLTIPS(status_tooltips)); status_popup = gtk_menu_new(); add_menu_item(status_popup, _ ("Play"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_play); add_menu_item(status_popup, _ ("Pause"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_pause); add_menu_item(status_popup, _ ("Stop"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_stop); add_menu_item(status_popup, _ ("Next"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_playlist_next); add_menu_item(status_popup, _ ("Prev"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_playlist_prev); /* add_menu_item(status_popup, _ ("Eject"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_eject); */ { int line = 0; #ifdef HAVE_XMMS_REMOTE_PLAYLIST_SHOW_ADDFILES add_menu_item(sub_menu, _ ("Add files"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_playlist_show_addfiles); line = 1; #endif #ifdef HAVE_XMMS_REMOTE_PLAYLIST_SHOW_ADDDIR add_menu_item(sub_menu, _ ("Add directory"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_playlist_show_adddir); line = 1; #endif #ifdef HAVE_XMMS_REMOTE_PLAYLIST_SHOW_ADDURL add_menu_item(sub_menu, _ ("Add URL"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_playlist_show_addurl); line = 1; #endif if(line) add_menu_item(sub_menu, NULL, NULL, NULL); } add_menu_item(status_popup, NULL, NULL, NULL); add_menu_item(status_popup, _ ("Toggle Repeat"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_toggle_repeat); add_menu_item(status_popup, _ ("Toggle Shuffle"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_toggle_shuffle); add_menu_item(status_popup, NULL, NULL, NULL); add_menu_item(status_popup, _ ("Toggle Main Window"), (GtkSignalFunc)toggle_main_window, NULL); add_menu_item(status_popup, _ ("Toggle Equalizer Window"), (GtkSignalFunc)toggle_equalizer_window, NULL); sub_menu = gtk_menu_new (); sub_menu_item = gtk_menu_item_new_with_label ( _("Playlist Window") ); gtk_menu_item_set_submenu (GTK_MENU_ITEM(sub_menu_item), sub_menu); gtk_widget_show (sub_menu_item); gtk_menu_append (GTK_MENU(status_popup), sub_menu_item); add_menu_item(sub_menu, _ ("Toggle Playlist Window"), (GtkSignalFunc)toggle_playlist_window, NULL); add_menu_item(sub_menu, NULL, NULL, NULL); //add_menu_item(sub_menu, _ ("Add Song"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_eject); add_menu_item(sub_menu, _ ("Add Song"), add_song_to_playlist, NULL); add_menu_item(sub_menu, NULL, NULL, NULL); #ifdef HAVE_XMMS_REMOTE_PLAYLIST_DELETE add_menu_item(sub_menu, _ ("Remove Current Song"), (GtkSignalFunc)remove_current_song, NULL); #endif add_menu_item(sub_menu, _ ("Clear Playlist"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_playlist_clear); add_menu_item(status_popup, NULL, NULL, NULL); add_menu_item(status_popup, _ ("About"), (GtkSignalFunc)status_docklet_about, NULL); sub_menu = gtk_menu_new (); sub_menu_item = gtk_menu_item_new_with_label ( _("Preferences") ); gtk_menu_item_set_submenu (GTK_MENU_ITEM(sub_menu_item), sub_menu ); gtk_widget_show (sub_menu_item); gtk_menu_append (GTK_MENU(status_popup), sub_menu_item); add_menu_item(sub_menu, _ ("XMMS"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_show_prefs_box); add_menu_item(sub_menu, _ ("Status Docklet"), (GtkSignalFunc)status_docklet_configure, NULL); #ifdef HAVE_XMMS_REMOTE_QUIT add_menu_item(status_popup, NULL, NULL, NULL); add_menu_item(status_popup, _ ("Quit XMMS"), (GtkSignalFunc)xmms_remote_function_callback, (gpointer)xmms_remote_quit); #endif /* Must be done before showing the window */ if ( status_docklet_config.freedesktop_docklet_support == FALSE ) setup_legacy_docklet_properties(status_docklet->window); status_docklet_load_config(); gtk_widget_show(status_docklet); status_docklet_image_state_set(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_LAST); timeout_tag = gtk_timeout_add(1000, timeout_callback, NULL); } void status_docklet_load_images(void) { if ( status_image == NULL || status_docklet == NULL ) return; status_docklet_image_load(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_PLAYING, status_docklet_config.playing_image, status_docklet_config.playing_image_delay); status_docklet_image_load(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_PAUSED, status_docklet_config.paused_image, status_docklet_config.paused_image_delay); status_docklet_image_load(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_STOPPED, status_docklet_config.stopped_image, status_docklet_config.stopped_image_delay); } static void add_menu_item(GtkWidget *menu, const gchar *name, GtkSignalFunc callback, gpointer data) { GtkWidget *item; if ( name ) item = gtk_menu_item_new_with_label( name ); else item = gtk_menu_item_new (); if ( callback ) gtk_signal_connect (GTK_OBJECT(item), "activate", callback, data); gtk_menu_append(GTK_MENU(menu), item); gtk_widget_show(item); } static void cleanup(void) { if ( timeout_tag != -1 ) gtk_timeout_remove(timeout_tag); timeout_tag = -1; if( status_docklet ) gtk_object_destroy(GTK_OBJECT(status_docklet)); if ( status_tooltips ) gtk_object_destroy(GTK_OBJECT(status_tooltips)); } static gint timeout_callback (gpointer data) { gchar *title; gint pos; static gchar *last_title = NULL; /* stop now if the window has gone. */ if ( status_docklet == NULL ) return FALSE; if ( last_title == NULL ) last_title = g_strdup(""); pos = xmms_remote_get_playlist_pos(status_plugin.xmms_session); title = xmms_remote_get_playlist_title(status_plugin.xmms_session, pos); if ( title != NULL && g_strcasecmp(title, last_title) ) { gtk_tooltips_set_tip(GTK_TOOLTIPS(status_tooltips), GTK_WIDGET(status_docklet), title, NULL); if ( status_docklet_config.freedesktop_docklet_support && status_docklet_config.balloon_delay ) egg_tray_icon_send_message ( EGG_TRAY_ICON(status_docklet), status_docklet_config.balloon_delay * 1000, title, -1 ); g_free(last_title); last_title = title; } else { g_free(title); } if ( xmms_remote_is_paused(status_plugin.xmms_session) ) status_docklet_image_state_set(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_PAUSED); else if ( xmms_remote_is_playing(status_plugin.xmms_session) ) status_docklet_image_state_set(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_PLAYING); else status_docklet_image_state_set(STATUS_DOCKLET_IMAGE(status_image), STATUS_DOCKLET_STATE_STOPPED); /* Keep going... */ return TRUE; } static gint button_press_callback (GtkWidget *widget, GdkEventButton *event) { gint i; StatusDockletButtonModifier mod = STATUS_DOCKLET_BUTTON_MODIFIER_NONE; if ( event->state & GDK_SHIFT_MASK ) mod = STATUS_DOCKLET_BUTTON_MODIFIER_SHIFT; if ( event->state & GDK_CONTROL_MASK ) mod = STATUS_DOCKLET_BUTTON_MODIFIER_CONTROL; if ( event->state & GDK_MOD1_MASK ) mod = STATUS_DOCKLET_BUTTON_MODIFIER_ALT; switch ( status_docklet_config.button_actions[mod][event->button-1] ) { case STATUS_DOCKLET_BUTTON_ACTION_NONE: return FALSE; case STATUS_DOCKLET_BUTTON_ACTION_TOGGLE_WINDOWS: toggle_all_windows(); break; case STATUS_DOCKLET_BUTTON_ACTION_PLAYPAUSE: #ifdef HAVE_XMMS_REMOTE_PLAY_PAUSE xmms_remote_play_pause(status_plugin.xmms_session); #else if ( xmms_remote_is_playing (status_plugin.xmms_session) ) xmms_remote_pause(status_plugin.xmms_session); else xmms_remote_play(status_plugin.xmms_session); #endif break; case STATUS_DOCKLET_BUTTON_ACTION_STOP: xmms_remote_stop(status_plugin.xmms_session); break; case STATUS_DOCKLET_BUTTON_ACTION_VOLUME_UP: i = xmms_remote_get_main_volume(status_plugin.xmms_session); i += 5; if ( i > 100 ) i = 100; xmms_remote_set_main_volume(status_plugin.xmms_session, i); break; case STATUS_DOCKLET_BUTTON_ACTION_VOLUME_DOWN: i = xmms_remote_get_main_volume(status_plugin.xmms_session); i -= 5; if ( i < 0 ) i = 0; xmms_remote_set_main_volume(status_plugin.xmms_session, i); break; case STATUS_DOCKLET_BUTTON_ACTION_FORWARD: xmms_remote_playlist_next(status_plugin.xmms_session); break; case STATUS_DOCKLET_BUTTON_ACTION_BACKWARD: xmms_remote_playlist_prev(status_plugin.xmms_session); break; case STATUS_DOCKLET_BUTTON_ACTION_MENU: gtk_menu_popup (GTK_MENU(status_popup), NULL, NULL, NULL, NULL, event->button, event->time); break; case STATUS_DOCKLET_BUTTON_ACTION_ADD_FILES: //xmms_remote_eject(status_plugin.xmms_session); add_song_to_playlist(); break; default: return FALSE; } return TRUE; } static void drag_data_received_callback (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time) { xmms_remote_playlist_add_url_string(status_plugin.xmms_session, (gchar *)selection_data->data); gtk_drag_finish (context, TRUE, FALSE, time); } static gint xmms_remote_function_callback (GtkWidget *widget, gpointer data) { void (*func)(gint xmms_session) = (void(*)(gint xmms_session))data; func(status_plugin.xmms_session); return TRUE; } static void toggle_all_windows(void) { gboolean window_shown; window_shown = xmms_remote_is_main_win(status_plugin.xmms_session); if (window_shown) { // remove all windows... playlist_was_shown = xmms_remote_is_pl_win(status_plugin.xmms_session); eq_was_shown = xmms_remote_is_eq_win(status_plugin.xmms_session); if (eq_was_shown) xmms_remote_eq_win_toggle(status_plugin.xmms_session, !eq_was_shown); if (playlist_was_shown) xmms_remote_pl_win_toggle(status_plugin.xmms_session, !playlist_was_shown); xmms_remote_main_win_toggle(status_plugin.xmms_session, !window_shown); } else { // restore windows xmms_remote_main_win_toggle(status_plugin.xmms_session, !window_shown); if (eq_was_shown) xmms_remote_eq_win_toggle(status_plugin.xmms_session, eq_was_shown); if (playlist_was_shown) xmms_remote_pl_win_toggle(status_plugin.xmms_session, playlist_was_shown); } } static void toggle_main_window (void) { gboolean window_shown;; window_shown = xmms_remote_is_main_win(status_plugin.xmms_session); xmms_remote_main_win_toggle(status_plugin.xmms_session, !window_shown); } static void toggle_equalizer_window (void) { gboolean window_shown;; window_shown = xmms_remote_is_eq_win(status_plugin.xmms_session); xmms_remote_eq_win_toggle(status_plugin.xmms_session, !window_shown); } static void toggle_playlist_window (void) { gboolean window_shown;; window_shown = xmms_remote_is_pl_win(status_plugin.xmms_session); xmms_remote_pl_win_toggle(status_plugin.xmms_session, !window_shown); } #ifdef HAVE_XMMS_REMOTE_PLAYLIST_DELETE static void remove_current_song (void) { gint pos; pos = xmms_remote_get_playlist_pos(status_plugin.xmms_session); xmms_remote_playlist_delete(status_plugin.xmms_session, pos); } #endif static void add_song_to_playlist(void) { GtkWidget *filebrowser; filebrowser = util_create_filebrowser(FALSE); }