Code

make several functions return void
[ncmpc.git] / src / screen.c
1 /*
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include "screen.h"
22 #include "screen_utils.h"
23 #include "config.h"
24 #include "ncmpc.h"
25 #include "support.h"
26 #include "mpdclient.h"
27 #include "utils.h"
28 #include "command.h"
29 #include "options.h"
30 #include "colors.h"
31 #include "strfsong.h"
32 #include "wreadln.h"
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <time.h>
39 #include <locale.h>
41 #define SCREEN_PLAYLIST_ID     0
42 #define SCREEN_BROWSE_ID       1
43 #define SCREEN_ARTIST_ID       2
44 #define SCREEN_HELP_ID         100
45 #define SCREEN_KEYDEF_ID       101
46 #define SCREEN_CLOCK_ID        102
47 #define SCREEN_SEARCH_ID       103
48 #define SCREEN_LYRICS_ID           104
52 /* screens */
53 extern const struct screen_functions screen_playlist;
54 extern const struct screen_functions screen_browse;
55 #ifdef ENABLE_ARTIST_SCREEN
56 extern const struct screen_functions screen_artist;
57 #endif
58 extern const struct screen_functions screen_help;
59 #ifdef ENABLE_SEARCH_SCREEN
60 extern const struct screen_functions screen_search;
61 #endif
62 #ifdef ENABLE_KEYDEF_SCREEN
63 extern const struct screen_functions screen_keydef;
64 #endif
65 #ifdef ENABLE_CLOCK_SCREEN
66 extern const struct screen_functions screen_clock;
67 #endif
68 extern const struct screen_functions screen_lyrics;
70 typedef struct screen_functions * (*screen_get_mode_functions_fn_t) (void);
72 static const struct
73 {
74         gint id;
75         const gchar *name;
76         const struct screen_functions *functions;
77 } screens[] = {
78         { SCREEN_PLAYLIST_ID, "playlist", &screen_playlist },
79         { SCREEN_BROWSE_ID, "browse", &screen_browse },
80 #ifdef ENABLE_ARTIST_SCREEN
81         { SCREEN_ARTIST_ID, "artist", &screen_artist },
82 #endif
83         { SCREEN_HELP_ID, "help", &screen_help },
84 #ifdef ENABLE_SEARCH_SCREEN
85         { SCREEN_SEARCH_ID, "search", &screen_search },
86 #endif
87 #ifdef ENABLE_KEYDEF_SCREEN
88         { SCREEN_KEYDEF_ID, "keydef", &screen_keydef },
89 #endif
90 #ifdef ENABLE_CLOCK_SCREEN
91         { SCREEN_CLOCK_ID, "clock", &screen_clock },
92 #endif
93 #ifdef ENABLE_LYRICS_SCREEN
94         { SCREEN_LYRICS_ID, "lyrics", &screen_lyrics },
95 #endif
96 };
98 #define NUM_SCREENS (sizeof(screens) / sizeof(screens[0]))
100 static gboolean welcome = TRUE;
101 static struct screen screen;
102 static const struct screen_functions *mode_fn = &screen_playlist;
103 static int seek_id = -1;
104 static int seek_target_time = 0;
106 gint
107 screen_get_id(const char *name)
109         guint i;
111         for (i = 0; i < NUM_SCREENS; ++i)
112                 if (strcmp(name, screens[i].name) == 0)
113                         return screens[i].id;
115         return -1;
118 static gint
119 lookup_mode(gint id)
121         guint i;
123         for (i = 0; i < NUM_SCREENS; ++i)
124                 if (screens[i].id == id)
125                         return i;
127         return -1;
130 gint get_cur_mode_id(void)
132         return screens[screen.mode].id;
135 static void
136 switch_screen_mode(gint id, mpdclient_t *c)
138         gint new_mode;
140         if( id == screens[screen.mode].id )
141                 return;
143         new_mode = lookup_mode(id);
144         if (new_mode < 0)
145                 return;
147         /* close the old mode */
148         if (mode_fn->close != NULL)
149                 mode_fn->close();
151         /* get functions for the new mode */
152         D("switch_screen(%s)\n", screens[new_mode].name );
153         mode_fn = screens[new_mode].functions;
154         screen.mode = new_mode;
155         screen.painted = 0;
157         /* open the new mode */
158         if (mode_fn->open != NULL)
159                 mode_fn->open(&screen, c);
162 static int
163 find_configured_screen(const char *name)
165         unsigned i;
167         for (i = 0; options.screen_list[i] != NULL; ++i)
168                 if (strcmp(options.screen_list[i], name) == 0)
169                         return i;
171         return -1;
174 static void
175 screen_next_mode(mpdclient_t *c, int offset)
177         int max = g_strv_length(options.screen_list);
178         int current, next;
180         /* find current screen */
181         current = find_configured_screen(screens[screen.mode].name);
182         next = current + offset;
183         if (next<0)
184                 next = max-1;
185         else if (next>=max)
186                 next = 0;
188         D("current mode: %d:%d    next:%d\n", current, max, next);
189         switch_screen_mode(screen_get_id(options.screen_list[next]), c);
192 static void
193 paint_top_window2(const char *header, mpdclient_t *c)
195         char flags[5];
196         WINDOW *w = screen.top_window.w;
197         char buf[32];
199         if (header[0]) {
200                 colors_use(w, COLOR_TITLE_BOLD);
201                 mvwaddstr(w, 0, 0, header);
202         } else {
203                 colors_use(w, COLOR_TITLE_BOLD);
204                 waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE));
205                 colors_use(w, COLOR_TITLE);
206                 waddstr(w, _(":Help  "));
207                 colors_use(w, COLOR_TITLE_BOLD);
208                 waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE));
209                 colors_use(w, COLOR_TITLE);
210                 waddstr(w, _(":Playlist  "));
211                 colors_use(w, COLOR_TITLE_BOLD);
212                 waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE));
213                 colors_use(w, COLOR_TITLE);
214                 waddstr(w, _(":Browse  "));
215 #ifdef ENABLE_ARTIST_SCREEN
216                 colors_use(w, COLOR_TITLE_BOLD);
217                 waddstr(w, get_key_names(CMD_SCREEN_ARTIST, FALSE));
218                 colors_use(w, COLOR_TITLE);
219                 waddstr(w, _(":Artist  "));
220 #endif
221 #ifdef ENABLE_SEARCH_SCREEN
222                 colors_use(w, COLOR_TITLE_BOLD);
223                 waddstr(w, get_key_names(CMD_SCREEN_SEARCH, FALSE));
224                 colors_use(w, COLOR_TITLE);
225                 waddstr(w, _(":Search  "));
226 #endif
227 #ifdef ENABLE_LYRICS_SCREEN
228                 colors_use(w, COLOR_TITLE_BOLD);
229                 waddstr(w, get_key_names(CMD_SCREEN_LYRICS, FALSE));
230                 colors_use(w, COLOR_TITLE);
231                 waddstr(w, _(":Lyrics  "));
232 #endif
233         }
234         if (c->status->volume==MPD_STATUS_NO_VOLUME) {
235                 g_snprintf(buf, 32, _("Volume n/a "));
236         } else {
237                 g_snprintf(buf, 32, _(" Volume %d%%"), c->status->volume);
238         }
239         colors_use(w, COLOR_TITLE);
240         mvwaddstr(w, 0, screen.top_window.cols-my_strlen(buf), buf);
242         flags[0] = 0;
243         if( c->status->repeat )
244                 g_strlcat(flags, "r", sizeof(flags));
245         if( c->status->random )
246                 g_strlcat(flags, "z", sizeof(flags));;
247         if( c->status->crossfade )
248                 g_strlcat(flags, "x", sizeof(flags));
249         if( c->status->updatingDb )
250                 g_strlcat(flags, "U", sizeof(flags));
251         colors_use(w, COLOR_LINE);
252         mvwhline(w, 1, 0, ACS_HLINE, screen.top_window.cols);
253         if (flags[0]) {
254                 wmove(w,1,screen.top_window.cols-strlen(flags)-3);
255                 waddch(w, '[');
256                 colors_use(w, COLOR_LINE_BOLD);
257                 waddstr(w, flags);
258                 colors_use(w, COLOR_LINE);
259                 waddch(w, ']');
260         }
261         wnoutrefresh(w);
264 static void
265 paint_top_window(const char *header, mpdclient_t *c, int full_repaint)
267         static int prev_volume = -1;
268         static size_t prev_header_len = -1;
269         WINDOW *w = screen.top_window.w;
271         if (prev_header_len!=my_strlen(header)) {
272                 prev_header_len = my_strlen(header);
273                 full_repaint = 1;
274         }
276         if (full_repaint) {
277                 wmove(w, 0, 0);
278                 wclrtoeol(w);
279         }
281         if (prev_volume!=c->status->volume || full_repaint)
282                 paint_top_window2(header, c);
285 static void
286 paint_progress_window(mpdclient_t *c)
288         double p;
289         int width;
290         int elapsedTime = c->status->elapsedTime;
292         if (c->status==NULL || IS_STOPPED(c->status->state)) {
293                 mvwhline(screen.progress_window.w, 0, 0, ACS_HLINE,
294                          screen.progress_window.cols);
295                 wnoutrefresh(screen.progress_window.w);
296                 return;
297         }
299         if (c->song && seek_id == c->song->id)
300                 elapsedTime = seek_target_time;
302         p = ((double) elapsedTime) / ((double) c->status->totalTime);
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         mpd_Status *status = c->status;
319         mpd_Song *song = c->song;
320         int elapsedTime = 0;
321         const char *str = NULL;
322         int x = 0;
324         if( time(NULL) - screen.status_timestamp <= SCREEN_STATUS_MESSAGE_TIME )
325                 return;
327         wmove(w, 0, 0);
328         wclrtoeol(w);
329         colors_use(w, COLOR_STATUS_BOLD);
331         switch(status->state) {
332         case MPD_STATUS_STATE_PLAY:
333                 str = _("Playing:");
334                 break;
335         case MPD_STATUS_STATE_PAUSE:
336                 str = _("[Paused]");
337                 break;
338         case MPD_STATUS_STATE_STOP:
339         default:
340                 break;
341         }
343         if (str) {
344                 waddstr(w, str);
345                 x += my_strlen(str)+1;
346         }
348         /* create time string */
349         memset(screen.buf, 0, screen.buf_size);
350         if (IS_PLAYING(status->state) || IS_PAUSED(status->state)) {
351                 if (status->totalTime > 0) {
352                         /*checks the conf to see whether to display elapsed or remaining time */
353                         if(!strcmp(options.timedisplay_type,"elapsed"))
354                                 elapsedTime = c->status->elapsedTime;
355                         else if(!strcmp(options.timedisplay_type,"remaining"))
356                                 elapsedTime = (c->status->totalTime - c->status->elapsedTime);
358                         if( c->song && seek_id == c->song->id )
359                                 elapsedTime = seek_target_time;
360                         /*write out the time, using hours if time over 60 minutes*/
361                         if (c->status->totalTime > 3600) {
362                                 g_snprintf(screen.buf, screen.buf_size,
363                                            " [%i:%02i:%02i/%i:%02i:%02i]",
364                                            elapsedTime/3600, (elapsedTime%3600)/60, elapsedTime%60,
365                                            status->totalTime/3600, (status->totalTime%3600)/60,  status->totalTime%60);
366                         } else {
367                                 g_snprintf(screen.buf, screen.buf_size,
368                                            " [%i:%02i/%i:%02i]",
369                                            elapsedTime/60, elapsedTime%60,
370                                            status->totalTime/60,   status->totalTime%60 );
371                         }
372                 } else {
373                         g_snprintf(screen.buf, screen.buf_size,
374                                    " [%d kbps]", status->bitRate );
375                 }
376         } else {
377                 time_t timep;
379                 time(&timep);
380                 strftime(screen.buf, screen.buf_size, "%X ",localtime(&timep));
381         }
383         /* display song */
384         if (IS_PLAYING(status->state) || IS_PAUSED(status->state)) {
385                 char songname[MAX_SONGNAME_LENGTH];
386                 int width = COLS-x-my_strlen(screen.buf);
388                 if (song)
389                         strfsong(songname, MAX_SONGNAME_LENGTH, STATUS_FORMAT, song);
390                 else
391                         songname[0] = '\0';
393                 colors_use(w, COLOR_STATUS);
394                 /* scroll if the song name is to long */
395                 if (options.scroll && my_strlen(songname) > (size_t)width) {
396                         static  scroll_state_t st = { 0, 0 };
397                         char *tmp = strscroll(songname, options.scroll_sep, width, &st);
399                         g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
400                         g_free(tmp);
401                 }
402                 //mvwaddnstr(w, 0, x, songname, width);
403                 mvwaddstr(w, 0, x, songname);
404         }
406         /* display time string */
407         if (screen.buf[0]) {
408                 x = screen.status_window.cols - strlen(screen.buf);
409                 colors_use(w, COLOR_STATUS_TIME);
410                 mvwaddstr(w, 0, x, screen.buf);
411         }
413         wnoutrefresh(w);
416 void
417 screen_exit(void)
419         guint i;
421         endwin();
423         if (mode_fn->close != NULL)
424                 mode_fn->close();
426         /* close and exit all screens (playlist,browse,help...) */
427         for (i = 0; i < NUM_SCREENS; ++i) {
428                 const struct screen_functions *sf = screens[i].functions;
430                 if (sf->exit)
431                         sf->exit();
432         }
434         string_list_free(screen.find_history);
435         g_free(screen.buf);
436         g_free(screen.findbuf);
439 void
440 screen_resize(void)
442         guint i;
444         D("Resize rows %d->%d, cols %d->%d\n",screen.rows,LINES,screen.cols,COLS);
445         if (COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS) {
446                 screen_exit();
447                 fprintf(stderr, _("Error: Screen to small!\n"));
448                 exit(EXIT_FAILURE);
449         }
451         resizeterm(LINES, COLS);
453         screen.cols = COLS;
454         screen.rows = LINES;
456         /* top window */
457         screen.top_window.cols = screen.cols;
458         wresize(screen.top_window.w, 2, screen.cols);
460         /* main window */
461         screen.main_window.cols = screen.cols;
462         screen.main_window.rows = screen.rows-4;
463         wresize(screen.main_window.w, screen.main_window.rows, screen.cols);
464         wclear(screen.main_window.w);
466         /* progress window */
467         screen.progress_window.cols = screen.cols;
468         wresize(screen.progress_window.w, 1, screen.cols);
469         mvwin(screen.progress_window.w, screen.rows-2, 0);
471         /* status window */
472         screen.status_window.cols = screen.cols;
473         wresize(screen.status_window.w, 1, screen.cols);
474         mvwin(screen.status_window.w, screen.rows-1, 0);
476         screen.buf_size = screen.cols;
477         g_free(screen.buf);
478         screen.buf = g_malloc(screen.cols);
480         /* close and exit all screens (playlist,browse,help...) */
481         for (i = 0; i < NUM_SCREENS; ++i) {
482                 const struct screen_functions *sf = screens[i].functions;
484                 if (sf->resize)
485                         sf->resize(screen.main_window.cols, screen.main_window.rows);
486         }
489         /* ? - without this the cursor becomes visible with aterm & Eterm */
490         curs_set(1);
491         curs_set(0);
493         screen.painted = 0;
496 void
497 screen_status_message(const char *msg)
499         WINDOW *w = screen.status_window.w;
501         wmove(w, 0, 0);
502         wclrtoeol(w);
503         colors_use(w, COLOR_STATUS_ALERT);
504         waddstr(w, msg);
505         wnoutrefresh(w);
506         screen.status_timestamp = time(NULL);
509 void
510 screen_status_printf(const char *format, ...)
512         char *msg;
513         va_list ap;
515         va_start(ap,format);
516         msg = g_strdup_vprintf(format,ap);
517         va_end(ap);
518         screen_status_message(msg);
519         g_free(msg);
522 void
523 ncurses_init(void)
526         /* initialize the curses library */
527         initscr();
528         /* initialize color support */
529         colors_start();
530         /* tell curses not to do NL->CR/NL on output */
531         nonl();
532         /*  use raw mode (ignore interrupt,quit,suspend, and flow control ) */
533 #ifdef ENABLE_RAW_MODE
534         //  raw();
535 #endif
536         /* don't echo input */
537         noecho();
538         /* set cursor invisible */
539         curs_set(0);
540         /* enable extra keys */
541         keypad(stdscr, TRUE);
542         /* return from getch() without blocking */
543         timeout(SCREEN_TIMEOUT);
544         /* initialize mouse support */
545 #ifdef HAVE_GETMOUSE
546         if( options.enable_mouse )
547                 mousemask(ALL_MOUSE_EVENTS, NULL);
548 #endif
550         if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
551                 {
552                         fprintf(stderr, _("Error: Screen to small!\n"));
553                         exit(EXIT_FAILURE);
554                 }
555         screen.mode = 0;
556         screen.cols = COLS;
557         screen.rows = LINES;
559         screen.buf  = g_malloc(screen.cols);
560         screen.buf_size = screen.cols;
561         screen.findbuf = NULL;
562         screen.painted = 0;
563         screen.start_timestamp = time(NULL);
564         screen.input_timestamp = time(NULL);
565         screen.last_cmd = CMD_NONE;
567         /* create top window */
568         screen.top_window.rows = 2;
569         screen.top_window.cols = screen.cols;
570         screen.top_window.w = newwin(screen.top_window.rows,
571                                       screen.top_window.cols,
572                                       0, 0);
573         leaveok(screen.top_window.w, TRUE);
574         keypad(screen.top_window.w, TRUE);
576         /* create main window */
577         screen.main_window.rows = screen.rows-4;
578         screen.main_window.cols = screen.cols;
579         screen.main_window.w = newwin(screen.main_window.rows,
580                                        screen.main_window.cols,
581                                        2,
582                                        0);
584         //  leaveok(screen.main_window.w, TRUE); temporary disabled
585         keypad(screen.main_window.w, TRUE);
587         /* create progress window */
588         screen.progress_window.rows = 1;
589         screen.progress_window.cols = screen.cols;
590         screen.progress_window.w = newwin(screen.progress_window.rows,
591                                            screen.progress_window.cols,
592                                            screen.rows-2,
593                                            0);
594         leaveok(screen.progress_window.w, TRUE);
596         /* create status window */
597         screen.status_window.rows = 1;
598         screen.status_window.cols = screen.cols;
599         screen.status_window.w = newwin(screen.status_window.rows,
600                                          screen.status_window.cols,
601                                          screen.rows-1,
602                                          0);
604         leaveok(screen.status_window.w, FALSE);
605         keypad(screen.status_window.w, TRUE);
607         if( options.enable_colors )
608                 {
609                         /* set background attributes */
610                         wbkgd(stdscr, COLOR_PAIR(COLOR_LIST));
611                         wbkgd(screen.main_window.w,     COLOR_PAIR(COLOR_LIST));
612                         wbkgd(screen.top_window.w,      COLOR_PAIR(COLOR_TITLE));
613                         wbkgd(screen.progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
614                         wbkgd(screen.status_window.w,   COLOR_PAIR(COLOR_STATUS));
615                         colors_use(screen.progress_window.w, COLOR_PROGRESSBAR);
616                 }
618         refresh();
621 void
622 screen_init(mpdclient_t *c)
624         guint i;
626         /* initialize screens */
627         for (i = 0; i < NUM_SCREENS; ++i) {
628                 const struct screen_functions *fn = screens[i].functions;
630                 if (fn->init)
631                         fn->init(screen.main_window.w,
632                                  screen.main_window.cols,
633                                  screen.main_window.rows);
634         }
636         if (mode_fn->open != NULL)
637                 mode_fn->open(&screen, c);
639         /* initialize wreadln */
640         wrln_wgetch = my_wgetch;
641         wrln_max_history_length = 16;
644 void
645 screen_paint(mpdclient_t *c)
647         const char *title = NULL;
649         if (mode_fn->get_title != NULL)
650                 title = mode_fn->get_title(screen.buf, screen.buf_size);
652         D("screen_paint(%s)\n", title);
653         /* paint the title/header window */
654         if( title )
655                 paint_top_window(title, c, 1);
656         else
657                 paint_top_window("", c, 1);
659         /* paint the main window */
660         wclear(screen.main_window.w);
661         if (mode_fn->paint != NULL)
662                 mode_fn->paint(&screen, c);
664         paint_progress_window(c);
665         paint_status_window(c);
666         screen.painted = 1;
667         wmove(screen.main_window.w, 0, 0);
668         wnoutrefresh(screen.main_window.w);
670         /* tell curses to update */
671         doupdate();
674 void
675 screen_update(mpdclient_t *c)
677         static int repeat = -1;
678         static int random_enabled = -1;
679         static int crossfade = -1;
680         static int dbupdate = -1;
682         if( !screen.painted )
683                 return screen_paint(c);
685         /* print a message if mpd status has changed */
686         if (repeat < 0) {
687                 repeat = c->status->repeat;
688                 random_enabled = c->status->random;
689                 crossfade = c->status->crossfade;
690                 dbupdate = c->status->updatingDb;
691         }
693         if (repeat != c->status->repeat)
694                 screen_status_printf(c->status->repeat ?
695                                      _("Repeat is on") :
696                                      _("Repeat is off"));
698         if (random_enabled != c->status->random)
699                 screen_status_printf(c->status->random ?
700                                      _("Random is on") :
701                                      _("Random is off"));
703         if (crossfade != c->status->crossfade)
704                 screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
706         if (dbupdate && dbupdate != c->status->updatingDb) {
707                 screen_status_printf(_("Database updated!"));
708                 mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
709         }
711         repeat = c->status->repeat;
712         random_enabled = c->status->random;
713         crossfade = c->status->crossfade;
714         dbupdate = c->status->updatingDb;
716         /* update title/header window */
717         if (welcome && screen.last_cmd==CMD_NONE &&
718             time(NULL)-screen.start_timestamp <= SCREEN_WELCOME_TIME)
719                 paint_top_window("", c, 0);
720         else if (mode_fn->get_title != NULL) {
721                 paint_top_window(mode_fn->get_title(screen.buf,screen.buf_size), c, 0);
722                 welcome = FALSE;
723         } else
724                 paint_top_window("", c, 0);
726         /* update the main window */
727         if (mode_fn->update != NULL)
728                 mode_fn->update(&screen, c);
730         /* update progress window */
731         paint_progress_window(c);
733         /* update status window */
734         paint_status_window(c);
736         /* move the cursor to the origin */
737         wmove(screen.main_window.w, 0, 0);
738         wnoutrefresh(screen.main_window.w);
740         /* tell curses to update */
741         doupdate();
744 void
745 screen_idle(mpdclient_t *c)
747         if (c->song && seek_id == c->song->id &&
748             (screen.last_cmd == CMD_SEEK_FORWARD ||
749              screen.last_cmd == CMD_SEEK_BACKWARD))
750                 mpdclient_cmd_seek(c, seek_id, seek_target_time);
752         screen.last_cmd = CMD_NONE;
753         seek_id = -1;
756 #ifdef HAVE_GETMOUSE
757 int
758 screen_get_mouse_event(mpdclient_t *c,
759                        list_window_t *lw, int lw_length,
760                        unsigned long *bstate, int *row)
762         MEVENT event;
764         /* retreive the mouse event from ncurses */
765         getmouse(&event);
766         D("mouse: id=%d  y=%d,x=%d,z=%d\n",event.id,event.y,event.x,event.z);
767         /* calculate the selected row in the list window */
768         *row = event.y - screen.top_window.rows;
769         /* copy button state bits */
770         *bstate = event.bstate;
771         /* if button 2 was pressed switch screen */
772         if (event.bstate & BUTTON2_CLICKED) {
773                 screen_cmd(c, CMD_SCREEN_NEXT);
774                 return 1;
775         }
777         /* if the even occured above the list window move up */
778         if (*row < 0 && lw) {
779                 if (event.bstate & BUTTON3_CLICKED)
780                         list_window_first(lw);
781                 else
782                         list_window_previous_page(lw);
783                 return 1;
784         }
786         /* if the even occured below the list window move down */
787         if ((unsigned)*row >= lw->rows && lw) {
788                 if (event.bstate & BUTTON3_CLICKED)
789                         list_window_last(lw, lw_length);
790                 else
791                         list_window_next_page(lw, lw_length);
792                 return 1;
793         }
795         return 0;
797 #endif
799 void
800 screen_cmd(mpdclient_t *c, command_t cmd)
802         screen.input_timestamp = time(NULL);
803         screen.last_cmd = cmd;
804         welcome = FALSE;
806         if (mode_fn->cmd != NULL && mode_fn->cmd(&screen, c, cmd))
807                 return;
809         switch(cmd) {
810         case CMD_PLAY:
811                 mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
812                 break;
813         case CMD_PAUSE:
814                 mpdclient_cmd_pause(c, !IS_PAUSED(c->status->state));
815                 break;
816         case CMD_STOP:
817                 mpdclient_cmd_stop(c);
818                 break;
819         case CMD_SEEK_FORWARD:
820                 if (!IS_STOPPED(c->status->state)) {
821                         if (c->song && seek_id != c->song->id) {
822                                 seek_id = c->song->id;
823                                 seek_target_time = c->status->elapsedTime;
824                         }
825                         seek_target_time+=options.seek_time;
826                         if (seek_target_time < c->status->totalTime)
827                                 break;
828                         seek_target_time = c->status->totalTime;
829                         /* seek_target_time=0; */
830                 }
831                 break;
832                 /* fall through... */
833         case CMD_TRACK_NEXT:
834                 if (!IS_STOPPED(c->status->state))
835                         mpdclient_cmd_next(c);
836                 break;
837         case CMD_SEEK_BACKWARD:
838                 if (!IS_STOPPED(c->status->state)) {
839                         if (seek_id != c->song->id) {
840                                 seek_id = c->song->id;
841                                 seek_target_time = c->status->elapsedTime;
842                         }
843                         seek_target_time-=options.seek_time;
844                         if (seek_target_time < 0)
845                                 seek_target_time=0;
846                 }
847                 break;
848         case CMD_TRACK_PREVIOUS:
849                 if (!IS_STOPPED(c->status->state))
850                         mpdclient_cmd_prev(c);
851                 break;
852         case CMD_SHUFFLE:
853                 if (mpdclient_cmd_shuffle(c) == 0)
854                         screen_status_message(_("Shuffled playlist!"));
855                 break;
856         case CMD_CLEAR:
857                 if (mpdclient_cmd_clear(c) == 0)
858                         screen_status_message(_("Cleared playlist!"));
859                 break;
860         case CMD_REPEAT:
861                 mpdclient_cmd_repeat(c, !c->status->repeat);
862                 break;
863         case CMD_RANDOM:
864                 mpdclient_cmd_random(c, !c->status->random);
865                 break;
866         case CMD_CROSSFADE:
867                 if (c->status->crossfade)
868                         mpdclient_cmd_crossfade(c, 0);
869                 else
870                         mpdclient_cmd_crossfade(c, options.crossfade_time);
871                 break;
872         case CMD_DB_UPDATE:
873                 if (!c->status->updatingDb) {
874                         if( mpdclient_cmd_db_update_utf8(c,NULL)==0 )
875                                 screen_status_printf(_("Database update started!"));
876                 } else
877                         screen_status_printf(_("Database update running..."));
878                 break;
879         case CMD_VOLUME_UP:
880                 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
881                         mpdclient_cmd_volume(c, ++c->status->volume);
882                 break;
883         case CMD_VOLUME_DOWN:
884                 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
885                         mpdclient_cmd_volume(c, --c->status->volume);
886                 break;
887         case CMD_TOGGLE_FIND_WRAP:
888                 options.find_wrap = !options.find_wrap;
889                 screen_status_printf(options.find_wrap ?
890                                      _("Find mode: Wrapped") :
891                                      _("Find mode: Normal"));
892                 break;
893         case CMD_TOGGLE_AUTOCENTER:
894                 options.auto_center = !options.auto_center;
895                 screen_status_printf(options.auto_center ?
896                                      _("Auto center mode: On") :
897                                      _("Auto center mode: Off"));
898                 break;
899         case CMD_SCREEN_UPDATE:
900                 screen.painted = 0;
901                 break;
902         case CMD_SCREEN_PREVIOUS:
903                 screen_next_mode(c, -1);
904                 break;
905         case CMD_SCREEN_NEXT:
906                 screen_next_mode(c, 1);
907                 break;
908         case CMD_SCREEN_PLAY:
909                 switch_screen_mode(SCREEN_PLAYLIST_ID, c);
910                 break;
911         case CMD_SCREEN_FILE:
912                 switch_screen_mode(SCREEN_BROWSE_ID, c);
913                 break;
914         case CMD_SCREEN_HELP:
915                 switch_screen_mode(SCREEN_HELP_ID, c);
916                 break;
917         case CMD_SCREEN_SEARCH:
918                 switch_screen_mode(SCREEN_SEARCH_ID, c);
919                 break;
920         case CMD_SCREEN_ARTIST:
921                 switch_screen_mode(SCREEN_ARTIST_ID, c);
922                 break;
923         case CMD_SCREEN_KEYDEF:
924                 switch_screen_mode(SCREEN_KEYDEF_ID, c);
925                 break;
926         case CMD_SCREEN_CLOCK:
927                 switch_screen_mode(SCREEN_CLOCK_ID, c);
928                 break;
929         case CMD_SCREEN_LYRICS:
930                 switch_screen_mode(SCREEN_LYRICS_ID, c);
931                 break;
932         case CMD_QUIT:
933                 exit(EXIT_SUCCESS);
934         default:
935                 break;
936         }