I am not awake in the morning, move get_display.
[gmpc.git] / src / main.c
blob3d0ef605c15c2fb243a388193224fa9d6c51577e
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 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"
61 #include "internal-plugins.h"
62 #include "log.h"
63 #include "mpd-easy-commands.h"
65 /**
66 * Global objects that give signals
69 GtkApplication *gmpc_application = NULL;
72 /* gives signal on connection changes, and state changes of mpd.*/
73 GmpcConnection *gmpcconn = NULL;
74 /* Implements, and gives signals on profiles */
75 GmpcProfiles *gmpc_profiles = NULL;
76 /* Implements, and gives signals on meta_data*/
77 GmpcMetaWatcher *gmw = NULL;
78 /* Easy command */
79 GmpcEasyCommand *gmpc_easy_command = NULL;
80 /* Playlist3 messages */
81 Playlist3MessagePlugin *pl3_messages = NULL;
83 /* The playlist backend */
84 GtkTreeModel *playlist = NULL;
86 GObject *paned_size_group = NULL;
87 /**
88 * This flag indicate the requested connection state by the user.
89 * If the user presses disconnect, you don't want to auto-connect anymore.
90 **/
91 int gmpc_connected = FALSE;
93 static void connection_changed_real(
94 GmpcConnection * gmpcconn,
95 MpdObj * mi,
96 int connect,
97 gpointer data);
99 static void gmpc_status_changed_callback_real(
100 GmpcConnection * gmpcconn,
101 MpdObj * mi,
102 ChangedStatusType what,
103 gpointer data);
106 * Define some local functions
109 static void gmpc_easy_command_set_default_entries(void);
110 static void gmpc_mmkeys_connect_signals(GObject *keys);
111 /** handle connection changed */
112 static void connection_changed(MpdObj * mi, int connect, gpointer data);
114 /** Error callback */
115 static int error_callback(MpdObj * mi,
116 int error_id,
117 char *error_msg,
118 gpointer data);
120 /** init stock icons */
121 static void init_stock_icons(void);
124 * the xml fle pointer to the player window
126 static GtkBuilder *xml_password_window = NULL;
127 static int autoconnect_callback(void);
130 * the ID of the autoconnect timeout callback
132 static guint autoconnect_timeout = 0;
135 * The Config object
137 config_obj *config = NULL;
140 * The Connection object
142 MpdObj *connection = NULL;
144 /* Glade prototypes, these would be static otherwise */
145 void send_password(void);
147 static void print_version(void);
151 * Forward libxml errors into GLib.log errors with LibXML error domain
153 static void xml_error_func(void *ctx, const char *msg, ...)
155 va_list ap;
156 va_start(ap, msg);
157 g_logv("LibXML", G_LOG_LEVEL_DEBUG, msg, ap);
158 va_end(ap);
160 /* \todo why is this here? */
161 static xmlGenericErrorFunc handler = (xmlGenericErrorFunc) xml_error_func;
164 static gboolean hide_on_start(void)
166 pl3_hide();
167 return FALSE;
169 static int handle_commandline(GApplication *app, GApplicationCommandLine *cmd, gpointer data)
171 gchar **argv;
172 gint argc;
174 argv = g_application_command_line_get_arguments(cmd, &argc);
175 printf("Commandline handler: %i\n", argc);
176 if(argc > 1) {
177 int i;
178 for ( i = 1; i < argc; i++) {
179 printf("executing: %s\n" , argv[i]);
180 gmpc_easy_command_do_query(gmpc_easy_command, argv[i]);
182 }else {
183 printf("activate\n");
184 g_application_activate(gmpc_application);
187 return EXIT_SUCCESS;
191 int main(int argc, char **argv)
193 GdkDisplay *display = NULL;
194 #ifdef WIN32
195 gchar *packagedir = NULL;
196 #endif
197 #ifdef ENABLE_MMKEYS
198 MmKeys *keys = NULL;
199 #endif
201 /* A string used severall times to create a path */
202 gchar *url = NULL;
204 INIT_TIC_TAC();
206 log_init();
209 * Setup NLS
211 #ifdef ENABLE_NLS
212 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Setting NLS");
213 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
214 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
215 textdomain(GETTEXT_PACKAGE);
216 #endif
218 //gtk_set_locale();
219 // setlocale();
221 TEC("Setting up locale");
223 parse_options(&argc, &argv);
225 /* Show the version, if requested */
226 if (settings.show_version)
228 print_version();
229 return EXIT_SUCCESS;
231 TEC("Parsing command line options");
233 log_set_debug_level(settings.debug_level);
234 TEC("Set debug level")
235 /* Show the bug-information dialog */
236 if (settings.show_bug_information)
238 bug_information_file_new(stdout);
239 return EXIT_SUCCESS;
244 * Init libxml.
245 * Libxml is not used (directly) by gmpc.
246 * But via glade and several plugins use it.
247 * I need to initialize it before the threading is started.
248 * So moved to gmpc.
250 * This fixes the plugin crasher bug on windows.
252 xmlInitParser();
253 initGenericErrorDefaultFunc(&handler);
256 * Check if threading is supported, if so, start it.
257 * Don't fail here, stuff like can cause that it is allready initialized.
259 if (!g_thread_supported())
260 g_thread_init(NULL);
262 TEC("Initializing threading");
264 * initialize gtk
266 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Initializing gtk ");
268 #ifdef WIN32
270 * This loads an extra gtk rc file on windows.
271 * This is used to re-enable rule-hint in the treeview.
272 * (this is forced off on windows).
274 packagedir = g_win32_get_package_installation_directory_of_module(NULL);
275 url = g_build_filename(packagedir,
276 "share", "gmpc",
277 "gmpc-gtk-win32.rc", NULL);
278 q_free(packagedir);
279 gtk_rc_add_default_file(url);
280 g_free(url);
281 #endif
284 /* initialize gtk */
285 gmpc_application = gtk_application_new("org.gmpclient.gmpc", G_APPLICATION_HANDLES_COMMAND_LINE);
286 /* Get Display */
287 display = gdk_display_get_default ();
289 GError *error = NULL;
292 if(!g_application_register(G_APPLICATION(gmpc_application),NULL, &error))
294 g_error("Failed to register instance: %s", error->message);
295 return EXIT_FAILURE;
298 // Check if we are already running.
299 if(g_application_get_is_remote(G_APPLICATION(gmpc_application)))
301 g_debug("Already running....");
302 return g_application_run(G_APPLICATION(gmpc_application), argc, argv);
305 g_signal_connect(G_OBJECT(gmpc_application), "command-line", G_CALLBACK(handle_commandline), NULL);
306 g_signal_connect(G_OBJECT(gmpc_application), "activate", G_CALLBACK(pl3_show_and_position_window), NULL);
308 TEC("Gtk init");
312 GError *error = NULL;
313 GtkCssProvider *provider = gtk_css_provider_new ();
314 gchar *path = g_build_filename(PACKAGE_DATA_DIR, "gmpc", "gmpc.css", NULL);
316 gtk_css_provider_load_from_path(provider, path, &error);
318 printf("Loading: %s\n", path);
321 if(error != NULL) {
322 g_error("Failed to load css file: %s:%s",path, error->message);
323 g_free(path);
324 g_error_free(error);
326 GdkScreen *screen = gdk_display_get_default_screen (display);
328 gtk_style_context_add_provider_for_screen (
329 screen, GTK_STYLE_PROVIDER (provider),
330 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
332 g_object_unref (provider);
333 g_free(path);
337 /* Hack to override the icon theme, on recursive zeltak request */
338 if(settings.icon_theme != NULL) {
339 gtk_settings_set_string_property(gtk_settings_get_default(),
340 "gtk-icon-theme-name" , settings.icon_theme,NULL);
344 * Call create_gmpc_paths();
345 * This function checks if the path needed path are available
346 * and creates them if needed.
348 create_gmpc_paths();
349 TEC("Check version and create paths");
353 * Open the config file
356 * Check if the user has forced a different config file location.
357 * else set to ~/.gmpc/gmpc.cfg
359 if (!settings.config_path)
361 url = gmpc_get_user_path("gmpc.cfg");
362 } else
364 url = g_strdup(settings.config_path);
368 * Open it
370 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
371 "Trying to open the config file: %s", url);
372 config = cfg_open(url);
375 * Show gtk error message and quit if config failed to open.
377 if (config == NULL)
379 g_log(LOG_DOMAIN, G_LOG_LEVEL_ERROR,
380 "Failed to save/load configuration:\n%s\n", url);
381 show_error_message(_("Failed to load the configuration system."));
382 return EXIT_FAILURE;
384 TEC("Opening config file: %s", url);
385 q_free(url);
388 * \TODO, Check if version changed, then say something about it
390 * Enable this function if we need todo some upgrading on version change.
391 * Removal of this current content destroys config conversion from 0.17 and
392 * up
394 url = cfg_get_single_value_as_string(config, "Default", "version");
395 if (url == NULL || strcmp(url, VERSION))
397 cfg_set_single_value_as_string(config, "Default", "version", VERSION);
399 if (url) q_free(url);
400 TEC("New version check");
403 if (settings.quit)
405 cfg_close(config);
406 return EXIT_SUCCESS;
409 /* Easy command */
410 gmpc_easy_command = gmpc_easy_command_new();
411 TEC("Init easy command")
412 gmpc_easy_command_set_default_entries();
413 TEC("Set easy commands")
414 mpd_easy_commands_init();
415 TEC("Set MPD Easy commands");
416 /* Advanced search */
417 advanced_search_init();
418 TEC("Init advanced search");
420 /* PanedSizeGroup */
421 paned_size_group = (GObject *) gmpc_paned_size_group_new();
423 gmpc_profiles = gmpc_profiles_new();
424 /* If user requested a profile, look it up and set it active */
425 if (settings.profile_name)
427 gmpc_profiles_set_profile_from_name(gmpc_profiles,
428 settings.profile_name);
430 TEC("Setting up gmpc idle,signals and profiles");
432 * Initialize the new metadata subsystem.
434 meta_data_init();
436 TEC("Initializing metadata system");
437 pixbuf_cache_create();
438 TEC("Pixbuf cache create()");
441 * stock icons
443 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Loading stock icons");
444 init_stock_icons();
445 TEC("Init stock icons");
447 * Create connection object
449 connection = mpd_new_default();
450 if (connection == NULL)
453 * if failed, print error message
455 g_log(LOG_DOMAIN,
456 G_LOG_LEVEL_ERROR,
457 "Failed to create connection object\n");
458 show_error_message(_("Failed to setup libmpd"));
459 abort();
461 TEC("Setting up mpd connection object");
463 * Connect signals to the connection object
465 mpd_signal_connect_status_changed(connection,
466 GmpcStatusChangedCallback, NULL);
467 mpd_signal_connect_error(connection,
468 error_callback, NULL);
469 mpd_signal_connect_connection_changed(connection,
470 connection_changed, NULL);
472 * Just some trick to provide glib signals
474 gmpcconn = (GmpcConnection *) gmpc_connection_new();
475 g_signal_connect(G_OBJECT(gmpcconn),
476 "connection_changed",
477 G_CALLBACK(connection_changed_real), NULL);
478 g_signal_connect(G_OBJECT(gmpcconn),
479 "status_changed",
480 G_CALLBACK(gmpc_status_changed_callback_real), NULL);
482 TEC("Setting up mpd object signal system");
484 * New Metadata object
486 gmw = gmpc_meta_watcher_new();
487 TEC("Initializing metadata watcher");
491 /** init the error messages */
492 pl3_messages = playlist3_message_plugin_new();
494 playlist = (GtkTreeModel*)gmpc_mpddata_model_playlist_new(
495 gmpcconn,
496 connection);
497 gmpc_mpddata_model_disable_image(GMPC_MPDDATA_MODEL(playlist));
500 * Add the internall plugins
502 plugin_manager_load_internal_plugins();
506 * load dynamic plugins
508 if (!settings.disable_plugins)
510 plugin_manager_load_plugins();
514 * Create the main window
516 create_playlist3();
517 TEC("Creating playlist window");
519 /* time todo some initialisation of plugins */
520 plugin_manager_initialize_plugins();
523 * First run dialog
525 * If gmpc is ran for the first time, we want to show a wizard that helps
526 * the user getting started.
528 if (cfg_get_single_value_as_int_with_default(config,
529 "Default",
530 "first-run",
533 setup_assistant();
534 cfg_set_single_value_as_int(config, "Default", "first-run", 0);
535 TEC("Setup first run assistant");
539 * If autoconnect is enabled, tell gmpc that it's in state it should connect
541 if (cfg_get_single_value_as_int_with_default(config,
542 "connection",
543 "autoconnect",
544 DEFAULT_AUTOCONNECT))
546 gmpc_connected = TRUE;
549 * create timeouts
550 * get the status every 1/2 second should be enough, but it's configurable.
552 g_timeout_add(cfg_get_single_value_as_int_with_default(config,
553 "connection",
554 "mpd-update-speed",
555 500), (GSourceFunc) update_mpd_status, NULL);
557 * create the autoconnect timeout,
558 * if autoconnect enable, it will check every 5 seconds
559 * if you are still connected, and reconnects you if not.
561 autoconnect_timeout = g_timeout_add_seconds(5,
562 (GSourceFunc) autoconnect_callback, NULL);
565 * Call this when entering the main loop,
566 * so you are connected on startup, not 5 seconds later
568 g_idle_add((GSourceFunc) autoconnect_callback, NULL);
569 if (settings.fullscreen)
571 g_idle_add((GSourceFunc) pl3_window_fullscreen, NULL);
575 * If the user wants gmpc to be started hidden,
576 * call pl3_hide after the mainloop started running
578 if (cfg_get_single_value_as_int_with_default(config,
579 "Default",
580 "start-hidden",
581 FALSE) ||
582 settings.start_hidden)
584 g_timeout_add(250, (GSourceFunc) hide_on_start, NULL);
586 TEC("Setting up timers");
588 #ifdef ENABLE_MMKEYS
589 if (GDK_IS_X11_DISPLAY(display))
592 * Setup Multimedia Keys
594 keys = mmkeys_new();
595 gmpc_mmkeys_connect_signals(G_OBJECT(keys));
596 TEC("Setting up multimedia keys");
598 #endif
600 url = gmpc_get_user_path("gmpc.key");
601 gtk_accel_map_load(url);
602 q_free(url);
606 * run the main loop
608 //gtk_main();
609 int retv = g_application_run(G_APPLICATION(gmpc_application), argc, argv);
612 * Shutting Down
613 * cleaning up.
615 url = gmpc_get_user_path("gmpc.key");
616 gtk_accel_map_save(url);
617 q_free(url);
619 /* Quit _all_ downloads */
620 gmpc_easy_async_quit();
622 /* tell the plugins to save themself. */
623 plugin_manager_save_state();
625 /* Should fix some possible crashes */
626 gtk_tree_view_set_model(playlist3_get_category_tree_view(), NULL);
629 * Clear metadata struct
631 meta_data_destroy();
633 /* time todo some destruction of plugins */
634 plugin_manager_destroy_plugins();
636 playlist3_destroy();
638 g_object_unref(playlist);
639 g_object_unref(G_OBJECT(gmw));
641 /* Destroy PanedSizeGroup */
642 g_object_unref(paned_size_group);
644 * Close the config file
646 TOC("Starting save config");
647 cfg_close(config);
648 TOC("Saved config");
649 g_object_unref(gmpc_profiles);
650 g_object_unref(gmpcconn);
652 pixbuf_cache_destroy();
654 * This now gets destroyed with the plugins
656 advanced_search_destroy();
658 * Destroy the connection object
660 mpd_free(connection);
662 /* Reset xml error function and cleanup */
663 initGenericErrorDefaultFunc((xmlGenericErrorFunc *) NULL);
664 xmlCleanupParser();
665 /* cleanup */
667 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Quit....\n");
668 return retv;
673 * Function to quiet the program
675 void main_quit(void)
677 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Quiting gmpc....");
679 * close playlist and store size
681 pl3_hide();
683 * Remove the autoconnect timeout,
685 if (autoconnect_timeout)
686 g_source_remove(autoconnect_timeout);
689 * Call the connection changed.
690 * so it saves the playlist pos
692 mpd_signal_connect_connection_changed(connection, NULL, NULL);
695 * Disconnect when connected
697 if (mpd_check_connected(connection))
699 if (cfg_get_single_value_as_int_with_default(config,
700 "connection", "stop-on-exit", FALSE))
702 mpd_player_stop(connection);
704 mpd_disconnect(connection);
707 * Exit main loop
709 gtk_widget_destroy(playlist3_get_window());
714 * Callback that get's called every 5 seconds,
715 * and tries to autoconnect
716 * (when enabled)
719 static int autoconnect_backoff = 0;
720 static int autoconnect_callback(void)
722 /* Don't autoconnect while showing the first start assistant */
723 if (setup_assistant_is_running())
724 return FALSE;
726 /* check if there is an connection. */
727 if (!mpd_check_connected(connection))
729 /* connect when autoconnect is enabled, the user wants to be connected
731 if (gmpc_connected
732 && cfg_get_single_value_as_int_with_default(config,
733 "connection", "autoconnect", DEFAULT_AUTOCONNECT))
735 connect_to_mpd();
738 if (autoconnect_backoff < 60)
739 autoconnect_backoff += 1;
740 /* keep the timeout running */
741 if (autoconnect_timeout)
742 g_source_remove(autoconnect_timeout);
743 autoconnect_timeout = g_timeout_add_seconds(5 + autoconnect_backoff,
744 (GSourceFunc) autoconnect_callback, NULL);
745 return FALSE;
749 static void init_stock_icons(void)
751 char *path;
753 path = gmpc_get_full_image_path();
754 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
755 q_free(path);
757 gtk_window_set_default_icon_name("gmpc");
759 #ifdef WIN32
760 /* The Windows gtkrc sets this to 0, so images don't work on buttons */
761 gtk_settings_set_long_property(gtk_settings_get_default(),
762 "gtk-button-images", TRUE, "main");
763 #endif
765 return;
770 * Handle status changed callback from the libmpd object
771 * This involves propegating the signal
773 void GmpcStatusChangedCallback(MpdObj * mi,
774 ChangedStatusType what,
775 void *userdata)
777 g_signal_emit_by_name(gmpcconn, "status-changed", mi, what);
781 /* The actual handling of the status changed signal */
782 static void gmpc_status_changed_callback_real(GmpcConnection * conn,
783 MpdObj * mi,
784 ChangedStatusType what,
785 gpointer data)
787 /* When permission changes, update the advanced search regex */
788 if (what & MPD_CST_PERMISSION)
790 advanced_search_update_taglist();
793 * Make the plugins recieve the signals
795 plugin_manager_status_changed(mi, what);
799 /*******************************
800 * Error handling
801 * TODO: Needs to be redone/rethought
804 static void password_dialog_response(
805 GtkWidget * dialog,
806 gint response,
807 gpointer data)
809 gchar *path;
810 switch (response)
812 case 0:
813 return;
814 case GTK_RESPONSE_OK:
816 path = (char *)gtk_entry_get_text(
817 GTK_ENTRY(gtk_builder_get_object(xml_password_window,
818 "pass_entry")));
819 mpd_set_password(connection, path);
820 if (gtk_toggle_button_get_active
821 (GTK_TOGGLE_BUTTON(gtk_builder_get_object(
822 xml_password_window,
823 "ck_save_pass"))))
825 connection_set_password(path);
827 mpd_send_password(connection);
829 break;
830 default:
831 if (mpd_server_check_command_allowed(connection, "status") !=
832 MPD_SERVER_COMMAND_ALLOWED)
834 playlist3_show_error_message(
835 _("GMPC has insufficient permissions on the mpd server."),
836 ERROR_CRITICAL);
837 mpd_disconnect(connection);
839 break;
841 gtk_widget_destroy(
842 (GtkWidget *) gtk_builder_get_object(xml_password_window,
843 "password-dialog"));
844 g_object_unref(xml_password_window);
845 xml_password_window = NULL;
849 static void password_dialog(int failed)
851 GtkWidget *pl3_win = playlist3_get_window();
852 gchar *path = NULL;
853 if (xml_password_window)
854 return;
855 path = gmpc_get_full_glade_path("password-dialog.ui");
856 xml_password_window = gtk_builder_new();
857 gtk_builder_add_from_file(xml_password_window, path, NULL);
858 gtk_window_set_transient_for(GTK_WINDOW
859 (gtk_builder_get_object(xml_password_window, "password-dialog")),
860 GTK_WINDOW(pl3_win));
861 q_free(path);
862 if (!xml_password_window)
863 return;
864 if (failed)
866 path = g_strdup_printf(
867 _("Failed to set password on: '%s'\nPlease try again"),
868 mpd_get_hostname(connection));
869 } else
871 path = g_strdup_printf(
872 _("Please enter your password for: '%s'"),
873 mpd_get_hostname(connection));
875 gtk_label_set_text(
876 GTK_LABEL(gtk_builder_get_object(xml_password_window, "pass_label")),
877 path);
878 q_free(path);
880 g_signal_connect(G_OBJECT
881 (gtk_builder_get_object
882 (xml_password_window, "password-dialog")), "response",
883 G_CALLBACK(password_dialog_response), xml_password_window);
887 void send_password(void)
889 password_dialog(FALSE);
892 static void playlist_support_help_button_clicked(GObject *a)
894 open_help("ghelp:gmpc?ProblemSolving");
898 static int error_callback(MpdObj * mi,
899 int error_id,
900 char *error_msg,
901 gpointer data)
903 int autoconnect = cfg_get_single_value_as_int_with_default(config,
904 "connection",
905 "autoconnect",
906 DEFAULT_AUTOCONNECT);
908 /* if we are not connected we show a reconnect */
909 if (!mpd_check_connected(mi))
911 GtkWidget *button;
912 char *str;
913 /* no response? then we just ignore it when autoconnecting. */
914 if (error_id == 15 && autoconnect)
915 return FALSE;
917 str = g_markup_printf_escaped("<b>%s %i: %s</b>",
918 _("error code"),
919 error_id,
920 error_msg);
921 playlist3_show_error_message(str, ERROR_CRITICAL);
922 button = gtk_button_new_from_stock(GTK_STOCK_CONNECT);
923 g_signal_connect(G_OBJECT(button),
924 "clicked",
925 G_CALLBACK(connect_to_mpd), NULL);
926 playlist3_error_add_widget(button);
927 g_free(str);
928 } else
930 if (setup_assistant_is_running()
931 && (error_id == MPD_ACK_ERROR_PERMISSION ||
932 error_id == MPD_ACK_ERROR_PASSWORD))
934 gchar *str = g_markup_printf_escaped("<b>%s</b>",
935 _("Insufficient permission to connect to mpd. Check password"));
936 setup_assistant_set_error(str);
937 q_free(str);
938 return TRUE;
940 if(error_id == MPD_ACK_ERROR_SYSTEM || error_id == MPD_ACK_ERROR_NO_EXIST) {
941 if(g_regex_match_simple(".*{.*playlist.*}.*", error_msg,
942 0,G_REGEX_MATCH_NOTEMPTY))
944 GtkWidget *button = NULL;
945 if(favorites != NULL) {
946 gmpc_favorites_list_set_disable(favorites,TRUE);
948 playlist_editor_set_disabled();
949 playlist3_show_error_message(
950 _("Playlist support in MPD is not working. See the "
951 "manual on possible fixes.\n"
952 "Playlist editor and favorites are now disabled."
954 , ERROR_WARNING);
956 button = gtk_button_new_from_stock(GTK_STOCK_HELP);
957 g_signal_connect(G_OBJECT(button), "clicked",
958 G_CALLBACK(playlist_support_help_button_clicked), NULL);
959 playlist3_error_add_widget(button);
960 return FALSE;
963 if (error_id == MPD_ACK_ERROR_PASSWORD)
965 password_dialog(TRUE);
966 } else if (error_id == MPD_ACK_ERROR_PERMISSION)
968 password_dialog(FALSE);
969 } else
971 gchar *str = g_markup_printf_escaped("<b>%s %i: %s</b>",
972 _("error code"), error_id,
973 error_msg);
974 playlist3_show_error_message(str, ERROR_CRITICAL);
975 g_free(str);
978 return FALSE;
983 * handle a connection changed
985 static void connection_changed(MpdObj * mi, int connected, gpointer data)
987 /* propagate the signal to the connection object */
988 if (mpd_check_connected(mi) != connected)
990 g_log(LOG_DOMAIN,
991 G_LOG_LEVEL_ERROR,
992 "Connection state differs from actual state: act: %i\n",
993 !connected);
996 * Check version
998 if (connected && !mpd_server_check_version(mi, 0, 13, 0))
1000 gchar *value = g_markup_printf_escaped("<b>%s</b>",
1001 _("MPD versions before 0.13.0 are not supported"));
1002 /* disable user connect ! */
1003 gmpc_connected = FALSE;
1004 mpd_disconnect(mi);
1005 /* Give error */
1006 playlist3_show_error_message(value, ERROR_CRITICAL);
1007 g_free(value);
1009 /* Remove timeout */
1010 if (connected)
1012 if (autoconnect_timeout)
1013 g_source_remove(autoconnect_timeout);
1014 autoconnect_timeout = 0;
1015 autoconnect_backoff = 0;
1017 if (connected)
1019 advanced_search_update_taglist();
1022 * force an update of status, to check password
1024 if (connected)
1026 mpd_status_update(mi);
1027 if (connected != mpd_check_connected(mi))
1029 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "State differs, exit");
1030 /* Probly disconnected when getting status.. exiting */
1031 return;
1035 /* remove this when it does not fix it */
1036 g_signal_emit_by_name(gmpcconn,
1037 "connection-changed",
1039 mpd_check_connected(mi));
1043 static void connection_changed_real(
1044 GmpcConnection * obj,
1045 MpdObj * mi,
1046 int connected,
1047 gpointer data)
1050 * propegate signals
1052 g_log(LOG_DOMAIN,
1053 G_LOG_LEVEL_DEBUG,
1054 "Connection changed %i-%i \n",
1055 connected,
1056 mpd_check_connected(mi));
1057 plugin_manager_connection_changed(mi, connected);
1060 * force an update of status
1062 if (connected)
1063 mpd_status_update(mi);
1065 if (connected)
1067 playlist3_show_error_message(_("Connected to mpd"), ERROR_INFO);
1068 } else
1070 playlist3_show_error_message(_("Disconnected from mpd"), ERROR_INFO);
1073 if (!connected)
1075 if (autoconnect_timeout)
1076 g_source_remove(autoconnect_timeout);
1077 autoconnect_timeout = g_timeout_add_seconds(5,
1078 (GSourceFunc) autoconnect_callback, NULL);
1079 autoconnect_backoff = 0;
1085 * Shows an error message.
1087 void show_error_message(const gchar * string)
1089 GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL,
1090 GTK_DIALOG_MODAL,
1091 GTK_MESSAGE_ERROR,
1092 GTK_BUTTONS_CLOSE,
1093 "%s", string);
1094 gtk_widget_show(dialog);
1095 gtk_dialog_run(GTK_DIALOG(dialog));
1098 static void print_version(void)
1100 printf("%s\n", _("Gnome Music Player Client"));
1101 printf(GMPC_COPYRIGHT "\n\n");
1102 printf("%-25s: %s\n", _("Tagline"), GMPC_TAGLINE);
1103 printf("%-25s: %i.%i.%i\n", _("Version"),
1104 GMPC_MAJOR_VERSION,
1105 GMPC_MINOR_VERSION,
1106 GMPC_MICRO_VERSION);
1107 if (revision && revision[0] != '\0')
1109 printf("%-25s: %s\n", _("Revision"), revision);
1114 * Set a basic set of easycommand handlers.
1116 static void gmpc_easy_command_set_default_entries(void)
1118 gmpc_easy_command_add_entry_stock_id(gmpc_easy_command,
1119 _("quit"), "",
1120 _("Quit gmpc"),
1121 (GmpcEasyCommandCallback *) main_quit,
1122 NULL,GTK_STOCK_QUIT);
1124 gmpc_easy_command_add_entry(gmpc_easy_command,
1125 _("hide"), "",
1126 _("Hide gmpc"),
1127 (GmpcEasyCommandCallback *) pl3_hide,
1128 NULL);
1130 gmpc_easy_command_add_entry(gmpc_easy_command,
1131 _("show"), "",
1132 _("Show gmpc"),
1133 (GmpcEasyCommandCallback *) create_playlist3,
1134 NULL);
1136 gmpc_easy_command_add_entry(gmpc_easy_command,
1137 _("toggle"), "",
1138 _("Toggle gmpc visibility"),
1139 (GmpcEasyCommandCallback *) pl3_toggle_hidden,
1140 NULL);
1142 gmpc_easy_command_add_entry(gmpc_easy_command,
1143 _("show notification"), "",
1144 _("Show trayicon notification"),
1145 (GmpcEasyCommandCallback *) tray_icon2_create_tooltip,
1146 NULL);
1147 gmpc_easy_command_add_entry_stock_id(gmpc_easy_command,
1148 _("preferences"), "",
1149 _("Show preferences window"),
1150 (GmpcEasyCommandCallback *) create_preferences_window,
1151 NULL, GTK_STOCK_PREFERENCES);
1153 gmpc_easy_command_add_entry(gmpc_easy_command,
1154 _("bug information"), "",
1155 _("Show bug information"),
1156 (GmpcEasyCommandCallback *) bug_information_window_new,
1157 NULL);
1159 gmpc_easy_command_add_entry_icon_name(gmpc_easy_command,
1160 _("url"), "",
1161 _("Show add url window"),
1162 (GmpcEasyCommandCallback *) url_start,
1163 NULL,"add-url");
1165 gmpc_easy_command_add_entry_icon_name(gmpc_easy_command,
1166 _("url"), ".*://.*",
1167 _("Add url <scheme>://<path>"),
1168 (GmpcEasyCommandCallback *) url_start_easy_command,
1169 NULL,"add-url");
1172 static void gmpc_mmkeys_connect_signals(GObject *keys)
1174 g_signal_connect(keys,
1175 "mm_playpause",
1176 G_CALLBACK(play_song), NULL);
1178 g_signal_connect(keys,
1179 "mm_play",
1180 G_CALLBACK(real_play_song), NULL);
1182 g_signal_connect(keys,
1183 "mm_pause",
1184 G_CALLBACK(real_pause_song), NULL);
1186 g_signal_connect(keys,
1187 "mm_next",
1188 G_CALLBACK(next_song), NULL);
1190 g_signal_connect(keys,
1191 "mm_prev",
1192 G_CALLBACK(prev_song), NULL);
1194 g_signal_connect(keys,
1195 "mm_stop",
1196 G_CALLBACK(stop_song), NULL);
1198 g_signal_connect(keys,
1199 "mm_fastforward",
1200 G_CALLBACK(song_fastforward), NULL);
1202 g_signal_connect(keys,
1203 "mm_fastbackward",
1204 G_CALLBACK(song_fastbackward), NULL);
1206 g_signal_connect(keys,
1207 "mm_repeat",
1208 G_CALLBACK(repeat_toggle), NULL);
1210 g_signal_connect(keys,
1211 "mm_random",
1212 G_CALLBACK(random_toggle), NULL);
1214 g_signal_connect(keys,
1215 "mm_raise",
1216 G_CALLBACK(create_playlist3), NULL);
1218 g_signal_connect(keys,
1219 "mm_hide",
1220 G_CALLBACK(pl3_hide), NULL);
1222 g_signal_connect(keys,
1223 "mm_toggle_hidden",
1224 G_CALLBACK(pl3_toggle_hidden), NULL);
1226 g_signal_connect(keys,
1227 "mm_volume_up",
1228 G_CALLBACK(volume_up), NULL);
1230 g_signal_connect(keys,
1231 "mm_volume_down",
1232 G_CALLBACK(volume_down), NULL);
1234 g_signal_connect(keys,
1235 "mm_toggle_mute",
1236 G_CALLBACK(volume_toggle_mute), NULL);
1238 g_signal_connect(keys,
1239 "mm_show_notification",
1240 G_CALLBACK(tray_icon2_create_tooltip), NULL);
1242 g_signal_connect_swapped(keys,
1243 "mm_show_easy_command",
1244 G_CALLBACK(gmpc_easy_command_popup),
1245 gmpc_easy_command);
1248 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=80: */