Code

Added wreadln.c, wreadln.h a simple line editor
[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 "libmpdclient.h"
33 #include "mpc.h"
34 #include "command.h"
35 #include "options.h"
36 #include "colors.h"
37 #include "wreadln.h"
38 #include "screen.h"
39 #include "screen_play.h"
40 #include "screen_file.h"
41 #include "screen_help.h"
42 #include "screen_search.h"
43 #include "screen_utils.h"
45 #define ENABLE_STATUS_LINE_CLOCK
46 #define ENABLE_SCROLLING
48 #define DEFAULT_CROSSFADE_TIME 10
50 #define STATUS_MESSAGE_TIMEOUT 3
51 #define STATUS_LINE_MAX_SIZE   512
53 #ifdef ENABLE_KEYDEF_SCREEN
54 extern screen_functions_t *get_screen_keydef(void);
55 #endif
57 static screen_t *screen = NULL;
58 static screen_functions_t *mode_fn = NULL;
60 static void
61 switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
62 {
63   if( new_mode == screen->mode )
64     return;
66   /* close the old mode */
67   if( mode_fn && mode_fn->close )
68     mode_fn->close();
70   /* get functions for the new mode */
71   switch(new_mode)
72     {
73     case SCREEN_PLAY_WINDOW:
74       mode_fn = get_screen_playlist();
75       break;
76     case SCREEN_FILE_WINDOW:
77       mode_fn = get_screen_file();
78       break;
79     case SCREEN_HELP_WINDOW:
80       mode_fn = get_screen_help();
81       break;
82 #ifdef ENABLE_KEYDEF_SCREEN
83     case SCREEN_KEYDEF_WINDOW:
84       mode_fn = get_screen_keydef();
85       break;
86 #endif
87     default:
88       break;
89     }
91  screen->mode = new_mode;
92  screen->painted = 0;
94  /* open the new mode */
95  if( mode_fn && mode_fn->open )
96    mode_fn->open(screen, c);
98 }
100 static void
101 paint_top_window(char *header, mpd_client_t *c, int clear)
103   char flags[4];
104   static int prev_volume = -1;
105   static int prev_header_len = -1;
106   WINDOW *w = screen->top_window.w;
108   if(prev_header_len!=strlen(header))
109     {
110       prev_header_len = strlen(header);
111       clear = 1;
112     }
114   if(clear)
115     {
116       wmove(w, 0, 0);
117       wclrtoeol(w);
118     }
120   if(prev_volume!=c->status->volume || clear)
121     {
122       char buf[32];
124       if( header[0] )
125         {
126           colors_use(w, COLOR_TITLE_BOLD);
127           mvwaddstr(w, 0, 0, header);
128         }
129       else
130         {
131           colors_use(w, COLOR_TITLE_BOLD);
132           waddstr(w, get_key_names(CMD_SCREEN_HELP, FALSE));
133           colors_use(w, COLOR_TITLE);
134           waddstr(w, _(":Help  "));
135           colors_use(w, COLOR_TITLE_BOLD);
136           waddstr(w, get_key_names(CMD_SCREEN_PLAY, FALSE));
137           colors_use(w, COLOR_TITLE);
138           waddstr(w, _(":Playlist  "));
139           colors_use(w, COLOR_TITLE_BOLD);
140           waddstr(w, get_key_names(CMD_SCREEN_FILE, FALSE));
141           colors_use(w, COLOR_TITLE);
142           waddstr(w, _(":Browse"));
143         }
144       if( c->status->volume==MPD_STATUS_NO_VOLUME )
145         {
146           snprintf(buf, 32, _("Volume n/a "));
147         }
148       else
149         {
150           snprintf(buf, 32, _(" Volume %d%%"), c->status->volume); 
151         }
152       colors_use(w, COLOR_TITLE);
153       mvwaddstr(w, 0, screen->top_window.cols-strlen(buf), buf);
155       flags[0] = 0;
156       if( c->status->repeat )
157         strcat(flags, "r");
158       if( c->status->random )
159         strcat(flags, "z");
160       if( c->status->crossfade )
161         strcat(flags, "x");
162       if( c->status->updatingDb )
163         strcat(flags, "U");
164       colors_use(w, COLOR_LINE);
165       mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
166       if( flags[0] )
167         {
168           wmove(w,1,screen->top_window.cols-strlen(flags)-3);
169           waddch(w, '[');
170           colors_use(w, COLOR_LINE_BOLD);
171           waddstr(w, flags);
172           colors_use(w, COLOR_LINE);
173           waddch(w, ']');
174         }
175       wnoutrefresh(w);
176     }
179 static void
180 paint_progress_window(mpd_client_t *c)
182   double p;
183   int width;
184   int elapsedTime = c->status->elapsedTime;
186   if( c->status==NULL || IS_STOPPED(c->status->state) )
187     {
188       mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE, 
189                screen->progress_window.cols);
190       wnoutrefresh(screen->progress_window.w);
191       return;
192     }
194   if( c->seek_song_id == c->song_id )
195     elapsedTime = c->seek_target_time;
197   p = ((double) elapsedTime) / ((double) c->status->totalTime);
198   
199   width = (int) (p * (double) screen->progress_window.cols);
200   mvwhline(screen->progress_window.w, 
201            0, 0,
202            ACS_HLINE, 
203            screen->progress_window.cols);
204   whline(screen->progress_window.w, '=', width-1);
205   mvwaddch(screen->progress_window.w, 0, width-1, 'O');
206   wnoutrefresh(screen->progress_window.w);
209 #ifdef ENABLE_SCROLLING
210 static char *
211 scroll_string(char *str, char *sep, int width)
213   static int offset = 0;
214   static time_t t = 0;
215   char *tmp, *buf;
216   size_t len;
218   if( offset==0 )
219     {
220       offset++;
221       return g_strdup(str);
222     }
223  
224   /* create a buffer containing the string and the separator */
225   tmp = g_malloc(strlen(str)+strlen(sep)+1);
226   strcpy(tmp, str);
227   strcat(tmp, sep);
228   len = strlen(tmp);
230   if( offset >= len )
231    offset = 0;
232   
233   /* create the new scrolled string */
234   buf = g_malloc(width+1);
235   strncpy(buf, tmp+offset, width);
236   if( strlen(buf) < width )
237     strncat(buf, tmp, width-strlen(buf));
239   if( time(NULL)-t >= 1 )
240     {
241       t = time(NULL);
242       offset++;
243     }
244   g_free(tmp);
245   return buf;
247 #endif
249 static void 
250 paint_status_window(mpd_client_t *c)
252   WINDOW *w = screen->status_window.w;
253   mpd_Status *status = c->status;
254   mpd_Song *song   = c->song;
255   int elapsedTime = c->status->elapsedTime;
256   int x = 0;
258   if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT )
259     return;
260   
261   
262   wmove(w, 0, 0);
263   wclrtoeol(w);
264   colors_use(w, COLOR_STATUS_BOLD);
265   
266   switch(status->state)
267     {
268     case MPD_STATUS_STATE_STOP:
269       waddstr(w, _("Stopped! "));
270       break;
271     case MPD_STATUS_STATE_PLAY:
272       waddstr(w, _("Playing:"));
273       break;
274     case MPD_STATUS_STATE_PAUSE:
275       waddstr(w, _("[Paused]"));
276       break;
277     default:
278       break;
279     }
280   x += 9;
282   /* create time string */
283   memset(screen->buf, 0, screen->buf_size);
284   if( IS_PLAYING(status->state) || IS_PAUSED(status->state) )
285     {
286       if( status->totalTime > 0 )
287         {
288           if( c->seek_song_id == c->song_id )
289             elapsedTime = c->seek_target_time;
290           snprintf(screen->buf, screen->buf_size, 
291                    " [%i:%02i/%i:%02i]",
292                    elapsedTime/60, elapsedTime%60,
293                    status->totalTime/60,   status->totalTime%60 );
294         }
295       else
296         {
297           snprintf(screen->buf, screen->buf_size,  " [%d kbps]", status->bitRate );
298         }
299     }
300 #ifdef ENABLE_STATUS_LINE_CLOCK
301   else
302     {
303       time_t timep;
305       time(&timep);
306       /* Note: setlocale(LC_TIME,"") should be used first */
307       //strftime(screen->buf, screen->buf_size, "%x  - %X ",localtime(&timep));
308       strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep));
309     }
310 #endif
312   /* display song */
313   if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) &&  song )
314     {
315       char *songname = mpc_get_song_name(song);
316       int width = COLS-x-strlen(screen->buf);
318       colors_use(w, COLOR_STATUS);
319 #ifdef ENABLE_SCROLLING
320       if( strlen(songname) > width )
321         {
322           char *tmp = scroll_string(songname, " *** ", width);
323           strcpy(songname, tmp);
324           g_free(tmp);
325         }
326 #endif
327       mvwaddnstr(w, 0, x, songname, width);
328     } 
330   /* distplay time string */
331   if( screen->buf[0] )
332     {
333       x = screen->status_window.cols - strlen(screen->buf);
334       colors_use(w, COLOR_STATUS_TIME);
335       mvwaddstr(w, 0, x, screen->buf);
336     }
338   wnoutrefresh(w);
341 GList *
342 screen_free_string_list(GList *list)
344   GList *l = g_list_first(list);
345   
346   while(l)
347     {
348       g_free(l->data);
349       l->data = NULL;
350       l=l->next;
351     }
352   g_list_free(list);
353   return NULL;
356 int
357 screen_exit(void)
359   endwin();
360   if( screen )
361     {
362       GList *list = g_list_first(screen->screen_list);
364       /* close and exit all screens (playlist,browse,help...) */
365       while( list )
366         {
367           screen_functions_t *mode_fn = list->data;
369           if( mode_fn && mode_fn->close )
370             mode_fn->close();
371           if( mode_fn && mode_fn->exit )
372             mode_fn->exit();
373           list->data = NULL;
374           list=list->next;
375         }
376       g_list_free(screen->screen_list);
377       screen_free_string_list(screen->find_history);
378       g_free(screen->buf);
379       g_free(screen->findbuf);
380       
381       g_free(screen);
382       screen = NULL;
383     }
384   return 0;
387 void
388 screen_resize(void)
390   GList *list;
392 #ifdef DEBUG
393   fprintf(stderr, "Resize rows %d->%d, cols %d->%d\n",
394           screen->rows, LINES,
395           screen->cols, COLS);
396 #endif
397       
398   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
399     {
400       screen_exit();
401       fprintf(stderr, _("Error: Screen to small!\n"));
402       exit(EXIT_FAILURE);
403     }
405   resizeterm(LINES, COLS);
407   screen->cols = COLS;
408   screen->rows = LINES;
410   /* top window */
411   screen->top_window.cols = screen->cols;
412   wresize(screen->top_window.w, 2, screen->cols);
414   /* main window */
415   screen->main_window.cols = screen->cols;
416   screen->main_window.rows = screen->rows-4;
417   wresize(screen->main_window.w, screen->main_window.rows, screen->cols);
418   wclear(screen->main_window.w);
420   /* progress window */
421   screen->progress_window.cols = screen->cols;
422   wresize(screen->progress_window.w, 1, screen->cols);
423   mvwin(screen->progress_window.w, screen->rows-2, 0);
425   /* status window */
426   screen->status_window.cols = screen->cols;
427   wresize(screen->status_window.w, 1, screen->cols);
428   mvwin(screen->status_window.w, screen->rows-1, 0);
430   screen->buf_size = screen->cols;
431   g_free(screen->buf);
432   screen->buf = g_malloc(screen->cols);
434   list = g_list_first(screen->screen_list);
435   while( list )
436     {
437       screen_functions_t *mode_fn = list->data;
439       if( mode_fn && mode_fn->resize )
440         mode_fn->resize(screen->main_window.cols, screen->main_window.rows);
442       list=list->next;
443     }
445   /* ? - without this the cursor becomes visible with aterm & Eterm */
446   curs_set(1);
447   curs_set(0);     
449   screen->painted = 0;
452 void 
453 screen_status_message(char *msg)
455   WINDOW *w = screen->status_window.w;
457   wmove(w, 0, 0);
458   wclrtoeol(w);
459   colors_use(w, COLOR_STATUS_ALERT);
460   waddstr(w, msg);
461   wnoutrefresh(w);
462   screen->status_timestamp = time(NULL);
465 void 
466 screen_status_printf(char *format, ...)
468   char buffer[STATUS_LINE_MAX_SIZE];
469   va_list ap;
470   
471   va_start(ap,format);
472   vsnprintf(buffer,sizeof(buffer),format,ap);
473   va_end(ap);
474   screen_status_message(buffer);
477 int
478 screen_init(void)
480   GList *list;
482   /* initialize the curses library */
483   initscr();
484   /* initialize color support */
485   colors_start();
486   /* tell curses not to do NL->CR/NL on output */
487   nonl();          
488   /* take input chars one at a time, no wait for \n */  
489   cbreak();       
490   /* don't echo input */
491   noecho();    
492   /* set cursor invisible */     
493   curs_set(0);     
494   /* enable extra keys */
495   keypad(stdscr, TRUE);  
496   /* return from getch() without blocking */
497   timeout(SCREEN_TIMEOUT);
499   if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
500     {
501       fprintf(stderr, _("Error: Screen to small!\n"));
502       exit(EXIT_FAILURE);
503     }
505   screen = g_malloc(sizeof(screen_t));
506   memset(screen, 0, sizeof(screen_t));
507   screen->mode = SCREEN_PLAY_WINDOW;
508   screen->cols = COLS;
509   screen->rows = LINES;
510   screen->buf  = g_malloc(screen->cols);
511   screen->buf_size = screen->cols;
512   screen->findbuf = NULL;
513   screen->painted = 0;
514   screen->start_timestamp = time(NULL);
515   screen->input_timestamp = time(NULL);
516   screen->last_cmd = CMD_NONE;
518   /* create top window */
519   screen->top_window.rows = 2;
520   screen->top_window.cols = screen->cols;
521   screen->top_window.w = newwin(screen->top_window.rows, 
522                                   screen->top_window.cols,
523                                   0, 0);
524   leaveok(screen->top_window.w, TRUE);
525   keypad(screen->top_window.w, TRUE);  
527   /* create main window */
528   screen->main_window.rows = screen->rows-4;
529   screen->main_window.cols = screen->cols;
530   screen->main_window.w = newwin(screen->main_window.rows, 
531                                  screen->main_window.cols,
532                                  2, 
533                                  0);
535   //  leaveok(screen->main_window.w, TRUE); temporary disabled
536   keypad(screen->main_window.w, TRUE);  
538   /* create progress window */
539   screen->progress_window.rows = 1;
540   screen->progress_window.cols = screen->cols;
541   screen->progress_window.w = newwin(screen->progress_window.rows, 
542                                      screen->progress_window.cols,
543                                      screen->rows-2, 
544                                      0);
545   leaveok(screen->progress_window.w, TRUE);
546   
547   /* create status window */
548   screen->status_window.rows = 1;
549   screen->status_window.cols = screen->cols;
550   screen->status_window.w = newwin(screen->status_window.rows, 
551                                    screen->status_window.cols,
552                                    screen->rows-1, 
553                                    0);
555   leaveok(screen->status_window.w, FALSE);
556   keypad(screen->status_window.w, TRUE);  
558   if( options.enable_colors )
559     {
560       /* set background attributes */
561       wbkgd(stdscr, COLOR_PAIR(COLOR_LIST)); 
562       wbkgd(screen->main_window.w,     COLOR_PAIR(COLOR_LIST));
563       wbkgd(screen->top_window.w,      COLOR_PAIR(COLOR_TITLE));
564       wbkgd(screen->progress_window.w, COLOR_PAIR(COLOR_PROGRESSBAR));
565       wbkgd(screen->status_window.w,   COLOR_PAIR(COLOR_STATUS));
566       colors_use(screen->progress_window.w, COLOR_PROGRESSBAR);
567     }
569   /* initialize screens */
570   screen->screen_list = NULL;
571   screen->screen_list = g_list_append(screen->screen_list, 
572                                       (gpointer) get_screen_playlist());
573   screen->screen_list = g_list_append(screen->screen_list, 
574                                       (gpointer) get_screen_file());
575   screen->screen_list = g_list_append(screen->screen_list, 
576                                       (gpointer) get_screen_help());
577 #ifdef ENABLE_KEYDEF_SCREEN
578   screen->screen_list = g_list_append(screen->screen_list, 
579                                       (gpointer) get_screen_keydef());
580 #endif
582   list = screen->screen_list;
583   while( list )
584     {
585       screen_functions_t *fn = list->data;
586       
587       if( fn && fn->init )
588         fn->init(screen->main_window.w, 
589                  screen->main_window.cols,
590                  screen->main_window.rows);
591       
592       list = list->next;
593     }
595   mode_fn = get_screen_playlist();
597   /* initialize wreadln */
598   wrln_resize_callback = screen_resize;
600   return 0;
603 void 
604 screen_paint(mpd_client_t *c)
606   /* paint the title/header window */
607   if( mode_fn && mode_fn->get_title )
608     paint_top_window(mode_fn->get_title(), c, 1);
609   else
610     paint_top_window("", c, 1);
612   /* paint the main window */
613   if( mode_fn && mode_fn->paint )
614     mode_fn->paint(screen, c);
615   
616   paint_progress_window(c);
617   paint_status_window(c);
618   screen->painted = 1;
619   wmove(screen->main_window.w, 0, 0);  
620   wnoutrefresh(screen->main_window.w);
622   /* tell curses to update */
623   doupdate();
626 void 
627 screen_update(mpd_client_t *c)
629   static int repeat = -1;
630   static int random = -1;
631   static int crossfade = -1;
632   static int dbupdate = -1;
633   static int welcome = 1;
634   list_window_t *lw = NULL;
636   if( !screen->painted )
637     return screen_paint(c);
639   /* print a message if mpd status has changed */
640   if( repeat<0 )
641     {
642       repeat = c->status->repeat;
643       random = c->status->random;
644       crossfade = c->status->crossfade;
645       dbupdate = c->status->updatingDb;
646     }
647   if( repeat != c->status->repeat )
648     screen_status_printf(c->status->repeat ? 
649                          _("Repeat is on") :
650                          _("Repeat is off"));
651   if( random != c->status->random )
652     screen_status_printf(c->status->random ?
653                          _("Random is on") :
654                          _("Random is off"));
655                          
656   if( crossfade != c->status->crossfade )
657     screen_status_printf(_("Crossfade %d seconds"), c->status->crossfade);
658   if( dbupdate && dbupdate != c->status->updatingDb )
659     screen_status_printf(_("Database updated!"));
661   repeat = c->status->repeat;
662   random = c->status->random;
663   crossfade = c->status->crossfade;
664   dbupdate = c->status->updatingDb;
666   /* update title/header window */
667   if( welcome && screen->last_cmd==CMD_NONE &&
668       time(NULL)-screen->start_timestamp <= SCREEN_WELCOME_TIME)
669     paint_top_window("", c, 0);
670   else if( mode_fn && mode_fn->get_title )
671     {
672       paint_top_window(mode_fn->get_title(), c, 0);
673       welcome = 0;
674     }
675   else
676     paint_top_window("", c, 0);
678   /* update the main window */
679   if( mode_fn && mode_fn->paint )
680     mode_fn->update(screen, c);
682   if( mode_fn && mode_fn->get_lw )
683     lw = mode_fn->get_lw();
685   /* update progress window */
686   paint_progress_window(c);
688   /* update status window */
689   paint_status_window(c);
691   /* move the cursor to the selected row in the main window */
692   if( lw )
693     wmove(screen->main_window.w, LW_ROW(lw), 0);   
694   else
695     wmove(screen->main_window.w, 0, 0);   
696   wnoutrefresh(screen->main_window.w);
698   /* tell curses to update */
699   doupdate();
702 void
703 screen_idle(mpd_client_t *c)
705   if( c->seek_song_id ==  c->song_id &&
706       (screen->last_cmd == CMD_SEEK_FORWARD || 
707        screen->last_cmd == CMD_SEEK_BACKWARD) )
708     {
709       mpd_sendSeekCommand(c->connection, 
710                           c->seek_song_id, 
711                           c->seek_target_time);
712       mpd_finishCommand(c->connection);
713     }
715   screen->last_cmd = CMD_NONE;
716   c->seek_song_id = -1;
719 void 
720 screen_cmd(mpd_client_t *c, command_t cmd)
722   int n = 0;
723   screen_mode_t new_mode = screen->mode;
725   screen->input_timestamp = time(NULL);
726   screen->last_cmd = cmd;
728   if( mode_fn && mode_fn->cmd && mode_fn->cmd(screen, c, cmd) )
729     return;
731   switch(cmd)
732     {
733     case CMD_PLAY:
734       if( screen->mode == SCREEN_PLAY_WINDOW )
735         n = play_get_selected();
736       else
737         n = -1;
738       mpd_sendPlayCommand(c->connection, n);
739       mpd_finishCommand(c->connection);
740       break;
741     case CMD_PAUSE:
742       mpd_sendPauseCommand(c->connection);
743       mpd_finishCommand(c->connection);
744       break;
745     case CMD_STOP:
746       mpd_sendStopCommand(c->connection);
747       mpd_finishCommand(c->connection);
748       break;
749     case CMD_SEEK_FORWARD:
750       if( !IS_STOPPED(c->status->state) )
751         {
752           if( c->seek_song_id != c->song_id )
753             {
754               c->seek_song_id = c->song_id;
755               c->seek_target_time = c->status->elapsedTime;
756             }
757           c->seek_target_time++;
758           if( c->seek_target_time < c->status->totalTime )
759             break;
760           c->seek_target_time=0;
761         }
762       /* fall through... */
763     case CMD_TRACK_NEXT:
764       if( !IS_STOPPED(c->status->state) )
765         {
766           mpd_sendNextCommand(c->connection);
767           mpd_finishCommand(c->connection);
768         }
769       break;
770     case CMD_SEEK_BACKWARD:
771       if( !IS_STOPPED(c->status->state) )
772         {
773           if( c->seek_song_id != c->song_id )
774             {
775               c->seek_song_id = c->song_id;
776               c->seek_target_time = c->status->elapsedTime;
777             }
778           c->seek_target_time--;
779           if( c->seek_target_time < 0 )
780             c->seek_target_time=0;
781         }
782       break;
783     case CMD_TRACK_PREVIOUS:
784       if( !IS_STOPPED(c->status->state) )
785         {
786           mpd_sendPrevCommand(c->connection);
787           mpd_finishCommand(c->connection);
788         }
789       break;   
790     case CMD_SHUFFLE:
791       mpd_sendShuffleCommand(c->connection);
792       mpd_finishCommand(c->connection);
793       screen_status_message(_("Shuffled playlist!"));
794       break;
795     case CMD_CLEAR:
796       mpd_sendClearCommand(c->connection);
797       mpd_finishCommand(c->connection);
798       file_clear_highlights(c);
799       screen_status_message(_("Cleared playlist!"));
800       break;
801     case CMD_REPEAT:
802       n = !c->status->repeat;
803       mpd_sendRepeatCommand(c->connection, n);
804       mpd_finishCommand(c->connection);
805       break;
806     case CMD_RANDOM:
807       n = !c->status->random;
808       mpd_sendRandomCommand(c->connection, n);
809       mpd_finishCommand(c->connection);
810       break;
811     case CMD_CROSSFADE:
812       if( c->status->crossfade )
813         n = 0;
814       else
815         n = DEFAULT_CROSSFADE_TIME;
816       mpd_sendCrossfadeCommand(c->connection, n);
817       mpd_finishCommand(c->connection);
818       break;
819     case CMD_DB_UPDATE:
820       if( !c->status->updatingDb )
821         {
822           mpd_sendUpdateCommand(c->connection);
823           n = mpd_getUpdateId(c->connection);
824           mpd_finishCommand(c->connection);
825           if( !mpc_error(c) )
826             screen_status_printf(_("Database update started [%d]"), n);
827         }
828       else
829         screen_status_printf(_("Database update running..."));
830       break;
831     case CMD_VOLUME_UP:
832       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
833         {
834           c->status->volume=c->status->volume+1;
835           mpd_sendSetvolCommand(c->connection, c->status->volume  );
836           mpd_finishCommand(c->connection);
837         }
838       break;
839     case CMD_VOLUME_DOWN:
840       if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
841         {
842           c->status->volume=c->status->volume-1;
843           mpd_sendSetvolCommand(c->connection, c->status->volume  );
844           mpd_finishCommand(c->connection);
845         }
846       break;
847     case CMD_TOGGLE_FIND_WRAP:
848       options.find_wrap = !options.find_wrap;
849       screen_status_printf(options.find_wrap ? 
850                            _("Find mode: Wrapped") :
851                            _("Find mode: Normal"));
852       break;
853     case CMD_TOGGLE_AUTOCENTER:
854       options.auto_center = !options.auto_center;
855       screen_status_printf(options.auto_center ?
856                            _("Auto center mode: On") :
857                            _("Auto center mode: Off"));
858       break;
859     case CMD_SCREEN_PREVIOUS:
860       if( screen->mode > SCREEN_PLAY_WINDOW )
861         new_mode = screen->mode - 1;
862       else
863         new_mode = SCREEN_HELP_WINDOW-1;
864       switch_screen_mode(new_mode, c);
865       break;
866     case CMD_SCREEN_NEXT:
867       new_mode = screen->mode + 1;
868       if( new_mode >= SCREEN_HELP_WINDOW )
869         new_mode = SCREEN_PLAY_WINDOW;
870       switch_screen_mode(new_mode, c);
871       break;
872     case CMD_SCREEN_PLAY:
873       switch_screen_mode(SCREEN_PLAY_WINDOW, c);
874       break;
875     case CMD_SCREEN_FILE:
876       switch_screen_mode(SCREEN_FILE_WINDOW, c);
877       break;
878     case CMD_SCREEN_SEARCH:
879       switch_screen_mode(SCREEN_SEARCH_WINDOW, c);
880       break;
881     case CMD_SCREEN_HELP:
882       switch_screen_mode(SCREEN_HELP_WINDOW, c);
883       break;
884 #ifdef ENABLE_KEYDEF_SCREEN 
885     case CMD_SCREEN_KEYDEF:
886       switch_screen_mode(SCREEN_KEYDEF_WINDOW, c);
887       break;
888 #endif
889     case CMD_QUIT:
890       exit(EXIT_SUCCESS);
891     default:
892       break;
893     }