Cleanups of metadata.c.
[gmpc.git] / src / main.c
blob0fe9b9e940db1140fcd20690ae5ff538dfb79493
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2011 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <strings.h>
25 #include <libxml/parser.h>
27 /** Gtk/glib glade stuff */
28 #include <gtk/gtk.h>
30 #include <libmpd/debug_printf.h>
31 /* header files */
32 #include "main.h"
33 #include "playlist3.h"
35 #include "misc.h"
36 #include "advanced-search.h"
37 #include "gmpc_easy_download.h"
39 #include "setup-assistant.h"
41 #include "gmpc-mpddata-model-playlist.h"
42 #include "bug-information.h"
44 #include "pixbuf-cache.h"
45 #include "options.h"
46 #include "preferences.h"
48 #include "plugin-man.h"
49 #include "browsers/playlist3-playlist-editor.h"
51 #ifdef ENABLE_MMKEYS
52 #include "mm-keys.h"
53 #endif
55 #define LOG_DOMAIN "Gmpc"
56 /**
57 * Get revision
59 #include "revision.h"
60 #include "ipc.h"
62 #include "internal-plugins.h"
63 #include "log.h"
64 #include "mpd-easy-commands.h"
66 /**
67 * Global objects that give signals
69 /* gives signal on connection changes, and state changes of mpd.*/
70 GmpcConnection *gmpcconn = NULL;
71 /* Implements, and gives signals on profiles */
72 GmpcProfiles *gmpc_profiles = NULL;
73 /* Implements, and gives signals on meta_data*/
74 GmpcMetaWatcher *gmw = NULL;
75 /* Easy command */
76 GmpcEasyCommand *gmpc_easy_command = NULL;
77 /* Playlist3 messages */
78 Playlist3MessagePlugin *pl3_messages = NULL;
80 /* The playlist backend */
81 GtkTreeModel *playlist = NULL;
83 GObject *paned_size_group = NULL;
84 /**
85 * This flag indicate the requested connection state by the user.
86 * If the user presses disconnect, you don't want to auto-connect anymore.
87 **/
88 int gmpc_connected = FALSE;
90 static void connection_changed_real(
91 GmpcConnection * gmpcconn,
92 MpdObj * mi,
93 int connect,
94 gpointer data);
96 static void gmpc_status_changed_callback_real(
97 GmpcConnection * gmpcconn,
98 MpdObj * mi,
99 ChangedStatusType what,
100 gpointer data);
103 * Define some local functions
106 static void gmpc_easy_command_set_default_entries(void);
107 static void gmpc_mmkeys_connect_signals(GObject *keys);
108 /** handle connection changed */
109 static void connection_changed(MpdObj * mi, int connect, gpointer data);
111 /** Error callback */
112 static int error_callback(MpdObj * mi,
113 int error_id,
114 char *error_msg,
115 gpointer data);
117 /** init stock icons */
118 static void init_stock_icons(void);
121 * the xml fle pointer to the player window
123 static GtkBuilder *xml_password_window = NULL;
124 static int autoconnect_callback(void);
127 * the ID of the autoconnect timeout callback
129 static guint autoconnect_timeout = 0;
132 * The Config object
134 config_obj *config = NULL;
137 * The Connection object
139 MpdObj *connection = NULL;
141 /* Glade prototypes, these would be static otherwise */
142 void send_password(void);
144 static void print_version(void);
148 * Forward libxml errors into GLib.log errors with LibXML error domain
150 static void xml_error_func(void *ctx, const char *msg, ...)
152 va_list ap;
153 va_start(ap, msg);
154 g_logv("LibXML", G_LOG_LEVEL_DEBUG, msg, ap);
155 va_end(ap);
157 /* \todo why is this here? */
158 static xmlGenericErrorFunc handler = (xmlGenericErrorFunc) xml_error_func;
161 static gboolean hide_on_start(void)
163 pl3_hide();
164 return FALSE;
168 int main(int argc, char **argv)
170 #ifdef WIN32
171 gchar *packagedir = NULL;
172 #endif
173 #ifdef ENABLE_MMKEYS
174 MmKeys *keys = NULL;
175 #endif
176 #ifdef HAVE_IPC
177 GObject *ipc = NULL;
178 #endif
180 /* A string used severall times to create a path */
181 gchar *url = NULL;
183 INIT_TIC_TAC();
185 log_init();
188 * Setup NLS
190 #ifdef ENABLE_NLS
191 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Setting NLS");
192 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
193 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
194 textdomain(GETTEXT_PACKAGE);
195 #endif
197 gtk_set_locale();
199 TEC("Setting up locale");
201 parse_options(&argc, &argv);
203 /* Show the version, if requested */
204 if (settings.show_version)
206 print_version();
207 return EXIT_SUCCESS;
209 TEC("Parsing command line options");
211 log_set_debug_level(settings.debug_level);
212 TEC("Set debug level")
213 /* Show the bug-information dialog */
214 if (settings.show_bug_information)
216 bug_information_file_new(stdout);
217 return EXIT_SUCCESS;
222 * Init libxml.
223 * Libxml is not used (directly) by gmpc.
224 * But via glade and several plugins use it.
225 * I need to initialize it before the threading is started.
226 * So moved to gmpc.
228 * This fixes the plugin crasher bug on windows.
230 xmlInitParser();
231 initGenericErrorDefaultFunc(&handler);
234 * Check if threading is supported, if so, start it.
235 * Don't fail here, stuff like can cause that it is allready initialized.
237 if (!g_thread_supported())
238 g_thread_init(NULL);
240 TEC("Initializing threading");
242 * initialize gtk
244 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Initializing gtk ");
246 #ifdef WIN32
248 * This loads an extra gtk rc file on windows.
249 * This is used to re-enable rule-hint in the treeview.
250 * (this is forced off on windows).
252 packagedir = g_win32_get_package_installation_directory_of_module(NULL);
253 url = g_build_filename(packagedir,
254 "share", "gmpc",
255 "gmpc-gtk-win32.rc", NULL);
256 q_free(packagedir);
257 gtk_rc_add_default_file(url);
258 g_free(url);
259 #endif
261 /* initialize gtk */
262 gtk_init(&argc, &argv);
263 TEC("Gtk init");
265 /* Hack to override the icon theme, on recursive zeltak request */
266 if(settings.icon_theme != NULL) {
267 gtk_settings_set_string_property(gtk_settings_get_default(),
268 "gtk-icon-theme-name" , settings.icon_theme,NULL);
272 * Call create_gmpc_paths();
273 * This function checks if the path needed path are available
274 * and creates them if needed.
276 create_gmpc_paths();
277 TEC("Check version and create paths");
280 * COMMANDLINE_OPTION:
281 * Cleanup the metadata database and quit.
283 if (settings.clean_config)
285 /* start the metadata system */
286 meta_data_init();
287 //printf("Cleaning up cover file..\n");
288 /* Call the cleanup */
289 //metadata_cache_cleanup();
290 printf("Done..\n");
291 /* Destroy the meta data system and exit. */
292 meta_data_destroy();
293 TEC("Database cleanup");
294 return EXIT_SUCCESS;
298 * Open the config file
301 * Check if the user has forced a different config file location.
302 * else set to ~/.gmpc/gmpc.cfg
304 if (!settings.config_path)
306 url = gmpc_get_user_path("gmpc.cfg");
307 } else
309 url = g_strdup(settings.config_path);
313 * Open it
315 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
316 "Trying to open the config file: %s", url);
317 config = cfg_open(url);
320 * Show gtk error message and quit if config failed to open.
322 if (config == NULL)
324 g_log(LOG_DOMAIN, G_LOG_LEVEL_ERROR,
325 "Failed to save/load configuration:\n%s\n", url);
326 show_error_message(_("Failed to load the configuration system."));
327 return EXIT_FAILURE;
329 TEC("Opening config file: %s", url);
330 q_free(url);
333 * \TODO, Check if version changed, then say something about it
335 * Enable this function if we need todo some upgrading on version change.
336 * Removal of this current content destroys config conversion from 0.17 and
337 * up
339 url = cfg_get_single_value_as_string(config, "Default", "version");
340 if (url == NULL || strcmp(url, VERSION))
342 cfg_set_single_value_as_string(config, "Default", "version", VERSION);
344 if (url) q_free(url);
345 TEC("New version check");
348 #ifdef HAVE_IPC
349 if (cfg_get_single_value_as_int_with_default(config,
350 "Default",
351 "allow-multiple",
352 FALSE) == FALSE)
354 ipc = gmpc_tools_ipc_new();
355 if(gmpc_tools_ipc_is_running(ipc))
357 if(settings.quit)
358 gmpc_tools_ipc_send(ipc, COMMAND_EASYCOMMAND,"quit");
359 else
360 gmpc_tools_ipc_send(ipc, COMMAND_EASYCOMMAND,"show");
362 cfg_close(config);
363 config = NULL;
364 TEC("IPC setup and quitting");
365 return EXIT_SUCCESS;
368 #endif
369 if (settings.quit)
371 cfg_close(config);
372 return EXIT_SUCCESS;
375 /* Easy command */
376 gmpc_easy_command = gmpc_easy_command_new();
377 TEC("Init easy command")
378 gmpc_easy_command_set_default_entries();
379 TEC("Set easy commands")
380 mpd_easy_commands_init();
381 TEC("Set MPD Easy commands");
382 /* Advanced search */
383 advanced_search_init();
384 TEC("Init advanced search");
386 /* PanedSizeGroup */
387 paned_size_group = (GObject *) gmpc_paned_size_group_new();
389 gmpc_profiles = gmpc_profiles_new();
390 /* If user requested a profile, look it up and set it active */
391 if (settings.profile_name)
393 gmpc_profiles_set_profile_from_name(gmpc_profiles,
394 settings.profile_name);
396 TEC("Setting up gmpc idle,signals and profiles");
398 * Initialize the new metadata subsystem.
400 meta_data_init();
402 TEC("Initializing metadata system");
403 pixbuf_cache_create();
404 TEC("Pixbuf cache create()");
407 * stock icons
409 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Loading stock icons");
410 init_stock_icons();
411 TEC("Init stock icons");
413 * Create connection object
415 connection = mpd_new_default();
416 if (connection == NULL)
419 * if failed, print error message
421 g_log(LOG_DOMAIN,
422 G_LOG_LEVEL_ERROR,
423 "Failed to create connection object\n");
424 show_error_message(_("Failed to setup libmpd"));
425 abort();
427 TEC("Setting up mpd connection object");
429 * Connect signals to the connection object
431 mpd_signal_connect_status_changed(connection,
432 GmpcStatusChangedCallback, NULL);
433 mpd_signal_connect_error(connection,
434 error_callback, NULL);
435 mpd_signal_connect_connection_changed(connection,
436 connection_changed, NULL);
438 * Just some trick to provide glib signals
440 gmpcconn = (GmpcConnection *) gmpc_connection_new();
441 g_signal_connect(G_OBJECT(gmpcconn),
442 "connection_changed",
443 G_CALLBACK(connection_changed_real), NULL);
444 g_signal_connect(G_OBJECT(gmpcconn),
445 "status_changed",
446 G_CALLBACK(gmpc_status_changed_callback_real), NULL);
448 TEC("Setting up mpd object signal system");
450 * New Metadata object
452 gmw = gmpc_meta_watcher_new();
453 TEC("Initializing metadata watcher");
457 /** init the error messages */
458 pl3_messages = playlist3_message_plugin_new();
460 playlist = (GtkTreeModel*)gmpc_mpddata_model_playlist_new(
461 gmpcconn,
462 connection);
463 gmpc_mpddata_model_disable_image(GMPC_MPDDATA_MODEL(playlist));
466 * Add the internall plugins
468 plugin_manager_load_internal_plugins();
472 * load dynamic plugins
474 if (!settings.disable_plugins)
476 plugin_manager_load_plugins();
478 /* time todo some initialisation of plugins */
479 plugin_manager_initialize_plugins();
482 * Create the main window
484 create_playlist3();
485 TEC("Creating playlist window");
486 #ifdef HAVE_IPC
487 if(ipc)
489 gmpc_tools_ipc_watch_window(ipc, GTK_WINDOW(playlist3_get_window()));
490 TEC("Setup unique app to watch main window");
492 #endif
495 * First run dialog
497 * If gmpc is ran for the first time, we want to show a wizard that helps
498 * the user getting started.
500 if (cfg_get_single_value_as_int_with_default(config,
501 "Default",
502 "first-run",
505 setup_assistant();
506 cfg_set_single_value_as_int(config, "Default", "first-run", 0);
507 TEC("Setup first run assistant");
511 * If autoconnect is enabled, tell gmpc that it's in state it should connect
513 if (cfg_get_single_value_as_int_with_default(config,
514 "connection",
515 "autoconnect",
516 DEFAULT_AUTOCONNECT))
518 gmpc_connected = TRUE;
521 * create timeouts
522 * get the status every 1/2 second should be enough, but it's configurable.
524 g_timeout_add(cfg_get_single_value_as_int_with_default(config,
525 "connection",
526 "mpd-update-speed",
527 500), (GSourceFunc) update_mpd_status, NULL);
529 * create the autoconnect timeout,
530 * if autoconnect enable, it will check every 5 seconds
531 * if you are still connected, and reconnects you if not.
533 autoconnect_timeout = g_timeout_add_seconds(5,
534 (GSourceFunc) autoconnect_callback, NULL);
537 * Call this when entering the main loop,
538 * so you are connected on startup, not 5 seconds later
540 gtk_init_add((GSourceFunc) autoconnect_callback, NULL);
541 if (settings.fullscreen)
543 gtk_init_add((GSourceFunc) pl3_window_fullscreen, NULL);
547 * If the user wants gmpc to be started hidden,
548 * call pl3_hide after the mainloop started running
550 if (cfg_get_single_value_as_int_with_default(config,
551 "Default",
552 "start-hidden",
553 FALSE) ||
554 settings.start_hidden)
556 g_timeout_add(250, (GSourceFunc) hide_on_start, NULL);
558 TEC("Setting up timers");
560 #ifdef ENABLE_MMKEYS
562 * Setup Multimedia Keys
564 keys = mmkeys_new();
565 gmpc_mmkeys_connect_signals(G_OBJECT(keys));
566 TEC("Setting up multimedia keys");
567 #endif
569 url = gmpc_get_user_path("gmpc.key");
570 gtk_accel_map_load(url);
571 q_free(url);
575 * run the main loop
577 gtk_main();
580 * Shutting Down
581 * cleaning up.
583 url = gmpc_get_user_path("gmpc.key");
584 gtk_accel_map_save(url);
585 q_free(url);
587 #ifdef HAVE_IPC
588 if(ipc != NULL)
590 g_object_unref(ipc);
592 #endif
593 /* Quit _all_ downloads */
594 gmpc_easy_async_quit();
596 /* tell the plugins to save themself. */
597 plugin_manager_save_state();
599 /* Should fix some possible crashes */
600 gtk_tree_view_set_model(playlist3_get_category_tree_view(), NULL);
603 * Clear metadata struct
605 meta_data_destroy();
607 /* time todo some destruction of plugins */
608 plugin_manager_destroy_plugins();
610 playlist3_destroy();
612 g_object_unref(playlist);
613 g_object_unref(G_OBJECT(gmw));
615 /* Destroy PanedSizeGroup */
616 g_object_unref(paned_size_group);
618 * Close the config file
620 TOC("Starting save config");
621 cfg_close(config);
622 TOC("Saved config");
623 g_object_unref(gmpc_profiles);
624 g_object_unref(gmpcconn);
626 pixbuf_cache_destroy();
628 * This now gets destroyed with the plugins
630 advanced_search_destroy();
632 * Destroy the connection object
634 mpd_free(connection);
636 /* Reset xml error function and cleanup */
637 initGenericErrorDefaultFunc((xmlGenericErrorFunc *) NULL);
638 xmlCleanupParser();
639 /* cleanup */
640 gmpc_mpddata_treeview_cleanup();
642 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Quit....\n");
643 return EXIT_SUCCESS;
648 * Function to quiet the program
650 void main_quit(void)
652 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Quiting gmpc....");
654 * close playlist and store size
656 pl3_hide();
658 * Remove the autoconnect timeout,
660 if (autoconnect_timeout)
661 g_source_remove(autoconnect_timeout);
664 * Call the connection changed.
665 * so it saves the playlist pos
667 mpd_signal_connect_connection_changed(connection, NULL, NULL);
670 * Disconnect when connected
672 if (mpd_check_connected(connection))
674 if (cfg_get_single_value_as_int_with_default(config,
675 "connection", "stop-on-exit", FALSE))
677 mpd_player_stop(connection);
679 mpd_disconnect(connection);
682 * Exit main loop
684 gtk_main_quit();
689 * Callback that get's called every 5 seconds,
690 * and tries to autoconnect
691 * (when enabled)
694 static int autoconnect_backoff = 0;
695 static int autoconnect_callback(void)
697 /* Don't autoconnect while showing the first start assistant */
698 if (setup_assistant_is_running())
699 return FALSE;
701 /* check if there is an connection. */
702 if (!mpd_check_connected(connection))
704 /* connect when autoconnect is enabled, the user wants to be connected
706 if (gmpc_connected
707 && cfg_get_single_value_as_int_with_default(config,
708 "connection", "autoconnect", DEFAULT_AUTOCONNECT))
710 connect_to_mpd();
713 if (autoconnect_backoff < 60)
714 autoconnect_backoff += 1;
715 /* keep the timeout running */
716 if (autoconnect_timeout)
717 g_source_remove(autoconnect_timeout);
718 autoconnect_timeout = g_timeout_add_seconds(5 + autoconnect_backoff,
719 (GSourceFunc) autoconnect_callback, NULL);
720 return FALSE;
724 static void init_stock_icons(void)
726 char *path;
728 path = gmpc_get_full_image_path();
729 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
730 q_free(path);
732 gtk_window_set_default_icon_name("gmpc");
734 #ifdef WIN32
735 /* The Windows gtkrc sets this to 0, so images don't work on buttons */
736 gtk_settings_set_long_property(gtk_settings_get_default(),
737 "gtk-button-images", TRUE, "main");
738 #endif
740 return;
745 * Handle status changed callback from the libmpd object
746 * This involves propegating the signal
748 void GmpcStatusChangedCallback(MpdObj * mi,
749 ChangedStatusType what,
750 void *userdata)
752 g_signal_emit_by_name(gmpcconn, "status-changed", mi, what);
756 /* The actual handling of the status changed signal */
757 static void gmpc_status_changed_callback_real(GmpcConnection * conn,
758 MpdObj * mi,
759 ChangedStatusType what,
760 gpointer data)
762 /* When permission changes, update the advanced search regex */
763 if (what & MPD_CST_PERMISSION)
765 advanced_search_update_taglist();
768 * Make the plugins recieve the signals
770 plugin_manager_status_changed(mi, what);
774 /*******************************
775 * Error handling
776 * TODO: Needs to be redone/rethought
779 static void password_dialog_response(
780 GtkWidget * dialog,
781 gint response,
782 gpointer data)
784 gchar *path;
785 switch (response)
787 case 0:
788 return;
789 case GTK_RESPONSE_OK:
791 path = (char *)gtk_entry_get_text(
792 GTK_ENTRY(gtk_builder_get_object(xml_password_window,
793 "pass_entry")));
794 mpd_set_password(connection, path);
795 if (gtk_toggle_button_get_active
796 (GTK_TOGGLE_BUTTON(gtk_builder_get_object(
797 xml_password_window,
798 "ck_save_pass"))))
800 connection_set_password(path);
802 mpd_send_password(connection);
804 break;
805 default:
806 if (mpd_server_check_command_allowed(connection, "status") !=
807 MPD_SERVER_COMMAND_ALLOWED)
809 playlist3_show_error_message(
810 _("GMPC has insufficient permissions on the mpd server."),
811 ERROR_CRITICAL);
812 mpd_disconnect(connection);
814 break;
816 gtk_widget_destroy(
817 (GtkWidget *) gtk_builder_get_object(xml_password_window,
818 "password-dialog"));
819 g_object_unref(xml_password_window);
820 xml_password_window = NULL;
824 static void password_dialog(int failed)
826 GtkWidget *pl3_win = playlist3_get_window();
827 gchar *path = NULL;
828 if (xml_password_window)
829 return;
830 path = gmpc_get_full_glade_path("password-dialog.ui");
831 xml_password_window = gtk_builder_new();
832 gtk_builder_add_from_file(xml_password_window, path, NULL);
833 gtk_window_set_transient_for(GTK_WINDOW
834 (gtk_builder_get_object(xml_password_window, "password-dialog")),
835 GTK_WINDOW(pl3_win));
836 q_free(path);
837 if (!xml_password_window)
838 return;
839 if (failed)
841 path = g_strdup_printf(
842 _("Failed to set password on: '%s'\nPlease try again"),
843 mpd_get_hostname(connection));
844 } else
846 path = g_strdup_printf(
847 _("Please enter your password for: '%s'"),
848 mpd_get_hostname(connection));
850 gtk_label_set_text(
851 GTK_LABEL(gtk_builder_get_object(xml_password_window, "pass_label")),
852 path);
853 q_free(path);
855 g_signal_connect(G_OBJECT
856 (gtk_builder_get_object
857 (xml_password_window, "password-dialog")), "response",
858 G_CALLBACK(password_dialog_response), xml_password_window);
862 void send_password(void)
864 password_dialog(FALSE);
867 static void playlist_support_help_button_clicked(GObject *a)
869 open_help("ghelp:gmpc?ProblemSolving");
873 static int error_callback(MpdObj * mi,
874 int error_id,
875 char *error_msg,
876 gpointer data)
878 int autoconnect = cfg_get_single_value_as_int_with_default(config,
879 "connection",
880 "autoconnect",
881 DEFAULT_AUTOCONNECT);
883 /* if we are not connected we show a reconnect */
884 if (!mpd_check_connected(mi))
886 GtkWidget *button;
887 char *str;
888 /* no response? then we just ignore it when autoconnecting. */
889 if (error_id == 15 && autoconnect)
890 return FALSE;
892 str = g_markup_printf_escaped("<b>%s %i: %s</b>",
893 _("error code"),
894 error_id,
895 error_msg);
896 playlist3_show_error_message(str, ERROR_CRITICAL);
897 button = gtk_button_new_from_stock(GTK_STOCK_CONNECT);
898 g_signal_connect(G_OBJECT(button),
899 "clicked",
900 G_CALLBACK(connect_to_mpd), NULL);
901 playlist3_error_add_widget(button);
902 g_free(str);
903 } else
905 if (setup_assistant_is_running()
906 && (error_id == MPD_ACK_ERROR_PERMISSION ||
907 error_id == MPD_ACK_ERROR_PASSWORD))
909 gchar *str = g_markup_printf_escaped("<b>%s</b>",
910 _("Insufficient permission to connect to mpd. Check password"));
911 setup_assistant_set_error(str);
912 q_free(str);
913 return TRUE;
915 if(error_id == MPD_ACK_ERROR_SYSTEM || error_id == MPD_ACK_ERROR_NO_EXIST) {
916 if(g_regex_match_simple(".*{.*playlist.*}.*", error_msg,
917 0,G_REGEX_MATCH_NOTEMPTY))
919 GtkWidget *button = NULL;
920 if(favorites != NULL) {
921 gmpc_favorites_list_set_disable(favorites,TRUE);
923 playlist_editor_set_disabled();
924 playlist3_show_error_message(
925 _("Playlist support in MPD is not working. See the "
926 "manual on possible fixes.\n"
927 "Playlist editor and favorites are now disabled."
929 , ERROR_WARNING);
931 button = gtk_button_new_from_stock(GTK_STOCK_HELP);
932 g_signal_connect(G_OBJECT(button), "clicked",
933 G_CALLBACK(playlist_support_help_button_clicked), NULL);
934 playlist3_error_add_widget(button);
935 return FALSE;
938 if (error_id == MPD_ACK_ERROR_PASSWORD)
940 password_dialog(TRUE);
941 } else if (error_id == MPD_ACK_ERROR_PERMISSION)
943 password_dialog(FALSE);
944 } else
946 gchar *str = g_markup_printf_escaped("<b>%s %i: %s</b>",
947 _("error code"), error_id,
948 error_msg);
949 playlist3_show_error_message(str, ERROR_CRITICAL);
950 g_free(str);
953 return FALSE;
958 * handle a connection changed
960 static void connection_changed(MpdObj * mi, int connected, gpointer data)
962 /* propagate the signal to the connection object */
963 if (mpd_check_connected(mi) != connected)
965 g_log(LOG_DOMAIN,
966 G_LOG_LEVEL_ERROR,
967 "Connection state differs from actual state: act: %i\n",
968 !connected);
971 * Check version
973 if (connected && !mpd_server_check_version(mi, 0, 13, 0))
975 gchar *value = g_markup_printf_escaped("<b>%s</b>",
976 _("MPD versions before 0.13.0 are not supported"));
977 /* disable user connect ! */
978 gmpc_connected = FALSE;
979 mpd_disconnect(mi);
980 /* Give error */
981 playlist3_show_error_message(value, ERROR_CRITICAL);
982 g_free(value);
984 /* Remove timeout */
985 if (connected)
987 if (autoconnect_timeout)
988 g_source_remove(autoconnect_timeout);
989 autoconnect_timeout = 0;
990 autoconnect_backoff = 0;
992 if (connected)
994 advanced_search_update_taglist();
997 * force an update of status, to check password
999 if (connected)
1001 mpd_status_update(mi);
1002 if (connected != mpd_check_connected(mi))
1004 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "State differs, exit");
1005 /* Probly disconnected when getting status.. exiting */
1006 return;
1010 /* remove this when it does not fix it */
1011 g_signal_emit_by_name(gmpcconn,
1012 "connection-changed",
1014 mpd_check_connected(mi));
1018 static void connection_changed_real(
1019 GmpcConnection * obj,
1020 MpdObj * mi,
1021 int connected,
1022 gpointer data)
1025 * propegate signals
1027 g_log(LOG_DOMAIN,
1028 G_LOG_LEVEL_DEBUG,
1029 "Connection changed %i-%i \n",
1030 connected,
1031 mpd_check_connected(mi));
1032 plugin_manager_connection_changed(mi, connected);
1035 * force an update of status
1037 if (connected)
1038 mpd_status_update(mi);
1040 if (connected)
1042 playlist3_show_error_message(_("Connected to mpd"), ERROR_INFO);
1043 } else
1045 playlist3_show_error_message(_("Disconnected from mpd"), ERROR_INFO);
1048 if (!connected)
1050 if (autoconnect_timeout)
1051 g_source_remove(autoconnect_timeout);
1052 autoconnect_timeout = g_timeout_add_seconds(5,
1053 (GSourceFunc) autoconnect_callback, NULL);
1054 autoconnect_backoff = 0;
1060 * Shows an error message.
1062 void show_error_message(const gchar * string)
1064 GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL,
1065 GTK_DIALOG_MODAL,
1066 GTK_MESSAGE_ERROR,
1067 GTK_BUTTONS_CLOSE,
1068 "%s", string);
1069 gtk_widget_show(dialog);
1070 gtk_dialog_run(GTK_DIALOG(dialog));
1073 static void print_version(void)
1075 printf("%s\n", _("Gnome Music Player Client"));
1076 printf(GMPC_COPYRIGHT "\n\n");
1077 printf("%-25s: %s\n", _("Tagline"), GMPC_TAGLINE);
1078 printf("%-25s: %i.%i.%i\n", _("Version"),
1079 GMPC_MAJOR_VERSION,
1080 GMPC_MINOR_VERSION,
1081 GMPC_MICRO_VERSION);
1082 if (revision && revision[0] != '\0')
1084 printf("%-25s: %s\n", _("Revision"), revision);
1089 * Set a basic set of easycommand handlers.
1091 static void gmpc_easy_command_set_default_entries(void)
1093 gmpc_easy_command_add_entry_stock_id(gmpc_easy_command,
1094 _("quit"), "",
1095 _("Quit gmpc"),
1096 (GmpcEasyCommandCallback *) main_quit,
1097 NULL,GTK_STOCK_QUIT);
1099 gmpc_easy_command_add_entry(gmpc_easy_command,
1100 _("hide"), "",
1101 _("Hide gmpc"),
1102 (GmpcEasyCommandCallback *) pl3_hide,
1103 NULL);
1105 gmpc_easy_command_add_entry(gmpc_easy_command,
1106 _("show"), "",
1107 _("Show gmpc"),
1108 (GmpcEasyCommandCallback *) create_playlist3,
1109 NULL);
1111 gmpc_easy_command_add_entry(gmpc_easy_command,
1112 _("toggle"), "",
1113 _("Toggle gmpc visibility"),
1114 (GmpcEasyCommandCallback *) pl3_toggle_hidden,
1115 NULL);
1117 gmpc_easy_command_add_entry(gmpc_easy_command,
1118 _("show notification"), "",
1119 _("Show trayicon notification"),
1120 (GmpcEasyCommandCallback *) tray_icon2_create_tooltip,
1121 NULL);
1122 gmpc_easy_command_add_entry_stock_id(gmpc_easy_command,
1123 _("preferences"), "",
1124 _("Show preferences window"),
1125 (GmpcEasyCommandCallback *) create_preferences_window,
1126 NULL, GTK_STOCK_PREFERENCES);
1128 gmpc_easy_command_add_entry(gmpc_easy_command,
1129 _("bug information"), "",
1130 _("Show bug information"),
1131 (GmpcEasyCommandCallback *) bug_information_window_new,
1132 NULL);
1134 gmpc_easy_command_add_entry_icon_name(gmpc_easy_command,
1135 _("url"), "",
1136 _("Show add url window"),
1137 (GmpcEasyCommandCallback *) url_start,
1138 NULL,"add-url");
1140 gmpc_easy_command_add_entry_icon_name(gmpc_easy_command,
1141 _("url"), ".*://.*",
1142 _("Add url <scheme>://<path>"),
1143 (GmpcEasyCommandCallback *) url_start_easy_command,
1144 NULL,"add-url");
1147 static void gmpc_mmkeys_connect_signals(GObject *keys)
1149 g_signal_connect(keys,
1150 "mm_playpause",
1151 G_CALLBACK(play_song), NULL);
1153 g_signal_connect(keys,
1154 "mm_play",
1155 G_CALLBACK(real_play_song), NULL);
1157 g_signal_connect(keys,
1158 "mm_pause",
1159 G_CALLBACK(real_pause_song), NULL);
1161 g_signal_connect(keys,
1162 "mm_next",
1163 G_CALLBACK(next_song), NULL);
1165 g_signal_connect(keys,
1166 "mm_prev",
1167 G_CALLBACK(prev_song), NULL);
1169 g_signal_connect(keys,
1170 "mm_stop",
1171 G_CALLBACK(stop_song), NULL);
1173 g_signal_connect(keys,
1174 "mm_fastforward",
1175 G_CALLBACK(song_fastforward), NULL);
1177 g_signal_connect(keys,
1178 "mm_fastbackward",
1179 G_CALLBACK(song_fastbackward), NULL);
1181 g_signal_connect(keys,
1182 "mm_repeat",
1183 G_CALLBACK(repeat_toggle), NULL);
1185 g_signal_connect(keys,
1186 "mm_random",
1187 G_CALLBACK(random_toggle), NULL);
1189 g_signal_connect(keys,
1190 "mm_raise",
1191 G_CALLBACK(create_playlist3), NULL);
1193 g_signal_connect(keys,
1194 "mm_hide",
1195 G_CALLBACK(pl3_hide), NULL);
1197 g_signal_connect(keys,
1198 "mm_toggle_hidden",
1199 G_CALLBACK(pl3_toggle_hidden), NULL);
1201 g_signal_connect(keys,
1202 "mm_volume_up",
1203 G_CALLBACK(volume_up), NULL);
1205 g_signal_connect(keys,
1206 "mm_volume_down",
1207 G_CALLBACK(volume_down), NULL);
1209 g_signal_connect(keys,
1210 "mm_toggle_mute",
1211 G_CALLBACK(volume_toggle_mute), NULL);
1213 g_signal_connect(keys,
1214 "mm_show_notification",
1215 G_CALLBACK(tray_icon2_create_tooltip), NULL);
1217 g_signal_connect_swapped(keys,
1218 "mm_show_easy_command",
1219 G_CALLBACK(gmpc_easy_command_popup),
1220 gmpc_easy_command);
1223 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=80: */