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