3012fa31ae668494f3126b78bffd67c271f9a119
1 /*
2 * $Id: screen.c,v 1.10 2004/03/17 14:50:12 kalle Exp $
3 *
4 */
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <time.h>
11 #include <glib.h>
12 #include <ncurses.h>
14 #include "libmpdclient.h"
15 #include "mpc.h"
16 #include "command.h"
17 #include "screen.h"
18 #include "screen_play.h"
19 #include "screen_file.h"
20 #include "screen_help.h"
21 #include "screen_search.h"
23 #define STATUS_MESSAGE_TIMEOUT 3
24 #define STATUS_LINE_MAX_SIZE 512
26 static screen_t *screen = NULL;
28 static void
29 switch_screen_mode(screen_mode_t new_mode, mpd_client_t *c)
30 {
31 if( new_mode == screen->mode )
32 return;
34 switch(screen->mode)
35 {
36 case SCREEN_PLAY_WINDOW:
37 play_close(screen, c);
38 break;
39 case SCREEN_FILE_WINDOW:
40 file_close(screen, c);
41 break;
42 case SCREEN_SEARCH_WINDOW:
43 search_close(screen, c);
44 break;
45 case SCREEN_HELP_WINDOW:
46 help_close(screen, c);
47 break;
48 }
50 screen->mode = new_mode;
51 screen->painted = 0;
53 switch(screen->mode)
54 {
55 case SCREEN_PLAY_WINDOW:
56 play_open(screen, c);
57 break;
58 case SCREEN_FILE_WINDOW:
59 file_open(screen, c);
60 break;
61 case SCREEN_SEARCH_WINDOW:
62 search_open(screen, c);
63 break;
64 case SCREEN_HELP_WINDOW:
65 help_open(screen, c);
66 break;
67 }
68 }
70 static void
71 paint_top_window(char *header, int volume, int clear)
72 {
73 static int prev_volume = -1;
74 WINDOW *w = screen->top_window.w;
76 if(clear)
77 {
78 wclear(w);
79 }
81 if(prev_volume!=volume || clear)
82 {
83 char buf[12];
85 wattron(w, A_BOLD);
86 mvwaddstr(w, 0, 0, header );
87 wattroff(w, A_BOLD);
88 if( volume==MPD_STATUS_NO_VOLUME )
89 {
90 snprintf(buf, 12, "Volume n/a ");
91 }
92 else
93 {
94 snprintf(buf, 12, "Volume %3d%%", volume);
95 }
96 mvwaddstr(w, 0, screen->top_window.cols-12, buf);
98 mvwhline(w, 1, 0, ACS_HLINE, screen->top_window.cols);
100 wrefresh(w);
101 }
102 }
104 static void
105 paint_progress_window(mpd_client_t *c)
106 {
107 double p;
108 int width;
110 if( c->status==NULL || !IS_PLAYING(c->status->state) )
111 {
112 mvwhline(screen->progress_window.w, 0, 0, ACS_HLINE,
113 screen->progress_window.cols);
114 wrefresh(screen->progress_window.w);
115 return;
116 }
118 p = ((double) c->status->elapsedTime) / ((double) c->status->totalTime);
120 width = (int) (p * (double) screen->progress_window.cols);
122 mvwhline(screen->progress_window.w,
123 0, 0,
124 ACS_HLINE,
125 screen->progress_window.cols);
127 whline(screen->progress_window.w, '=', width-1);
129 mvwaddch(screen->progress_window.w, 0, width-1, 'O');
130 wrefresh(screen->progress_window.w);
131 }
133 static void
134 paint_status_window(mpd_client_t *c)
135 {
136 WINDOW *w = screen->status_window.w;
137 mpd_Status *status = c->status;
138 mpd_Song *song = c->song;
139 int x = 0;
141 if( time(NULL) - screen->status_timestamp <= STATUS_MESSAGE_TIMEOUT )
142 return;
144 wmove(w, 0, 0);
145 wclrtoeol(w);
147 switch(status->state)
148 {
149 case MPD_STATUS_STATE_STOP:
150 wattron(w, A_BOLD);
151 waddstr(w, "Stopped! ");
152 wattroff(w, A_BOLD);
153 break;
154 case MPD_STATUS_STATE_PLAY:
155 waddstr(w, "Playing:");
156 break;
157 case MPD_STATUS_STATE_PAUSE:
158 wattron(w, A_BOLD);
159 waddstr(w, "Paused:");
160 wattroff(w, A_BOLD);
161 break;
162 default:
163 waddstr(w, "Warning: Music Player Daemon in unknown state!");
164 break;
165 }
166 x += 10;
168 if( IS_PLAYING(status->state) && song )
169 {
170 mvwaddstr(w, 0, x, mpc_get_song_name(song));
171 }
174 /* time */
175 if( IS_PLAYING(status->state) )
176 {
177 x = screen->status_window.cols - strlen(screen->buf);
179 snprintf(screen->buf, screen->buf_size,
180 " [%i:%02i/%i:%02i] ",
181 status->elapsedTime/60, status->elapsedTime%60,
182 status->totalTime/60, status->totalTime%60 );
183 mvwaddstr(w, 0, x, screen->buf);
185 }
186 #if 1
187 else if( c->status->state == MPD_STATUS_STATE_STOP )
188 {
189 time_t timep;
190 x = screen->status_window.cols - strlen(screen->buf);
192 time(&timep);
193 //strftime(screen->buf, screen->buf_size, "%X ", localtime(&timep));
194 strftime(screen->buf, screen->buf_size, "%R ", localtime(&timep));
195 mvwaddstr(w, 0, x, screen->buf);
196 }
197 #endif
200 wrefresh(w);
201 }
205 int
206 screen_exit(void)
207 {
208 endwin();
209 if( screen )
210 {
211 screen->playlist = list_window_free(screen->playlist);
212 screen->filelist = list_window_free(screen->filelist);
213 screen->helplist = list_window_free(screen->helplist);
214 free(screen->buf);
215 free(screen->findbuf);
216 free(screen);
217 screen = NULL;
218 }
219 return 0;
220 }
222 void
223 screen_resized(int sig)
224 {
225 screen_exit();
226 if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
227 {
228 fprintf(stderr, "Error: Screen to small!\n");
229 exit(EXIT_FAILURE);
230 }
231 screen_init();
232 }
234 void
235 screen_status_message(char *msg)
236 {
237 WINDOW *w = screen->status_window.w;
239 wmove(w, 0, 0);
240 wclrtoeol(w);
241 wattron(w, A_BOLD);
242 waddstr(w, msg);
243 wattroff(w, A_BOLD);
244 wrefresh(w);
245 screen->status_timestamp = time(NULL);
246 }
248 void
249 screen_status_printf(char *format, ...)
250 {
251 char buffer[STATUS_LINE_MAX_SIZE];
252 va_list ap;
254 va_start(ap,format);
255 vsnprintf(buffer,sizeof(buffer),format,ap);
256 va_end(ap);
257 screen_status_message(buffer);
258 }
260 int
261 screen_init(void)
262 {
263 /* initialize the curses library */
264 initscr();
265 start_color();
266 use_default_colors();
267 /* tell curses not to do NL->CR/NL on output */
268 nonl();
269 /* take input chars one at a time, no wait for \n */
270 cbreak();
271 /* don't echo input */
272 noecho();
273 /* set cursor invisible */
274 curs_set(0);
275 /* return from getch() without blocking */
276 // nodelay(stdscr, TRUE);
277 keypad(stdscr, TRUE);
278 timeout(100); /*void wtimeout(WINDOW *win, int delay);*/
281 if( COLS<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
282 {
283 fprintf(stderr, "Error: Screen to small!\n");
284 exit(EXIT_FAILURE);
285 }
287 screen = malloc(sizeof(screen_t));
288 memset(screen, 0, sizeof(screen_t));
289 screen->mode = SCREEN_PLAY_WINDOW;
290 screen->cols = COLS;
291 screen->rows = LINES;
292 screen->buf = malloc(screen->cols);
293 screen->buf_size = screen->cols;
294 screen->findbuf = NULL;
295 screen->painted = 0;
297 /* create top window */
298 screen->top_window.rows = 2;
299 screen->top_window.cols = screen->cols;
300 screen->top_window.w = newwin(screen->top_window.rows,
301 screen->top_window.cols,
302 0, 0);
303 leaveok(screen->top_window.w, TRUE);
304 keypad(screen->top_window.w, TRUE);
306 /* create main window */
307 screen->main_window.rows = screen->rows-4;
308 screen->main_window.cols = screen->cols;
309 screen->main_window.w = newwin(screen->main_window.rows,
310 screen->main_window.cols,
311 2,
312 0);
313 screen->playlist = list_window_init( screen->main_window.w,
314 screen->main_window.cols,
315 screen->main_window.rows );
316 screen->filelist = list_window_init( screen->main_window.w,
317 screen->main_window.cols,
318 screen->main_window.rows );
319 screen->helplist = list_window_init( screen->main_window.w,
320 screen->main_window.cols,
321 screen->main_window.rows );
322 leaveok(screen->main_window.w, TRUE);
323 keypad(screen->main_window.w, TRUE);
325 /* create progress window */
326 screen->progress_window.rows = 1;
327 screen->progress_window.cols = screen->cols;
328 screen->progress_window.w = newwin(screen->progress_window.rows,
329 screen->progress_window.cols,
330 screen->rows-2,
331 0);
332 leaveok(screen->progress_window.w, TRUE);
334 /* create status window */
335 screen->status_window.rows = 1;
336 screen->status_window.cols = screen->cols;
337 screen->status_window.w = newwin(screen->status_window.rows,
338 screen->status_window.cols,
339 screen->rows-1,
340 0);
341 leaveok(screen->status_window.w, FALSE);
342 keypad(screen->status_window.w, TRUE);
344 return 0;
345 }
347 void
348 screen_paint(mpd_client_t *c)
349 {
350 switch(screen->mode)
351 {
352 case SCREEN_PLAY_WINDOW:
353 paint_top_window(TOP_HEADER_PLAY, c->status->volume, 1);
354 play_paint(screen, c);
355 break;
356 case SCREEN_FILE_WINDOW:
357 paint_top_window(file_get_header(c), c->status->volume, 1);
358 file_paint(screen, c);
359 break;
360 case SCREEN_SEARCH_WINDOW:
361 paint_top_window(TOP_HEADER_SEARCH, c->status->volume, 1);
362 search_paint(screen, c);
363 break;
364 case SCREEN_HELP_WINDOW:
365 paint_top_window(TOP_HEADER_PLAY, c->status->volume, 1);
366 help_paint(screen, c);
367 break;
368 }
370 paint_progress_window(c);
371 paint_status_window(c);
372 screen->painted = 1;
373 }
375 void
376 screen_update(mpd_client_t *c)
377 {
378 if( !screen->painted )
379 return screen_paint(c);
381 switch(screen->mode)
382 {
383 case SCREEN_PLAY_WINDOW:
384 paint_top_window(TOP_HEADER_PLAY, c->status->volume, 0);
385 play_update(screen, c);
386 break;
387 case SCREEN_FILE_WINDOW:
388 paint_top_window(file_get_header(c), c->status->volume, 0);
389 file_update(screen, c);
390 break;
391 case SCREEN_SEARCH_WINDOW:
392 paint_top_window(TOP_HEADER_SEARCH, c->status->volume, 0);
393 search_update(screen, c);
394 break;
395 case SCREEN_HELP_WINDOW:
396 paint_top_window(TOP_HEADER_HELP, c->status->volume, 0);
397 help_update(screen, c);
398 break;
399 }
400 paint_progress_window(c);
401 paint_status_window(c);
402 }
404 void
405 screen_cmd(mpd_client_t *c, command_t cmd)
406 {
407 int n;
408 // char buf[256];
409 screen_mode_t new_mode = screen->mode;
411 switch(screen->mode)
412 {
413 case SCREEN_PLAY_WINDOW:
414 if( play_cmd(screen, c, cmd) )
415 return;
416 break;
417 case SCREEN_FILE_WINDOW:
418 if( file_cmd(screen, c, cmd) )
419 return;
420 break;
421 case SCREEN_SEARCH_WINDOW:
422 if( search_cmd(screen, c, cmd) )
423 return;
424 break;
425 case SCREEN_HELP_WINDOW:
426 if( help_cmd(screen, c, cmd) )
427 return;
428 break;
429 }
431 switch(cmd)
432 {
433 case CMD_PLAY:
434 mpd_sendPlayCommand(c->connection, screen->playlist->selected);
435 mpd_finishCommand(c->connection);
436 break;
437 case CMD_PAUSE:
438 mpd_sendPauseCommand(c->connection);
439 mpd_finishCommand(c->connection);
440 break;
441 case CMD_STOP:
442 mpd_sendStopCommand(c->connection);
443 mpd_finishCommand(c->connection);
444 break;
445 case CMD_TRACK_NEXT:
446 if( IS_PLAYING(c->status->state) )
447 {
448 mpd_sendNextCommand(c->connection);
449 mpd_finishCommand(c->connection);
450 }
451 break;
452 case CMD_TRACK_PREVIOUS:
453 if( IS_PLAYING(c->status->state) )
454 {
455 mpd_sendPrevCommand(c->connection);
456 mpd_finishCommand(c->connection);
457 }
458 break;
459 case CMD_SHUFFLE:
460 mpd_sendShuffleCommand(c->connection);
461 mpd_finishCommand(c->connection);
462 screen_status_message("Shuffled playlist!");
463 break;
464 case CMD_CLEAR:
465 mpd_sendClearCommand(c->connection);
466 mpd_finishCommand(c->connection);
467 file_clear_highlights(c);
468 screen_status_message("Cleared playlist!");
469 break;
470 case CMD_REPEAT:
471 n = !c->status->repeat;
472 mpd_sendRepeatCommand(c->connection, n);
473 mpd_finishCommand(c->connection);
474 screen_status_printf("Repeat is %s", n ? "On" : "Off");
475 break;
476 case CMD_RANDOM:
477 n = !c->status->random;
478 mpd_sendRandomCommand(c->connection, n);
479 mpd_finishCommand(c->connection);
480 screen_status_printf("Random is %s", n ? "On" : "Off");
481 break;
482 case CMD_VOLUME_UP:
483 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume<100 )
484 {
485 c->status->volume=c->status->volume+1;
486 mpd_sendSetvolCommand(c->connection, c->status->volume );
487 mpd_finishCommand(c->connection);
488 screen_status_printf("Volume %d%%", c->status->volume);
489 }
490 break;
491 case CMD_VOLUME_DOWN:
492 if( c->status->volume!=MPD_STATUS_NO_VOLUME && c->status->volume>0 )
493 {
494 c->status->volume=c->status->volume-1;
495 mpd_sendSetvolCommand(c->connection, c->status->volume );
496 mpd_finishCommand(c->connection);
497 screen_status_printf("Volume %d%%", c->status->volume);
498 }
499 break;
500 case CMD_SCREEN_PREVIOUS:
501 if( screen->mode > SCREEN_PLAY_WINDOW )
502 new_mode = screen->mode - 1;
503 else
504 new_mode = SCREEN_HELP_WINDOW-1;
505 switch_screen_mode(new_mode, c);
506 break;
507 case CMD_SCREEN_NEXT:
508 new_mode = screen->mode + 1;
509 if( new_mode >= SCREEN_HELP_WINDOW )
510 new_mode = SCREEN_PLAY_WINDOW;
511 switch_screen_mode(new_mode, c);
512 break;
513 case CMD_SCREEN_PLAY:
514 switch_screen_mode(SCREEN_PLAY_WINDOW, c);
515 break;
516 case CMD_SCREEN_FILE:
517 switch_screen_mode(SCREEN_FILE_WINDOW, c);
518 break;
519 case CMD_SCREEN_SEARCH:
520 switch_screen_mode(SCREEN_SEARCH_WINDOW, c);
521 break;
522 case CMD_SCREEN_HELP:
523 switch_screen_mode(SCREEN_HELP_WINDOW, c);
524 break;
525 case CMD_QUIT:
526 exit(EXIT_SUCCESS);
527 case CMD_LIST_FIND:
528 case CMD_LIST_FIND_NEXT:
529 case CMD_NONE:
530 case CMD_DELETE:
531 case CMD_SELECT:
532 case CMD_LIST_PREVIOUS:
533 case CMD_LIST_NEXT:
534 case CMD_LIST_FIRST:
535 case CMD_LIST_LAST:
536 case CMD_LIST_NEXT_PAGE:
537 case CMD_LIST_PREVIOUS_PAGE:
538 break;
539 }
541 }