c63f9b804b5e994926b5bb8f548747cdb96c95ad
[paraslash.git] / sdl_gui.c
1 /*
2  * Copyright (C) 2003-2007 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file sdl_gui.c SDL-based interface for paraslash */
8
9 #include <sys/types.h>
10 #include <dirent.h>
11
12 #include "para.h"
13 #include "gui_common.h"
14 #include "fd.h"
15
16
17 #include <SDL/SDL.h>
18 #include "SFont.h"
19
20 #include <SDL/SDL_image.h>
21 #include <SDL/SDL_events.h>
22 #include <SDL/SDL_keyboard.h>
23 #include <SDL/SDL_keysym.h>
24 #include <sys/time.h> /* timeval, needed for select */
25
26 #include "sdl_gui.cmdline.h"
27
28 #define FRAME_RED 100
29 #define FRAME_GREEN 200
30 #define FRAME_BLUE 200
31
32 SDL_Surface *screen;
33 static int width = 0;
34 static int height = 0;
35
36 extern const char *status_item_list[NUM_STAT_ITEMS];
37 struct sdl_gui_args_info args_info;
38
39 #define FRAME_WIDTH 10
40 #define FONT_HEIGHT 36
41
42 #define INPUT_WIDTH width - 2 * FRAME_WIDTH
43 #define INPUT_X FRAME_WIDTH
44 #define INPUT_HEIGHT (args_info.interactive_flag? FONT_HEIGHT : 0)
45 #define INPUT_Y height - FRAME_WIDTH - INPUT_HEIGHT
46
47 #define OUTPUT_WIDTH width - 2 * FRAME_WIDTH
48 #define OUTPUT_X FRAME_WIDTH
49 #define OUTPUT_Y FRAME_WIDTH
50 #define OUTPUT_HEIGHT (height - INPUT_HEIGHT - 2 * FRAME_WIDTH)
51
52 #define NUM_LINES (height - 2 * FRAME_WIDTH - INPUT_HEIGHT) / FONT_HEIGHT
53
54 #define M_YELLOW 0
55 #define N_YELLOW 1
56
57 #define LEFT 1
58 #define RIGHT 2
59 #define CENTER 3
60
61
62 struct stat_item{
63         const char *name;
64         const char *prefix;
65         const char *postfix;
66         char *content;
67         unsigned x;
68         unsigned y;
69         unsigned w;
70         unsigned h;
71         Uint8 r;
72         Uint8 g;
73         Uint8 b;
74         int font;
75         int align;
76 };
77
78 struct font {
79         char name[MAXLINE];
80         SFont_FontInfo fontinfo;
81 };
82
83 struct font fonts[] = {
84         {
85                 .name = "24P_Arial_Metallic_Yellow.png",
86                 .fontinfo = {NULL, {0}, 0}
87         },
88         {
89                 .name = "24P_Arial_NeonYellow.png",
90                 .fontinfo = {NULL, {0}, 0}
91         },
92         {
93                 .name = "24P_Copperplate_Blue.png",
94                 .fontinfo = {NULL, {0}, 0}
95         },
96         {
97                 .name = "",
98                 .fontinfo = {NULL, {0}, 0}
99         }
100 };
101
102
103 #define PIC_WIDTH width * 3 / 10
104 #define PIC_HEIGHT height / 3
105
106 #define INPUT_FONT 0
107 #define OUTPUT_FONT 1
108 #define MSG_FONT 2
109
110
111 static struct stat_item stat_items[NUM_STAT_ITEMS];
112
113 void para_log(__a_unused int ll, __a_unused const char* fmt,...) /* no logging */
114 {
115 }
116
117 static void init_stat_items(void)
118 {
119         int i;
120         struct stat_item *s = stat_items;
121
122         for (i = 0; i < NUM_STAT_ITEMS; i++) {
123                 s[i].w = 0;
124                 s[i].content = NULL;
125         }
126
127
128         s[SI_STATUS_BAR].prefix = "";
129         s[SI_STATUS_BAR].postfix = "";
130         s[SI_STATUS_BAR].x = 0;
131         s[SI_STATUS_BAR].y = 10;
132         s[SI_STATUS_BAR].w = 100;
133         s[SI_STATUS_BAR].h = FONT_HEIGHT;
134         s[SI_STATUS_BAR].r = 0;
135         s[SI_STATUS_BAR].g = 0;
136         s[SI_STATUS_BAR].b = 0;
137         s[SI_STATUS_BAR].font = M_YELLOW;
138         s[SI_STATUS_BAR].align = CENTER;
139
140         s[SI_PLAY_TIME].prefix = "";
141         s[SI_PLAY_TIME].postfix = "";
142         s[SI_PLAY_TIME].x = 35;
143         s[SI_PLAY_TIME].y = 20;
144         s[SI_PLAY_TIME].w = 65;
145         s[SI_PLAY_TIME].h = FONT_HEIGHT;
146         s[SI_PLAY_TIME].r = 0;
147         s[SI_PLAY_TIME].g = 0;
148         s[SI_PLAY_TIME].b = 0;
149         s[SI_PLAY_TIME].font = M_YELLOW;
150         s[SI_PLAY_TIME].align = CENTER;
151
152         s[SI_STATUS].prefix = "";
153         s[SI_STATUS].postfix = "";
154         s[SI_STATUS].x = 35;
155         s[SI_STATUS].y = 28;
156         s[SI_STATUS].w = 12;
157         s[SI_STATUS].h = FONT_HEIGHT;
158         s[SI_STATUS].r = 0;
159         s[SI_STATUS].g = 0;
160         s[SI_STATUS].b = 0;
161         s[SI_STATUS].font = N_YELLOW;
162         s[SI_STATUS].align = LEFT;
163
164         s[SI_STATUS_FLAGS].prefix = " (";
165         s[SI_STATUS_FLAGS].postfix = ")";
166         s[SI_STATUS_FLAGS].x = 47;
167         s[SI_STATUS_FLAGS].y = 28;
168         s[SI_STATUS_FLAGS].w = 15;
169         s[SI_STATUS_FLAGS].h = FONT_HEIGHT;
170         s[SI_STATUS_FLAGS].r = 0;
171         s[SI_STATUS_FLAGS].g = 0;
172         s[SI_STATUS_FLAGS].b = 0;
173         s[SI_STATUS_FLAGS].font = N_YELLOW;
174         s[SI_STATUS_FLAGS].align = CENTER;
175
176         s[SI_NUM_PLAYED].prefix = "#";
177         s[SI_NUM_PLAYED].postfix = "";
178         s[SI_NUM_PLAYED].x = 62;
179         s[SI_NUM_PLAYED].y = 28;
180         s[SI_NUM_PLAYED].w = 13;
181         s[SI_NUM_PLAYED].h = FONT_HEIGHT;
182         s[SI_NUM_PLAYED].r = 0;
183         s[SI_NUM_PLAYED].g = 0;
184         s[SI_NUM_PLAYED].b = 0;
185         s[SI_NUM_PLAYED].font = N_YELLOW;
186         s[SI_NUM_PLAYED].align = CENTER;
187
188         s[SI_UPTIME].prefix = "Up: ";
189         s[SI_UPTIME].postfix = "";
190         s[SI_UPTIME].x = 75;
191         s[SI_UPTIME].y = 28;
192         s[SI_UPTIME].w = 25;
193         s[SI_UPTIME].h = FONT_HEIGHT;
194         s[SI_UPTIME].r = 0;
195         s[SI_UPTIME].g = 0;
196         s[SI_UPTIME].b = 0;
197         s[SI_UPTIME].font = N_YELLOW;
198         s[SI_UPTIME].align = RIGHT;
199
200         s[SI_SELECTOR].prefix = "selector: ";
201         s[SI_SELECTOR].postfix = "";
202         s[SI_SELECTOR].x = 35;
203         s[SI_SELECTOR].y = 48;
204         s[SI_SELECTOR].w = 35;
205         s[SI_SELECTOR].h = FONT_HEIGHT;
206         s[SI_SELECTOR].r = 0;
207         s[SI_SELECTOR].g = 0;
208         s[SI_SELECTOR].b = 0;
209         s[SI_SELECTOR].font = N_YELLOW;
210         s[SI_SELECTOR].align = LEFT;
211
212         s[SI_FORMAT].prefix = "Format: ";
213         s[SI_FORMAT].postfix = "";
214         s[SI_FORMAT].x = 70;
215         s[SI_FORMAT].y = 48;
216         s[SI_FORMAT].w = 30;
217         s[SI_FORMAT].h = FONT_HEIGHT;
218         s[SI_FORMAT].r = 0;
219         s[SI_FORMAT].g = 0;
220         s[SI_FORMAT].b = 0;
221         s[SI_FORMAT].font = N_YELLOW;
222         s[SI_FORMAT].align = RIGHT;
223
224         s[SI_MTIME].prefix = "MTime: ";
225         s[SI_MTIME].postfix = "";
226         s[SI_MTIME].x = 35;
227         s[SI_MTIME].y = 35;
228         s[SI_MTIME].w = 65;
229         s[SI_MTIME].h = FONT_HEIGHT;
230         s[SI_MTIME].r = 0;
231         s[SI_MTIME].g = 0;
232         s[SI_MTIME].b = 0;
233         s[SI_MTIME].font = N_YELLOW;
234         s[SI_MTIME].align = LEFT;
235
236         s[SI_FILE_SIZE].prefix = "Size: ";
237         s[SI_FILE_SIZE].postfix = "kb";
238         s[SI_FILE_SIZE].x = 35;
239         s[SI_FILE_SIZE].y = 42;
240         s[SI_FILE_SIZE].w = 20;
241         s[SI_FILE_SIZE].h = FONT_HEIGHT;
242         s[SI_FILE_SIZE].r = 0;
243         s[SI_FILE_SIZE].g = 0;
244         s[SI_FILE_SIZE].b = 0;
245         s[SI_FILE_SIZE].font = N_YELLOW;
246         s[SI_FILE_SIZE].align = LEFT;
247
248         s[SI_AUDIO_INFO1].prefix = "";
249         s[SI_AUDIO_INFO1].postfix = "";
250         s[SI_AUDIO_INFO1].x = 0;
251         s[SI_AUDIO_INFO1].y = 60;
252         s[SI_AUDIO_INFO1].w = 100;
253         s[SI_AUDIO_INFO1].h = FONT_HEIGHT;
254         s[SI_AUDIO_INFO1].r = 0;
255         s[SI_AUDIO_INFO1].g = 0;
256         s[SI_AUDIO_INFO1].b = 0;
257         s[SI_AUDIO_INFO1].font = N_YELLOW;
258         s[SI_AUDIO_INFO1].align = CENTER;
259
260         s[SI_AUDIO_INFO2].prefix = "";
261         s[SI_AUDIO_INFO2].postfix = "";
262         s[SI_AUDIO_INFO2].x = 0;
263         s[SI_AUDIO_INFO2].y = 65;
264         s[SI_AUDIO_INFO2].w = 100;
265         s[SI_AUDIO_INFO2].h = FONT_HEIGHT;
266         s[SI_AUDIO_INFO2].r = 0;
267         s[SI_AUDIO_INFO2].g = 0;
268         s[SI_AUDIO_INFO2].b = 0;
269         s[SI_AUDIO_INFO2].font = N_YELLOW;
270         s[SI_AUDIO_INFO2].align = CENTER;
271
272         s[SI_AUDIO_INFO3].prefix = "";
273         s[SI_AUDIO_INFO3].postfix = "";
274         s[SI_AUDIO_INFO3].x = 0;
275         s[SI_AUDIO_INFO3].y = 70;
276         s[SI_AUDIO_INFO3].w = 100;
277         s[SI_AUDIO_INFO3].h = FONT_HEIGHT;
278         s[SI_AUDIO_INFO3].r = 0;
279         s[SI_AUDIO_INFO3].g = 0;
280         s[SI_AUDIO_INFO3].b = 0;
281         s[SI_AUDIO_INFO3].font = N_YELLOW;
282         s[SI_AUDIO_INFO3].align = CENTER;
283
284         s[SI_DBINFO1].name = "dbinfo1:";
285         s[SI_DBINFO1].prefix = "";
286         s[SI_DBINFO1].postfix = "";
287         s[SI_DBINFO1].x = 0;
288         s[SI_DBINFO1].y = 83;
289         s[SI_DBINFO1].w = 100;
290         s[SI_DBINFO1].h = FONT_HEIGHT;
291         s[SI_DBINFO1].r = 0;
292         s[SI_DBINFO1].g = 0;
293         s[SI_DBINFO1].b = 0;
294         s[SI_DBINFO1].font = N_YELLOW;
295         s[SI_DBINFO1].align = CENTER;
296
297         s[SI_DBINFO2].prefix = "";
298         s[SI_DBINFO2].postfix = "";
299         s[SI_DBINFO2].x = 0;
300         s[SI_DBINFO2].y = 88;
301         s[SI_DBINFO2].w = 100;
302         s[SI_DBINFO2].h = FONT_HEIGHT;
303         s[SI_DBINFO2].r = 0;
304         s[SI_DBINFO2].g = 0;
305         s[SI_DBINFO2].b = 0;
306         s[SI_DBINFO2].font = N_YELLOW;
307         s[SI_DBINFO2].align = CENTER;
308
309         s[SI_DBINFO3].name = "dbinfo3:";
310         s[SI_DBINFO3].prefix = "";
311         s[SI_DBINFO3].postfix = "";
312         s[SI_DBINFO3].x = 0;
313         s[SI_DBINFO3].y = 93;
314         s[SI_DBINFO3].w = 100;
315         s[SI_DBINFO3].h = FONT_HEIGHT;
316         s[SI_DBINFO3].r = 0;
317         s[SI_DBINFO3].g = 0;
318         s[SI_DBINFO3].b = 0;
319         s[SI_DBINFO3].font = N_YELLOW;
320         s[SI_DBINFO3].align = CENTER;
321 }
322
323 /*
324  * init SDL libary and set window title
325  */
326 static void init_SDL(void)
327 {
328         if (SDL_Init(SDL_INIT_VIDEO) == -1) {
329                 fprintf(stderr,
330                         "Couldn't initialize SDL: %s\n", SDL_GetError());
331                 exit(1);
332         }
333         /* Clean up on exit */
334         atexit(SDL_Quit);
335         /* Initialize the display */
336         if (args_info.fullscreen_flag)
337                 screen = SDL_SetVideoMode(width, height, 0, SDL_FULLSCREEN);
338         else
339                 screen = SDL_SetVideoMode(width, height, 0, 0);
340         if (!screen) {
341                 fprintf(stderr, "Couldn't set video mode: %s\n",
342                         SDL_GetError());
343                 exit(1);
344         }
345         SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
346         SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
347         SDL_EventState(SDL_MOUSEBUTTONUP, SDL_IGNORE);
348         /* Set the window manager title bar */
349         SDL_WM_SetCaption("The Gui of death that makes you blind (paraslash "
350                 PACKAGE_VERSION ")", "SFont");
351 }
352
353 /*
354  * draw rectangular frame of width FRAME_WIDTH
355  */
356 static void draw_frame(Uint8 r, Uint8 g, Uint8 b) {
357         SDL_Rect rect;
358
359         rect.x = 0;
360         rect.y = 0;
361         rect.w = width;
362         rect.h = FRAME_WIDTH;
363         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
364         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
365
366         rect.x = 0;
367         rect.y = height - FRAME_WIDTH;
368         rect.w = width;
369         rect.h = FRAME_WIDTH;
370         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
371         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
372
373         rect.x = 0;
374         rect.y = FRAME_WIDTH;
375         rect.w = FRAME_WIDTH;
376         rect.h = height -  2 * FRAME_WIDTH;
377         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
378         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
379
380         rect.x = width - FRAME_WIDTH;
381         rect.y = FRAME_WIDTH;
382         rect.w = FRAME_WIDTH;
383         rect.h = height -  2 * FRAME_WIDTH;
384         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
385         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
386 }
387
388 /*
389  * fill input rect with color
390  */
391 static void fill_input_rect(void)
392 {
393         SDL_Rect rect;
394
395         rect.x = INPUT_X;
396         rect.y = INPUT_Y;
397         rect.w = INPUT_WIDTH;
398         rect.h = INPUT_HEIGHT;
399         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 10, 150, 10));
400 }
401
402 /*
403  * fill output rect with color
404  */
405 static void fill_output_rect(void)
406 {
407         SDL_Rect rect;
408
409         rect.x = OUTPUT_X;
410         rect.y = OUTPUT_Y;
411         rect.w = OUTPUT_WIDTH;
412         rect.h = OUTPUT_HEIGHT;
413         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 0, 0, 0));
414 }
415
416 /*
417  * convert tab to space
418  */
419 static void tab2space(char *text)
420 {
421         char *p = text;
422         while (*p) {
423                 if (*p == '\t')
424                         *p = ' ';
425                 p++;
426         }
427 }
428
429 static void print_msg(const char *msg)
430 {
431         SFont_FontInfo *font = &(fonts[MSG_FONT].fontinfo);
432         char *buf = strdup(msg);
433         int len = strlen(buf);
434
435         if (!buf)
436                 return;
437         while (TextWidth2(font, buf) > INPUT_WIDTH && len > 0) {
438                 *(buf + len) = '\0';
439                 len--;
440         }
441         fill_input_rect();
442         PutString2(screen, font, INPUT_X, INPUT_Y, buf);
443         free(buf);
444 }
445
446 static void update_all(void)
447 {
448         SDL_UpdateRect(screen, 0, 0, 0, 0);
449 }
450
451 static void update_input(void)
452 {
453         SDL_UpdateRect(screen, INPUT_X, INPUT_Y, INPUT_WIDTH, INPUT_HEIGHT);
454
455 }
456
457 /*
458  * wait for key, ignore all other events, return 0 if there is no key event
459  * pending. Otherwise return keysym of key
460  */
461 SDLKey get_key(void)
462 {
463         SDL_Event event;
464
465         while (SDL_PollEvent(&event) > 0) {
466                 if(event.type != SDL_KEYDOWN)
467                         continue;
468 //              printf("Key pressed, scancode: 0x%x\n",
469 //                      event.key.keysym.scancode);
470                 return event.key.keysym.sym;
471         }
472         return 0;
473 }
474
475 /*
476  * print message, wait for key (blocking), return 1 for 'q', 0 else
477  */
478 static SDLKey hit_key(const char *msg)
479 {
480         SDLKey sym;
481
482         print_msg(msg);
483         update_input();
484         while (!(sym = get_key()))
485                 ;
486         fill_input_rect();
487         update_input();
488         if (sym == SDLK_q)
489                 return 1;
490         else
491                 return 0;
492 }
493
494 /*
495  * read paraslash command from input, execute it and print results
496  */
497 static int command_handler(void)
498 {
499         FILE *f;
500         unsigned count = 0;
501         char text[MAXLINE]="";
502         char buf[MAXLINE]="";
503         SFont_FontInfo *font = &fonts[OUTPUT_FONT].fontinfo;
504
505 //      printf("string input\n");
506         SFont_Input2(screen, &fonts[INPUT_FONT].fontinfo,
507                 INPUT_X, INPUT_Y - 5, INPUT_WIDTH, text);
508         if (!strlen(text))
509                 return 1;
510         if (!strcmp(text, "exit") || !strcmp(text, "quit"))
511                 return 0;
512         if (text[0] == '!') {
513                 if (text[1] == '\0')
514                         return 1;
515                 f = popen(text + 1, "r");
516         } else {
517                 sprintf(buf, BINDIR "/para_client %s 2>&1", text);
518                 f = popen(buf, "r");
519         }
520         if (!f)
521                 return 0;
522         fill_output_rect();
523         while(fgets(text, MAXLINE - 1, f)) {
524                 int len;
525
526                 tab2space(text);
527                 len = strlen(text);
528         //      printf("string: %s\n", dest);
529                 while (TextWidth2(font, text) > width - 2 * FRAME_WIDTH &&
530                                 len > 0) {
531                         text[len] = '\0';
532                         len--;
533                 }
534                 PutString2(screen, font, OUTPUT_X,
535                         OUTPUT_Y + count * FONT_HEIGHT, text);
536                 count++;
537                 if (count >= NUM_LINES) {
538                         update_all();
539                         if (hit_key("Hit any key to continue, q to return"))
540                                 goto out;
541                         count = 0;
542                         fill_output_rect();
543                 }
544         }
545         update_all();
546         hit_key("Hit any key to return");
547 out:    fill_output_rect();
548         pclose(f);
549         return 1;
550 }
551
552
553 /*
554  * Add prefix and postfix to string, delete characters from the end
555  * if its length exceeds the max length defined in stat_items[item]
556  */
557 char *transform_string(int item)
558 {
559         struct stat_item s = stat_items[item];
560         size_t len;
561         char *ret;
562         unsigned pixels = s.w * (width - 2 * FRAME_WIDTH) / 100;
563         SFont_FontInfo *font = &(fonts[s.font].fontinfo);
564
565         ret = make_message("%s%s%s", s.prefix, s.content, s.postfix);
566         len = strlen(ret);
567         while (TextWidth2(font, ret) > pixels && len > 0) {
568                 *(ret + len) = '\0';
569                 len--;
570         }
571         return ret;
572 }
573
574 SDL_Surface *load_jpg(void)
575 {
576         SDL_RWops *rwop;
577         int fds[3] = {0, 1, 0};
578         pid_t pid;
579         FILE *f;
580
581         if (para_exec_cmdline_pid(&pid, args_info.pic_cmd_arg, fds) < 0)
582                 return NULL;
583         f = fdopen(fds[1], "r");
584         if (!f)
585                 return NULL;
586         if (!(rwop = SDL_RWFromFP(f, 0)))
587                 return NULL;
588         return IMG_LoadJPG_RW(rwop);
589 }
590
591 void update_pic(void)
592 {
593         SDL_Surface *img;
594         SDL_Rect src_pic_rect = {
595                 .x = 0,
596                 .y = 0,
597                 .w = PIC_WIDTH,
598                 .h = PIC_HEIGHT,
599         };
600         SDL_Rect dest_pic_rect = {
601                 .x = FRAME_WIDTH,
602                 .y = OUTPUT_HEIGHT / 5,
603                 .w = PIC_WIDTH,
604                 .h = PIC_HEIGHT,
605         };
606
607         if (!screen)
608                 return;
609
610         if (!(img = load_jpg()))
611                 return;
612         SDL_FillRect(screen, &dest_pic_rect, SDL_MapRGB(screen->format,
613                 0, 0, 0));
614         SDL_BlitSurface(img, &src_pic_rect, screen, &dest_pic_rect);
615         SDL_Flip(screen);
616         SDL_FreeSurface(img);
617 }
618
619 /*
620  * update status item number i.
621  */
622 static void do_update(int i)
623 {
624         static int last_played = -1;
625         SDL_Rect rect;
626         char *buf;
627         SFont_FontInfo *font = &(fonts[stat_items[i].font].fontinfo);
628         if (!stat_items[i].w)
629                 return;
630
631         rect.x = stat_items[i].x * (width - FRAME_WIDTH * 2) / 100
632                 + FRAME_WIDTH;
633         rect.y = stat_items[i].y * (height - 2 * FRAME_WIDTH - INPUT_HEIGHT)
634                 / 100;
635         rect.w = stat_items[i].w * (width - 2 * FRAME_WIDTH) / 100;
636         rect.h = stat_items[i].h;
637         buf = transform_string(i);
638         SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format,
639                 stat_items[i].r, stat_items[i].g, stat_items[i].b));
640         switch(stat_items[i].align) {
641         case CENTER:
642                 PutString2(screen, font,
643                         rect.x + (rect.w - TextWidth2(font, buf)) / 2,
644                         rect.y, buf);
645                 break;
646         case LEFT:
647                 PutString2(screen, font, rect.x, rect.y, buf);
648                 break;
649         case RIGHT:
650                 PutString2(screen, font, rect.x + (rect.w -
651                         TextWidth2(font, buf)), rect.y, buf);
652                 break;
653         }
654         free(buf);
655         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
656         if (i == SI_NUM_PLAYED && atoi(stat_items[i].content) != last_played) {
657                 update_pic();
658                 last_played = atoi(stat_items[i].content);
659         };
660 }
661
662 /*
663  * Check if buf is a known status line. If so call do_update and return 1.
664  * Return 0 otherwise.
665  */
666 int update_status(char *buf, __a_unused void *data)
667 {
668         int i;
669
670         i = stat_line_valid(buf);
671         if (i < 0)
672                 return 1;
673         //free(stat_items[i].content);
674         stat_items[i].content = para_strdup(buf +
675                 strlen(status_item_list[i]) + 1);
676         do_update(i);
677         return 1;
678 }
679
680 /*
681  * Read stat line from pipe if pipe is ready, call update_status to
682  * display information.
683  */
684 static int draw_status(int fd)
685 {
686         fd_set rfds;
687         int ret;
688         struct timeval tv;
689
690         tv.tv_sec = 0;
691         tv.tv_usec = 3000000;
692         FD_ZERO(&rfds);
693         FD_SET(fd, &rfds);
694         ret = para_select(fd + 1, &rfds, NULL, &tv);
695         if (ret <= 0)
696                 return 0;
697         if (read_audiod_pipe(fd, update_status) > 0)
698                 return 1;
699         free(stat_items[SI_STATUS_BAR].content);
700         stat_items[SI_STATUS_BAR].content =
701                 para_strdup("audiod not running!?\n");
702         update_all();
703         sleep(1);
704         return -1;
705 }
706
707 static void clean_exit(int ret)
708 {
709         SDL_Quit();
710         exit(ret);
711 }
712
713 static void print_help(void)
714 {
715         print_msg("Hit q to quit, any other key to enter command mode");
716 }
717
718 static int configfile_exists(void)
719 {
720         if (!args_info.config_file_given) {
721                 char *home = para_homedir();
722                 args_info.config_file_arg = make_message(
723                         "%s/.paraslash/sdl_gui.conf", home);
724                 free(home);
725         }
726         return file_exists(args_info.config_file_arg);
727 }
728
729 /*
730  * MAIN
731  */
732 int main(int argc, char *argv[])
733 {
734         int i, ret, fd = -1;
735         SDLKey sym;
736
737         sdl_gui_cmdline_parser(argc, argv, &args_info);
738         HANDLE_VERSION_FLAG("sdl_gui", args_info);
739         ret = configfile_exists();
740 //      printf("w=%i,h=%i,ret=%i, cf=%s\n", width, height, ret, args_info.config_file_arg);
741
742         if (!ret && args_info.config_file_given) {
743                 fprintf(stderr, "Can't read config file %s\n",
744                         args_info.config_file_arg);
745                 exit(EXIT_FAILURE);
746         }
747         if (ret) {
748                 struct sdl_gui_cmdline_parser_params params = {
749                         .override = 0,
750                         .initialize = 0,
751                         .check_required = 0,
752                         .check_ambiguity = 0
753                 };
754                 sdl_gui_cmdline_parser_config_file(args_info.config_file_arg,
755                         &args_info, &params);
756         }
757         signal(SIGCHLD, SIG_IGN);
758         width = args_info.width_arg;
759         height = args_info.height_arg;
760 //      printf("w=%i,h=%i,ret=%i, cf=%s\n", width, height, ret, args_info.config_file_arg);
761         init_stat_items();
762         init_SDL();
763         for (i = 0; fonts[i].name[0]; i++) {
764                 char buf[MAXLINE];
765                 sprintf(buf, "%s/%s", FONTDIR, fonts[i].name);
766                 /* Load the font - You don't have to use the IMGlib for this */
767                 fonts[i].fontinfo.Surface = IMG_Load(buf);
768                 /* Prepare the font for use */
769                 InitFont2(&fonts[i].fontinfo);
770         }
771         draw_frame(FRAME_RED, FRAME_GREEN, FRAME_BLUE);
772         if (args_info.interactive_flag) {
773                 print_help();
774                 update_input();
775         }
776         for (;;) {
777                 if (fd < 0) {
778                         fd = para_open_audiod_pipe(args_info.stat_cmd_arg);
779                         if (fd < 0)
780                                 clean_exit(EXIT_FAILURE);
781                 }
782                 ret = draw_status(fd);
783                 if (ret < 0) {
784                         close(fd);
785                         fd = -1;
786                 }
787                 if (SDL_QuitRequested())
788                         clean_exit(0);
789                 while ((sym = get_key())) {
790                         if (!args_info.interactive_flag)
791                                 clean_exit(0);
792                         if (sym == SDLK_q)
793                                 clean_exit(0);
794                         if (       sym == SDLK_LSHIFT
795                                 || sym == SDLK_RSHIFT
796                                 || sym == SDLK_LMETA
797                                 || sym == SDLK_RMETA
798                                 || sym == SDLK_RCTRL
799                                 || sym == SDLK_LCTRL
800                                 || sym == SDLK_MODE
801                                 || sym == SDLK_CAPSLOCK
802                                 || sym == SDLK_LALT
803                                 || sym == SDLK_RALT
804                                 || sym == SDLK_RSUPER
805                                 || sym == SDLK_LSUPER
806                                 || sym == SDLK_COMPOSE
807                                 )
808                                 continue;
809                         fill_input_rect();
810                         update_input();
811                         if (!command_handler())
812                                 clean_exit(0);
813                         fill_output_rect();
814                         print_help();
815                         update_pic();
816                         SDL_UpdateRect(screen, 0, 0, 0, 0);
817                         break;
818                 }
819         }
820 }