Code

New configuraton option: screen-list
[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"
43 #define MAX_SONGNAME_LENGTH   512
45 #define SCREEN_PLAYLIST_ID     0
46 #define SCREEN_BROWSE_ID       1
47 #define SCREEN_ARTIST_ID       2
48 #define SCREEN_HELP_ID         100
49 #define SCREEN_KEYDEF_ID       101
50 #define SCREEN_CLOCK_ID        102
51 #define SCREEN_SEARCH_ID       103
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);
64 typedef screen_functions_t * (*screen_get_mode_functions_fn_t) (void);
66 typedef struct
67 {
68   gint id;
69   gchar *name;
70   screen_get_mode_functions_fn_t get_mode_functions;
71 } screen_mode_info_t;
74 static screen_mode_info_t screens[] = {
75   { SCREEN_PLAYLIST_ID, "playlist", get_screen_playlist },
76   { SCREEN_BROWSE_ID,   "browse",   get_screen_browse },
77 #ifdef ENABLE_ARTIST_SCREEN
78   { SCREEN_ARTIST_ID,   "artist",   get_screen_artist },
79 #endif
80   { SCREEN_HELP_ID,     "help",     get_screen_help },
81 #ifdef ENABLE_SEARCH_SCREEN
82   { SCREEN_SEARCH_ID,   "search",   get_screen_search },
83 #endif
84 #ifdef ENABLE_KEYDEF_SCREEN
85   { SCREEN_KEYDEF_ID,   "keydef",   get_screen_keydef },
86 #endif
87 #ifdef ENABLE_CLOCK_SCREEN
88   { SCREEN_CLOCK_ID,    "clock",    get_screen_clock },
89 #endif
90   { G_MAXINT, NULL,      NULL }
91 };
93 static gboolean welcome = TRUE;
94 static screen_t *screen = NULL;
95 static screen_functions_t *mode_fn = NULL;
96 static int seek_id = -1;
97 static int seek_target_time = 0;
99 gint
100 screen_get_id(char *name)
102   gint i=0;
104   while( screens[i].name )
105     {
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     {
120       if( screens[i].id == id )
121         return i;
122       i++;
123     }
124   return -1;
127 static void
128 switch_screen_mode(gint id, mpdclient_t *c)
130   gint new_mode;
132   if( id == screens[screen->mode].id )
133     return;
135   /* close the old mode */
136   if( mode_fn && mode_fn->close )
137     mode_fn->close();
139   /* get functions for the new mode */
140   new_mode = lookup_mode(id);
141   if( new_mode>=0 && screens[new_mode].get_mode_functions )
142     {
143       D("switch_screen(%s)\n", screens[new_mode].name );
144       mode_fn = screens[new_mode].get_mode_functions();
145       screen->mode = new_mode;
146     }
148   screen->painted = 0;
149   
150   /* open the new mode */
151   if( mode_fn && mode_fn->open )
152     mode_fn->open(screen, c);
156 static void
157 screen_next_mode(mpdclient_t *c, int offset)
159   int max = g_strv_length(options.screen_list);
160   int current, next;
161   int i;
163   /* find current screen */
164   current = -1;
165   i = 0;
166   while( options.screen_list[i] )
167     {
168       if( strcmp(options.screen_list[i], screens[screen->mode].name) == 0 )
169         current = i;
170       i++;
171     }
172   next = current + offset;
173   if( next<0 )
174     next = max-1;
175   else if( next>=max )
176     next = 0;
178   D("current mode: %d:%d    next:%d\n", current, max, next);
179   switch_screen_mode(screen_get_id(options.screen_list[next]), c);
182 static void
183 paint_top_window(char *header, mpdclient_t *c, int clear)
185   char flags[5];
186   static int prev_volume = -1;
187   static int prev_header_len = -1;
188   WINDOW *w = screen->top_window.w;
190   if(prev_header_len!=strlen(header))
191     {
192       prev_header_len = strlen(header);
193       clear = 1;
194     }
196   if(clear)
197     {
198       wmove(w, 0, 0);
199       wclrtoeol(w);
200     }
202   if(prev_volume!=c->status->volume || clear)
203     {
204       char buf[32];
206       if( header[0] )
207         {
208           colors_use(w, COLOR_TITLE_BOLD);
209           mvwaddstr(w, 0, 0, header);
210         }
211       else
212         {
213           colors_use(w, COLOR_TITLE_BOLD);
214           waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE));
215           colors_use(w, COLOR_TITLE);
216           waddstr(w, _(":Help  "));
217           colors_use(w, COLOR_TITLE_BOLD);
218           waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE));
219           colors_use(w, COLOR_TITLE);
220           waddstr(w, _(":Playlist  "));
221           colors_use(w, COLOR_TITLE_BOLD);
222           waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE));
223           colors_use(w, COLOR_TITLE);
224           waddstr(w, _(":Browse  "));
225 #ifdef ENABLE_ARTIST_SCREEN
226           colors_use(w, COLOR_TITLE_BOLD);
227           waddstr(w, get_key_names(CMD_SCREEN_ARTIST, FALSE));
228           colors_use(w, COLOR_TITLE);
229           waddstr(w, _(":Artist  "));
230 #endif
231 #ifdef ENABLE_SEARCH_SCREEN
232           colors_use(w, COLOR_TITLE_BOLD);
233           waddstr(w, get_key_names(CMD_SCREEN_SEARCH, FALSE));
234           colors_use(w, COLOR_TITLE);
235           waddstr(w, _(":Search  "));
236 #endif
237         }
238       if( c->status->volume==MPD_STATUS_NO_VOLUME )
239         {
240           g_snprintf(buf, 32, _("Volume n/a "));
241         }
242       else
243         {
244           g_snprintf(buf, 32, _(" Volume %d%%"), c->status->volume); 
245         }
246       colors_use(w, COLOR_TITLE);
247       mvwaddstr(w, 0, screen->top_window.cols-strlen(buf), buf);
249       flags[0] = 0;
250       if( c->status->repeat )
251         g_strlcat(flags, "r", sizeof(flags));
252       if( c->status->random )
253         g_strlcat(flags, "z", sizeof(flags));;
254       if( c->status->crossfade )
255         g_strlcat(flags, "x", sizeof(flags));
256       if( c->status->updatingDb )
257         g_strlcat(flags, "U", sizeof(flags));
258       colors_use(w, COLOR_LINE);
259       mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
260       if( flags[0] )
261         {
262           wmove(w,1,screen->top_window.cols-strlen(flags)-3);
263           waddch(w, '[');
264           colors_use(w, COLOR_LINE_BOLD);
265           waddstr(w, flags);
266           colors_use(w, COLOR_LINE);
267           waddch(w, ']');
268         }
269       wnoutrefresh(w);
270     }
273 static void
274 paint_progress_window(mpdclient_t *c)
276   double p;
277   int width;
278   int elapsedTime = c->status->elapsedTime;
280   if( c->status==NULL || IS_STOPPED(c->status->state) )
281     {
282       mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE, 
283                screen->progress_window.cols);
284       wnoutrefresh(screen->progress_window.w);
285       return;
286     }
288   if( c->song && seek_id == c->song->id )
289     elapsedTime = seek_target_time;
291   p = ((double) elapsedTime) / ((double) c->status->totalTime);
292   
293   width = (int) (p * (double) screen->progress_window.cols);
294   mvwhline(screen->progress_window.w, 
295            0, 0,
296            ACS_HLINE, 
297            screen->progress_window.cols);
298   whline(screen->progress_window.w, '=', width-1);
299   mvwaddch(screen->progress_window.w, 0, width-1, 'O');
300   wnoutrefresh(screen->progress_window.w);
303 static void 
304 paint_status_window(mpdclient_t *c)
306   WINDOW *w = screen->status_window.w;
307   mpd_Status *status = c->status;
308   mpd_Song *song   = c->song;
309   int elapsedTime = c->status->elapsedTime;
310   char *str = NULL;
311   int x = 0;
313   if( time(NULL) - screen->status_timestamp <= SCREEN_STATUS_MESSAGE_TIME )
314     return;
315    
316   wmove(w, 0, 0);
317   wclrtoeol(w);
318   colors_use(w, COLOR_STATUS_BOLD);
319   
320   switch(status->state)
321     {
322     case MPD_STATUS_STATE_PLAY:
323       str = _("Playing:");
324       break;
325     case MPD_STATUS_STATE_PAUSE:
326       str = _("[Paused]");
327       break;
328     case MPD_STATUS_STATE_STOP:
329     default:
330       break;
331     }
333   if( str )
334     {
335       waddstr(w, str);
336       x += strlen(str)+1;
337     }
339   /* create time string */
340   memset(screen->buf, 0, screen->buf_size);
341   if( IS_PLAYING(status->state) || IS_PAUSED(status->state) )
342     {
343       if( status->totalTime > 0 )
344         {
345           if( c->song && seek_id == c->song->id )
346             elapsedTime = seek_target_time;
347           g_snprintf(screen->buf, screen->buf_size, 
348                    " [%i:%02i/%i:%02i]",
349                    elapsedTime/60, elapsedTime%60,
350                    status->totalTime/60,   status->totalTime%60 );
351         }
352       else
353         {
354           g_snprintf(screen->buf, screen->buf_size,  
355                      " [%d kbps]", status->bitRate );
356         }
357     }
358   else
359     {
360       time_t timep;
362       time(&timep);
363       strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
364     }
366   /* display song */
367   if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) )
368     {
369       char songname[MAX_SONGNAME_LENGTH];
370       int width = COLS-x-strlen(screen->buf);
372       if( song )
373         strfsong(songname, MAX_SONGNAME_LENGTH, STATUS_FORMAT, song);
374       else
375         songname[0] = '\0';
377       colors_use(w, COLOR_STATUS);
378       /* scroll if the song name is to long */
379       if( strlen(songname) > width )
380         {
381           static  scroll_state_t st = { 0, 0 };
382           char *tmp = strscroll(songname, " *** ", width, &st);
384           g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
385           g_free(tmp);    
386         }
387       mvwaddnstr(w, 0, x, songname, width);
388     } 
390   /* display time string */
391   if( screen->buf[0] )
392     {
393       x = screen->status_window.cols - strlen(screen->buf);
394       colors_use(w, COLOR_STATUS_TIME);
395       mvwaddstr(w, 0, x, screen->buf);
396     }
398   wnoutrefresh(w);
401 int
402 screen_exit(void)
404   endwin();
405   if( screen )
406     {
407       gint i;
409       /* close and exit all screens (playlist,browse,help...) */
410       i=0;
411       while( screens[i].get_mode_functions )
412         {
413           screen_functions_t *mode_fn = screens[i].get_mode_functions();
415           if( mode_fn && mode_fn->close )
416             mode_fn->close();
417           if( mode_fn && mode_fn->exit )
418             mode_fn->exit();
420           i++;
421         }
422      
423       string_list_free(screen->find_history);
424       g_free(screen->buf);
425       g_free(screen->findbuf);
426       
427       g_free(screen);
428       screen = NULL;
429     }
430   return 0;
433 void
434 screen_resize(void)
436   gint i;
438   D("Resize rows %d->%d, cols %d->%d\n",screen->rows,LINES,screen->cols,COLS);
439   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
440     {
441       screen_exit();
442       fprintf(stderr, _("Error: Screen to small!\n"));
443       exit(EXIT_FAILURE);
444     }
446   resizeterm(LINES, COLS);
448   screen->cols = COLS;
449   screen->rows = LINES;
451   /* top window */
452   screen->top_window.cols = screen->cols;
453   wresize(screen->top_window.w, 2, screen->cols);
455   /* main window */
456   screen->main_window.cols = screen->cols;
457   screen->main_window.rows = screen->rows-4;
458   wresize(screen->main_window.w, screen->main_window.rows, screen->cols);
459   wclear(screen->main_window.w);
461   /* progress window */
462   screen->progress_window.cols = screen->cols;
463   wresize(screen->progress_window.w, 1, screen->cols);
464   mvwin(screen->progress_window.w, screen->rows-2, 0);
466   /* status window */
467   screen->status_window.cols = screen->cols;
468   wresize(screen->status_window.w, 1, screen->cols);
469   mvwin(screen->status_window.w, screen->rows-1, 0);
471   screen->buf_size = screen->cols;
472   g_free(screen->buf);
473   screen->buf = g_malloc(screen->cols);
475   /* close and exit all screens (playlist,browse,help...) */
476   i=0;
477   while( screens[i].get_mode_functions )
478     {
479       screen_functions_t *mode_fn = screens[i].get_mode_functions();
481       if( mode_fn && mode_fn->resize )
482         mode_fn->resize(screen->main_window.cols, screen->main_window.rows);
484       i++;
485     }
487   /* ? - without this the cursor becomes visible with aterm & Eterm */
488   curs_set(1);
489   curs_set(0);     
491   screen->painted = 0;
494 void 
495 screen_status_message(char *msg)
497   WINDOW *w = screen->status_window.w;
499   wmove(w, 0, 0);
500   wclrtoeol(w);
501   colors_use(w, COLOR_STATUS_ALERT);
502   waddstr(w, msg);
503   wnoutrefresh(w);
504   screen->status_timestamp = time(NULL);
507 void 
508 screen_status_printf(char *format, ...)
510   char *msg;
511   va_list ap;
512   
513   va_start(ap,format);
514   msg = g_strdup_vprintf(format,ap);
515   va_end(ap);
516   screen_status_message(msg);
517   g_free(msg);
520 int
521 screen_init(mpdclient_t *c)
523   gint i;
525   /* initialize the curses library */
526   initscr();
527   /* initialize color support */
528   colors_start();
529   /* tell curses not to do NL->CR/NL on output */
530   nonl();          
531   /*  use raw mode (ignore interrupt,quit,suspend, and flow control ) */
532 #ifdef ENABLE_RAW_MODE
533   raw();
534 #endif
535   /* don't echo input */
536   noecho();    
537   /* set cursor invisible */     
538   curs_set(0);     
539   /* enable extra keys */
540   keypad(stdscr, TRUE);  
541   /* return from getch() without blocking */
542   timeout(SCREEN_TIMEOUT);
543   /* initialize mouse support */
544 #ifdef HAVE_GETMOUSE
545   if( options.enable_mouse )
546     mousemask(ALL_MOUSE_EVENTS, NULL);
547 #endif
549   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
550     {
551       fprintf(stderr, _("Error: Screen to small!\n"));
552       exit(EXIT_FAILURE);
553     }
555   screen = g_malloc(sizeof(screen_t));
556   memset(screen, 0, sizeof(screen_t));
557   screen->mode = 0;
558   screen->cols = COLS;
559   screen->rows = LINES;
560   screen->buf  = g_malloc(screen->cols);
561   screen->buf_size = screen->cols;
562   screen->findbuf = NULL;
563   screen->painted = 0;
564   screen->start_timestamp = time(NULL);
565   screen->input_timestamp = time(NULL);
566   screen->last_cmd = CMD_NONE;
568   /* create top window */
569   screen->top_window.rows = 2;
570   screen->top_window.cols = screen->cols;
571   screen->top_window.w = newwin(screen->top_window.rows, 
572                                   screen->top_window.cols,
573                                   0, 0);
574   leaveok(screen->top_window.w, TRUE);
575   keypad(screen->top_window.w, TRUE);  
577   /* create main window */
578   screen->main_window.rows = screen->rows-4;
579   screen->main_window.cols = screen->cols;
580   screen->main_window.w = newwin(screen->main_window.rows, 
581                                  screen->main_window.cols,
582                                  2, 
583                                  0);
585   //  leaveok(screen->main_window.w, TRUE); temporary disabled
586   keypad(screen->main_window.w, TRUE);  
588   /* create progress window */
589   screen->progress_window.rows = 1;
590   screen->progress_window.cols = screen->cols;
591   screen->progress_window.w = newwin(screen->progress_window.rows, 
592                                      screen->progress_window.cols,
593                                      screen->rows-2, 
594                                      0);
595   leaveok(screen->progress_window.w, TRUE);
596   
597   /* create status window */
598   screen->status_window.rows = 1;
599   screen->status_window.cols = screen->cols;
600   screen->status_window.w = newwin(screen->status_window.rows, 
601                                    screen->status_window.cols,
602                                    screen->rows-1, 
603                                    0);
605   leaveok(screen->status_window.w, FALSE);
606   keypad(screen->status_window.w, TRUE);  
608   if( options.enable_colors )
609     {
610       /* set background attributes */
611       wbkgd(stdscr, COLOR_PAIR(COLOR_LIST)); 
612       wbkgd(screen->main_window.w,     COLOR_PAIR(COLOR_LIST));
613       wbkgd(screen->top_window.w,      COLOR_PAIR(COLOR_TITLE));
614       wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
615       wbkgd(screen->status_window.w,   COLOR_PAIR(COLOR_STATUS));
616       colors_use(screen->progress_window.w, COLOR_PROGRESSBAR);
617     }
619   /* initialize screens */
620   i=0;
621   while( screens[i].get_mode_functions )
622     {
623       screen_functions_t *fn = screens[i].get_mode_functions();
625       if( fn && fn->init )
626         fn->init(screen->main_window.w, 
627                  screen->main_window.cols,
628                  screen->main_window.rows);
630       i++;
631     }
633 #if 0
634   /* broken */
635   mode_fn = NULL;
636   switch_screen_mode(screen_get_id(options.screen_list[0]), c);
637 #else
638   mode_fn = get_screen_playlist();
639 #endif
641   if( mode_fn && mode_fn->open )
642     mode_fn->open(screen, c);
644   /* initialize wreadln */
645   wrln_wgetch = my_wgetch;
646   wrln_max_history_length = 16;
648   return 0;
651 void 
652 screen_paint(mpdclient_t *c)
654   char *title = NULL;
656   if( mode_fn && mode_fn->get_title )
657     title = mode_fn->get_title(screen->buf,screen->buf_size);
659   D("screen_paint(%s)\n", title);
660   /* paint the title/header window */
661   if( title )
662     paint_top_window(title, c, 1);
663   else
664     paint_top_window("", c, 1);
666   /* paint the main window */
667   wclear(screen->main_window.w);
668   if( mode_fn && mode_fn->paint )
669     mode_fn->paint(screen, c);
670   
671   paint_progress_window(c);
672   paint_status_window(c);
673   screen->painted = 1;
674   wmove(screen->main_window.w, 0, 0);  
675   wnoutrefresh(screen->main_window.w);
677   /* tell curses to update */
678   doupdate();
681 void 
682 screen_update(mpdclient_t *c)
684   static int repeat = -1;
685   static int random = -1;
686   static int crossfade = -1;
687   static int dbupdate = -1;
688   list_window_t *lw = NULL;
690   if( !screen->painted )
691     return screen_paint(c);
693   /* print a message if mpd status has changed */
694   if( repeat<0 )
695     {
696       repeat = c->status->repeat;
697       random = c->status->random;
698       crossfade = c->status->crossfade;
699       dbupdate = c->status->updatingDb;
700     }
701   if( repeat != c->status->repeat )
702     screen_status_printf(c->status->repeat ? 
703                          _("Repeat is on") :
704                          _("Repeat is off"));
705   if( random != c->status->random )
706     screen_status_printf(c->status->random ?
707                          _("Random is on") :
708                          _("Random is off"));
709                          
710   if( crossfade != c->status->crossfade )
711     screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
712   if( dbupdate && dbupdate != c->status->updatingDb )
713     {
714       screen_status_printf(_("Database updated!"));
715       mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
716     }
718   repeat = c->status->repeat;
719   random = c->status->random;
720   crossfade = c->status->crossfade;
721   dbupdate = c->status->updatingDb;
723   /* update title/header window */
724   if( welcome && screen->last_cmd==CMD_NONE &&
725       time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME)
726     paint_top_window("", c, 0);
727   else if( mode_fn && mode_fn->get_title )
728     {
729       paint_top_window(mode_fn->get_title(screen->buf,screen->buf_size), c, 0);
730       welcome = FALSE;
731     }
732   else
733     paint_top_window("", c, 0);
735   /* update the main window */
736   if( mode_fn && mode_fn->paint )
737     mode_fn->update(screen, c);
739   if( mode_fn && mode_fn->get_lw )
740     lw = mode_fn->get_lw();
742   /* update progress window */
743   paint_progress_window(c);
745   /* update status window */
746   paint_status_window(c);
748   /* move the cursor to the selected row in the main window */
749   if( lw )
750     wmove(screen->main_window.w, LW_ROW(lw), 0);   
751   else
752     wmove(screen->main_window.w, 0, 0);   
753   wnoutrefresh(screen->main_window.w);
755   /* tell curses to update */
756   doupdate();
759 void
760 screen_idle(mpdclient_t *c)
762   if( c->song && seek_id ==  c->song->id &&
763       (screen->last_cmd == CMD_SEEK_FORWARD || 
764        screen->last_cmd == CMD_SEEK_BACKWARD) )
765     {
766       mpdclient_cmd_seek(c, seek_id, seek_target_time);
767     }
769   screen->last_cmd = CMD_NONE;
770   seek_id = -1;
773 #ifdef HAVE_GETMOUSE
774 int
775 screen_get_mouse_event(mpdclient_t *c,
776                        list_window_t *lw, int lw_length, 
777                        unsigned long *bstate, int *row)
779   MEVENT event;
781   /* retreive the mouse event from ncurses */
782   getmouse(&event);
783   D("mouse: id=%d  y=%d,x=%d,z=%d\n",event.id,event.y,event.x,event.z);
784   /* calculate the selected row in the list window */
785   *row = event.y - screen->top_window.rows;
786   /* copy button state bits */
787   *bstate = event.bstate;
788   /* if button 2 was pressed switch screen */
789   if( event.bstate & BUTTON2_CLICKED )
790     {
791       screen_cmd(c, CMD_SCREEN_NEXT);
792       return 1;
793     }
794   /* if the even occured above the list window move up */
795   if( *row<0 && lw )
796     {
797       if( event.bstate & BUTTON3_CLICKED )
798         list_window_first(lw);
799       else
800         list_window_previous_page(lw);
801       return 1;
802     }
803    /* if the even occured below the list window move down */
804   if( *row>=lw->rows && lw )
805     {
806       if( event.bstate & BUTTON3_CLICKED )
807         list_window_last(lw, lw_length);
808       else
809         list_window_next_page(lw, lw_length);
810       return 1;
811     } 
812   return 0;
814 #endif
816 void 
817 screen_cmd(mpdclient_t *c, command_t cmd)
819   screen->input_timestamp = time(NULL);
820   screen->last_cmd = cmd;
821   welcome = FALSE;
823   if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) )
824     return;
826   switch(cmd)
827     {
828     case CMD_PLAY:
829       mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
830       break;
831     case CMD_PAUSE:
832       mpdclient_cmd_pause(c, !IS_PAUSED(c->status->state));
833       break;
834     case CMD_STOP:
835       mpdclient_cmd_stop(c);
836       break;
837     case CMD_SEEK_FORWARD:
838       if( !IS_STOPPED(c->status->state) )
839         {
840           if( c->song && seek_id != c->song->id )
841             {
842               seek_id = c->song->id;
843               seek_target_time = c->status->elapsedTime;
844             }
845           seek_target_time+=options.seek_time;
846           if( seek_target_time < c->status->totalTime )
847             break;
848           seek_target_time = c->status->totalTime;
849           /* seek_target_time=0; */
850         }
851       break;
852       /* fall through... */
853     case CMD_TRACK_NEXT:
854       if( !IS_STOPPED(c->status->state) )
855         mpdclient_cmd_next(c);
856       break;
857     case CMD_SEEK_BACKWARD:
858       if( !IS_STOPPED(c->status->state) )
859         {
860           if( seek_id != c->song->id )
861             {
862               seek_id = c->song->id;
863               seek_target_time = c->status->elapsedTime;
864             }
865           seek_target_time-=options.seek_time;
866           if( seek_target_time < 0 )
867             seek_target_time=0;
868         }
869       break;
870     case CMD_TRACK_PREVIOUS:
871       if( !IS_STOPPED(c->status->state) )
872         mpdclient_cmd_prev(c);
873       break;   
874     case CMD_SHUFFLE:
875       if( mpdclient_cmd_shuffle(c) == 0 )
876         screen_status_message(_("Shuffled playlist!"));
877       break;
878     case CMD_CLEAR:
879       if( mpdclient_cmd_clear(c) == 0 )
880         screen_status_message(_("Cleared playlist!"));
881       break;
882     case CMD_REPEAT:
883       mpdclient_cmd_repeat(c, !c->status->repeat);
884       break;
885     case CMD_RANDOM:
886       mpdclient_cmd_random(c, !c->status->random);
887       break;
888     case CMD_CROSSFADE:
889       if(  c->status->crossfade )
890         mpdclient_cmd_crossfade(c, 0);
891       else
892         mpdclient_cmd_crossfade(c, options.crossfade_time);     
893       break;
894     case CMD_DB_UPDATE:
895       if( !c->status->updatingDb )
896         {
897           if( mpdclient_cmd_db_update_utf8(c,NULL)==0 )
898             screen_status_printf(_("Database update started!"));
899         }
900       else
901         screen_status_printf(_("Database update running..."));
902       break;
903     case CMD_VOLUME_UP:
904       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
905         mpdclient_cmd_volume(c, ++c->status->volume);
906       break;
907     case CMD_VOLUME_DOWN:
908       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
909         mpdclient_cmd_volume(c, --c->status->volume);
910       break;
911     case CMD_TOGGLE_FIND_WRAP:
912       options.find_wrap = !options.find_wrap;
913       screen_status_printf(options.find_wrap ? 
914                            _("Find mode: Wrapped") :
915                            _("Find mode: Normal"));
916       break;
917     case CMD_TOGGLE_AUTOCENTER:
918       options.auto_center = !options.auto_center;
919       screen_status_printf(options.auto_center ?
920                            _("Auto center mode: On") :
921                            _("Auto center mode: Off"));
922       break;
923     case CMD_SCREEN_UPDATE:
924       screen->painted = 0;
925       break;
926     case CMD_SCREEN_PREVIOUS:
927       screen_next_mode(c, -1);
928       break;
929     case CMD_SCREEN_NEXT:
930       screen_next_mode(c, 1);
931       break;
932     case CMD_SCREEN_PLAY:
933       switch_screen_mode(SCREEN_PLAYLIST_ID, c);
934       break;
935     case CMD_SCREEN_FILE:
936       switch_screen_mode(SCREEN_BROWSE_ID, c);
937       break;
938     case CMD_SCREEN_HELP:
939       switch_screen_mode(SCREEN_HELP_ID, c);
940       break;
941     case CMD_SCREEN_SEARCH:
942       switch_screen_mode(SCREEN_SEARCH_ID, c);
943       break;
944     case CMD_SCREEN_ARTIST:
945       switch_screen_mode(SCREEN_ARTIST_ID, c);
946       break;
947     case CMD_SCREEN_KEYDEF:
948       switch_screen_mode(SCREEN_KEYDEF_ID, c);
949       break;
950     case CMD_SCREEN_CLOCK:
951       switch_screen_mode(SCREEN_CLOCK_ID, c);
952       break;
953     case CMD_QUIT:
954       exit(EXIT_SUCCESS);
955     default:
956       break;
957     }