1 /*
2 * Copyright (C) 2005 Marc Pavot <marc.pavot@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20 #include "shell/ario-shell.h"
21
22 #include <gtk/gtk.h>
23 #include <gdk/gdk.h>
24 #include <config.h>
25 #include <string.h>
26 #include <glib/gi18n.h>
27
28 #include "ario-debug.h"
29 #include "ario-util.h"
30 #include "covers/ario-cover-handler.h"
31 #include "covers/ario-cover-manager.h"
32 #include "lib/ario-conf.h"
33 #include "lyrics/ario-lyrics-manager.h"
34 #include "notification/ario-notification-manager.h"
35 #include "playlist/ario-playlist-manager.h"
36 #include "plugins/ario-plugin-manager.h"
37 #include "preferences/ario-preferences.h"
38 #include "servers/ario-server.h"
39 #include "shell/ario-shell-coverdownloader.h"
40 #include "shell/ario-shell-coverselect.h"
41 #include "shell/ario-shell-lyrics.h"
42 #include "shell/ario-shell-preferences.h"
43 #include "shell/ario-shell-similarartists.h"
44 #include "sources/ario-source-manager.h"
45 #include "widgets/ario-firstlaunch.h"
46 #include "widgets/ario-header.h"
47 #include "widgets/ario-playlist.h"
48 #include "widgets/ario-status-bar.h"
49
50 static void ario_shell_finalize (GObject *object);
51 static void ario_shell_show (ArioShell *shell,
52 gboolean minimized);
53 static void ario_shell_cmd_quit (GSimpleAction *action,
54 GVariant *parameter,
55 gpointer data);
56 static void ario_shell_cmd_connect (GSimpleAction *action,
57 GVariant *parameter,
58 gpointer data);
59 static void ario_shell_cmd_disconnect (GSimpleAction *action,
60 GVariant *parameter,
61 gpointer data);
62 static void ario_shell_cmd_update (GSimpleAction *action,
63 GVariant *parameter,
64 gpointer data);
65 static void ario_shell_cmd_plugins (GSimpleAction *action,
66 GVariant *parameter,
67 gpointer data);
68 static void ario_shell_cmd_preferences (GSimpleAction *action,
69 GVariant *parameter,
70 gpointer data);
71 static void ario_shell_cmd_lyrics (GSimpleAction *action,
72 GVariant *parameter,
73 gpointer data);
74 static void ario_shell_cmd_cover_select (GSimpleAction *action,
75 GVariant *parameter,
76 gpointer data);
77 static void ario_shell_cmd_covers (GSimpleAction *action,
78 GVariant *parameter,
79 gpointer data);
80 static void ario_shell_cmd_similar_artists (GSimpleAction *action,
81 GVariant *parameter,
82 gpointer data);
83 static void ario_shell_cmd_add_similar (GSimpleAction *action,
84 GVariant *parameter,
85 gpointer data);
86 static void ario_shell_cmd_about (GSimpleAction *action,
87 GVariant *parameter,
88 gpointer data);
89 static void ario_shell_server_state_changed_cb (ArioServer *server,
90 ArioShell *shell);
91 static void ario_shell_server_song_changed_cb (ArioServer *server,
92 ArioShell *shell);
93 static gboolean ario_shell_window_state_cb (GtkWidget *widget,
94 GdkEvent *event,
95 ArioShell *shell);
96 static void ario_shell_sync_window_state (ArioShell *shell);
97 static void ario_shell_sync_paned (ArioShell *shell);
98 static void ario_shell_sync_server (ArioShell *shell);
99 static void ario_shell_sync_playlist_position (ArioShell *shell);
100 static void ario_shell_firstlaunch_delete_cb (ArioFirstlaunch *firstlaunch,
101 ArioShell *shell);
102 static void ario_shell_view_statusbar_changed_cb (GSimpleAction *action,
103 GVariant *parameter,
104 gpointer data);
105 static void ario_shell_view_upperpart_changed_cb (GSimpleAction *action,
106 GVariant *parameter,
107 gpointer data);
108 static void ario_shell_view_playlist_changed_cb (GSimpleAction *action,
109 GVariant *parameter,
110 gpointer data);
111 static void ario_shell_sync_statusbar_visibility (ArioShell *shell);
112 static void ario_shell_sync_upperpart_visibility (ArioShell *shell);
113 static void ario_shell_sync_playlist_visibility (ArioShell *shell);
114 static void ario_shell_playlist_position_changed_cb (guint notification_id,
115 ArioShell *shell);
116
117 struct ArioShellPrivate
118 {
119 GtkApplication * app;
120
121 ArioCoverHandler *cover_handler;
122 ArioPlaylistManager *playlist_manager;
123 ArioNotificationManager *notification_manager;
124 GtkWidget *header;
125 GtkWidget *paned;
126 GtkWidget *sourcemanager;
127 GtkWidget *playlist;
128 GtkWidget *status_bar;
129 GtkWidget *vbox;
130 GtkWidget *hbox;
131
132 gboolean statusbar_hidden;
133 gboolean upperpart_hidden;
134 gboolean playlist_hidden;
135 gboolean connected;
136 gboolean shown;
137
138 gboolean maximized;
139 gboolean visible;
140
141 int window_x;
142 int window_y;
143 int window_w;
144 int window_h;
145 };
146
147 enum
148 {
149 PROP_0,
150 };
151
152 static const GActionEntry shell_actions[] = {
153 { "connect", ario_shell_cmd_connect},
154 { "disconnect", ario_shell_cmd_disconnect},
155 { "update", ario_shell_cmd_update},
156 { "view-upperpart", ario_shell_view_upperpart_changed_cb, NULL, "false" },
157 { "view-playlist", ario_shell_view_playlist_changed_cb, NULL, "false" },
158 { "view-statusbar", ario_shell_view_statusbar_changed_cb, NULL, "false" },
159 { "view-lyrics", ario_shell_cmd_lyrics},
160 { "cover-select", ario_shell_cmd_cover_select},
161 { "dlcovers", ario_shell_cmd_covers},
162 { "similar-artists", ario_shell_cmd_similar_artists},
163 { "add-similar", ario_shell_cmd_add_similar},
164 { "preferences", ario_shell_cmd_preferences},
165 { "plugins", ario_shell_cmd_plugins},
166 { "about", ario_shell_cmd_about},
167 { "quit", ario_shell_cmd_quit},
168 };
169
170 #define ARIO_SHELL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ARIO_TYPE_SHELL, ArioShellPrivate))
G_DEFINE_TYPE(ArioShell,ario_shell,GTK_TYPE_APPLICATION_WINDOW)171 G_DEFINE_TYPE (ArioShell, ario_shell, GTK_TYPE_APPLICATION_WINDOW)
172
173 static void
174 ario_shell_class_init (ArioShellClass *klass)
175 {
176 ARIO_LOG_FUNCTION_START;
177 GObjectClass *object_class = (GObjectClass *) klass;
178
179 /* Virtual methods */
180 object_class->finalize = ario_shell_finalize;
181
182 /* Private attributes */
183 g_type_class_add_private (klass, sizeof (ArioShellPrivate));
184 }
185
186 static void
ario_shell_init(ArioShell * shell)187 ario_shell_init (ArioShell *shell)
188 {
189 ARIO_LOG_FUNCTION_START;
190 shell->priv = ARIO_SHELL_GET_PRIVATE (shell);
191 shell->priv->connected = FALSE;
192 shell->priv->shown = FALSE;
193
194 shell->priv->visible = TRUE;
195
196 shell->priv->window_x = -1;
197 shell->priv->window_y = -1;
198 shell->priv->window_w = -1;
199 shell->priv->window_h = -1;
200 }
201
202 static void
ario_shell_finalize(GObject * object)203 ario_shell_finalize (GObject *object)
204 {
205 ARIO_LOG_FUNCTION_START;
206 ArioShell *shell = ARIO_SHELL (object);
207
208 gtk_widget_hide (GTK_WIDGET(shell));
209
210 g_object_unref (shell->priv->playlist);
211 g_object_unref (shell->priv->sourcemanager);
212 g_object_unref (shell->priv->cover_handler);
213 g_object_unref (shell->priv->playlist_manager);
214 g_object_unref (shell->priv->notification_manager);
215
216 g_object_unref (ario_server_get_instance ());
217
218 G_OBJECT_CLASS (ario_shell_parent_class)->finalize (object);
219 }
220
221 ArioShell *
ario_shell_new(GtkApplication * app)222 ario_shell_new (GtkApplication * app)
223 {
224 ARIO_LOG_FUNCTION_START;
225 ArioShell *shell;
226
227 shell = g_object_new (ARIO_TYPE_SHELL, NULL);
228 shell->priv->app = app;
229
230 return shell;
231 }
232
233 static void
ario_shell_quit(ArioShell * shell)234 ario_shell_quit (ArioShell *shell)
235 {
236 ARIO_LOG_FUNCTION_START;
237
238 /* Stop music on exit if needed */
239 if (ario_conf_get_boolean (PREF_STOP_EXIT, PREF_STOP_EXIT_DEFAULT))
240 ario_server_do_stop ();
241
242 /* Stop main loop */
243 g_application_quit (G_APPLICATION (shell->priv->app));
244 }
245
246 static gboolean
ario_shell_window_delete_cb(GtkWidget * win,GdkEventAny * event,ArioShell * shell)247 ario_shell_window_delete_cb (GtkWidget *win,
248 GdkEventAny *event,
249 ArioShell *shell)
250 {
251 ARIO_LOG_FUNCTION_START;
252 if (ario_conf_get_boolean (PREF_HIDE_ON_CLOSE, PREF_HIDE_ON_CLOSE_DEFAULT)) {
253 ario_shell_set_visibility (shell, VISIBILITY_TOGGLE);
254 } else {
255 ario_shell_quit (shell);
256 }
257 return TRUE;
258 };
259
260 void
ario_shell_construct(ArioShell * shell,gboolean minimized)261 ario_shell_construct (ArioShell *shell,
262 gboolean minimized)
263 {
264 ARIO_LOG_FUNCTION_START;
265 GtkWidget *separator;
266 GAction *action;
267 ArioFirstlaunch *firstlaunch;
268 GtkBuilder *builder;
269 GMenuModel *menu;
270
271 g_return_if_fail (IS_ARIO_SHELL (shell));
272
273 /* Set main window properties */
274 gtk_window_set_title (GTK_WINDOW (shell), "Ario");
275 gtk_window_set_position (GTK_WINDOW (shell), GTK_WIN_POS_CENTER);
276
277 /* Create program icon */
278 gtk_window_set_default_icon_name ("ario");
279
280 /* Connect window destruction signal to exit program */
281 g_signal_connect (shell,
282 "delete_event",
283 G_CALLBACK (ario_shell_window_delete_cb),
284 shell);
285
286 /* Initialize UI */
287 builder = gtk_builder_new_from_file (UI_PATH "ario-shell-menu.ui");
288 menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
289 if (!g_application_get_is_remote (G_APPLICATION (shell->priv->app))) {
290 gtk_application_set_app_menu (shell->priv->app,
291 menu);
292 }
293 g_object_unref (builder);
294
295 /* Main window actions */
296 g_action_map_add_action_entries (G_ACTION_MAP (g_application_get_default ()),
297 shell_actions, G_N_ELEMENTS (shell_actions),
298 shell);
299
300 /* Initialize server object (MPD, XMMS, ....) */
301 ario_server_get_instance ();
302
303 /* Initialize cover art handler */
304 shell->priv->cover_handler = ario_cover_handler_new ();
305
306 /* Initialize playlist manager */
307 shell->priv->playlist_manager = ario_playlist_manager_get_instance ();
308
309 /* Initialize notification manager */
310 shell->priv->notification_manager = ario_notification_manager_get_instance ();
311
312 /* Add widgets to main window.
313 * Structure is:
314 * vbox
315 * ---header
316 * ---separator
317 * ---hbox
318 * -----hpaned/vpaned
319 * -------sourcemanager
320 * -------playlist
321 * ---status_bar
322 */
323
324 /* Create main vbox */
325 shell->priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
326
327 /* Create header */
328 shell->priv->header = ario_header_new ();
329
330 /* Create separator */
331 separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
332
333 /* Create playlist */
334 shell->priv->playlist = ario_playlist_new ();
335 g_object_ref (shell->priv->playlist);
336
337 /* Create source manager */
338 shell->priv->sourcemanager = ario_source_manager_get_instance ();
339 g_object_ref (shell->priv->sourcemanager);
340
341 /* Create the hbox(for tabs and playlist) */
342 shell->priv->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
343
344 /* Create status bar */
345 shell->priv->status_bar = ario_status_bar_new ();
346
347 /* Synchronize status bar checkbox in menu with preferences */
348 shell->priv->statusbar_hidden = ario_conf_get_boolean (PREF_STATUSBAR_HIDDEN, PREF_STATUSBAR_HIDDEN_DEFAULT);
349 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
350 "view-statusbar");
351 g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (!shell->priv->statusbar_hidden));
352
353 /* Synchronize upper part checkbox in menu with preferences */
354 shell->priv->upperpart_hidden = ario_conf_get_boolean (PREF_UPPERPART_HIDDEN, PREF_UPPERPART_HIDDEN_DEFAULT);
355 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
356 "view-upperpart");
357 g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (!shell->priv->upperpart_hidden));
358
359 /* Synchronize playlist checkbox in menu with preferences */
360 shell->priv->playlist_hidden = ario_conf_get_boolean (PREF_PLAYLIST_HIDDEN, PREF_PLAYLIST_HIDDEN_DEFAULT);
361 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
362 "view-playlist");
363 g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (!shell->priv->playlist_hidden));
364
365 /* Add widgets to vbox */
366 gtk_box_pack_start (GTK_BOX (shell->priv->vbox),
367 shell->priv->header,
368 FALSE, FALSE, 0);
369
370 gtk_box_pack_start (GTK_BOX (shell->priv->vbox),
371 separator,
372 FALSE, FALSE, 0);
373
374 gtk_box_pack_start (GTK_BOX (shell->priv->vbox),
375 shell->priv->hbox,
376 TRUE, TRUE, 0);
377
378 gtk_box_pack_start (GTK_BOX (shell->priv->vbox),
379 shell->priv->status_bar,
380 FALSE, FALSE, 0);
381
382 /* Add vbox to main window */
383 gtk_container_add (GTK_CONTAINER (shell), shell->priv->vbox);
384
385 /* First launch assistant */
386 if (!ario_conf_get_boolean (PREF_FIRST_TIME, PREF_FIRST_TIME_DEFAULT)) {
387 firstlaunch = ario_firstlaunch_new (shell->priv->app);
388 g_signal_connect (firstlaunch,
389 "destroy",
390 G_CALLBACK (ario_shell_firstlaunch_delete_cb),
391 shell);
392 gtk_widget_show_all (GTK_WIDGET (firstlaunch));
393 } else {
394 ario_shell_show (shell, minimized);
395 }
396
397 /* Synchronize main window state with preferences */
398 ario_shell_sync_window_state (shell);
399
400 /* Synchronize status bar visibility with preferences */
401 ario_shell_sync_statusbar_visibility (shell);
402
403 /* Synchronize upper part visibility with preferences */
404 ario_shell_sync_upperpart_visibility (shell);
405
406 /* Synchronize playlist visibility with preferences */
407 ario_shell_sync_playlist_visibility (shell);
408 }
409
410 void
ario_shell_shutdown(ArioShell * shell)411 ario_shell_shutdown (ArioShell *shell)
412 {
413 ARIO_LOG_FUNCTION_START;
414 int width, height;
415
416 /* If the main window is visible, we save a few preferences */
417 if (shell->priv->shown) {
418 if (shell->priv->paned) {
419 /* Save paned position */
420 ario_conf_set_integer (PREF_VPANED_POSITION,
421 gtk_paned_get_position (GTK_PANED (shell->priv->paned)));
422 }
423
424 /* Save window size */
425 if (!ario_conf_get_boolean (PREF_WINDOW_MAXIMIZED, PREF_WINDOW_MAXIMIZED_DEFAULT)) {
426 gtk_window_get_size (GTK_WINDOW (shell),
427 &width,
428 &height);
429
430 ario_conf_set_integer (PREF_WINDOW_WIDTH, width);
431 ario_conf_set_integer (PREF_WINDOW_HEIGHT, height);
432 }
433 }
434
435 /* Shutdown the playlist */
436 ario_playlist_shutdown ();
437
438 /* Shutdown the source manager */
439 ario_source_manager_shutdown ();
440
441 /* Shutdown the cover_manager */
442 ario_cover_manager_shutdown (ario_cover_manager_get_instance ());
443
444 /* Shutdown the lyrics_manager */
445 ario_lyrics_manager_shutdown (ario_lyrics_manager_get_instance ());
446
447 /* Shutdown the server object */
448 ario_server_shutdown ();
449 }
450
451 static void
ario_shell_show(ArioShell * shell,gboolean minimized)452 ario_shell_show (ArioShell *shell,
453 gboolean minimized)
454 {
455 ARIO_LOG_FUNCTION_START;
456 ArioServer *server = ario_server_get_instance ();
457
458 /* Connect signals for server state changes */
459 g_signal_connect (server,
460 "state_changed",
461 G_CALLBACK (ario_shell_server_state_changed_cb),
462 shell);
463
464 g_signal_connect (server,
465 "song_changed",
466 G_CALLBACK (ario_shell_server_song_changed_cb),
467 shell);
468
469 /* Autoconnect on startup if needed */
470 if (ario_conf_get_boolean (PREF_AUTOCONNECT, PREF_AUTOCONNECT_DEFAULT))
471 ario_server_connect ();
472
473 /* Show main window */
474 gtk_widget_show_all (GTK_WIDGET(shell));
475 shell->priv->shown = TRUE;
476
477 /* Synchonize the main window with server state */
478 ario_shell_sync_server (shell);
479
480 /* Synchronize playlist position with preferences */
481 ario_shell_sync_playlist_position (shell);
482
483 /* Synchronize paned with preferences */
484 ario_shell_sync_paned (shell);
485
486 /* Minimize window if needed */
487 if (minimized)
488 ario_shell_set_visibility (shell, VISIBILITY_HIDDEN);
489
490 /* Connect signal for window state changes */
491 g_signal_connect_object (shell,
492 "window-state-event",
493 G_CALLBACK (ario_shell_window_state_cb),
494 shell,
495 G_CONNECT_AFTER);
496
497 /* Update server db on startup if needed */
498 if (ario_conf_get_boolean (PREF_UPDATE_STARTUP, PREF_UPDATE_STARTUP_DEFAULT))
499 ario_server_update_db (NULL);
500
501 /* Notification for trees configuration changes */
502 ario_conf_notification_add (PREF_PLAYLIST_POSITION,
503 (ArioNotifyFunc) ario_shell_playlist_position_changed_cb,
504 shell);
505 }
506
507 void
ario_shell_present(ArioShell * shell)508 ario_shell_present (ArioShell *shell)
509 {
510 ARIO_LOG_FUNCTION_START;
511 if (ario_conf_get_boolean (PREF_FIRST_TIME, PREF_FIRST_TIME_DEFAULT)) {
512 ario_shell_set_visibility(shell, VISIBILITY_VISIBLE);
513 gtk_window_present (GTK_WINDOW (shell));
514 }
515 }
516
517 void
ario_shell_set_visibility(ArioShell * shell,ArioVisibility state)518 ario_shell_set_visibility (ArioShell *shell,
519 ArioVisibility state)
520 {
521 ARIO_LOG_FUNCTION_START;
522 switch (state)
523 {
524 case VISIBILITY_HIDDEN:
525 if (shell->priv->visible)
526 ario_shell_set_visibility (shell, VISIBILITY_TOGGLE);
527 break;
528 case VISIBILITY_VISIBLE:
529 if (!shell->priv->visible)
530 ario_shell_set_visibility (shell, VISIBILITY_TOGGLE);
531 break;
532 case VISIBILITY_TOGGLE:
533 shell->priv->visible = !shell->priv->visible;
534
535 if (shell->priv->visible == TRUE) {
536 /* Restore window state, size and position */
537 if (shell->priv->window_x >= 0 && shell->priv->window_y >= 0) {
538 gtk_window_move (GTK_WINDOW (shell),
539 shell->priv->window_x,
540 shell->priv->window_y);
541 }
542 if (!shell->priv->maximized
543 && (shell->priv->window_w >= 0 && shell->priv->window_y >=0)) {
544 gtk_window_resize (GTK_WINDOW (shell),
545 shell->priv->window_w,
546 shell->priv->window_h);
547 }
548
549 if (shell->priv->maximized)
550 gtk_window_maximize (GTK_WINDOW (shell));
551 gtk_widget_show (GTK_WIDGET(shell));
552
553 /* Restore paned position
554 * This is in a g_timeout_add because there seems to have a bug (#2798748) if I call
555 * ario_shell_sync_paned directly. I really don't understand why but this seems to work...*/
556 g_timeout_add (100, (GSourceFunc) ario_shell_sync_paned, shell);
557 } else {
558 /* Save window state, size and position */
559 shell->priv->maximized = ario_conf_get_boolean (PREF_WINDOW_MAXIMIZED, PREF_WINDOW_MAXIMIZED_DEFAULT);
560 gtk_window_get_position (GTK_WINDOW (shell),
561 &shell->priv->window_x,
562 &shell->priv->window_y);
563 gtk_window_get_size (GTK_WINDOW (shell),
564 &shell->priv->window_w,
565 &shell->priv->window_h);
566
567 /* Save paned position */
568 ario_conf_set_integer (PREF_VPANED_POSITION,
569 gtk_paned_get_position (GTK_PANED (shell->priv->paned)));
570
571 gtk_widget_hide (GTK_WIDGET(shell));
572 }
573 }
574 }
575
576 static void
ario_shell_cmd_quit(GSimpleAction * action,GVariant * parameter,gpointer data)577 ario_shell_cmd_quit (GSimpleAction *action,
578 GVariant *parameter,
579 gpointer data)
580 {
581 ARIO_LOG_FUNCTION_START;
582 ArioShell *shell = ARIO_SHELL (data);
583 ario_shell_quit (shell);
584 }
585
586 static void
ario_shell_cmd_connect(GSimpleAction * action,GVariant * parameter,gpointer data)587 ario_shell_cmd_connect (GSimpleAction *action,
588 GVariant *parameter,
589 gpointer data)
590 {
591 ARIO_LOG_FUNCTION_START;
592 ario_server_connect ();
593 }
594
595 static void
ario_shell_cmd_disconnect(GSimpleAction * action,GVariant * parameter,gpointer data)596 ario_shell_cmd_disconnect (GSimpleAction *action,
597 GVariant *parameter,
598 gpointer data)
599 {
600 ARIO_LOG_FUNCTION_START;
601 ario_server_disconnect ();
602 }
603
604 static void
ario_shell_cmd_update(GSimpleAction * action,GVariant * parameter,gpointer data)605 ario_shell_cmd_update (GSimpleAction *action,
606 GVariant *parameter,
607 gpointer data)
608 {
609 ARIO_LOG_FUNCTION_START;
610 ario_server_update_db (NULL);
611 }
612
613 static void
ario_shell_cmd_preferences(GSimpleAction * action,GVariant * parameter,gpointer data)614 ario_shell_cmd_preferences (GSimpleAction *action,
615 GVariant *parameter,
616 gpointer data)
617 {
618 ARIO_LOG_FUNCTION_START;
619 GtkWidget *prefs;
620 ArioShell *shell = ARIO_SHELL (data);
621
622 /* Create preferences dialog window */
623 prefs = ario_shell_preferences_new ();
624
625 gtk_window_set_transient_for (GTK_WINDOW (prefs),
626 GTK_WINDOW (shell));
627
628 gtk_widget_show_all (prefs);
629 }
630
631 static void
ario_shell_cmd_lyrics(GSimpleAction * action,GVariant * parameter,gpointer data)632 ario_shell_cmd_lyrics (GSimpleAction *action,
633 GVariant *parameter,
634 gpointer data)
635 {
636 ARIO_LOG_FUNCTION_START;
637 GtkWidget *lyrics;
638
639 /* Create lyrics dialog window */
640 lyrics = ario_shell_lyrics_new ();
641 if (lyrics)
642 gtk_widget_show_all (lyrics);
643 }
644
645 static void
ario_shell_cmd_about(GSimpleAction * action,GVariant * parameter,gpointer data)646 ario_shell_cmd_about (GSimpleAction *action,
647 GVariant *parameter,
648 gpointer data)
649 {
650 ARIO_LOG_FUNCTION_START;
651 ArioShell *shell = ARIO_SHELL (data);
652
653 /* Create about dialog window */
654 const char *authors[] = {
655 #include "AUTHORS.tab"
656 "",
657 NULL
658 };
659 const char *artists[] = {
660 "Luc Pavot",
661 NULL
662 };
663 GdkPixbuf *logo_pixbuf = gdk_pixbuf_new_from_file (PIXMAP_PATH "logo.png", NULL);
664 gtk_show_about_dialog (GTK_WINDOW (shell),
665 "name", "Ario",
666 "program-name", "Ario",
667 "version", PACKAGE_VERSION,
668 "copyright", "Copyright \xc2\xa9 2005-" CURRENT_DATE " Marc Pavot",
669 "comments", _("GTK client for MPD"),
670 "translator-credits", _("translator-credits"),
671 "authors", (const char **) authors,
672 "artists", (const char **) artists,
673 "logo", logo_pixbuf,
674 NULL);
675 if (logo_pixbuf)
676 g_object_unref (logo_pixbuf);
677 }
678
679 static void
ario_shell_server_song_set_title(ArioShell * shell)680 ario_shell_server_song_set_title (ArioShell *shell)
681 {
682 ARIO_LOG_FUNCTION_START;
683 gchar *window_title;
684 gchar *tmp;
685
686 switch (ario_server_get_current_state ()) {
687 case ARIO_STATE_PLAY:
688 case ARIO_STATE_PAUSE:
689 /* Window title containing song name */
690 tmp = ario_util_format_title (ario_server_get_current_song ());
691 window_title = g_strdup_printf ("Ario - %s", tmp);
692 gtk_window_set_title (GTK_WINDOW (shell), window_title);
693 g_free (window_title);
694 break;
695 default:
696 /* Default window title */
697 gtk_window_set_title (GTK_WINDOW (shell), "Ario");
698 break;
699 }
700 }
701
702 static void
ario_shell_server_song_changed_cb(ArioServer * server,ArioShell * shell)703 ario_shell_server_song_changed_cb (ArioServer *server,
704 ArioShell *shell)
705 {
706 ARIO_LOG_FUNCTION_START;
707 /* Change window title on song change */
708 ario_shell_server_song_set_title (shell);
709 }
710
711 static void
ario_shell_server_state_changed_cb(ArioServer * server,ArioShell * shell)712 ario_shell_server_state_changed_cb (ArioServer *server,
713 ArioShell *shell)
714 {
715 ARIO_LOG_FUNCTION_START;
716 shell->priv->connected = ario_server_is_connected ();
717
718 /* Synchronize main window with server state */
719 ario_shell_sync_server (shell);
720
721 /* Change window title on song change */
722 ario_shell_server_song_set_title (shell);
723 }
724
725 static void
ario_shell_cmd_cover_select(GSimpleAction * action,GVariant * parameter,gpointer data)726 ario_shell_cmd_cover_select (GSimpleAction *action,
727 GVariant *parameter,
728 gpointer data)
729 {
730 ARIO_LOG_FUNCTION_START;
731 GtkWidget *coverselect;
732 ArioServerAlbum server_album;
733
734 /* Launch cover selection dialog for current album */
735 server_album.artist = ario_server_get_current_artist ();
736 server_album.album = ario_server_get_current_album ();
737 server_album.path = g_path_get_dirname ((ario_server_get_current_song ())->file);
738
739 if (!server_album.album)
740 server_album.album = ARIO_SERVER_UNKNOWN;
741
742 if (!server_album.artist)
743 server_album.artist = ARIO_SERVER_UNKNOWN;
744
745 coverselect = ario_shell_coverselect_new (&server_album);
746 gtk_dialog_run (GTK_DIALOG (coverselect));
747 gtk_widget_destroy (coverselect);
748 g_free (server_album.path);
749 }
750
751 static void
ario_shell_cmd_covers(GSimpleAction * action,GVariant * parameter,gpointer data)752 ario_shell_cmd_covers (GSimpleAction *action,
753 GVariant *parameter,
754 gpointer data)
755 {
756 ARIO_LOG_FUNCTION_START;
757 GtkWidget *coverdownloader;
758
759 /* Launch cover art download dialog */
760 coverdownloader = ario_shell_coverdownloader_new ();
761
762 if (coverdownloader) {
763 ario_shell_coverdownloader_get_covers (ARIO_SHELL_COVERDOWNLOADER (coverdownloader),
764 GET_COVERS);
765 }
766 }
767
768 static void
ario_shell_cmd_similar_artists(GSimpleAction * action,GVariant * parameter,gpointer data)769 ario_shell_cmd_similar_artists (GSimpleAction *action,
770 GVariant *parameter,
771 gpointer data)
772 {
773 ARIO_LOG_FUNCTION_START;
774 GtkWidget *similarartists;
775
776 /* Launch similar artist dialog */
777 similarartists = ario_shell_similarartists_new ();
778 if (similarartists)
779 gtk_widget_show_all (similarartists);
780 }
781
782 static void
ario_shell_cmd_add_similar(GSimpleAction * action,GVariant * parameter,gpointer data)783 ario_shell_cmd_add_similar (GSimpleAction *action,
784 GVariant *parameter,
785 gpointer data)
786 {
787 ARIO_LOG_FUNCTION_START;
788
789 /* Add similar artists (from last.fm) to current playlist */
790 ario_shell_similarartists_add_similar_to_playlist (ario_server_get_current_artist (), -1);
791 }
792
793 static void
ario_shell_sync_paned(ArioShell * shell)794 ario_shell_sync_paned (ArioShell *shell)
795 {
796 ARIO_LOG_FUNCTION_START;
797 int pos;
798
799 /* Set paned position */
800 pos = ario_conf_get_integer (PREF_VPANED_POSITION, PREF_VPANED_POSITION_DEFAULT);
801 if (pos > 0 && shell->priv->paned)
802 gtk_paned_set_position (GTK_PANED (shell->priv->paned),
803 pos);
804 }
805
806 static gboolean
ario_shell_window_state_cb(GtkWidget * widget,GdkEvent * event,ArioShell * shell)807 ario_shell_window_state_cb (GtkWidget *widget,
808 GdkEvent *event,
809 ArioShell *shell)
810 {
811 ARIO_LOG_FUNCTION_START;
812 int width, height;
813 g_return_val_if_fail (widget != NULL, FALSE);
814
815 if ((event->type == GDK_WINDOW_STATE)
816 && !(event->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) {
817 /* Save window maximization state */
818 ario_conf_set_boolean (PREF_WINDOW_MAXIMIZED,
819 event->window_state.new_window_state &
820 GDK_WINDOW_STATE_MAXIMIZED);
821
822 if (event->window_state.changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
823 /* Save previous window size on maximization */
824 gtk_window_get_size (GTK_WINDOW (shell),
825 &width,
826 &height);
827
828 ario_conf_set_integer (PREF_WINDOW_WIDTH, width);
829 ario_conf_set_integer (PREF_WINDOW_HEIGHT, height);
830 }
831 }
832
833 return FALSE;
834 }
835
836 static void
ario_shell_sync_window_state(ArioShell * shell)837 ario_shell_sync_window_state (ArioShell *shell)
838 {
839 ARIO_LOG_FUNCTION_START;
840 int width = ario_conf_get_integer (PREF_WINDOW_WIDTH, PREF_WINDOW_WIDTH_DEFAULT);
841 int height = ario_conf_get_integer (PREF_WINDOW_HEIGHT, PREF_WINDOW_HEIGHT_DEFAULT);
842 gboolean maximized = ario_conf_get_boolean (PREF_WINDOW_MAXIMIZED, PREF_WINDOW_MAXIMIZED_DEFAULT);
843
844 /* Set main window size */
845 gtk_window_set_default_size (GTK_WINDOW (shell),
846 width, height);
847 gtk_window_resize (GTK_WINDOW (shell),
848 width, height);
849
850 /* Maximize main window if needed */
851 if (maximized)
852 gtk_window_maximize (GTK_WINDOW (shell));
853 else
854 gtk_window_unmaximize (GTK_WINDOW (shell));
855 }
856
857 static void
ario_shell_sync_server(ArioShell * shell)858 ario_shell_sync_server (ArioShell *shell)
859 {
860 ARIO_LOG_FUNCTION_START;
861 GAction *connect_action;
862 GAction *disconnect_action;
863 gboolean is_playing;
864 GAction *action;
865
866 /* Set connect entry visibility */
867 connect_action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
868 "connect");
869 g_simple_action_set_enabled (G_SIMPLE_ACTION (connect_action), !shell->priv->connected);
870
871 /* Set disconnect entry visibility */
872 disconnect_action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
873 "disconnect");
874 g_simple_action_set_enabled (G_SIMPLE_ACTION (disconnect_action), shell->priv->connected);
875
876 is_playing = ((shell->priv->connected)
877 && ((ario_server_get_current_state () == ARIO_STATE_PLAY)
878 || (ario_server_get_current_state () == ARIO_STATE_PAUSE)));
879
880 /* Set lyrics entry sensitivty */
881 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
882 "view-lyrics");
883 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), is_playing);
884
885 /* Set cover selection entry sensitivty */
886 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
887 "cover-select");
888 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), is_playing);
889
890 /* Set similar artists entry sensitivty */
891 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
892 "similar-artists");
893 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), is_playing);
894
895 /* Set similar artists addition entry sensitivty */
896 action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
897 "add-similar");
898 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), is_playing);
899 }
900
901 static void
ario_shell_sync_playlist_position(ArioShell * shell)902 ario_shell_sync_playlist_position (ArioShell *shell)
903 {
904 if (!shell->priv->playlist)
905 return;
906
907 /* Remove all widgets if playlist is in tabs */
908 int page_num = gtk_notebook_page_num (GTK_NOTEBOOK (shell->priv->sourcemanager), shell->priv->playlist);
909 if (page_num >= 0) {
910 ario_source_manager_remove (ARIO_SOURCE (shell->priv->playlist));
911 gtk_container_remove (GTK_CONTAINER (shell->priv->hbox), shell->priv->sourcemanager);
912 }
913
914 /* Remove all widgets if playlist is in a paned */
915 if (shell->priv->paned) {
916 /* Save paned position */
917 ario_conf_set_integer (PREF_VPANED_POSITION,
918 gtk_paned_get_position (GTK_PANED (shell->priv->paned)));
919
920 gtk_container_remove (GTK_CONTAINER (shell->priv->paned), shell->priv->playlist);
921 gtk_container_remove (GTK_CONTAINER (shell->priv->paned), shell->priv->sourcemanager);
922 gtk_container_remove (GTK_CONTAINER (shell->priv->hbox), shell->priv->paned);
923 shell->priv->paned = NULL;
924 }
925
926 switch (ario_conf_get_integer (PREF_PLAYLIST_POSITION, PREF_PLAYLIST_POSITION_DEFAULT))
927 {
928 case PLAYLIST_POSITION_BELOW:
929 /* Create paned (separation between upper part and playlist) */
930 shell->priv->paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
931
932 /* Add widgets to paned */
933 gtk_paned_pack1 (GTK_PANED (shell->priv->paned),
934 shell->priv->sourcemanager,
935 FALSE, FALSE);
936
937 gtk_paned_pack2 (GTK_PANED (shell->priv->paned),
938 shell->priv->playlist,
939 TRUE, FALSE);
940
941 gtk_box_pack_start (GTK_BOX (shell->priv->hbox),
942 shell->priv->paned,
943 TRUE, TRUE, 0);
944 gtk_widget_show_all (shell->priv->paned);
945
946 /* Synchronize paned with preferences */
947 ario_shell_sync_paned (shell);
948 break;
949 case PLAYLIST_POSITION_RIGHT:
950 /* Create paned (separation between left part and playlist) */
951 shell->priv->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
952
953 /* Add widgets to paned */
954 gtk_paned_pack1 (GTK_PANED (shell->priv->paned),
955 shell->priv->sourcemanager,
956 FALSE, FALSE);
957
958 gtk_paned_pack2 (GTK_PANED (shell->priv->paned),
959 shell->priv->playlist,
960 TRUE, FALSE);
961
962 gtk_box_pack_start (GTK_BOX (shell->priv->hbox),
963 shell->priv->paned,
964 TRUE, TRUE, 0);
965 gtk_widget_show_all (shell->priv->paned);
966
967 /* Synchronize paned with preferences */
968 ario_shell_sync_paned (shell);
969 break;
970 case PLAYLIST_POSITION_INSIDE:
971 default:
972 /* Add playlist to tabs */
973 ario_source_manager_append (ARIO_SOURCE (shell->priv->playlist));
974 gtk_box_pack_start (GTK_BOX (shell->priv->hbox),
975 shell->priv->sourcemanager,
976 TRUE, TRUE, 0);
977 gtk_widget_show_all (shell->priv->sourcemanager);
978 break;
979 }
980 }
981
982 static void
ario_shell_firstlaunch_delete_cb(ArioFirstlaunch * firstlaunch,ArioShell * shell)983 ario_shell_firstlaunch_delete_cb (ArioFirstlaunch *firstlaunch,
984 ArioShell *shell)
985 {
986 ARIO_LOG_FUNCTION_START;
987 /* Show main window when first launch assistant is deleted */
988 ario_shell_show (shell, FALSE);
989 }
990
991 static void
ario_shell_view_statusbar_changed_cb(GSimpleAction * action,GVariant * parameter,gpointer data)992 ario_shell_view_statusbar_changed_cb (GSimpleAction *action,
993 GVariant *parameter,
994 gpointer data)
995 {
996 ARIO_LOG_FUNCTION_START;
997 GVariant *old_state, *new_state;
998 ArioShell *shell = ARIO_SHELL (data);
999
1000 old_state = g_action_get_state (G_ACTION (action));
1001 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
1002 g_simple_action_set_state (action, new_state);
1003 g_variant_unref (old_state);
1004
1005 shell->priv->statusbar_hidden = !g_variant_get_boolean (new_state);
1006 ario_conf_set_boolean (PREF_STATUSBAR_HIDDEN, shell->priv->statusbar_hidden);
1007
1008 /* Synchronize status bar visibility */
1009 ario_shell_sync_statusbar_visibility (shell);
1010 }
1011
1012 static void
ario_shell_view_upperpart_changed_cb(GSimpleAction * action,GVariant * parameter,gpointer data)1013 ario_shell_view_upperpart_changed_cb (GSimpleAction *action,
1014 GVariant *parameter,
1015 gpointer data)
1016 {
1017 ARIO_LOG_FUNCTION_START;
1018 GVariant *old_state, *new_state;
1019 ArioShell *shell = ARIO_SHELL (data);
1020
1021 old_state = g_action_get_state (G_ACTION (action));
1022 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
1023 g_simple_action_set_state (action, new_state);
1024 g_variant_unref (old_state);
1025
1026 shell->priv->upperpart_hidden = !g_variant_get_boolean (new_state);
1027 ario_conf_set_boolean (PREF_UPPERPART_HIDDEN, shell->priv->upperpart_hidden);
1028
1029 /* Synchronize upper part visibility */
1030 ario_shell_sync_upperpart_visibility (shell);
1031 }
1032
1033 static void
ario_shell_view_playlist_changed_cb(GSimpleAction * action,GVariant * parameter,gpointer data)1034 ario_shell_view_playlist_changed_cb (GSimpleAction *action,
1035 GVariant *parameter,
1036 gpointer data)
1037 {
1038 ARIO_LOG_FUNCTION_START;
1039 GVariant *old_state, *new_state;
1040 ArioShell *shell = ARIO_SHELL (data);
1041
1042 old_state = g_action_get_state (G_ACTION (action));
1043 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
1044 g_simple_action_set_state (action, new_state);
1045 g_variant_unref (old_state);
1046
1047 shell->priv->playlist_hidden = !g_variant_get_boolean (new_state);
1048 ario_conf_set_boolean (PREF_PLAYLIST_HIDDEN, shell->priv->playlist_hidden);
1049
1050 /* Synchronize playlist visibility */
1051 ario_shell_sync_playlist_visibility (shell);
1052 }
1053
1054 static void
ario_shell_sync_statusbar_visibility(ArioShell * shell)1055 ario_shell_sync_statusbar_visibility (ArioShell *shell)
1056 {
1057 ARIO_LOG_FUNCTION_START;
1058 if (shell->priv->statusbar_hidden)
1059 gtk_widget_hide (GTK_WIDGET (shell->priv->status_bar));
1060 else
1061 gtk_widget_show (GTK_WIDGET (shell->priv->status_bar));
1062 }
1063
1064 static void
ario_shell_sync_upperpart_visibility(ArioShell * shell)1065 ario_shell_sync_upperpart_visibility (ArioShell *shell)
1066 {
1067 ARIO_LOG_FUNCTION_START;
1068 if (shell->priv->upperpart_hidden)
1069 gtk_widget_hide (GTK_WIDGET (shell->priv->sourcemanager));
1070 else
1071 gtk_widget_show (GTK_WIDGET (shell->priv->sourcemanager));
1072 }
1073
1074 static void
ario_shell_sync_playlist_visibility(ArioShell * shell)1075 ario_shell_sync_playlist_visibility (ArioShell *shell)
1076 {
1077 ARIO_LOG_FUNCTION_START;
1078 if (shell->priv->playlist_hidden)
1079 gtk_widget_hide (GTK_WIDGET (shell->priv->playlist));
1080 else
1081 gtk_widget_show (GTK_WIDGET (shell->priv->playlist));
1082 }
1083
1084 static gboolean
ario_shell_plugins_window_delete_cb(GtkWidget * window,GdkEventAny * event,gpointer data)1085 ario_shell_plugins_window_delete_cb (GtkWidget *window,
1086 GdkEventAny *event,
1087 gpointer data)
1088 {
1089 ARIO_LOG_FUNCTION_START;
1090 gtk_widget_destroy (GTK_WIDGET (window));
1091 return TRUE;
1092 }
1093
1094 static void
ario_shell_plugins_response_cb(GtkDialog * dialog,int response_id,gpointer data)1095 ario_shell_plugins_response_cb (GtkDialog *dialog,
1096 int response_id,
1097 gpointer data)
1098 {
1099 ARIO_LOG_FUNCTION_START;
1100 gtk_widget_destroy (GTK_WIDGET (dialog));
1101 }
1102
1103 static void
ario_shell_cmd_plugins(GSimpleAction * action,GVariant * parameter,gpointer data)1104 ario_shell_cmd_plugins (GSimpleAction *action,
1105 GVariant *parameter,
1106 gpointer data)
1107 {
1108 ARIO_LOG_FUNCTION_START;
1109 GtkWidget *window;
1110 GtkWidget *manager;
1111 ArioShell *shell = ARIO_SHELL (data);
1112
1113 /* Create plugins configuration dialog window */
1114 window = gtk_dialog_new_with_buttons (_("Configure Plugins"),
1115 GTK_WINDOW (shell),
1116 GTK_DIALOG_DESTROY_WITH_PARENT,
1117 _("_Close"),
1118 GTK_RESPONSE_CLOSE,
1119 NULL);
1120 gtk_container_set_border_width (GTK_CONTAINER (window), 5);
1121 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))), 2);
1122
1123 /* Connect signals for window destruction */
1124 g_signal_connect (window,
1125 "delete_event",
1126 G_CALLBACK (ario_shell_plugins_window_delete_cb),
1127 NULL);
1128 g_signal_connect (window,
1129 "response",
1130 G_CALLBACK (ario_shell_plugins_response_cb),
1131 NULL);
1132
1133 manager = ario_plugin_manager_new ();
1134 gtk_widget_show_all (GTK_WIDGET (manager));
1135 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (window))),
1136 manager);
1137
1138 gtk_window_set_default_size (GTK_WINDOW (window), 300, 350);
1139
1140 gtk_window_present (GTK_WINDOW (window));
1141 }
1142
1143 static void
ario_shell_playlist_position_changed_cb(guint notification_id,ArioShell * shell)1144 ario_shell_playlist_position_changed_cb (guint notification_id,
1145 ArioShell *shell)
1146 {
1147 ario_shell_sync_playlist_position(shell);
1148 }
1149