Code

included patch from Jonathan Fors
[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 = 0;
310   char *str = NULL;
311   char *timestr = NULL;
312   int x = 0;
314   if( time(NULL) - screen->status_timestamp <= SCREEN_STATUS_MESSAGE_TIME )
315     return;
316    
317   wmove(w, 0, 0);
318   wclrtoeol(w);
319   colors_use(w, COLOR_STATUS_BOLD);
320   
321   switch(status->state)
322     {
323     case MPD_STATUS_STATE_PLAY:
324       str = _("Playing:");
325       break;
326     case MPD_STATUS_STATE_PAUSE:
327       str = _("[Paused]");
328       break;
329     case MPD_STATUS_STATE_STOP:
330     default:
331       break;
332     }
334   if( str )
335     {
336       waddstr(w, str);
337       x += strlen(str)+1;
338     }
340   /* create time string */
341   memset(screen->buf, 0, screen->buf_size);
342   if( IS_PLAYING(status->state) || IS_PAUSED(status->state) )
343     {
344       if( status->totalTime > 0 )
345         {
346         
347         /*checks the conf to see whether to display elapsed or remaining time */
348         if(!strcmp(options.timedisplay_type,"elapsed"))
349           {
350              timestr= " [%i:%02i/%i:%02i]";         
351              elapsedTime = c->status->elapsedTime;
352           }
353         else if(!strcmp(options.timedisplay_type,"remaining"))
354           {
355             timestr= " [-%i:%02i/%i:%02i]";         
356             elapsedTime = (c->status->totalTime - c->status->elapsedTime);
357           }  
358         if( c->song && seek_id == c->song->id )
359             elapsedTime = seek_target_time;
360         /*write out the time*/
361           g_snprintf(screen->buf, screen->buf_size, 
362                    timestr,
363                    elapsedTime/60, elapsedTime%60,
364                    status->totalTime/60,   status->totalTime%60 );
365         }
366       else
367         {
368           g_snprintf(screen->buf, screen->buf_size,  
369                      " [%d kbps]", status->bitRate );
370         }
371     }
372   else
373     {
374       time_t timep;
376       time(&timep);
377       strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
378     }
380   /* display song */
381   if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) )
382     {
383       char songname[MAX_SONGNAME_LENGTH];
384       int width = COLS-x-strlen(screen->buf);
386       if( song )
387         strfsong(songname, MAX_SONGNAME_LENGTH, STATUS_FORMAT, song);
388       else
389         songname[0] = '\0';
391       colors_use(w, COLOR_STATUS);
392       /* scroll if the song name is to long */
393       if( strlen(songname) > width )
394         {
395           static  scroll_state_t st = { 0, 0 };
396           char *tmp = strscroll(songname, " *** ", width, &st);
398           g_strlcpy(songname, tmp, MAX_SONGNAME_LENGTH);
399           g_free(tmp);    
400         }
401       mvwaddnstr(w, 0, x, songname, width);
402     } 
404   /* display time string */
405   if( screen->buf[0] )
406     {
407       x = screen->status_window.cols - strlen(screen->buf);
408       colors_use(w, COLOR_STATUS_TIME);
409       mvwaddstr(w, 0, x, screen->buf);
410     }
412   wnoutrefresh(w);
415 int
416 screen_exit(void)
418   endwin();
419   if( screen )
420     {
421       gint i;
423       /* close and exit all screens (playlist,browse,help...) */
424       i=0;
425       while( screens[i].get_mode_functions )
426         {
427           screen_functions_t *mode_fn = screens[i].get_mode_functions();
429           if( mode_fn && mode_fn->close )
430             mode_fn->close();
431           if( mode_fn && mode_fn->exit )
432             mode_fn->exit();
434           i++;
435         }
436      
437       string_list_free(screen->find_history);
438       g_free(screen->buf);
439       g_free(screen->findbuf);
440       
441       g_free(screen);
442       screen = NULL;
443     }
444   return 0;
447 void
448 screen_resize(void)
450   gint i;
452   D("Resize rows %d->%d, cols %d->%d\n",screen->rows,LINES,screen->cols,COLS);
453   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
454     {
455       screen_exit();
456       fprintf(stderr, _("Error: Screen to small!\n"));
457       exit(EXIT_FAILURE);
458     }
460   resizeterm(LINES, COLS);
462   screen->cols = COLS;
463   screen->rows = LINES;
465   /* top window */
466   screen->top_window.cols = screen->cols;
467   wresize(screen->top_window.w, 2, screen->cols);
469   /* main window */
470   screen->main_window.cols = screen->cols;
471   screen->main_window.rows = screen->rows-4;
472   wresize(screen->main_window.w, screen->main_window.rows, screen->cols);
473   wclear(screen->main_window.w);
475   /* progress window */
476   screen->progress_window.cols = screen->cols;
477   wresize(screen->progress_window.w, 1, screen->cols);
478   mvwin(screen->progress_window.w, screen->rows-2, 0);
480   /* status window */
481   screen->status_window.cols = screen->cols;
482   wresize(screen->status_window.w, 1, screen->cols);
483   mvwin(screen->status_window.w, screen->rows-1, 0);
485   screen->buf_size = screen->cols;
486   g_free(screen->buf);
487   screen->buf = g_malloc(screen->cols);
489   /* close and exit all screens (playlist,browse,help...) */
490   i=0;
491   while( screens[i].get_mode_functions )
492     {
493       screen_functions_t *mode_fn = screens[i].get_mode_functions();
495       if( mode_fn && mode_fn->resize )
496         mode_fn->resize(screen->main_window.cols, screen->main_window.rows);
498       i++;
499     }
501   /* ? - without this the cursor becomes visible with aterm & Eterm */
502   curs_set(1);
503   curs_set(0);     
505   screen->painted = 0;
508 void 
509 screen_status_message(char *msg)
511   WINDOW *w = screen->status_window.w;
513   wmove(w, 0, 0);
514   wclrtoeol(w);
515   colors_use(w, COLOR_STATUS_ALERT);
516   waddstr(w, msg);
517   wnoutrefresh(w);
518   screen->status_timestamp = time(NULL);
521 void 
522 screen_status_printf(char *format, ...)
524   char *msg;
525   va_list ap;
526   
527   va_start(ap,format);
528   msg = g_strdup_vprintf(format,ap);
529   va_end(ap);
530   screen_status_message(msg);
531   g_free(msg);
534 int
535 screen_init(mpdclient_t *c)
537   gint i;
539   /* initialize the curses library */
540   initscr();
541   /* initialize color support */
542   colors_start();
543   /* tell curses not to do NL->CR/NL on output */
544   nonl();          
545   /*  use raw mode (ignore interrupt,quit,suspend, and flow control ) */
546 #ifdef ENABLE_RAW_MODE
547   raw();
548 #endif
549   /* don't echo input */
550   noecho();    
551   /* set cursor invisible */     
552   curs_set(0);     
553   /* enable extra keys */
554   keypad(stdscr, TRUE);  
555   /* return from getch() without blocking */
556   timeout(SCREEN_TIMEOUT);
557   /* initialize mouse support */
558 #ifdef HAVE_GETMOUSE
559   if( options.enable_mouse )
560     mousemask(ALL_MOUSE_EVENTS, NULL);
561 #endif
563   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
564     {
565       fprintf(stderr, _("Error: Screen to small!\n"));
566       exit(EXIT_FAILURE);
567     }
569   screen = g_malloc(sizeof(screen_t));
570   memset(screen, 0, sizeof(screen_t));
571   screen->mode = 0;
572   screen->cols = COLS;
573   screen->rows = LINES;
574   screen->buf  = g_malloc(screen->cols);
575   screen->buf_size = screen->cols;
576   screen->findbuf = NULL;
577   screen->painted = 0;
578   screen->start_timestamp = time(NULL);
579   screen->input_timestamp = time(NULL);
580   screen->last_cmd = CMD_NONE;
582   /* create top window */
583   screen->top_window.rows = 2;
584   screen->top_window.cols = screen->cols;
585   screen->top_window.w = newwin(screen->top_window.rows, 
586                                   screen->top_window.cols,
587                                   0, 0);
588   leaveok(screen->top_window.w, TRUE);
589   keypad(screen->top_window.w, TRUE);  
591   /* create main window */
592   screen->main_window.rows = screen->rows-4;
593   screen->main_window.cols = screen->cols;
594   screen->main_window.w = newwin(screen->main_window.rows, 
595                                  screen->main_window.cols,
596                                  2, 
597                                  0);
599   //  leaveok(screen->main_window.w, TRUE); temporary disabled
600   keypad(screen->main_window.w, TRUE);  
602   /* create progress window */
603   screen->progress_window.rows = 1;
604   screen->progress_window.cols = screen->cols;
605   screen->progress_window.w = newwin(screen->progress_window.rows, 
606                                      screen->progress_window.cols,
607                                      screen->rows-2, 
608                                      0);
609   leaveok(screen->progress_window.w, TRUE);
610   
611   /* create status window */
612   screen->status_window.rows = 1;
613   screen->status_window.cols = screen->cols;
614   screen->status_window.w = newwin(screen->status_window.rows, 
615                                    screen->status_window.cols,
616                                    screen->rows-1, 
617                                    0);
619   leaveok(screen->status_window.w, FALSE);
620   keypad(screen->status_window.w, TRUE);  
622   if( options.enable_colors )
623     {
624       /* set background attributes */
625       wbkgd(stdscr, COLOR_PAIR(COLOR_LIST)); 
626       wbkgd(screen->main_window.w,     COLOR_PAIR(COLOR_LIST));
627       wbkgd(screen->top_window.w,      COLOR_PAIR(COLOR_TITLE));
628       wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
629       wbkgd(screen->status_window.w,   COLOR_PAIR(COLOR_STATUS));
630       colors_use(screen->progress_window.w, COLOR_PROGRESSBAR);
631     }
633   /* initialize screens */
634   i=0;
635   while( screens[i].get_mode_functions )
636     {
637       screen_functions_t *fn = screens[i].get_mode_functions();
639       if( fn && fn->init )
640         fn->init(screen->main_window.w, 
641                  screen->main_window.cols,
642                  screen->main_window.rows);
644       i++;
645     }
647 #if 0
648   /* broken */
649   mode_fn = NULL;
650   switch_screen_mode(screen_get_id(options.screen_list[0]), c);
651 #else
652   mode_fn = get_screen_playlist();
653 #endif
655   if( mode_fn && mode_fn->open )
656     mode_fn->open(screen, c);
658   /* initialize wreadln */
659   wrln_wgetch = my_wgetch;
660   wrln_max_history_length = 16;
662   return 0;
665 void 
666 screen_paint(mpdclient_t *c)
668   char *title = NULL;
670   if( mode_fn && mode_fn->get_title )
671     title = mode_fn->get_title(screen->buf,screen->buf_size);
673   D("screen_paint(%s)\n", title);
674   /* paint the title/header window */
675   if( title )
676     paint_top_window(title, c, 1);
677   else
678     paint_top_window("", c, 1);
680   /* paint the main window */
681   wclear(screen->main_window.w);
682   if( mode_fn && mode_fn->paint )
683     mode_fn->paint(screen, c);
684   
685   paint_progress_window(c);
686   paint_status_window(c);
687   screen->painted = 1;
688   wmove(screen->main_window.w, 0, 0);  
689   wnoutrefresh(screen->main_window.w);
691   /* tell curses to update */
692   doupdate();
695 void 
696 screen_update(mpdclient_t *c)
698   static int repeat = -1;
699   static int random = -1;
700   static int crossfade = -1;
701   static int dbupdate = -1;
702   list_window_t *lw = NULL;
704   if( !screen->painted )
705     return screen_paint(c);
707   /* print a message if mpd status has changed */
708   if( repeat<0 )
709     {
710       repeat = c->status->repeat;
711       random = c->status->random;
712       crossfade = c->status->crossfade;
713       dbupdate = c->status->updatingDb;
714     }
715   if( repeat != c->status->repeat )
716     screen_status_printf(c->status->repeat ? 
717                          _("Repeat is on") :
718                          _("Repeat is off"));
719   if( random != c->status->random )
720     screen_status_printf(c->status->random ?
721                          _("Random is on") :
722                          _("Random is off"));
723                          
724   if( crossfade != c->status->crossfade )
725     screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
726   if( dbupdate && dbupdate != c->status->updatingDb )
727     {
728       screen_status_printf(_("Database updated!"));
729       mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
730     }
732   repeat = c->status->repeat;
733   random = c->status->random;
734   crossfade = c->status->crossfade;
735   dbupdate = c->status->updatingDb;
737   /* update title/header window */
738   if( welcome && screen->last_cmd==CMD_NONE &&
739       time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME)
740     paint_top_window("", c, 0);
741   else if( mode_fn && mode_fn->get_title )
742     {
743       paint_top_window(mode_fn->get_title(screen->buf,screen->buf_size), c, 0);
744       welcome = FALSE;
745     }
746   else
747     paint_top_window("", c, 0);
749   /* update the main window */
750   if( mode_fn && mode_fn->paint )
751     mode_fn->update(screen, c);
753   if( mode_fn && mode_fn->get_lw )
754     lw = mode_fn->get_lw();
756   /* update progress window */
757   paint_progress_window(c);
759   /* update status window */
760   paint_status_window(c);
762   /* move the cursor to the selected row in the main window */
763   if( lw )
764     wmove(screen->main_window.w, LW_ROW(lw), 0);   
765   else
766     wmove(screen->main_window.w, 0, 0);   
767   wnoutrefresh(screen->main_window.w);
769   /* tell curses to update */
770   doupdate();
773 void
774 screen_idle(mpdclient_t *c)
776   if( c->song && seek_id ==  c->song->id &&
777       (screen->last_cmd == CMD_SEEK_FORWARD || 
778        screen->last_cmd == CMD_SEEK_BACKWARD) )
779     {
780       mpdclient_cmd_seek(c, seek_id, seek_target_time);
781     }
783   screen->last_cmd = CMD_NONE;
784   seek_id = -1;
787 #ifdef HAVE_GETMOUSE
788 int
789 screen_get_mouse_event(mpdclient_t *c,
790                        list_window_t *lw, int lw_length, 
791                        unsigned long *bstate, int *row)
793   MEVENT event;
795   /* retreive the mouse event from ncurses */
796   getmouse(&event);
797   D("mouse: id=%d  y=%d,x=%d,z=%d\n",event.id,event.y,event.x,event.z);
798   /* calculate the selected row in the list window */
799   *row = event.y - screen->top_window.rows;
800   /* copy button state bits */
801   *bstate = event.bstate;
802   /* if button 2 was pressed switch screen */
803   if( event.bstate & BUTTON2_CLICKED )
804     {
805       screen_cmd(c, CMD_SCREEN_NEXT);
806       return 1;
807     }
808   /* if the even occured above the list window move up */
809   if( *row<0 && lw )
810     {
811       if( event.bstate & BUTTON3_CLICKED )
812         list_window_first(lw);
813       else
814         list_window_previous_page(lw);
815       return 1;
816     }
817    /* if the even occured below the list window move down */
818   if( *row>=lw->rows && lw )
819     {
820       if( event.bstate & BUTTON3_CLICKED )
821         list_window_last(lw, lw_length);
822       else
823         list_window_next_page(lw, lw_length);
824       return 1;
825     } 
826   return 0;
828 #endif
830 void 
831 screen_cmd(mpdclient_t *c, command_t cmd)
833   screen->input_timestamp = time(NULL);
834   screen->last_cmd = cmd;
835   welcome = FALSE;
837   if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) )
838     return;
840   switch(cmd)
841     {
842     case CMD_PLAY:
843       mpdclient_cmd_play(c, MPD_PLAY_AT_BEGINNING);
844       break;
845     case CMD_PAUSE:
846       mpdclient_cmd_pause(c, !IS_PAUSED(c->status->state));
847       break;
848     case CMD_STOP:
849       mpdclient_cmd_stop(c);
850       break;
851     case CMD_SEEK_FORWARD:
852       if( !IS_STOPPED(c->status->state) )
853         {
854           if( c->song && seek_id != c->song->id )
855             {
856               seek_id = c->song->id;
857               seek_target_time = c->status->elapsedTime;
858             }
859           seek_target_time+=options.seek_time;
860           if( seek_target_time < c->status->totalTime )
861             break;
862           seek_target_time = c->status->totalTime;
863           /* seek_target_time=0; */
864         }
865       break;
866       /* fall through... */
867     case CMD_TRACK_NEXT:
868       if( !IS_STOPPED(c->status->state) )
869         mpdclient_cmd_next(c);
870       break;
871     case CMD_SEEK_BACKWARD:
872       if( !IS_STOPPED(c->status->state) )
873         {
874           if( seek_id != c->song->id )
875             {
876               seek_id = c->song->id;
877               seek_target_time = c->status->elapsedTime;
878             }
879           seek_target_time-=options.seek_time;
880           if( seek_target_time < 0 )
881             seek_target_time=0;
882         }
883       break;
884     case CMD_TRACK_PREVIOUS:
885       if( !IS_STOPPED(c->status->state) )
886         mpdclient_cmd_prev(c);
887       break;   
888     case CMD_SHUFFLE:
889       if( mpdclient_cmd_shuffle(c) == 0 )
890         screen_status_message(_("Shuffled playlist!"));
891       break;
892     case CMD_CLEAR:
893       if( mpdclient_cmd_clear(c) == 0 )
894         screen_status_message(_("Cleared playlist!"));
895       break;
896     case CMD_REPEAT:
897       mpdclient_cmd_repeat(c, !c->status->repeat);
898       break;
899     case CMD_RANDOM:
900       mpdclient_cmd_random(c, !c->status->random);
901       break;
902     case CMD_CROSSFADE:
903       if(  c->status->crossfade )
904         mpdclient_cmd_crossfade(c, 0);
905       else
906         mpdclient_cmd_crossfade(c, options.crossfade_time);     
907       break;
908     case CMD_DB_UPDATE:
909       if( !c->status->updatingDb )
910         {
911           if( mpdclient_cmd_db_update_utf8(c,NULL)==0 )
912             screen_status_printf(_("Database update started!"));
913         }
914       else
915         screen_status_printf(_("Database update running..."));
916       break;
917     case CMD_VOLUME_UP:
918       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
919         mpdclient_cmd_volume(c, ++c->status->volume);
920       break;
921     case CMD_VOLUME_DOWN:
922       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
923         mpdclient_cmd_volume(c, --c->status->volume);
924       break;
925     case CMD_TOGGLE_FIND_WRAP:
926       options.find_wrap = !options.find_wrap;
927       screen_status_printf(options.find_wrap ? 
928                            _("Find mode: Wrapped") :
929                            _("Find mode: Normal"));
930       break;
931     case CMD_TOGGLE_AUTOCENTER:
932       options.auto_center = !options.auto_center;
933       screen_status_printf(options.auto_center ?
934                            _("Auto center mode: On") :
935                            _("Auto center mode: Off"));
936       break;
937     case CMD_SCREEN_UPDATE:
938       screen->painted = 0;
939       break;
940     case CMD_SCREEN_PREVIOUS:
941       screen_next_mode(c, -1);
942       break;
943     case CMD_SCREEN_NEXT:
944       screen_next_mode(c, 1);
945       break;
946     case CMD_SCREEN_PLAY:
947       switch_screen_mode(SCREEN_PLAYLIST_ID, c);
948       break;
949     case CMD_SCREEN_FILE:
950       switch_screen_mode(SCREEN_BROWSE_ID, c);
951       break;
952     case CMD_SCREEN_HELP:
953       switch_screen_mode(SCREEN_HELP_ID, c);
954       break;
955     case CMD_SCREEN_SEARCH:
956       switch_screen_mode(SCREEN_SEARCH_ID, c);
957       break;
958     case CMD_SCREEN_ARTIST:
959       switch_screen_mode(SCREEN_ARTIST_ID, c);
960       break;
961     case CMD_SCREEN_KEYDEF:
962       switch_screen_mode(SCREEN_KEYDEF_ID, c);
963       break;
964     case CMD_SCREEN_CLOCK:
965       switch_screen_mode(SCREEN_CLOCK_ID, c);
966       break;
967     case CMD_QUIT:
968       exit(EXIT_SUCCESS);
969     default:
970       break;
971     }