Code

fix shadow warnings
[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 screen_functions_t *get_screen_playlist(void);
54 extern screen_functions_t *get_screen_browse(void);
55 extern screen_functions_t *get_screen_help(void);
56 extern screen_functions_t *get_screen_search(void);
57 extern screen_functions_t *get_screen_artist(void);
58 extern screen_functions_t *get_screen_keydef(void);
59 extern screen_functions_t *get_screen_clock(void);
60 extern screen_functions_t *get_screen_lyrics(void);
62 typedef screen_functions_t * (*screen_get_mode_functions_fn_t) (void);
64 typedef struct
65 {
66         gint id;
67         const gchar *name;
68         screen_get_mode_functions_fn_t get_mode_functions;
69 } screen_mode_info_t;
72 static screen_mode_info_t screens[] = {
73         { SCREEN_PLAYLIST_ID, "playlist", get_screen_playlist },
74         { SCREEN_BROWSE_ID,   "browse",   get_screen_browse },
75 #ifdef ENABLE_ARTIST_SCREEN
76         { SCREEN_ARTIST_ID,   "artist",   get_screen_artist },
77 #endif
78         { SCREEN_HELP_ID,     "help",     get_screen_help },
79 #ifdef ENABLE_SEARCH_SCREEN
80         { SCREEN_SEARCH_ID,   "search",   get_screen_search },
81 #endif
82 #ifdef ENABLE_KEYDEF_SCREEN
83         { SCREEN_KEYDEF_ID,   "keydef",   get_screen_keydef },
84 #endif
85 #ifdef ENABLE_CLOCK_SCREEN
86         { SCREEN_CLOCK_ID,    "clock",    get_screen_clock },
87 #endif
88 #ifdef ENABLE_LYRICS_SCREEN
89         { SCREEN_LYRICS_ID,    "lyrics",    get_screen_lyrics },
90 #endif
91         { G_MAXINT, NULL,      NULL }
92 };
94 static gboolean welcome = TRUE;
95 static screen_t *screen = NULL;
96 static screen_functions_t *mode_fn = NULL;
97 static int seek_id = -1;
98 static int seek_target_time = 0;
100 gint
101 screen_get_id(const char *name)
103         gint i=0;
105         while (screens[i].name) {
106                 if (strcmp(name, screens[i].name) == 0)
107                         return screens[i].id;
108                 i++;
109         }
110         return -1;
113 static gint
114 lookup_mode(gint id)
116         gint i=0;
118         while (screens[i].name) {
119                 if (screens[i].id == id)
120                         return i;
121                 i++;
122         }
123         return -1;
126 gint get_cur_mode_id(void)
128         return screens[screen->mode].id;
131 static void
132 switch_screen_mode(gint id, mpdclient_t *c)
134         gint new_mode;
136         if( id == screens[screen->mode].id )
137                 return;
139         /* close the old mode */
140         if( mode_fn && mode_fn->close )
141                 mode_fn->close();
143         /* get functions for the new mode */
144         new_mode = lookup_mode(id);
145         if (new_mode>=0 && screens[new_mode].get_mode_functions) {
146                 D("switch_screen(%s)\n", screens[new_mode].name );
147                 mode_fn = screens[new_mode].get_mode_functions();
148                 screen->mode = new_mode;
149         }
151         screen->painted = 0;
153         /* open the new mode */
154         if (mode_fn && mode_fn->open)
155                 mode_fn->open(screen, c);
158 static void
159 screen_next_mode(mpdclient_t *c, int offset)
161         int max = g_strv_length(options.screen_list);
162         int current, next;
163         int i;
165         /* find current screen */
166         current = -1;
167         i = 0;
168         while (options.screen_list[i]) {
169                 if (strcmp(options.screen_list[i],
170                            screens[screen->mode].name) == 0)
171                         current = i;
172                 i++;
173         }
175         next = current + offset;
176         if (next<0)
177                 next = max-1;
178         else if (next>=max)
179                 next = 0;
181         D("current mode: %d:%d    next:%d\n", current, max, next);
182         switch_screen_mode(screen_get_id(options.screen_list[next]), c);
185 static void
186 paint_top_window2(const char *header, mpdclient_t *c)
188         char flags[5];
189         WINDOW *w = screen->top_window.w;
190         char buf[32];
192         if (header[0]) {
193                 colors_use(w, COLOR_TITLE_BOLD);
194                 mvwaddstr(w, 0, 0, header);
195         } else {
196                 colors_use(w, COLOR_TITLE_BOLD);
197                 waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE));
198                 colors_use(w, COLOR_TITLE);
199                 waddstr(w, _(":Help  "));
200                 colors_use(w, COLOR_TITLE_BOLD);
201                 waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE));
202                 colors_use(w, COLOR_TITLE);
203                 waddstr(w, _(":Playlist  "));
204                 colors_use(w, COLOR_TITLE_BOLD);
205                 waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE));
206                 colors_use(w, COLOR_TITLE);
207                 waddstr(w, _(":Browse  "));
208 #ifdef ENABLE_ARTIST_SCREEN
209                 colors_use(w, COLOR_TITLE_BOLD);
210                 waddstr(w, get_key_names(CMD_SCREEN_ARTIST, FALSE));
211                 colors_use(w, COLOR_TITLE);
212                 waddstr(w, _(":Artist  "));
213 #endif
214 #ifdef ENABLE_SEARCH_SCREEN
215                 colors_use(w, COLOR_TITLE_BOLD);
216                 waddstr(w, get_key_names(CMD_SCREEN_SEARCH, FALSE));
217                 colors_use(w, COLOR_TITLE);
218                 waddstr(w, _(":Search  "));
219 #endif
220 #ifdef ENABLE_LYRICS_SCREEN
221                 colors_use(w, COLOR_TITLE_BOLD);
222                 waddstr(w, get_key_names(CMD_SCREEN_LYRICS, FALSE));
223                 colors_use(w, COLOR_TITLE);
224                 waddstr(w, _(":Lyrics  "));
225 #endif
226         }
227         if (c->status->volume==MPD_STATUS_NO_VOLUME) {
228                 g_snprintf(buf, 32, _("Volume n/a "));
229         } else {
230                 g_snprintf(buf, 32, _(" Volume %d%%"), c->status->volume);
231         }
232         colors_use(w, COLOR_TITLE);
233         mvwaddstr(w, 0, screen->top_window.cols-my_strlen(buf), buf);
235         flags[0] = 0;
236         if( c->status->repeat )
237                 g_strlcat(flags, "r", sizeof(flags));
238         if( c->status->random )
239                 g_strlcat(flags, "z", sizeof(flags));;
240         if( c->status->crossfade )
241                 g_strlcat(flags, "x", sizeof(flags));
242         if( c->status->updatingDb )
243                 g_strlcat(flags, "U", sizeof(flags));
244         colors_use(w, COLOR_LINE);
245         mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
246         if (flags[0]) {
247                 wmove(w,1,screen->top_window.cols-strlen(flags)-3);
248                 waddch(w, '[');
249                 colors_use(w, COLOR_LINE_BOLD);
250                 waddstr(w, flags);
251                 colors_use(w, COLOR_LINE);
252                 waddch(w, ']');
253         }
254         wnoutrefresh(w);
257 static void
258 paint_top_window(const char *header, mpdclient_t *c, int full_repaint)
260         static int prev_volume = -1;
261         static int prev_header_len = -1;
262         WINDOW *w = screen->top_window.w;
264         if (prev_header_len!=my_strlen(header)) {
265                 prev_header_len = my_strlen(header);
266                 full_repaint = 1;
267         }
269         if (full_repaint) {
270                 wmove(w, 0, 0);
271                 wclrtoeol(w);
272         }
274         if (prev_volume!=c->status->volume || full_repaint)
275                 paint_top_window2(header, c);
278 static void
279 paint_progress_window(mpdclient_t *c)
281         double p;
282         int width;
283         int elapsedTime = c->status->elapsedTime;
285         if (c->status==NULL || IS_STOPPED(c->status->state)) {
286                 mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE,
287                          screen->progress_window.cols);
288                 wnoutrefresh(screen->progress_window.w);
289                 return;
290         }
292         if (c->song && seek_id == c->song->id)
293                 elapsedTime = seek_target_time;
295         p = ((double) elapsedTime) / ((double) c->status->totalTime);
297         width = (int) (p * (double) screen->progress_window.cols);
298         mvwhline(screen->progress_window.w,
299                  0, 0,
300                  ACS_HLINE,
301                  screen->progress_window.cols);
302         whline(screen->progress_window.w, '=', width-1);
303         mvwaddch(screen->progress_window.w, 0, width-1, 'O');
304         wnoutrefresh(screen->progress_window.w);
307 static void
308 paint_status_window(mpdclient_t *c)
310         WINDOW *w = screen->status_window.w;
311         mpd_Status *status = c->status;
312         mpd_Song *song = c->song;
313         int elapsedTime = 0;
314         const char *str = NULL;
315         int x = 0;
317         if( time(NULL) - screen->status_timestamp <= SCREEN_STATUS_MESSAGE_TIME )
318                 return;
320         wmove(w, 0, 0);
321         wclrtoeol(w);
322         colors_use(w, COLOR_STATUS_BOLD);
324         switch(status->state) {
325         case MPD_STATUS_STATE_PLAY:
326                 str = _("Playing:");
327                 break;
328         case MPD_STATUS_STATE_PAUSE:
329                 str = _("[Paused]");
330                 break;
331         case MPD_STATUS_STATE_STOP:
332         default:
333                 break;
334         }
336         if (str) {
337                 waddstr(w, str);
338                 x += my_strlen(str)+1;
339         }
341         /* create time string */
342         memset(screen->buf, 0, screen->buf_size);
343         if (IS_PLAYING(status->state) || IS_PAUSED(status->state)) {
344                 if (status->totalTime > 0) {
345                         /*checks the conf to see whether to display elapsed or remaining time */
346                         if(!strcmp(options.timedisplay_type,"elapsed"))
347                                 elapsedTime = c->status->elapsedTime;
348                         else if(!strcmp(options.timedisplay_type,"remaining"))
349                                 elapsedTime = (c->status->totalTime - c->status->elapsedTime);
351                         if( c->song && seek_id == c->song->id )
352                                 elapsedTime = seek_target_time;
353                         /*write out the time, using hours if time over 60 minutes*/
354                         if (c->status->totalTime > 3600) {
355                                 g_snprintf(screen->buf, screen->buf_size,
356                                            " [%i:%02i:%02i/%i:%02i:%02i]",
357                                            elapsedTime/3600, (elapsedTime%3600)/60, elapsedTime%60,
358                                            status->totalTime/3600, (status->totalTime%3600)/60,  status->totalTime%60);
359                         } else {
360                                 g_snprintf(screen->buf, screen->buf_size,
361                                            " [%i:%02i/%i:%02i]",
362                                            elapsedTime/60, elapsedTime%60,
363                                            status->totalTime/60,   status->totalTime%60 );
364                         }
365                 } else {
366                         g_snprintf(screen->buf, screen->buf_size,
367                                    " [%d kbps]", status->bitRate );
368                 }
369         } else {
370                 time_t timep;
372                 time(&timep);
373                 strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
374         }
376         /* display song */
377         if (IS_PLAYING(status->state) || IS_PAUSED(status->state)) {
378                 char songname[MAX_SONGNAME_LENGTH];
379                 int width = COLS-x-my_strlen(screen->buf);
381                 if (song)
382                         strfsong(songname, MAX_SONGNAME_LENGTH, STATUS_FORMAT, song);
383                 else
384                         songname[0] = '\0';
386                 colors_use(w, COLOR_STATUS);
387                 /* scroll if the song name is to long */
388                 if (options.scroll && my_strlen(songname) > width) {
389                         static  scroll_state_t st = { 0, 0 };
390                         char *tmp = strscroll(songname, options.scroll_sep, width, &st);
392                         g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
393                         g_free(tmp);
394                 }
395                 //mvwaddnstr(w, 0, x, songname, width);
396                 mvwaddstr(w, 0, x, songname);
397         }
399         /* display time string */
400         if (screen->buf[0]) {
401                 x = screen->status_window.cols - strlen(screen->buf);
402                 colors_use(w, COLOR_STATUS_TIME);
403                 mvwaddstr(w, 0, x, screen->buf);
404         }
406         wnoutrefresh(w);
409 int
410 screen_exit(void)
412         endwin();
413         if (screen) {
414                 gint i;
416                 /* close and exit all screens (playlist,browse,help...) */
417                 i=0;
418                 while (screens[i].get_mode_functions) {
419                         screen_functions_t *sf = screens[i].get_mode_functions();
421                         if (sf && sf->close)
422                                 sf->close();
423                         if (sf && sf->exit)
424                                 sf->exit();
426                         i++;
427                 }
429                 string_list_free(screen->find_history);
430                 g_free(screen->buf);
431                 g_free(screen->findbuf);
433                 g_free(screen);
434                 screen = NULL;
435         }
436         return 0;
439 void
440 screen_resize(void)
442         gint 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         i=0;
482         while (screens[i].get_mode_functions) {
483                 screen_functions_t *sf = screens[i].get_mode_functions();
485                 if (sf && sf->resize)
486                         sf->resize(screen->main_window.cols, screen->main_window.rows);
488                 i++;
489         }
491         /* ? - without this the cursor becomes visible with aterm & Eterm */
492         curs_set(1);
493         curs_set(0);
495         screen->painted = 0;
498 void
499 screen_status_message(const char *msg)
501         WINDOW *w = screen->status_window.w;
503         wmove(w, 0, 0);
504         wclrtoeol(w);
505         colors_use(w, COLOR_STATUS_ALERT);
506         waddstr(w, msg);
507         wnoutrefresh(w);
508         screen->status_timestamp = time(NULL);
511 void
512 screen_status_printf(const char *format, ...)
514         char *msg;
515         va_list ap;
517         va_start(ap,format);
518         msg = g_strdup_vprintf(format,ap);
519         va_end(ap);
520         screen_status_message(msg);
521         g_free(msg);
524 void
525 ncurses_init(void)
528         /* initialize the curses library */
529         initscr();
530         /* initialize color support */
531         colors_start();
532         /* tell curses not to do NL->CR/NL on output */
533         nonl();
534         /*  use raw mode (ignore interrupt,quit,suspend, and flow control ) */
535 #ifdef ENABLE_RAW_MODE
536         //  raw();
537 #endif
538         /* don't echo input */
539         noecho();
540         /* set cursor invisible */
541         curs_set(0);
542         /* enable extra keys */
543         keypad(stdscr, TRUE);
544         /* return from getch() without blocking */
545         timeout(SCREEN_TIMEOUT);
546         /* initialize mouse support */
547 #ifdef HAVE_GETMOUSE
548         if( options.enable_mouse )
549                 mousemask(ALL_MOUSE_EVENTS, NULL);
550 #endif
552         if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
553                 {
554                         fprintf(stderr, _("Error: Screen to small!\n"));
555                         exit(EXIT_FAILURE);
556                 }
557         screen = g_malloc(sizeof(screen_t));
558         memset(screen, 0, sizeof(screen_t));
559         screen->mode = 0;
560         screen->cols = COLS;
561         screen->rows = LINES;
563         screen->buf  = g_malloc(screen->cols);
564         screen->buf_size = screen->cols;
565         screen->findbuf = NULL;
566         screen->painted = 0;
567         screen->start_timestamp = time(NULL);
568         screen->input_timestamp = time(NULL);
569         screen->last_cmd = CMD_NONE;
571         /* create top window */
572         screen->top_window.rows = 2;
573         screen->top_window.cols = screen->cols;
574         screen->top_window.w = newwin(screen->top_window.rows,
575                                       screen->top_window.cols,
576                                       0, 0);
577         leaveok(screen->top_window.w, TRUE);
578         keypad(screen->top_window.w, TRUE);
580         /* create main window */
581         screen->main_window.rows = screen->rows-4;
582         screen->main_window.cols = screen->cols;
583         screen->main_window.w = newwin(screen->main_window.rows,
584                                        screen->main_window.cols,
585                                        2,
586                                        0);
588         //  leaveok(screen->main_window.w, TRUE); temporary disabled
589         keypad(screen->main_window.w, TRUE);
591         /* create progress window */
592         screen->progress_window.rows = 1;
593         screen->progress_window.cols = screen->cols;
594         screen->progress_window.w = newwin(screen->progress_window.rows,
595                                            screen->progress_window.cols,
596                                            screen->rows-2,
597                                            0);
598         leaveok(screen->progress_window.w, TRUE);
600         /* create status window */
601         screen->status_window.rows = 1;
602         screen->status_window.cols = screen->cols;
603         screen->status_window.w = newwin(screen->status_window.rows,
604                                          screen->status_window.cols,
605                                          screen->rows-1,
606                                          0);
608         leaveok(screen->status_window.w, FALSE);
609         keypad(screen->status_window.w, TRUE);
611         if( options.enable_colors )
612                 {
613                         /* set background attributes */
614                         wbkgd(stdscr, COLOR_PAIR(COLOR_LIST));
615                         wbkgd(screen->main_window.w,     COLOR_PAIR(COLOR_LIST));
616                         wbkgd(screen->top_window.w,      COLOR_PAIR(COLOR_TITLE));
617                         wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
618                         wbkgd(screen->status_window.w,   COLOR_PAIR(COLOR_STATUS));
619                         colors_use(screen->progress_window.w, COLOR_PROGRESSBAR);
620                 }
623 int
624 screen_init(mpdclient_t *c)
626         gint i;
628         /* initialize screens */
629         i=0;
630         while( screens[i].get_mode_functions )
631                 {
632                         screen_functions_t *fn = screens[i].get_mode_functions();
634                         if( fn && fn->init )
635                                 fn->init(screen->main_window.w,
636                                          screen->main_window.cols,
637                                          screen->main_window.rows);
639                         i++;
640                 }
642 #if 0
643         /* broken */
644         mode_fn = NULL;
645         switch_screen_mode(screen_get_id(options.screen_list[0]), c);
646 #else
647         mode_fn = get_screen_playlist();
648 #endif
650         if( mode_fn && mode_fn->open )
651                 mode_fn->open(screen, c);
653         /* initialize wreadln */
654         wrln_wgetch = my_wgetch;
655         wrln_max_history_length = 16;
657         return 0;
660 void
661 screen_paint(mpdclient_t *c)
663         const char *title = NULL;
665         if (mode_fn && mode_fn->get_title)
666                 title = mode_fn->get_title(screen->buf, screen->buf_size);
668         D("screen_paint(%s)\n", title);
669         /* paint the title/header window */
670         if( title )
671                 paint_top_window(title, c, 1);
672         else
673                 paint_top_window("", c, 1);
675         /* paint the main window */
676         wclear(screen->main_window.w);
677         if( mode_fn && mode_fn->paint )
678                 mode_fn->paint(screen, c);
680         paint_progress_window(c);
681         paint_status_window(c);
682         screen->painted = 1;
683         wmove(screen->main_window.w, 0, 0);
684         wnoutrefresh(screen->main_window.w);
686         /* tell curses to update */
687         doupdate();
690 void
691 screen_update(mpdclient_t *c)
693         static int repeat = -1;
694         static int random_enabled = -1;
695         static int crossfade = -1;
696         static int dbupdate = -1;
697         list_window_t *lw = NULL;
699         if( !screen->painted )
700                 return screen_paint(c);
702         /* print a message if mpd status has changed */
703         if (repeat < 0) {
704                 repeat = c->status->repeat;
705                 random_enabled = c->status->random;
706                 crossfade = c->status->crossfade;
707                 dbupdate = c->status->updatingDb;
708         }
710         if (repeat != c->status->repeat)
711                 screen_status_printf(c->status->repeat ?
712                                      _("Repeat is on") :
713                                      _("Repeat is off"));
715         if (random_enabled != c->status->random)
716                 screen_status_printf(c->status->random ?
717                                      _("Random is on") :
718                                      _("Random is off"));
720         if (crossfade != c->status->crossfade)
721                 screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
723         if (dbupdate && dbupdate != c->status->updatingDb) {
724                 screen_status_printf(_("Database updated!"));
725                 mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
726         }
728         repeat = c->status->repeat;
729         random_enabled = c->status->random;
730         crossfade = c->status->crossfade;
731         dbupdate = c->status->updatingDb;
733         /* update title/header window */
734         if (welcome && screen->last_cmd==CMD_NONE &&
735             time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME)
736                 paint_top_window("", c, 0);
737         else if (mode_fn && mode_fn->get_title) {
738                 paint_top_window(mode_fn->get_title(screen->buf,screen->buf_size), c, 0);
739                 welcome = FALSE;
740         } else
741                 paint_top_window("", c, 0);
743         /* update the main window */
744         if (mode_fn && mode_fn->paint)
745                 mode_fn->update(screen, c);
747         if (mode_fn && mode_fn->get_lw)
748                 lw = mode_fn->get_lw();
750         /* update progress window */
751         paint_progress_window(c);
753         /* update status window */
754         paint_status_window(c);
756         /* move the cursor to the selected row in the main window */
757         if (lw)
758                 wmove(screen->main_window.w, LW_ROW(lw), 0);
759         else
760                 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 && seek_id ==  c->song->id &&
771             (screen->last_cmd == CMD_SEEK_FORWARD ||
772              screen->last_cmd == CMD_SEEK_BACKWARD) )
773                 {
774                         mpdclient_cmd_seek(c, seek_id, seek_target_time);
775                 }
777         screen->last_cmd = CMD_NONE;
778         seek_id = -1;
781 #ifdef HAVE_GETMOUSE
782 int
783 screen_get_mouse_event(mpdclient_t *c,
784                        list_window_t *lw, int lw_length,
785                        unsigned long *bstate, int *row)
787         MEVENT event;
789         /* retreive the mouse event from ncurses */
790         getmouse(&event);
791         D("mouse: id=%d  y=%d,x=%d,z=%d\n",event.id,event.y,event.x,event.z);
792         /* calculate the selected row in the list window */
793         *row = event.y - screen->top_window.rows;
794         /* copy button state bits */
795         *bstate = event.bstate;
796         /* if button 2 was pressed switch screen */
797         if (event.bstate & BUTTON2_CLICKED) {
798                 screen_cmd(c, CMD_SCREEN_NEXT);
799                 return 1;
800         }
802         /* if the even occured above the list window move up */
803         if (*row < 0 && lw) {
804                 if (event.bstate & BUTTON3_CLICKED)
805                         list_window_first(lw);
806                 else
807                         list_window_previous_page(lw);
808                 return 1;
809         }
811         /* if the even occured below the list window move down */
812         if (*row >= lw->rows && lw) {
813                 if (event.bstate & BUTTON3_CLICKED)
814                         list_window_last(lw, lw_length);
815                 else
816                         list_window_next_page(lw, lw_length);
817                 return 1;
818         }
820         return 0;
822 #endif
824 void
825 screen_cmd(mpdclient_t *c, command_t cmd)
827         screen->input_timestamp = time(NULL);
828         screen->last_cmd = cmd;
829         welcome = FALSE;
831         if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) )
832                 return;
834         switch(cmd) {
835         case CMD_PLAY:
836                 mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
837                 break;
838         case CMD_PAUSE:
839                 mpdclient_cmd_pause(c, !IS_PAUSED(c->status->state));
840                 break;
841         case CMD_STOP:
842                 mpdclient_cmd_stop(c);
843                 break;
844         case CMD_SEEK_FORWARD:
845                 if (!IS_STOPPED(c->status->state)) {
846                         if (c->song && seek_id != c->song->id) {
847                                 seek_id = c->song->id;
848                                 seek_target_time = c->status->elapsedTime;
849                         }
850                         seek_target_time+=options.seek_time;
851                         if (seek_target_time < c->status->totalTime)
852                                 break;
853                         seek_target_time = c->status->totalTime;
854                         /* seek_target_time=0; */
855                 }
856                 break;
857                 /* fall through... */
858         case CMD_TRACK_NEXT:
859                 if (!IS_STOPPED(c->status->state))
860                         mpdclient_cmd_next(c);
861                 break;
862         case CMD_SEEK_BACKWARD:
863                 if (!IS_STOPPED(c->status->state)) {
864                         if (seek_id != c->song->id) {
865                                 seek_id = c->song->id;
866                                 seek_target_time = c->status->elapsedTime;
867                         }
868                         seek_target_time-=options.seek_time;
869                         if (seek_target_time < 0)
870                                 seek_target_time=0;
871                 }
872                 break;
873         case CMD_TRACK_PREVIOUS:
874                 if (!IS_STOPPED(c->status->state))
875                         mpdclient_cmd_prev(c);
876                 break;
877         case CMD_SHUFFLE:
878                 if (mpdclient_cmd_shuffle(c) == 0)
879                         screen_status_message(_("Shuffled playlist!"));
880                 break;
881         case CMD_CLEAR:
882                 if (mpdclient_cmd_clear(c) == 0)
883                         screen_status_message(_("Cleared playlist!"));
884                 break;
885         case CMD_REPEAT:
886                 mpdclient_cmd_repeat(c, !c->status->repeat);
887                 break;
888         case CMD_RANDOM:
889                 mpdclient_cmd_random(c, !c->status->random);
890                 break;
891         case CMD_CROSSFADE:
892                 if (c->status->crossfade)
893                         mpdclient_cmd_crossfade(c, 0);
894                 else
895                         mpdclient_cmd_crossfade(c, options.crossfade_time);
896                 break;
897         case CMD_DB_UPDATE:
898                 if (!c->status->updatingDb) {
899                         if( mpdclient_cmd_db_update_utf8(c,NULL)==0 )
900                                 screen_status_printf(_("Database update started!"));
901                 } else
902                         screen_status_printf(_("Database update running..."));
903                 break;
904         case CMD_VOLUME_UP:
905                 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
906                         mpdclient_cmd_volume(c, ++c->status->volume);
907                 break;
908         case CMD_VOLUME_DOWN:
909                 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
910                         mpdclient_cmd_volume(c, --c->status->volume);
911                 break;
912         case CMD_TOGGLE_FIND_WRAP:
913                 options.find_wrap = !options.find_wrap;
914                 screen_status_printf(options.find_wrap ?
915                                      _("Find mode: Wrapped") :
916                                      _("Find mode: Normal"));
917                 break;
918         case CMD_TOGGLE_AUTOCENTER:
919                 options.auto_center = !options.auto_center;
920                 screen_status_printf(options.auto_center ?
921                                      _("Auto center mode: On") :
922                                      _("Auto center mode: Off"));
923                 break;
924         case CMD_SCREEN_UPDATE:
925                 screen->painted = 0;
926                 break;
927         case CMD_SCREEN_PREVIOUS:
928                 screen_next_mode(c, -1);
929                 break;
930         case CMD_SCREEN_NEXT:
931                 screen_next_mode(c, 1);
932                 break;
933         case CMD_SCREEN_PLAY:
934                 switch_screen_mode(SCREEN_PLAYLIST_ID, c);
935                 break;
936         case CMD_SCREEN_FILE:
937                 switch_screen_mode(SCREEN_BROWSE_ID, c);
938                 break;
939         case CMD_SCREEN_HELP:
940                 switch_screen_mode(SCREEN_HELP_ID, c);
941                 break;
942         case CMD_SCREEN_SEARCH:
943                 switch_screen_mode(SCREEN_SEARCH_ID, c);
944                 break;
945         case CMD_SCREEN_ARTIST:
946                 switch_screen_mode(SCREEN_ARTIST_ID, c);
947                 break;
948         case CMD_SCREEN_KEYDEF:
949                 switch_screen_mode(SCREEN_KEYDEF_ID, c);
950                 break;
951         case CMD_SCREEN_CLOCK:
952                 switch_screen_mode(SCREEN_CLOCK_ID, c);
953                 break;
954         case CMD_SCREEN_LYRICS:
955                 switch_screen_mode(SCREEN_LYRICS_ID, c);
956                 break;
957         case CMD_QUIT:
958                 exit(EXIT_SUCCESS);
959         default:
960                 break;
961         }