Code

255cacd5393bb2a7e40918781b4511d185cda330
[ncmpc.git] / src / screen.c
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2009 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.
18 */
20 #include "screen.h"
21 #include "screen_list.h"
22 #include "screen_utils.h"
23 #include "config.h"
24 #include "i18n.h"
25 #include "charset.h"
26 #include "mpdclient.h"
27 #include "utils.h"
28 #include "options.h"
29 #include "colors.h"
30 #include "strfsong.h"
32 #ifndef NCMPC_MINI
33 #include "hscroll.h"
34 #endif
36 #include <mpd/client.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <stdarg.h>
41 #include <string.h>
42 #include <time.h>
43 #include <locale.h>
45 #ifndef NCMPC_MINI
46 /** welcome message time [s] */
47 static const GTime SCREEN_WELCOME_TIME = 10;
48 #endif
50 /* minimum window size */
51 static const int SCREEN_MIN_COLS = 14;
52 static const int SCREEN_MIN_ROWS = 5;
54 /* screens */
56 #ifndef NCMPC_MINI
57 static gboolean welcome = TRUE;
58 #endif
60 struct screen screen;
61 static const struct screen_functions *mode_fn = &screen_playlist;
62 static const struct screen_functions *mode_fn_prev = &screen_playlist;
63 static int seek_id = -1;
64 static int seek_target_time = 0;
66 gboolean
67 screen_is_visible(const struct screen_functions *sf)
68 {
69         return sf == mode_fn;
70 }
72 void
73 screen_switch(const struct screen_functions *sf, struct mpdclient *c)
74 {
75         assert(sf != NULL);
77         if (sf == mode_fn)
78                 return;
80         mode_fn_prev = mode_fn;
82         /* close the old mode */
83         if (mode_fn->close != NULL)
84                 mode_fn->close();
86         /* get functions for the new mode */
87         mode_fn = sf;
89         /* open the new mode */
90         if (mode_fn->open != NULL)
91                 mode_fn->open(c);
93         screen_paint(c);
94 }
96 void
97 screen_swap(struct mpdclient *c, const struct mpd_song *song)
98 {
99         if (song != NULL)
100         {
101                 if (false)
102                         { /* just a hack to make the ifdefs less ugly */ }
103 #ifdef ENABLE_SONG_SCREEN
104                 if (mode_fn_prev == &screen_song)
105                         screen_song_switch(c, song);
106 #endif
107 #ifdef ENABLE_LYRICS_SCREEN
108                 else if (mode_fn_prev == &screen_lyrics)
109                         screen_lyrics_switch(c, song, true);
110 #endif
111                 else
112                         screen_switch(mode_fn_prev, c);
113         }
114         else
115                 screen_switch(mode_fn_prev, c);
118 static int
119 find_configured_screen(const char *name)
121         unsigned i;
123         for (i = 0; options.screen_list[i] != NULL; ++i)
124                 if (strcmp(options.screen_list[i], name) == 0)
125                         return i;
127         return -1;
130 static void
131 screen_next_mode(mpdclient_t *c, int offset)
133         int max = g_strv_length(options.screen_list);
134         int current, next;
135         const struct screen_functions *sf;
137         /* find current screen */
138         current = find_configured_screen(screen_get_name(mode_fn));
139         next = current + offset;
140         if (next<0)
141                 next = max-1;
142         else if (next>=max)
143                 next = 0;
145         sf = screen_lookup_name(options.screen_list[next]);
146         if (sf != NULL)
147                 screen_switch(sf, c);
150 #ifndef NCMPC_MINI
151 static void
152 print_hotkey(WINDOW *w, command_t cmd, const char *label)
154         colors_use(w, COLOR_TITLE_BOLD);
155         waddstr(w, get_key_names(cmd, FALSE));
156         colors_use(w, COLOR_TITLE);
157         waddch(w, ':');
158         waddstr(w, label);
159         waddch(w, ' ');
160         waddch(w, ' ');
162 #endif
164 static inline int
165 get_volume(const struct mpd_status *status)
167         return status != NULL
168                 ? mpd_status_get_volume(status)
169                 : MPD_STATUS_NO_VOLUME;
172 static void
173 paint_top_window2(const char *header, mpdclient_t *c)
175         int volume;
176         char flags[5];
177         WINDOW *w = screen.top_window.w;
178         char buf[32];
180         if (header[0]) {
181                 colors_use(w, COLOR_TITLE_BOLD);
182                 mvwaddstr(w, 0, 0, header);
183 #ifndef NCMPC_MINI
184         } else {
185 #ifdef ENABLE_HELP_SCREEN
186                 print_hotkey(w, CMD_SCREEN_HELP, _("Help"));
187 #endif
188                 print_hotkey(w, CMD_SCREEN_PLAY, _("Playlist"));
189                 print_hotkey(w, CMD_SCREEN_FILE, _("Browse"));
190 #ifdef ENABLE_ARTIST_SCREEN
191                 print_hotkey(w, CMD_SCREEN_ARTIST, _("Artist"));
192 #endif
193 #ifdef ENABLE_SEARCH_SCREEN
194                 print_hotkey(w, CMD_SCREEN_SEARCH, _("Search"));
195 #endif
196 #ifdef ENABLE_LYRICS_SCREEN
197                 print_hotkey(w, CMD_SCREEN_LYRICS, _("Lyrics"));
198 #endif
199 #ifdef ENABLE_OUTPUTS_SCREEN
200                 print_hotkey(w, CMD_SCREEN_OUTPUTS, _("Outputs"));
201 #endif
202 #endif
203         }
205         volume = get_volume(c->status);
206         if (volume == MPD_STATUS_NO_VOLUME)
207                 g_snprintf(buf, 32, _("Volume n/a"));
208         else
209                 g_snprintf(buf, 32, _("Volume %d%%"), volume);
211         colors_use(w, COLOR_TITLE);
212         mvwaddstr(w, 0, screen.top_window.cols - utf8_width(buf), buf);
214         flags[0] = 0;
215         if (c->status != NULL) {
216                 if (mpd_status_get_repeat(c->status))
217                         g_strlcat(flags, "r", sizeof(flags));
218                 if (mpd_status_get_random(c->status))
219                         g_strlcat(flags, "z", sizeof(flags));
220                 if (mpd_status_get_single(c->status))
221                         g_strlcat(flags, "s", sizeof(flags));
222                 if (mpd_status_get_consume(c->status))
223                         g_strlcat(flags, "c", sizeof(flags));
224                 if (mpd_status_get_crossfade(c->status))
225                         g_strlcat(flags, "x", sizeof(flags));
226                 if (mpd_status_get_update_id(c->status) != 0)
227                         g_strlcat(flags, "U", sizeof(flags));
228         }
230         colors_use(w, COLOR_LINE);
231         mvwhline(w, 1, 0, ACS_HLINE, screen.top_window.cols);
232         if (flags[0]) {
233                 wmove(w,1,screen.top_window.cols-strlen(flags)-3);
234                 waddch(w, '[');
235                 colors_use(w, COLOR_LINE_BOLD);
236                 waddstr(w, flags);
237                 colors_use(w, COLOR_LINE);
238                 waddch(w, ']');
239         }
240         wnoutrefresh(w);
243 static inline int
244 volume_length(int volume)
246         if (volume == 100)
247                 return 3;
248         if (volume >= 10 && volume < 100)
249                 return 2;
250         if (volume >= 0 && volume < 10)
251                 return 1;
252         return -1;
255 static void
256 paint_top_window(const char *header, mpdclient_t *c, int full_repaint)
258         static int prev_volume = -1;
259         static unsigned prev_header_len = -1;
260         WINDOW *w = screen.top_window.w;
262         if (prev_header_len != utf8_width(header)) {
263                 prev_header_len = utf8_width(header);
264                 full_repaint = 1;
265         }
267         if (c->status &&
268             volume_length(prev_volume) !=
269             volume_length(mpd_status_get_volume(c->status)))
270                 full_repaint = 1;
272         if (full_repaint) {
273                 wmove(w, 0, 0);
274                 wclrtoeol(w);
275         }
277         if ((c->status != NULL &&
278              prev_volume != mpd_status_get_volume(c->status)) ||
279             full_repaint)
280                 paint_top_window2(header, c);
283 static void
284 paint_progress_window(mpdclient_t *c)
286         double p;
287         int width;
288         int elapsedTime;
290         if (c->status==NULL || IS_STOPPED(mpd_status_get_state(c->status))) {
291                 mvwhline(screen.progress_window.w, 0, 0, ACS_HLINE,
292                          screen.progress_window.cols);
293                 wnoutrefresh(screen.progress_window.w);
294                 return;
295         }
297         if (c->song != NULL && seek_id == (int)mpd_song_get_id(c->song))
298                 elapsedTime = seek_target_time;
299         else
300                 elapsedTime = mpd_status_get_elapsed_time(c->status);
302         p = ((double) elapsedTime) / ((double) mpd_status_get_total_time(c->status));
304         width = (int) (p * (double) screen.progress_window.cols);
305         mvwhline(screen.progress_window.w,
306                  0, 0,
307                  ACS_HLINE,
308                  screen.progress_window.cols);
309         whline(screen.progress_window.w, '=', width-1);
310         mvwaddch(screen.progress_window.w, 0, width-1, 'O');
311         wnoutrefresh(screen.progress_window.w);
314 static void
315 paint_status_window(mpdclient_t *c)
317         WINDOW *w = screen.status_window.w;
318         const struct mpd_status *status = c->status;
319         enum mpd_state state;
320         const struct mpd_song *song = c->song;
321         int elapsedTime = 0;
322 #ifdef NCMPC_MINI
323         static char bitrate[1];
324 #else
325         char bitrate[16];
326 #endif
327         const char *str = NULL;
328         int x = 0;
330         if( time(NULL) - screen.status_timestamp <= options.status_message_time )
331                 return;
333         wmove(w, 0, 0);
334         wclrtoeol(w);
335         colors_use(w, COLOR_STATUS_BOLD);
337         state = status == NULL ? MPD_STATE_UNKNOWN
338                 : mpd_status_get_state(status);
340         switch (state) {
341         case MPD_STATE_PLAY:
342                 str = _("Playing:");
343                 break;
344         case MPD_STATE_PAUSE:
345                 str = _("[Paused]");
346                 break;
347         case MPD_STATE_STOP:
348         default:
349                 break;
350         }
352         if (str) {
353                 waddstr(w, str);
354                 x += utf8_width(str) + 1;
355         }
357         /* create time string */
358         memset(screen.buf, 0, screen.buf_size);
359         if (IS_PLAYING(state) || IS_PAUSED(state)) {
360                 int total_time = mpd_status_get_total_time(status);
361                 if (total_time > 0) {
362                         /*checks the conf to see whether to display elapsed or remaining time */
363                         if(!strcmp(options.timedisplay_type,"elapsed"))
364                                 elapsedTime = mpd_status_get_elapsed_time(c->status);
365                         else if(!strcmp(options.timedisplay_type,"remaining"))
366                                 elapsedTime = total_time -
367                                         mpd_status_get_elapsed_time(c->status);
369                         if (c->song != NULL &&
370                             seek_id == (int)mpd_song_get_id(c->song))
371                                 elapsedTime = seek_target_time;
373                         /* display bitrate if visible-bitrate is true */
374 #ifndef NCMPC_MINI
375                         if (options.visible_bitrate) {
376                                 g_snprintf(bitrate, 16,
377                                            " [%d kbps]",
378                                            mpd_status_get_kbit_rate(status));
379                         } else {
380                                 bitrate[0] = '\0';
381                         }
382 #endif
384                         /*write out the time, using hours if time over 60 minutes*/
385                         if (total_time > 3600) {
386                                 g_snprintf(screen.buf, screen.buf_size,
387                                            "%s [%i:%02i:%02i/%i:%02i:%02i]",
388                                            bitrate, elapsedTime/3600, (elapsedTime%3600)/60, elapsedTime%60,
389                                            total_time / 3600,
390                                            (total_time % 3600)/60,
391                                            total_time % 60);
392                         } else {
393                                 g_snprintf(screen.buf, screen.buf_size,
394                                            "%s [%i:%02i/%i:%02i]",
395                                            bitrate, elapsedTime/60, elapsedTime%60,
396                                            total_time / 60, total_time % 60);
397                         }
398 #ifndef NCMPC_MINI
399                 } else {
400                         g_snprintf(screen.buf, screen.buf_size,
401                                    " [%d kbps]",
402                                    mpd_status_get_kbit_rate(status));
403 #endif
404                 }
405 #ifndef NCMPC_MINI
406         } else {
407                 if (options.display_time) {
408                         time_t timep;
410                         time(&timep);
411                         strftime(screen.buf, screen.buf_size, "%X ",localtime(&timep));
412                 }
413 #endif
414         }
416         /* display song */
417         if (IS_PLAYING(state) || IS_PAUSED(state)) {
418                 char songname[MAX_SONGNAME_LENGTH];
419 #ifndef NCMPC_MINI
420                 int width = COLS - x - utf8_width(screen.buf);
421 #endif
423                 if (song)
424                         strfsong(songname, MAX_SONGNAME_LENGTH,
425                                  options.status_format, song);
426                 else
427                         songname[0] = '\0';
429                 colors_use(w, COLOR_STATUS);
430                 /* scroll if the song name is to long */
431 #ifndef NCMPC_MINI
432                 if (options.scroll && utf8_width(songname) > (unsigned)width) {
433                         static  scroll_state_t st = { 0, 0 };
434                         char *tmp = strscroll(songname, options.scroll_sep, width, &st);
436                         g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
437                         g_free(tmp);
438                 }
439 #endif
440                 //mvwaddnstr(w, 0, x, songname, width);
441                 mvwaddstr(w, 0, x, songname);
442         }
444         /* display time string */
445         if (screen.buf[0]) {
446                 x = screen.status_window.cols - strlen(screen.buf);
447                 colors_use(w, COLOR_STATUS_TIME);
448                 mvwaddstr(w, 0, x, screen.buf);
449         }
451         wnoutrefresh(w);
454 void
455 screen_exit(void)
457         if (mode_fn->close != NULL)
458                 mode_fn->close();
460         screen_list_exit();
462         string_list_free(screen.find_history);
463         g_free(screen.buf);
464         g_free(screen.findbuf);
466         delwin(screen.top_window.w);
467         delwin(screen.main_window.w);
468         delwin(screen.progress_window.w);
469         delwin(screen.status_window.w);
472 void
473 screen_resize(struct mpdclient *c)
475         if (COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS) {
476                 screen_exit();
477                 fprintf(stderr, "%s", _("Error: Screen too small"));
478                 exit(EXIT_FAILURE);
479         }
481         resizeterm(LINES, COLS);
483         screen.cols = COLS;
484         screen.rows = LINES;
486         /* top window */
487         screen.top_window.cols = screen.cols;
488         wresize(screen.top_window.w, 2, screen.cols);
490         /* main window */
491         screen.main_window.cols = screen.cols;
492         screen.main_window.rows = screen.rows-4;
493         wresize(screen.main_window.w, screen.main_window.rows, screen.cols);
494         wclear(screen.main_window.w);
496         /* progress window */
497         screen.progress_window.cols = screen.cols;
498         wresize(screen.progress_window.w, 1, screen.cols);
499         mvwin(screen.progress_window.w, screen.rows-2, 0);
501         /* status window */
502         screen.status_window.cols = screen.cols;
503         wresize(screen.status_window.w, 1, screen.cols);
504         mvwin(screen.status_window.w, screen.rows-1, 0);
506         screen.buf_size = screen.cols;
507         g_free(screen.buf);
508         screen.buf = g_malloc(screen.cols);
510         /* resize all screens */
511         screen_list_resize(screen.main_window.cols, screen.main_window.rows);
513         /* ? - without this the cursor becomes visible with aterm & Eterm */
514         curs_set(1);
515         curs_set(0);
517         screen_paint(c);
520 void
521 screen_status_message(const char *msg)
523         WINDOW *w = screen.status_window.w;
525         wmove(w, 0, 0);
526         wclrtoeol(w);
527         colors_use(w, COLOR_STATUS_ALERT);
528         waddstr(w, msg);
529         wnoutrefresh(w);
530         screen.status_timestamp = time(NULL);
533 void
534 screen_status_printf(const char *format, ...)
536         char *msg;
537         va_list ap;
539         va_start(ap,format);
540         msg = g_strdup_vprintf(format,ap);
541         va_end(ap);
542         screen_status_message(msg);
543         g_free(msg);
546 void
547 screen_init(mpdclient_t *c)
549         if (COLS < SCREEN_MIN_COLS || LINES < SCREEN_MIN_ROWS) {
550                 fprintf(stderr, "%s\n", _("Error: Screen too small"));
551                 exit(EXIT_FAILURE);
552         }
554         screen.cols = COLS;
555         screen.rows = LINES;
557         screen.buf  = g_malloc(screen.cols);
558         screen.buf_size = screen.cols;
559         screen.findbuf = NULL;
560         screen.start_timestamp = time(NULL);
561         screen.last_cmd = CMD_NONE;
563         /* create top window */
564         screen.top_window.rows = 2;
565         screen.top_window.cols = screen.cols;
566         screen.top_window.w = newwin(screen.top_window.rows,
567                                       screen.top_window.cols,
568                                       0, 0);
569         leaveok(screen.top_window.w, TRUE);
570         keypad(screen.top_window.w, TRUE);
572         /* create main window */
573         screen.main_window.rows = screen.rows-4;
574         screen.main_window.cols = screen.cols;
575         screen.main_window.w = newwin(screen.main_window.rows,
576                                        screen.main_window.cols,
577                                        2,
578                                        0);
580         //  leaveok(screen.main_window.w, TRUE); temporary disabled
581         keypad(screen.main_window.w, TRUE);
583         /* create progress window */
584         screen.progress_window.rows = 1;
585         screen.progress_window.cols = screen.cols;
586         screen.progress_window.w = newwin(screen.progress_window.rows,
587                                            screen.progress_window.cols,
588                                            screen.rows-2,
589                                            0);
590         leaveok(screen.progress_window.w, TRUE);
592         /* create status window */
593         screen.status_window.rows = 1;
594         screen.status_window.cols = screen.cols;
595         screen.status_window.w = newwin(screen.status_window.rows,
596                                          screen.status_window.cols,
597                                          screen.rows-1,
598                                          0);
600         leaveok(screen.status_window.w, FALSE);
601         keypad(screen.status_window.w, TRUE);
603 #ifdef ENABLE_COLORS
604         if (options.enable_colors) {
605                 /* set background attributes */
606                 wbkgd(stdscr, COLOR_PAIR(COLOR_LIST));
607                 wbkgd(screen.main_window.w,     COLOR_PAIR(COLOR_LIST));
608                 wbkgd(screen.top_window.w,      COLOR_PAIR(COLOR_TITLE));
609                 wbkgd(screen.progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
610                 wbkgd(screen.status_window.w,   COLOR_PAIR(COLOR_STATUS));
611                 colors_use(screen.progress_window.w, COLOR_PROGRESSBAR);
612         }
613 #endif
615         refresh();
617         /* initialize screens */
618         screen_list_init(screen.main_window.w,
619                          screen.main_window.cols, screen.main_window.rows);
621         if (mode_fn->open != NULL)
622                 mode_fn->open(c);
625 void
626 screen_paint(mpdclient_t *c)
628         const char *title = NULL;
630         if (mode_fn->get_title != NULL)
631                 title = mode_fn->get_title(screen.buf, screen.buf_size);
633         /* paint the title/header window */
634         if( title )
635                 paint_top_window(title, c, 1);
636         else
637                 paint_top_window("", c, 1);
639         /* paint the bottom window */
641         paint_progress_window(c);
642         paint_status_window(c);
644         /* paint the main window */
646         wclear(screen.main_window.w);
647         if (mode_fn->paint != NULL)
648                 mode_fn->paint();
650         /* move the cursor to the origin */
652         if (!options.hardware_cursor)
653                 wmove(screen.main_window.w, 0, 0);
655         wnoutrefresh(screen.main_window.w);
657         /* tell curses to update */
658         doupdate();
661 void
662 screen_update(mpdclient_t *c)
664 #ifndef NCMPC_MINI
665         static bool initialized = false;
666         static bool repeat;
667         static bool random_enabled;
668         static bool single;
669         static bool consume;
670         static unsigned crossfade;
671         static unsigned dbupdate;
673         /* print a message if mpd status has changed */
674         if (c->status != NULL) {
675                 if (!initialized) {
676                         repeat = mpd_status_get_repeat(c->status);
677                         random_enabled = mpd_status_get_random(c->status);
678                         single = mpd_status_get_single(c->status);
679                         consume = mpd_status_get_consume(c->status);
680                         crossfade = mpd_status_get_crossfade(c->status);
681                         dbupdate = mpd_status_get_update_id(c->status);
682                         initialized = true;
683                 }
685                 if (repeat != mpd_status_get_repeat(c->status))
686                         screen_status_printf(mpd_status_get_repeat(c->status) ?
687                                              _("Repeat mode is on") :
688                                              _("Repeat mode is off"));
690                 if (random_enabled != mpd_status_get_random(c->status))
691                         screen_status_printf(mpd_status_get_random(c->status) ?
692                                              _("Random mode is on") :
693                                              _("Random mode is off"));
695                 if (single != mpd_status_get_single(c->status))
696                         screen_status_printf(mpd_status_get_single(c->status) ?
697                                              /* "single" mode means
698                                                 that MPD will
699                                                 automatically stop
700                                                 after playing one
701                                                 single song */
702                                              _("Single mode is on") :
703                                              _("Single mode is off"));
705                 if (consume != mpd_status_get_consume(c->status))
706                         screen_status_printf(mpd_status_get_consume(c->status) ?
707                                              /* "consume" mode means
708                                                 that MPD removes each
709                                                 song which has
710                                                 finished playing */
711                                              _("Consume mode is on") :
712                                              _("Consume mode is off"));
714                 if (crossfade != mpd_status_get_crossfade(c->status))
715                         screen_status_printf(_("Crossfade %d seconds"),
716                                              mpd_status_get_crossfade(c->status));
718                 if (dbupdate != 0 &&
719                     dbupdate != mpd_status_get_update_id(c->status)) {
720                         screen_status_printf(_("Database updated"));
721                 }
723                 repeat = mpd_status_get_repeat(c->status);
724                 random_enabled = mpd_status_get_random(c->status);
725                 single = mpd_status_get_single(c->status);
726                 consume = mpd_status_get_consume(c->status);
727                 crossfade = mpd_status_get_crossfade(c->status);
728                 dbupdate = mpd_status_get_update_id(c->status);
729         }
731         /* update title/header window */
732         if (welcome && options.welcome_screen_list &&
733             screen.last_cmd==CMD_NONE &&
734             time(NULL)-screen.start_timestamp <= SCREEN_WELCOME_TIME)
735                 paint_top_window("", c, 0);
736         else
737 #endif
738         if (mode_fn->get_title != NULL) {
739                 paint_top_window(mode_fn->get_title(screen.buf,screen.buf_size), c, 0);
740 #ifndef NCMPC_MINI
741                 welcome = FALSE;
742 #endif
743         } else
744                 paint_top_window("", c, 0);
746         /* update progress window */
747         paint_progress_window(c);
749         /* update status window */
750         paint_status_window(c);
752         /* update the main window */
753         if (mode_fn->update != NULL)
754                 mode_fn->update(c);
756         /* move the cursor to the origin */
758         if (!options.hardware_cursor)
759                 wmove(screen.main_window.w, 0, 0);
761         wnoutrefresh(screen.main_window.w);
763         /* tell curses to update */
764         doupdate();
767 void
768 screen_idle(mpdclient_t *c)
770         if (c->song != NULL && seek_id == (int)mpd_song_get_id(c->song) &&
771             (screen.last_cmd == CMD_SEEK_FORWARD ||
772              screen.last_cmd == CMD_SEEK_BACKWARD))
773                 mpdclient_cmd_seek(c, seek_id, seek_target_time);
775         screen.last_cmd = CMD_NONE;
776         seek_id = -1;
779 #ifdef HAVE_GETMOUSE
780 int
781 screen_get_mouse_event(mpdclient_t *c, unsigned long *bstate, int *row)
783         MEVENT event;
785         /* retrieve the mouse event from ncurses */
786         getmouse(&event);
787         /* calculate the selected row in the list window */
788         *row = event.y - screen.top_window.rows;
789         /* copy button state bits */
790         *bstate = event.bstate;
791         /* if button 2 was pressed switch screen */
792         if (event.bstate & BUTTON2_CLICKED) {
793                 screen_cmd(c, CMD_SCREEN_NEXT);
794                 return 1;
795         }
797         return 0;
799 #endif
801 static int
802 screen_client_cmd(mpdclient_t *c, command_t cmd)
804         if (c->connection == NULL || c->status == NULL)
805                 return 0;
807         switch(cmd) {
808                 /*
809         case CMD_PLAY:
810                 mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
811                 break;
812                 */
813         case CMD_PAUSE:
814                 mpdclient_cmd_pause(c, !IS_PAUSED(mpd_status_get_state(c->status)));
815                 break;
816         case CMD_STOP:
817                 mpdclient_cmd_stop(c);
818                 break;
819         case CMD_CROP:
820                 mpdclient_cmd_crop(c);
821                 break;
822         case CMD_SEEK_FORWARD:
823                 if (!IS_STOPPED(mpd_status_get_state(c->status))) {
824                         if (c->song != NULL &&
825                             seek_id != (int)mpd_song_get_id(c->song)) {
826                                 seek_id = mpd_song_get_id(c->song);
827                                 seek_target_time = mpd_status_get_elapsed_time(c->status);
828                         }
829                         seek_target_time+=options.seek_time;
830                         if (seek_target_time < (int)mpd_status_get_total_time(c->status))
831                                 break;
832                         seek_target_time = mpd_status_get_total_time(c->status);
833                         /* seek_target_time=0; */
834                 }
835                 break;
836                 /* fall through... */
837         case CMD_TRACK_NEXT:
838                 if (!IS_STOPPED(mpd_status_get_state(c->status)))
839                         mpdclient_cmd_next(c);
840                 break;
841         case CMD_SEEK_BACKWARD:
842                 if (!IS_STOPPED(mpd_status_get_state(c->status))) {
843                         if (seek_id != (int)mpd_song_get_id(c->song)) {
844                                 seek_id = mpd_song_get_id(c->song);
845                                 seek_target_time = mpd_status_get_elapsed_time(c->status);
846                         }
847                         seek_target_time-=options.seek_time;
848                         if (seek_target_time < 0)
849                                 seek_target_time=0;
850                 }
851                 break;
852         case CMD_TRACK_PREVIOUS:
853                 if (!IS_STOPPED(mpd_status_get_state(c->status)))
854                         mpdclient_cmd_prev(c);
855                 break;
856         case CMD_SHUFFLE:
857                 if (mpdclient_cmd_shuffle(c) == 0)
858                         screen_status_message(_("Shuffled playlist"));
859                 break;
860         case CMD_CLEAR:
861                 if (mpdclient_cmd_clear(c) == 0)
862                         screen_status_message(_("Cleared playlist"));
863                 break;
864         case CMD_REPEAT:
865                 mpdclient_cmd_repeat(c, !mpd_status_get_repeat(c->status));
866                 break;
867         case CMD_RANDOM:
868                 mpdclient_cmd_random(c, !mpd_status_get_random(c->status));
869                 break;
870         case CMD_SINGLE:
871                 mpdclient_cmd_single(c, !mpd_status_get_single(c->status));
872                 break;
873         case CMD_CONSUME:
874                 mpdclient_cmd_consume(c, !mpd_status_get_consume(c->status));
875                 break;
876         case CMD_CROSSFADE:
877                 if (mpd_status_get_crossfade(c->status))
878                         mpdclient_cmd_crossfade(c, 0);
879                 else
880                         mpdclient_cmd_crossfade(c, options.crossfade_time);
881                 break;
882         case CMD_DB_UPDATE:
883                 if (!mpd_status_get_update_id(c->status)) {
884                         if( mpdclient_cmd_db_update(c,NULL)==0 )
885                                 screen_status_printf(_("Database update started"));
886                 } else
887                         screen_status_printf(_("Database update running..."));
888                 break;
889         case CMD_VOLUME_UP:
890                 mpdclient_cmd_volume_up(c);
891                 break;
892         case CMD_VOLUME_DOWN:
893                 mpdclient_cmd_volume_down(c);
894                 break;
896         default:
897                 return 0;
898         }
900         return 1;
903 void
904 screen_cmd(mpdclient_t *c, command_t cmd)
906         screen.last_cmd = cmd;
907 #ifndef NCMPC_MINI
908         welcome = FALSE;
909 #endif
911         if (mode_fn->cmd != NULL && mode_fn->cmd(c, cmd))
912                 return;
914         if (screen_client_cmd(c, cmd))
915                 return;
917         switch(cmd) {
918         case CMD_TOGGLE_FIND_WRAP:
919                 options.find_wrap = !options.find_wrap;
920                 screen_status_printf(options.find_wrap ?
921                                      _("Find mode: Wrapped") :
922                                      _("Find mode: Normal"));
923                 break;
924         case CMD_TOGGLE_AUTOCENTER:
925                 options.auto_center = !options.auto_center;
926                 screen_status_printf(options.auto_center ?
927                                      _("Auto center mode: On") :
928                                      _("Auto center mode: Off"));
929                 break;
930         case CMD_SCREEN_UPDATE:
931                 screen_paint(c);
932                 break;
933         case CMD_SCREEN_PREVIOUS:
934                 screen_next_mode(c, -1);
935                 break;
936         case CMD_SCREEN_NEXT:
937                 screen_next_mode(c, 1);
938                 break;
939         case CMD_SCREEN_PLAY:
940                 screen_switch(&screen_playlist, c);
941                 break;
942         case CMD_SCREEN_FILE:
943                 screen_switch(&screen_browse, c);
944                 break;
945 #ifdef ENABLE_HELP_SCREEN
946         case CMD_SCREEN_HELP:
947                 screen_switch(&screen_help, c);
948                 break;
949 #endif
950 #ifdef ENABLE_SEARCH_SCREEN
951         case CMD_SCREEN_SEARCH:
952                 screen_switch(&screen_search, c);
953                 break;
954 #endif
955 #ifdef ENABLE_ARTIST_SCREEN
956         case CMD_SCREEN_ARTIST:
957                 screen_switch(&screen_artist, c);
958                 break;
959 #endif
960 #ifdef ENABLE_SONG_SCREEN
961         case CMD_SCREEN_SONG:
962                 screen_switch(&screen_song, c);
963                 break;
964 #endif
965 #ifdef ENABLE_KEYDEF_SCREEN
966         case CMD_SCREEN_KEYDEF:
967                 screen_switch(&screen_keydef, c);
968                 break;
969 #endif
970 #ifdef ENABLE_LYRICS_SCREEN
971         case CMD_SCREEN_LYRICS:
972                 screen_switch(&screen_lyrics, c);
973                 break;
974 #endif
975 #ifdef ENABLE_OUTPUTS_SCREEN
976         case CMD_SCREEN_OUTPUTS:
977                 screen_switch(&screen_outputs, c);
978                 break;
979         case CMD_SCREEN_SWAP:
980                 screen_swap(c, NULL);
981                 break;
982 #endif
984         default:
985                 break;
986         }