1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2010 The Music Player Daemon Project
3 * Project homepage: http://musicpd.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.
21 #include "screen_interface.h"
22 #include "screen_list.h"
23 #include "screen_utils.h"
24 #include "screen_status.h"
28 #include "mpdclient.h"
32 #include "player_command.h"
33 #include "screen_help.h"
34 #include "screen_queue.h"
35 #include "screen_file.h"
36 #include "screen_artist.h"
37 #include "screen_search.h"
38 #include "screen_song.h"
39 #include "screen_keydef.h"
40 #include "screen_lyrics.h"
41 #include "screen_outputs.h"
42 #include "screen_chat.h"
44 #include <mpd/client.h>
53 /** welcome message time [s] */
54 static const GTime SCREEN_WELCOME_TIME
= 10;
57 /* minimum window size */
58 static const int SCREEN_MIN_COLS
= 14;
59 static const int SCREEN_MIN_ROWS
= 5;
64 static const struct screen_functions
*mode_fn
= &screen_queue
;
65 static const struct screen_functions
*mode_fn_prev
= &screen_queue
;
68 screen_is_visible(const struct screen_functions
*sf
)
74 screen_switch(const struct screen_functions
*sf
, struct mpdclient
*c
)
81 mode_fn_prev
= mode_fn
;
83 /* close the old mode */
84 if (mode_fn
->close
!= NULL
)
87 /* get functions for the new mode */
90 /* open the new mode */
91 if (mode_fn
->open
!= NULL
)
98 screen_swap(struct mpdclient
*c
, const struct mpd_song
*song
)
103 { /* just a hack to make the ifdefs less ugly */ }
104 #ifdef ENABLE_SONG_SCREEN
105 if (mode_fn_prev
== &screen_song
)
106 screen_song_switch(c
, song
);
108 #ifdef ENABLE_LYRICS_SCREEN
109 else if (mode_fn_prev
== &screen_lyrics
)
110 screen_lyrics_switch(c
, song
, true);
113 screen_switch(mode_fn_prev
, c
);
116 screen_switch(mode_fn_prev
, c
);
120 find_configured_screen(const char *name
)
124 for (i
= 0; options
.screen_list
[i
] != NULL
; ++i
)
125 if (strcmp(options
.screen_list
[i
], name
) == 0)
132 screen_next_mode(struct mpdclient
*c
, int offset
)
134 int max
= g_strv_length(options
.screen_list
);
136 const struct screen_functions
*sf
;
138 /* find current screen */
139 current
= find_configured_screen(screen_get_name(mode_fn
));
140 next
= current
+ offset
;
146 sf
= screen_lookup_name(options
.screen_list
[next
]);
148 screen_switch(sf
, c
);
152 paint_top_window(const char *header
, const struct mpdclient
*c
)
154 title_bar_paint(&screen
.title_bar
, header
, c
->status
);
158 update_progress_window(struct mpdclient
*c
, bool repaint
)
160 unsigned elapsed
, duration
;
162 if (c
->status
== NULL
)
164 else if (seek_id
>= 0 && seek_id
== mpd_status_get_song_id(c
->status
))
165 elapsed
= seek_target_time
;
167 elapsed
= mpd_status_get_elapsed_time(c
->status
);
169 duration
= mpdclient_is_playing(c
)
170 ? mpd_status_get_total_time(c
->status
)
173 if (progress_bar_set(&screen
.progress_bar
, elapsed
, duration
) ||
175 progress_bar_paint(&screen
.progress_bar
);
181 if (mode_fn
->close
!= NULL
)
186 string_list_free(screen
.find_history
);
188 g_free(screen
.findbuf
);
190 title_bar_deinit(&screen
.title_bar
);
191 delwin(screen
.main_window
.w
);
192 progress_bar_deinit(&screen
.progress_bar
);
193 status_bar_deinit(&screen
.status_bar
);
196 if (screen
.welcome_source_id
!= 0)
197 g_source_remove(screen
.welcome_source_id
);
202 screen_resize(struct mpdclient
*c
)
204 if (COLS
<SCREEN_MIN_COLS
|| LINES
<SCREEN_MIN_ROWS
) {
206 fprintf(stderr
, "%s\n", _("Error: Screen too small"));
210 resize_term(LINES
, COLS
);
212 resizeterm(LINES
, COLS
);
218 title_bar_resize(&screen
.title_bar
, screen
.cols
);
221 screen
.main_window
.cols
= screen
.cols
;
222 screen
.main_window
.rows
= screen
.rows
-4;
223 wresize(screen
.main_window
.w
, screen
.main_window
.rows
, screen
.cols
);
224 wclear(screen
.main_window
.w
);
226 /* progress window */
227 progress_bar_resize(&screen
.progress_bar
, screen
.cols
,
229 progress_bar_paint(&screen
.progress_bar
);
232 status_bar_resize(&screen
.status_bar
, screen
.cols
, screen
.rows
- 1, 0);
233 status_bar_paint(&screen
.status_bar
, c
->status
, c
->song
);
235 screen
.buf_size
= screen
.cols
;
237 screen
.buf
= g_malloc(screen
.cols
);
239 /* resize all screens */
240 screen_list_resize(screen
.main_window
.cols
, screen
.main_window
.rows
);
242 /* ? - without this the cursor becomes visible with aterm & Eterm */
251 welcome_timer_callback(gpointer data
)
253 struct mpdclient
*c
= data
;
256 screen
.welcome_source_id
= 0;
259 paint_top_window(mode_fn
->get_title
!= NULL
260 ? mode_fn
->get_title(screen
.buf
, screen
.buf_size
)
270 screen_init(struct mpdclient
*c
)
272 if (COLS
< SCREEN_MIN_COLS
|| LINES
< SCREEN_MIN_ROWS
) {
273 fprintf(stderr
, "%s\n", _("Error: Screen too small"));
280 screen
.buf
= g_malloc(screen
.cols
);
281 screen
.buf_size
= screen
.cols
;
282 screen
.findbuf
= NULL
;
285 if (options
.welcome_screen_list
)
286 screen
.welcome_source_id
=
287 g_timeout_add(SCREEN_WELCOME_TIME
* 1000,
288 welcome_timer_callback
, c
);
291 /* create top window */
292 title_bar_init(&screen
.title_bar
, screen
.cols
, 0, 0);
294 /* create main window */
295 window_init(&screen
.main_window
, screen
.rows
- 4, screen
.cols
, 2, 0);
297 if (!options
.hardware_cursor
)
298 leaveok(screen
.main_window
.w
, TRUE
);
300 keypad(screen
.main_window
.w
, TRUE
);
302 /* create progress window */
303 progress_bar_init(&screen
.progress_bar
, screen
.cols
,
305 progress_bar_paint(&screen
.progress_bar
);
307 /* create status window */
308 status_bar_init(&screen
.status_bar
, screen
.cols
, screen
.rows
- 1, 0);
309 status_bar_paint(&screen
.status_bar
, c
->status
, c
->song
);
312 if (options
.enable_colors
) {
313 /* set background attributes */
314 wbkgd(stdscr
, COLOR_PAIR(COLOR_LIST
));
315 wbkgd(screen
.main_window
.w
, COLOR_PAIR(COLOR_LIST
));
316 wbkgd(screen
.title_bar
.window
.w
, COLOR_PAIR(COLOR_TITLE
));
317 wbkgd(screen
.progress_bar
.window
.w
,
318 COLOR_PAIR(COLOR_PROGRESSBAR
));
319 wbkgd(screen
.status_bar
.window
.w
, COLOR_PAIR(COLOR_STATUS
));
320 colors_use(screen
.progress_bar
.window
.w
, COLOR_PROGRESSBAR
);
326 /* initialize screens */
327 screen_list_init(screen
.main_window
.w
,
328 screen
.main_window
.cols
, screen
.main_window
.rows
);
330 if (mode_fn
->open
!= NULL
)
335 screen_paint(struct mpdclient
*c
)
337 const char *title
= NULL
;
339 if (mode_fn
->get_title
!= NULL
)
340 title
= mode_fn
->get_title(screen
.buf
, screen
.buf_size
);
342 /* paint the title/header window */
344 paint_top_window(title
, c
);
346 paint_top_window("", c
);
348 /* paint the bottom window */
350 update_progress_window(c
, true);
351 status_bar_paint(&screen
.status_bar
, c
->status
, c
->song
);
353 /* paint the main window */
355 wclear(screen
.main_window
.w
);
356 if (mode_fn
->paint
!= NULL
)
359 /* move the cursor to the origin */
361 if (!options
.hardware_cursor
)
362 wmove(screen
.main_window
.w
, 0, 0);
364 wnoutrefresh(screen
.main_window
.w
);
366 /* tell curses to update */
371 screen_update(struct mpdclient
*c
)
374 static bool was_connected
;
375 static bool initialized
= false;
377 static bool random_enabled
;
380 static unsigned crossfade
;
382 /* print a message if mpd status has changed */
383 if ((c
->events
& MPD_IDLE_OPTIONS
) && c
->status
!= NULL
) {
385 repeat
= mpd_status_get_repeat(c
->status
);
386 random_enabled
= mpd_status_get_random(c
->status
);
387 single
= mpd_status_get_single(c
->status
);
388 consume
= mpd_status_get_consume(c
->status
);
389 crossfade
= mpd_status_get_crossfade(c
->status
);
393 if (repeat
!= mpd_status_get_repeat(c
->status
))
394 screen_status_printf(mpd_status_get_repeat(c
->status
) ?
395 _("Repeat mode is on") :
396 _("Repeat mode is off"));
398 if (random_enabled
!= mpd_status_get_random(c
->status
))
399 screen_status_printf(mpd_status_get_random(c
->status
) ?
400 _("Random mode is on") :
401 _("Random mode is off"));
403 if (single
!= mpd_status_get_single(c
->status
))
404 screen_status_printf(mpd_status_get_single(c
->status
) ?
405 /* "single" mode means
410 _("Single mode is on") :
411 _("Single mode is off"));
413 if (consume
!= mpd_status_get_consume(c
->status
))
414 screen_status_printf(mpd_status_get_consume(c
->status
) ?
415 /* "consume" mode means
416 that MPD removes each
419 _("Consume mode is on") :
420 _("Consume mode is off"));
422 if (crossfade
!= mpd_status_get_crossfade(c
->status
))
423 screen_status_printf(_("Crossfade %d seconds"),
424 mpd_status_get_crossfade(c
->status
));
426 repeat
= mpd_status_get_repeat(c
->status
);
427 random_enabled
= mpd_status_get_random(c
->status
);
428 single
= mpd_status_get_single(c
->status
);
429 consume
= mpd_status_get_consume(c
->status
);
430 crossfade
= mpd_status_get_crossfade(c
->status
);
433 if ((c
->events
& MPD_IDLE_DATABASE
) != 0 && was_connected
&&
434 mpdclient_is_connected(c
))
435 screen_status_printf(_("Database updated"));
436 was_connected
= mpdclient_is_connected(c
);
438 /* update title/header window */
439 if (screen
.welcome_source_id
!= 0)
440 paint_top_window("", c
);
443 if (mode_fn
->get_title
!= NULL
) {
444 paint_top_window(mode_fn
->get_title(screen
.buf
,screen
.buf_size
), c
);
446 paint_top_window("", c
);
448 /* update progress window */
449 update_progress_window(c
, false);
451 /* update status window */
452 status_bar_paint(&screen
.status_bar
, c
->status
, c
->song
);
454 /* update the main window */
455 if (mode_fn
->update
!= NULL
)
458 /* move the cursor to the origin */
460 if (!options
.hardware_cursor
)
461 wmove(screen
.main_window
.w
, 0, 0);
463 wnoutrefresh(screen
.main_window
.w
);
465 /* tell curses to update */
471 screen_get_mouse_event(struct mpdclient
*c
, unsigned long *bstate
, int *row
)
475 /* retrieve the mouse event from curses */
481 /* calculate the selected row in the list window */
482 *row
= event
.y
- screen
.title_bar
.window
.rows
;
483 /* copy button state bits */
484 *bstate
= event
.bstate
;
485 /* if button 2 was pressed switch screen */
486 if (event
.bstate
& BUTTON2_CLICKED
) {
487 screen_cmd(c
, CMD_SCREEN_NEXT
);
496 screen_cmd(struct mpdclient
*c
, command_t cmd
)
499 if (screen
.welcome_source_id
!= 0) {
500 g_source_remove(screen
.welcome_source_id
);
501 screen
.welcome_source_id
= 0;
505 if (mode_fn
->cmd
!= NULL
&& mode_fn
->cmd(c
, cmd
))
508 if (handle_player_command(c
, cmd
))
512 case CMD_TOGGLE_FIND_WRAP
:
513 options
.find_wrap
= !options
.find_wrap
;
514 screen_status_printf(options
.find_wrap
?
515 _("Find mode: Wrapped") :
516 _("Find mode: Normal"));
518 case CMD_TOGGLE_AUTOCENTER
:
519 options
.auto_center
= !options
.auto_center
;
520 screen_status_printf(options
.auto_center
?
521 _("Auto center mode: On") :
522 _("Auto center mode: Off"));
524 case CMD_SCREEN_UPDATE
:
527 case CMD_SCREEN_PREVIOUS
:
528 screen_next_mode(c
, -1);
530 case CMD_SCREEN_NEXT
:
531 screen_next_mode(c
, 1);
533 case CMD_SCREEN_PLAY
:
534 screen_switch(&screen_queue
, c
);
536 case CMD_SCREEN_FILE
:
537 screen_switch(&screen_browse
, c
);
539 #ifdef ENABLE_HELP_SCREEN
540 case CMD_SCREEN_HELP
:
541 screen_switch(&screen_help
, c
);
544 #ifdef ENABLE_SEARCH_SCREEN
545 case CMD_SCREEN_SEARCH
:
546 screen_switch(&screen_search
, c
);
549 #ifdef ENABLE_ARTIST_SCREEN
550 case CMD_SCREEN_ARTIST
:
551 screen_switch(&screen_artist
, c
);
554 #ifdef ENABLE_SONG_SCREEN
555 case CMD_SCREEN_SONG
:
556 screen_switch(&screen_song
, c
);
559 #ifdef ENABLE_KEYDEF_SCREEN
560 case CMD_SCREEN_KEYDEF
:
561 screen_switch(&screen_keydef
, c
);
564 #ifdef ENABLE_LYRICS_SCREEN
565 case CMD_SCREEN_LYRICS
:
566 screen_switch(&screen_lyrics
, c
);
569 #ifdef ENABLE_OUTPUTS_SCREEN
570 case CMD_SCREEN_OUTPUTS
:
571 screen_switch(&screen_outputs
, c
);
574 #ifdef ENABLE_CHAT_SCREEN
575 case CMD_SCREEN_CHAT
:
576 screen_switch(&screen_chat
, c
);
579 case CMD_SCREEN_SWAP
:
580 screen_swap(c
, NULL
);