Code

fix function prototypes
[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 <stdlib.h>
22 #include <unistd.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <time.h>
26 #include <locale.h>
27 #include <glib.h>
28 #include <ncurses.h>
30 #include "config.h"
31 #include "ncmpc.h"
32 #include "support.h"
33 #include "mpdclient.h"
34 #include "utils.h"
35 #include "command.h"
36 #include "options.h"
37 #include "colors.h"
38 #include "strfsong.h"
39 #include "wreadln.h"
40 #include "screen.h"
41 #include "screen_utils.h"
44 #define SCREEN_PLAYLIST_ID     0
45 #define SCREEN_BROWSE_ID       1
46 #define SCREEN_ARTIST_ID       2
47 #define SCREEN_HELP_ID         100
48 #define SCREEN_KEYDEF_ID       101
49 #define SCREEN_CLOCK_ID        102
50 #define SCREEN_SEARCH_ID       103
51 #define SCREEN_LYRICS_ID           104
55 /* screens */
56 extern screen_functions_t *get_screen_playlist(void);
57 extern screen_functions_t *get_screen_browse(void);
58 extern screen_functions_t *get_screen_help(void);
59 extern screen_functions_t *get_screen_search(void);
60 extern screen_functions_t *get_screen_artist(void);
61 extern screen_functions_t *get_screen_keydef(void);
62 extern screen_functions_t *get_screen_clock(void);
63 extern screen_functions_t *get_screen_lyrics(void);
65 typedef screen_functions_t * (*screen_get_mode_functions_fn_t) (void);
67 typedef struct
68 {
69         gint id;
70         const gchar *name;
71         screen_get_mode_functions_fn_t get_mode_functions;
72 } screen_mode_info_t;
75 static screen_mode_info_t screens[] = {
76         { SCREEN_PLAYLIST_ID, "playlist", get_screen_playlist },
77         { SCREEN_BROWSE_ID,   "browse",   get_screen_browse },
78 #ifdef ENABLE_ARTIST_SCREEN
79         { SCREEN_ARTIST_ID,   "artist",   get_screen_artist },
80 #endif
81         { SCREEN_HELP_ID,     "help",     get_screen_help },
82 #ifdef ENABLE_SEARCH_SCREEN
83         { SCREEN_SEARCH_ID,   "search",   get_screen_search },
84 #endif
85 #ifdef ENABLE_KEYDEF_SCREEN
86         { SCREEN_KEYDEF_ID,   "keydef",   get_screen_keydef },
87 #endif
88 #ifdef ENABLE_CLOCK_SCREEN
89         { SCREEN_CLOCK_ID,    "clock",    get_screen_clock },
90 #endif
91 #ifdef ENABLE_LYRICS_SCREEN
92         { SCREEN_LYRICS_ID,    "lyrics",    get_screen_lyrics },
93 #endif
94         { G_MAXINT, NULL,      NULL }
95 };
97 static gboolean welcome = TRUE;
98 static screen_t *screen = NULL;
99 static screen_functions_t *mode_fn = NULL;
100 static int seek_id = -1;
101 static int seek_target_time = 0;
103 gint
104 screen_get_id(const char *name)
106         gint i=0;
108         while (screens[i].name) {
109                 if (strcmp(name, screens[i].name) == 0)
110                         return screens[i].id;
111                 i++;
112         }
113         return -1;
116 static gint
117 lookup_mode(gint id)
119         gint i=0;
121         while (screens[i].name) {
122                 if (screens[i].id == id)
123                         return i;
124                 i++;
125         }
126         return -1;
129 gint get_cur_mode_id(void)
131         return screens[screen->mode].id;
134 static void
135 switch_screen_mode(gint id, mpdclient_t *c)
137         gint new_mode;
139         if( id == screens[screen->mode].id )
140                 return;
142         /* close the old mode */
143         if( mode_fn && mode_fn->close )
144                 mode_fn->close();
146         /* get functions for the new mode */
147         new_mode = lookup_mode(id);
148         if (new_mode>=0 && screens[new_mode].get_mode_functions) {
149                 D("switch_screen(%s)\n", screens[new_mode].name );
150                 mode_fn = screens[new_mode].get_mode_functions();
151                 screen->mode = new_mode;
152         }
154         screen->painted = 0;
156         /* open the new mode */
157         if (mode_fn && mode_fn->open)
158                 mode_fn->open(screen, c);
161 static void
162 screen_next_mode(mpdclient_t *c, int offset)
164         int max = g_strv_length(options.screen_list);
165         int current, next;
166         int i;
168         /* find current screen */
169         current = -1;
170         i = 0;
171         while (options.screen_list[i]) {
172                 if (strcmp(options.screen_list[i],
173                            screens[screen->mode].name) == 0)
174                         current = i;
175                 i++;
176         }
178         next = current + offset;
179         if (next<0)
180                 next = max-1;
181         else if (next>=max)
182                 next = 0;
184         D("current mode: %d:%d    next:%d\n", current, max, next);
185         switch_screen_mode(screen_get_id(options.screen_list[next]), c);
188 static void
189 paint_top_window2(const char *header, mpdclient_t *c)
191         char flags[5];
192         WINDOW *w = screen->top_window.w;
193         char buf[32];
195         if (header[0]) {
196                 colors_use(w, COLOR_TITLE_BOLD);
197                 mvwaddstr(w, 0, 0, header);
198         } else {
199                 colors_use(w, COLOR_TITLE_BOLD);
200                 waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE));
201                 colors_use(w, COLOR_TITLE);
202                 waddstr(w, _(":Help  "));
203                 colors_use(w, COLOR_TITLE_BOLD);
204                 waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE));
205                 colors_use(w, COLOR_TITLE);
206                 waddstr(w, _(":Playlist  "));
207                 colors_use(w, COLOR_TITLE_BOLD);
208                 waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE));
209                 colors_use(w, COLOR_TITLE);
210                 waddstr(w, _(":Browse  "));
211 #ifdef ENABLE_ARTIST_SCREEN
212                 colors_use(w, COLOR_TITLE_BOLD);
213                 waddstr(w, get_key_names(CMD_SCREEN_ARTIST, FALSE));
214                 colors_use(w, COLOR_TITLE);
215                 waddstr(w, _(":Artist  "));
216 #endif
217 #ifdef ENABLE_SEARCH_SCREEN
218                 colors_use(w, COLOR_TITLE_BOLD);
219                 waddstr(w, get_key_names(CMD_SCREEN_SEARCH, FALSE));
220                 colors_use(w, COLOR_TITLE);
221                 waddstr(w, _(":Search  "));
222 #endif
223 #ifdef ENABLE_LYRICS_SCREEN
224                 colors_use(w, COLOR_TITLE_BOLD);
225                 waddstr(w, get_key_names(CMD_SCREEN_LYRICS, FALSE));
226                 colors_use(w, COLOR_TITLE);
227                 waddstr(w, _(":Lyrics  "));
228 #endif
229         }
230         if (c->status->volume==MPD_STATUS_NO_VOLUME) {
231                 g_snprintf(buf, 32, _("Volume n/a "));
232         } else {
233                 g_snprintf(buf, 32, _(" Volume %d%%"), c->status->volume);
234         }
235         colors_use(w, COLOR_TITLE);
236         mvwaddstr(w, 0, screen->top_window.cols-my_strlen(buf), buf);
238         flags[0] = 0;
239         if( c->status->repeat )
240                 g_strlcat(flags, "r", sizeof(flags));
241         if( c->status->random )
242                 g_strlcat(flags, "z", sizeof(flags));;
243         if( c->status->crossfade )
244                 g_strlcat(flags, "x", sizeof(flags));
245         if( c->status->updatingDb )
246                 g_strlcat(flags, "U", sizeof(flags));
247         colors_use(w, COLOR_LINE);
248         mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
249         if (flags[0]) {
250                 wmove(w,1,screen->top_window.cols-strlen(flags)-3);
251                 waddch(w, '[');
252                 colors_use(w, COLOR_LINE_BOLD);
253                 waddstr(w, flags);
254                 colors_use(w, COLOR_LINE);
255                 waddch(w, ']');
256         }
257         wnoutrefresh(w);
260 static void
261 paint_top_window(const char *header, mpdclient_t *c, int clear)
263         static int prev_volume = -1;
264         static int prev_header_len = -1;
265         WINDOW *w = screen->top_window.w;
267         if (prev_header_len!=my_strlen(header)) {
268                 prev_header_len = my_strlen(header);
269                 clear = 1;
270         }
272         if (clear) {
273                 wmove(w, 0, 0);
274                 wclrtoeol(w);
275         }
277         if (prev_volume!=c->status->volume || clear)
278                 paint_top_window2(header, c);
281 static void
282 paint_progress_window(mpdclient_t *c)
284         double p;
285         int width;
286         int elapsedTime = c->status->elapsedTime;
288         if (c->status==NULL || IS_STOPPED(c->status->state)) {
289                 mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE,
290                          screen->progress_window.cols);
291                 wnoutrefresh(screen->progress_window.w);
292                 return;
293         }
295         if (c->song && seek_id == c->song->id)
296                 elapsedTime = seek_target_time;
298         p = ((double) elapsedTime) / ((double) c->status->totalTime);
300         width = (int) (p * (double) screen->progress_window.cols);
301         mvwhline(screen->progress_window.w,
302                  0, 0,
303                  ACS_HLINE,
304                  screen->progress_window.cols);
305         whline(screen->progress_window.w, '=', width-1);
306         mvwaddch(screen->progress_window.w, 0, width-1, 'O');
307         wnoutrefresh(screen->progress_window.w);
310 static void
311 paint_status_window(mpdclient_t *c)
313         WINDOW *w = screen->status_window.w;
314         mpd_Status *status = c->status;
315         mpd_Song *song = c->song;
316         int elapsedTime = 0;
317         const char *str = NULL;
318         int x = 0;
320         if( time(NULL) - screen->status_timestamp <= SCREEN_STATUS_MESSAGE_TIME )
321                 return;
323         wmove(w, 0, 0);
324         wclrtoeol(w);
325         colors_use(w, COLOR_STATUS_BOLD);
327         switch(status->state) {
328         case MPD_STATUS_STATE_PLAY:
329                 str = _("Playing:");
330                 break;
331         case MPD_STATUS_STATE_PAUSE:
332                 str = _("[Paused]");
333                 break;
334         case MPD_STATUS_STATE_STOP:
335         default:
336                 break;
337         }
339         if (str) {
340                 waddstr(w, str);
341                 x += my_strlen(str)+1;
342         }
344         /* create time string */
345         memset(screen->buf, 0, screen->buf_size);
346         if (IS_PLAYING(status->state) || IS_PAUSED(status->state)) {
347                 if (status->totalTime > 0) {
348                         /*checks the conf to see whether to display elapsed or remaining time */
349                         if(!strcmp(options.timedisplay_type,"elapsed"))
350                                 elapsedTime = c->status->elapsedTime;
351                         else if(!strcmp(options.timedisplay_type,"remaining"))
352                                 elapsedTime = (c->status->totalTime - c->status->elapsedTime);
354                         if( c->song && seek_id == c->song->id )
355                                 elapsedTime = seek_target_time;
356                         /*write out the time, using hours if time over 60 minutes*/
357                         if (c->status->totalTime > 3600) {
358                                 g_snprintf(screen->buf, screen->buf_size,
359                                            " [%i:%02i:%02i/%i:%02i:%02i]",
360                                            elapsedTime/3600, (elapsedTime%3600)/60, elapsedTime%60,
361                                            status->totalTime/3600, (status->totalTime%3600)/60,  status->totalTime%60);
362                         } else {
363                                 g_snprintf(screen->buf, screen->buf_size,
364                                            " [%i:%02i/%i:%02i]",
365                                            elapsedTime/60, elapsedTime%60,
366                                            status->totalTime/60,   status->totalTime%60 );
367                         }
368                 } else {
369                         g_snprintf(screen->buf, screen->buf_size,
370                                    " [%d kbps]", status->bitRate );
371                 }
372         } else {
373                 time_t timep;
375                 time(&timep);
376                 strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
377         }
379         /* display song */
380         if (IS_PLAYING(status->state) || IS_PAUSED(status->state)) {
381                 char songname[MAX_SONGNAME_LENGTH];
382                 int width = COLS-x-my_strlen(screen->buf);
384                 if (song)
385                         strfsong(songname, MAX_SONGNAME_LENGTH, STATUS_FORMAT, song);
386                 else
387                         songname[0] = '\0';
389                 colors_use(w, COLOR_STATUS);
390                 /* scroll if the song name is to long */
391                 if (options.scroll && my_strlen(songname) > width) {
392                         static  scroll_state_t st = { 0, 0 };
393                         char *tmp = strscroll(songname, options.scroll_sep, width, &st);
395                         g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
396                         g_free(tmp);
397                 }
398                 //mvwaddnstr(w, 0, x, songname, width);
399                 mvwaddstr(w, 0, x, songname);
400         }
402         /* display time string */
403         if (screen->buf[0]) {
404                 x = screen->status_window.cols - strlen(screen->buf);
405                 colors_use(w, COLOR_STATUS_TIME);
406                 mvwaddstr(w, 0, x, screen->buf);
407         }
409         wnoutrefresh(w);
412 int
413 screen_exit(void)
415         endwin();
416         if (screen) {
417                 gint i;
419                 /* close and exit all screens (playlist,browse,help...) */
420                 i=0;
421                 while (screens[i].get_mode_functions) {
422                         screen_functions_t *mode_fn = screens[i].get_mode_functions();
424                         if (mode_fn && mode_fn->close)
425                                 mode_fn->close();
426                         if (mode_fn && mode_fn->exit)
427                                 mode_fn->exit();
429                         i++;
430                 }
432                 string_list_free(screen->find_history);
433                 g_free(screen->buf);
434                 g_free(screen->findbuf);
436                 g_free(screen);
437                 screen = NULL;
438         }
439         return 0;
442 void
443 screen_resize(void)
445         gint i;
447         D("Resize rows %d->%d, cols %d->%d\n",screen->rows,LINES,screen->cols,COLS);
448         if (COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS) {
449                 screen_exit();
450                 fprintf(stderr, _("Error: Screen to small!\n"));
451                 exit(EXIT_FAILURE);
452         }
454         resizeterm(LINES, COLS);
456         screen->cols = COLS;
457         screen->rows = LINES;
459         /* top window */
460         screen->top_window.cols = screen->cols;
461         wresize(screen->top_window.w, 2, screen->cols);
463         /* main window */
464         screen->main_window.cols = screen->cols;
465         screen->main_window.rows = screen->rows-4;
466         wresize(screen->main_window.w, screen->main_window.rows, screen->cols);
467         wclear(screen->main_window.w);
469         /* progress window */
470         screen->progress_window.cols = screen->cols;
471         wresize(screen->progress_window.w, 1, screen->cols);
472         mvwin(screen->progress_window.w, screen->rows-2, 0);
474         /* status window */
475         screen->status_window.cols = screen->cols;
476         wresize(screen->status_window.w, 1, screen->cols);
477         mvwin(screen->status_window.w, screen->rows-1, 0);
479         screen->buf_size = screen->cols;
480         g_free(screen->buf);
481         screen->buf = g_malloc(screen->cols);
483         /* close and exit all screens (playlist,browse,help...) */
484         i=0;
485         while (screens[i].get_mode_functions) {
486                 screen_functions_t *mode_fn = screens[i].get_mode_functions();
488                 if (mode_fn && mode_fn->resize)
489                         mode_fn->resize(screen->main_window.cols, screen->main_window.rows);
491                 i++;
492         }
494         /* ? - without this the cursor becomes visible with aterm & Eterm */
495         curs_set(1);
496         curs_set(0);
498         screen->painted = 0;
501 void
502 screen_status_message(const char *msg)
504         WINDOW *w = screen->status_window.w;
506         wmove(w, 0, 0);
507         wclrtoeol(w);
508         colors_use(w, COLOR_STATUS_ALERT);
509         waddstr(w, msg);
510         wnoutrefresh(w);
511         screen->status_timestamp = time(NULL);
514 void
515 screen_status_printf(const char *format, ...)
517         char *msg;
518         va_list ap;
520         va_start(ap,format);
521         msg = g_strdup_vprintf(format,ap);
522         va_end(ap);
523         screen_status_message(msg);
524         g_free(msg);
527 void
528 ncurses_init(void)
531         /* initialize the curses library */
532         initscr();
533         /* initialize color support */
534         colors_start();
535         /* tell curses not to do NL->CR/NL on output */
536         nonl();
537         /*  use raw mode (ignore interrupt,quit,suspend, and flow control ) */
538 #ifdef ENABLE_RAW_MODE
539         //  raw();
540 #endif
541         /* don't echo input */
542         noecho();
543         /* set cursor invisible */
544         curs_set(0);
545         /* enable extra keys */
546         keypad(stdscr, TRUE);
547         /* return from getch() without blocking */
548         timeout(SCREEN_TIMEOUT);
549         /* initialize mouse support */
550 #ifdef HAVE_GETMOUSE
551         if( options.enable_mouse )
552                 mousemask(ALL_MOUSE_EVENTS, NULL);
553 #endif
555         if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
556                 {
557                         fprintf(stderr, _("Error: Screen to small!\n"));
558                         exit(EXIT_FAILURE);
559                 }
560         screen = g_malloc(sizeof(screen_t));
561         memset(screen, 0, sizeof(screen_t));
562         screen->mode = 0;
563         screen->cols = COLS;
564         screen->rows = LINES;
566         screen->buf  = g_malloc(screen->cols);
567         screen->buf_size = screen->cols;
568         screen->findbuf = NULL;
569         screen->painted = 0;
570         screen->start_timestamp = time(NULL);
571         screen->input_timestamp = time(NULL);
572         screen->last_cmd = CMD_NONE;
574         /* create top window */
575         screen->top_window.rows = 2;
576         screen->top_window.cols = screen->cols;
577         screen->top_window.w = newwin(screen->top_window.rows,
578                                       screen->top_window.cols,
579                                       0, 0);
580         leaveok(screen->top_window.w, TRUE);
581         keypad(screen->top_window.w, TRUE);
583         /* create main window */
584         screen->main_window.rows = screen->rows-4;
585         screen->main_window.cols = screen->cols;
586         screen->main_window.w = newwin(screen->main_window.rows,
587                                        screen->main_window.cols,
588                                        2,
589                                        0);
591         //  leaveok(screen->main_window.w, TRUE); temporary disabled
592         keypad(screen->main_window.w, TRUE);
594         /* create progress window */
595         screen->progress_window.rows = 1;
596         screen->progress_window.cols = screen->cols;
597         screen->progress_window.w = newwin(screen->progress_window.rows,
598                                            screen->progress_window.cols,
599                                            screen->rows-2,
600                                            0);
601         leaveok(screen->progress_window.w, TRUE);
603         /* create status window */
604         screen->status_window.rows = 1;
605         screen->status_window.cols = screen->cols;
606         screen->status_window.w = newwin(screen->status_window.rows,
607                                          screen->status_window.cols,
608                                          screen->rows-1,
609                                          0);
611         leaveok(screen->status_window.w, FALSE);
612         keypad(screen->status_window.w, TRUE);
614         if( options.enable_colors )
615                 {
616                         /* set background attributes */
617                         wbkgd(stdscr, COLOR_PAIR(COLOR_LIST));
618                         wbkgd(screen->main_window.w,     COLOR_PAIR(COLOR_LIST));
619                         wbkgd(screen->top_window.w,      COLOR_PAIR(COLOR_TITLE));
620                         wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
621                         wbkgd(screen->status_window.w,   COLOR_PAIR(COLOR_STATUS));
622                         colors_use(screen->progress_window.w, COLOR_PROGRESSBAR);
623                 }
626 int
627 screen_init(mpdclient_t *c)
629         gint i;
631         /* initialize screens */
632         i=0;
633         while( screens[i].get_mode_functions )
634                 {
635                         screen_functions_t *fn = screens[i].get_mode_functions();
637                         if( fn && fn->init )
638                                 fn->init(screen->main_window.w,
639                                          screen->main_window.cols,
640                                          screen->main_window.rows);
642                         i++;
643                 }
645 #if 0
646         /* broken */
647         mode_fn = NULL;
648         switch_screen_mode(screen_get_id(options.screen_list[0]), c);
649 #else
650         mode_fn = get_screen_playlist();
651 #endif
653         if( mode_fn && mode_fn->open )
654                 mode_fn->open(screen, c);
656         /* initialize wreadln */
657         wrln_wgetch = my_wgetch;
658         wrln_max_history_length = 16;
660         return 0;
663 void
664 screen_paint(mpdclient_t *c)
666         const char *title = NULL;
668         if (mode_fn && mode_fn->get_title)
669                 title = mode_fn->get_title(screen->buf, screen->buf_size);
671         D("screen_paint(%s)\n", title);
672         /* paint the title/header window */
673         if( title )
674                 paint_top_window(title, c, 1);
675         else
676                 paint_top_window("", c, 1);
678         /* paint the main window */
679         wclear(screen->main_window.w);
680         if( mode_fn && mode_fn->paint )
681                 mode_fn->paint(screen, c);
683         paint_progress_window(c);
684         paint_status_window(c);
685         screen->painted = 1;
686         wmove(screen->main_window.w, 0, 0);
687         wnoutrefresh(screen->main_window.w);
689         /* tell curses to update */
690         doupdate();
693 void
694 screen_update(mpdclient_t *c)
696         static int repeat = -1;
697         static int random = -1;
698         static int crossfade = -1;
699         static int dbupdate = -1;
700         list_window_t *lw = NULL;
702         if( !screen->painted )
703                 return screen_paint(c);
705         /* print a message if mpd status has changed */
706         if (repeat < 0) {
707                 repeat = c->status->repeat;
708                 random = c->status->random;
709                 crossfade = c->status->crossfade;
710                 dbupdate = c->status->updatingDb;
711         }
713         if (repeat != c->status->repeat)
714                 screen_status_printf(c->status->repeat ?
715                                      _("Repeat is on") :
716                                      _("Repeat is off"));
718         if (random != c->status->random)
719                 screen_status_printf(c->status->random ?
720                                      _("Random is on") :
721                                      _("Random is off"));
723         if (crossfade != c->status->crossfade)
724                 screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
726         if (dbupdate && dbupdate != c->status->updatingDb) {
727                 screen_status_printf(_("Database updated!"));
728                 mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
729         }
731         repeat = c->status->repeat;
732         random = c->status->random;
733         crossfade = c->status->crossfade;
734         dbupdate = c->status->updatingDb;
736         /* update title/header window */
737         if (welcome && screen->last_cmd==CMD_NONE &&
738             time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME)
739                 paint_top_window("", c, 0);
740         else if (mode_fn && mode_fn->get_title) {
741                 paint_top_window(mode_fn->get_title(screen->buf,screen->buf_size), c, 0);
742                 welcome = FALSE;
743         } else
744                 paint_top_window("", c, 0);
746         /* update the main window */
747         if (mode_fn && mode_fn->paint)
748                 mode_fn->update(screen, c);
750         if (mode_fn && mode_fn->get_lw)
751                 lw = mode_fn->get_lw();
753         /* update progress window */
754         paint_progress_window(c);
756         /* update status window */
757         paint_status_window(c);
759         /* move the cursor to the selected row in the main window */
760         if (lw)
761                 wmove(screen->main_window.w, LW_ROW(lw), 0);
762         else
763                 wmove(screen->main_window.w, 0, 0);
764         wnoutrefresh(screen->main_window.w);
766         /* tell curses to update */
767         doupdate();
770 void
771 screen_idle(mpdclient_t *c)
773         if( c->song && seek_id ==  c->song->id &&
774             (screen->last_cmd == CMD_SEEK_FORWARD ||
775              screen->last_cmd == CMD_SEEK_BACKWARD) )
776                 {
777                         mpdclient_cmd_seek(c, seek_id, seek_target_time);
778                 }
780         screen->last_cmd = CMD_NONE;
781         seek_id = -1;
784 #ifdef HAVE_GETMOUSE
785 int
786 screen_get_mouse_event(mpdclient_t *c,
787                        list_window_t *lw, int lw_length,
788                        unsigned long *bstate, int *row)
790         MEVENT event;
792         /* retreive the mouse event from ncurses */
793         getmouse(&event);
794         D("mouse: id=%d  y=%d,x=%d,z=%d\n",event.id,event.y,event.x,event.z);
795         /* calculate the selected row in the list window */
796         *row = event.y - screen->top_window.rows;
797         /* copy button state bits */
798         *bstate = event.bstate;
799         /* if button 2 was pressed switch screen */
800         if (event.bstate & BUTTON2_CLICKED) {
801                 screen_cmd(c, CMD_SCREEN_NEXT);
802                 return 1;
803         }
805         /* if the even occured above the list window move up */
806         if (*row < 0 && lw) {
807                 if (event.bstate & BUTTON3_CLICKED)
808                         list_window_first(lw);
809                 else
810                         list_window_previous_page(lw);
811                 return 1;
812         }
814         /* if the even occured below the list window move down */
815         if (*row >= lw->rows && lw) {
816                 if (event.bstate & BUTTON3_CLICKED)
817                         list_window_last(lw, lw_length);
818                 else
819                         list_window_next_page(lw, lw_length);
820                 return 1;
821         }
823         return 0;
825 #endif
827 void
828 screen_cmd(mpdclient_t *c, command_t cmd)
830         screen->input_timestamp = time(NULL);
831         screen->last_cmd = cmd;
832         welcome = FALSE;
834         if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) )
835                 return;
837         switch(cmd) {
838         case CMD_PLAY:
839                 mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
840                 break;
841         case CMD_PAUSE:
842                 mpdclient_cmd_pause(c, !IS_PAUSED(c->status->state));
843                 break;
844         case CMD_STOP:
845                 mpdclient_cmd_stop(c);
846                 break;
847         case CMD_SEEK_FORWARD:
848                 if (!IS_STOPPED(c->status->state)) {
849                         if (c->song && seek_id != c->song->id) {
850                                 seek_id = c->song->id;
851                                 seek_target_time = c->status->elapsedTime;
852                         }
853                         seek_target_time+=options.seek_time;
854                         if (seek_target_time < c->status->totalTime)
855                                 break;
856                         seek_target_time = c->status->totalTime;
857                         /* seek_target_time=0; */
858                 }
859                 break;
860                 /* fall through... */
861         case CMD_TRACK_NEXT:
862                 if (!IS_STOPPED(c->status->state))
863                         mpdclient_cmd_next(c);
864                 break;
865         case CMD_SEEK_BACKWARD:
866                 if (!IS_STOPPED(c->status->state)) {
867                         if (seek_id != c->song->id) {
868                                 seek_id = c->song->id;
869                                 seek_target_time = c->status->elapsedTime;
870                         }
871                         seek_target_time-=options.seek_time;
872                         if (seek_target_time < 0)
873                                 seek_target_time=0;
874                 }
875                 break;
876         case CMD_TRACK_PREVIOUS:
877                 if (!IS_STOPPED(c->status->state))
878                         mpdclient_cmd_prev(c);
879                 break;
880         case CMD_SHUFFLE:
881                 if (mpdclient_cmd_shuffle(c) == 0)
882                         screen_status_message(_("Shuffled playlist!"));
883                 break;
884         case CMD_CLEAR:
885                 if (mpdclient_cmd_clear(c) == 0)
886                         screen_status_message(_("Cleared playlist!"));
887                 break;
888         case CMD_REPEAT:
889                 mpdclient_cmd_repeat(c, !c->status->repeat);
890                 break;
891         case CMD_RANDOM:
892                 mpdclient_cmd_random(c, !c->status->random);
893                 break;
894         case CMD_CROSSFADE:
895                 if (c->status->crossfade)
896                         mpdclient_cmd_crossfade(c, 0);
897                 else
898                         mpdclient_cmd_crossfade(c, options.crossfade_time);
899                 break;
900         case CMD_DB_UPDATE:
901                 if (!c->status->updatingDb) {
902                         if( mpdclient_cmd_db_update_utf8(c,NULL)==0 )
903                                 screen_status_printf(_("Database update started!"));
904                 } else
905                         screen_status_printf(_("Database update running..."));
906                 break;
907         case CMD_VOLUME_UP:
908                 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
909                         mpdclient_cmd_volume(c, ++c->status->volume);
910                 break;
911         case CMD_VOLUME_DOWN:
912                 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
913                         mpdclient_cmd_volume(c, --c->status->volume);
914                 break;
915         case CMD_TOGGLE_FIND_WRAP:
916                 options.find_wrap = !options.find_wrap;
917                 screen_status_printf(options.find_wrap ?
918                                      _("Find mode: Wrapped") :
919                                      _("Find mode: Normal"));
920                 break;
921         case CMD_TOGGLE_AUTOCENTER:
922                 options.auto_center = !options.auto_center;
923                 screen_status_printf(options.auto_center ?
924                                      _("Auto center mode: On") :
925                                      _("Auto center mode: Off"));
926                 break;
927         case CMD_SCREEN_UPDATE:
928                 screen->painted = 0;
929                 break;
930         case CMD_SCREEN_PREVIOUS:
931                 screen_next_mode(c, -1);
932                 break;
933         case CMD_SCREEN_NEXT:
934                 screen_next_mode(c, 1);
935                 break;
936         case CMD_SCREEN_PLAY:
937                 switch_screen_mode(SCREEN_PLAYLIST_ID, c);
938                 break;
939         case CMD_SCREEN_FILE:
940                 switch_screen_mode(SCREEN_BROWSE_ID, c);
941                 break;
942         case CMD_SCREEN_HELP:
943                 switch_screen_mode(SCREEN_HELP_ID, c);
944                 break;
945         case CMD_SCREEN_SEARCH:
946                 switch_screen_mode(SCREEN_SEARCH_ID, c);
947                 break;
948         case CMD_SCREEN_ARTIST:
949                 switch_screen_mode(SCREEN_ARTIST_ID, c);
950                 break;
951         case CMD_SCREEN_KEYDEF:
952                 switch_screen_mode(SCREEN_KEYDEF_ID, c);
953                 break;
954         case CMD_SCREEN_CLOCK:
955                 switch_screen_mode(SCREEN_CLOCK_ID, c);
956                 break;
957         case CMD_SCREEN_LYRICS:
958                 switch_screen_mode(SCREEN_LYRICS_ID, c);
959                 break;
960         case CMD_QUIT:
961                 exit(EXIT_SUCCESS);
962         default:
963                 break;
964         }