]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/demos/nanox/launcher.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / demos / nanox / launcher.c
1 /* 
2  * The contents of this file are subject to the Mozilla Public License
3  * Version 1.1 (the "License"); you may not use this file except in
4  * compliance with the License. You may obtain a copy of the License at
5  * http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS IS"
8  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9  * License for the specific language governing rights and limitations
10  * under the License.
11  * 
12  * The Original Code is NanoLauncher.
13  * 
14  * The Initial Developer of the Original Code is Alex Holden.
15  * Portions created by Alex Holden are Copyright (C) 2000
16  * Alex Holden <alex@linuxhacker.org>. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the terms
21  * of the GNU General Public license (the  "[GNU] License"), in which case the
22  * provisions of [GNU] License are applicable instead of those
23  * above.  If you wish to allow use of your version of this file only
24  * under the terms of the [GNU] License and not to allow others to use
25  * your version of this file under the MPL, indicate your decision by
26  * deleting  the provisions above and replace  them with the notice and
27  * other provisions required by the [GNU] License.  If you do not delete
28  * the provisions above, a recipient may use your version of this file
29  * under either the MPL or the [GNU] License.
30  */
31
32 /*
33  * A simple application launcher for Nano-X by Alex Holden.
34  *
35  * The application needs to be started with the first argument specifying
36  * the location of it's configuration file. The format of the file is
37  * extremely simple- each line can contain either a comment (indicated by
38  * beginning the line with a '#' symbol) or an item description.
39  * An item description consists of the name of the item (the title which
40  * appears underneath the icon on the launcher button) followed by the name
41  * of the icon file (or '-' for no icon) and the command to execute when the
42  * item is clicked on. The command can optionally be followed by a limited
43  * number of arguments to pass to the program when it is executed (increase
44  * MAX_ARGUMENTS in launcher.h if you need more). The program will currently
45  * only allow one icon size (specified at compile time by the ICON_WIDTH and
46  * ICON_HEIGHT parameters). The program only loads each icon file once even if
47  * it is used multiple times, so you can save a small amount of memory by
48  * using the same icon for several programs. If you want to change the size
49  * of the item buttons, change ITEM_WIDTH and ITEM_HEIGHT in launcher.h.
50  * The way the launcher decides whether to draw a vertical panel on the left
51  * hand side of the screen or a horizontal panel along the bottom is by
52  * looking at the width and height of the screen- the panel will be placed on
53  * the side on portrait screens and on the bottom on landscape screens.
54  */
55
56 #include <stdio.h>
57 #include <errno.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <ctype.h>
61 #include <signal.h>
62 #include <unistd.h>
63 #include <sys/wait.h>
64
65 #define MWINCLUDECOLORS
66 #include "nano-X.h"
67 #include "launcher.h"
68
69 void reaper(int signum) { while(waitpid(WAIT_ANY, NULL, WNOHANG) > 0); }
70
71 void *my_malloc(size_t size)
72 {
73         void *ret;
74
75         if(!(ret = malloc(size))) {
76                 fprintf(stderr, "Out of memory\n");
77                 exit(1);
78         }
79
80         return ret;
81 }
82
83 void usage(void)
84 {
85         fprintf(stderr, "Usage: launcher <config-file>\n");
86         exit(3);
87 }
88
89 prog_item *make_prog_item(char *buf, int lineno)
90 {
91         char *p, *pp, *command;
92         prog_item *prog;
93         int n;
94
95         p = buf;
96
97         prog = my_malloc(sizeof(prog_item));
98
99         for(n = 0; n < MAX_ARGUMENTS; n++) prog->argv[n] = NULL;
100
101         while(isspace(*p)) p++;
102         if(!*p) {
103                 fprintf(stderr, "Premature end of line on line %d of config "
104                                 "file\n", lineno);
105                 return 0;
106         }
107         command = p;
108         while(*p && (!isspace(*p))) p++;
109         *p++ = 0;
110         if(!(prog->command = strdup(command))) {
111                 free(prog);
112                 goto nomem;
113         }
114         pp = p - 1;
115         while(--pp != command) {
116                 if(*pp == '/') {
117                         pp++;
118                         break;
119                 }
120         }
121         if(!(prog->argv[0] = strdup(pp))) {
122                 free(prog->command);
123                 free(prog);
124                 goto nomem;
125         }
126
127         n = 1;
128         while(*p) {
129                 while(isspace(*p)) p++;
130                 if(!*p) break;
131                 pp = p;
132                 while(*p && (!isspace(*p))) p++;
133                 *p++ = 0;
134                 if(!(prog->argv[n] = strdup(pp))) {
135                         for(n = MAX_ARGUMENTS; n; n--)
136                                 if(prog->argv[n]) free(prog->argv[n]);
137                         free(prog->command);
138                         free(prog);
139                         goto nomem;
140                 }
141                 if(++n == (MAX_ARGUMENTS - 1)) {
142                         fprintf(stderr, "Too many arguments on line "
143                                 "%d of the config file\n", lineno);
144                         break; 
145                 }
146         }
147
148         return prog;
149
150 nomem:
151         fprintf(stderr, "Out of memory parsing line %d of the config "
152                         "file\n", lineno);
153         return 0;
154 }
155
156 void set_window_background_colour(char *buf, int lineno)
157 {
158         GR_WM_PROPERTIES props;
159         char *p = buf, *pp;
160
161         while(isspace(*p)) p++;
162         if(!*p) {
163                 fprintf(stderr, "Premature end of line on line %d of config "
164                                 "file\n", lineno);
165                 return;
166         }
167         pp = p;
168         while(*p && (!isspace(*p))) p++;
169         *p = 0;
170
171         if(!strcmp(pp, "BLACK")) props.background = BLACK;
172         else if(!strcmp(pp, "BLUE")) props.background = BLUE;
173         else if(!strcmp(pp, "GREEN")) props.background = GREEN;
174         else if(!strcmp(pp, "CYAN")) props.background = CYAN;
175         else if(!strcmp(pp, "RED")) props.background = RED;
176         else if(!strcmp(pp, "MAGENTA")) props.background = MAGENTA;
177         else if(!strcmp(pp, "BROWN")) props.background = BROWN;
178         else if(!strcmp(pp, "LTGRAY")) props.background = LTGRAY;
179         else if(!strcmp(pp, "GRAY")) props.background = GRAY;
180         else if(!strcmp(pp, "LTBLUE")) props.background = LTBLUE;
181         else if(!strcmp(pp, "LTGREEN")) props.background = LTGREEN;
182         else if(!strcmp(pp, "LTCYAN")) props.background = LTCYAN;
183         else if(!strcmp(pp, "LTRED")) props.background = LTRED;
184         else if(!strcmp(pp, "LTMAGENTA")) props.background = LTMAGENTA;
185         else if(!strcmp(pp, "YELLOW")) props.background = YELLOW;
186         else if(!strcmp(pp, "WHITE")) props.background = WHITE;
187         else {
188                 fprintf(stderr, "Invalid colour \"%s\" on line %d of config "
189                                                         "file\n", pp, lineno);
190                 return;
191         }
192
193         props.flags = GR_WM_FLAGS_BACKGROUND;
194         GrSetWMProperties(GR_ROOT_WINDOW_ID, &props);
195 }
196
197 void parse_config_line(lstate *state, char *buf, int lineno)
198 {
199         char *p, *pp, *name, *icon;
200         int n;
201         litem *new_litem, *li;
202         sitem *new_sitem;
203         GR_IMAGE_INFO imageinfo;
204
205         p = buf;
206
207         if((!*p) || (*p == '#') || (*p == '\n')) return;
208
209         while(isspace(*p)) p++;
210         name = p;
211         while(*p && (!isspace(*p))) p++;
212         if(!*p) goto premature;
213         *p++ = 0;
214
215         if(!strcmp(name, "$screensaver")) {
216                 new_sitem = my_malloc(sizeof(sitem));
217                 if(!(new_sitem->prog = make_prog_item(p, lineno))) {
218                         free(new_sitem);
219                         return;
220                 }
221                 new_sitem->next = NULL;
222                 if(!state->sitems) {
223                         state->sitems = new_sitem;
224                         state->cursitem = new_sitem;
225                 } else {
226                         new_sitem->next = state->sitems;
227                         state->sitems = new_sitem;
228                 }
229                 return;
230         } else if(!strcmp(name, "$screensaver_timeout")) {
231                 n = strtol(p, NULL, 10);
232                 GrSetScreenSaverTimeout(n);
233                 return;
234         } else if(!strcmp(name, "$window_background_image")) {
235                 while(isspace(*p)) p++;
236                 if(!*p) goto premature;
237                 pp = p;
238                 while(*p && (!isspace(*p))) p++;
239                 *p = 0;
240                 state->window_background_image = strdup(pp);
241                 return;
242         } else if(!strcmp(name, "$window_background_mode")) {
243                 state->window_background_mode = (int) strtol(p, NULL, 10);
244                 return;
245         } else if(!strcmp(name, "$window_background_colour")) {
246                 set_window_background_colour(p, lineno);
247                 return;
248         }
249
250         while(isspace(*p)) p++;
251         if(!*p) goto premature;
252         icon = p;
253         while(*p && (!isspace(*p))) p++;
254         if(!*p) goto premature;
255         *p++ = 0;
256
257         new_litem = my_malloc(sizeof(litem));
258         if(!(new_litem->name = strdup(name))) {
259                 free(new_litem);
260                 goto nomem;
261         }
262         if(!(new_litem->icon = strdup(icon))) {
263                 free(new_litem->name);
264                 free(new_litem);
265                 goto nomem;
266         }
267         if(!(new_litem->prog = make_prog_item(p, lineno))) {
268                 free(new_litem->name);
269                 free(new_litem->icon);
270                 free(new_litem);
271                 return;
272         }
273         new_litem->iconid = 0;
274         if(strcmp("-", icon)) {
275                 li = state->litems;
276                 while(li) {
277                         if(!(strcmp(icon, li->name))) {
278                                 new_litem->iconid = li->iconid;
279                                 break;
280                         }
281                         li = li->next;
282                 }
283                 if(!new_litem->iconid) {
284                         if(!(new_litem->iconid = GrLoadImageFromFile(icon, 0))){
285                                 fprintf(stderr, "Couldn't load icon \"%s\"\n",
286                                                                         icon);
287                         } else {
288                                 GrGetImageInfo(new_litem->iconid, &imageinfo);
289                                 if((imageinfo.width != ICON_WIDTH) ||
290                                         (imageinfo.height != ICON_HEIGHT)) {
291                                         fprintf(stderr, "Icon \"%s\" is the "
292                                         "wrong size (%dx%d instead of %dx%d)"
293                                         "\n", icon, imageinfo.width,
294                                         imageinfo.height, ICON_WIDTH,
295                                         ICON_HEIGHT);
296                                         GrFreeImage(new_litem->iconid);
297                                         new_litem->iconid = 0;
298                                 }
299                         }
300                 }
301         }
302
303         new_litem->prev = NULL;
304         new_litem->next = NULL;
305         if(!state->litems) {
306                 state->lastlitem = new_litem;
307                 state->litems = new_litem;
308         } else {
309                 new_litem->next = state->litems;
310                 state->litems->prev = new_litem;
311                 state->litems = new_litem;
312         }
313
314         state->numlitems++;
315
316         return;
317
318 nomem:
319         fprintf(stderr, "Out of memory\n");
320         exit(1);
321
322 premature:
323         fprintf(stderr, "Premature end of line on line %d of config file\n",
324                                                                 lineno);
325 }
326
327 void read_config(lstate *state)
328 {
329         int lineno = 1;
330         FILE *fp;
331         char *buf = my_malloc(256);
332
333         if(!(fp = fopen(state->config_file, "r"))) {
334                 fprintf(stderr, "Couldn't open config file \"%s\"\n",
335                                                         state->config_file);
336                 exit(2);
337         }
338
339         state->litems = NULL;
340         state->numlitems = 0;
341         state->sitems = NULL;
342
343         while(fgets(buf, 256, fp)) {
344                 parse_config_line(state, buf, lineno);
345                 lineno++;
346         }
347
348         fclose(fp);
349         free(buf);
350
351         if(!state->numlitems) {
352                 fprintf(stderr, "No valid launcher items in config file\n");
353                 exit(5);
354         }
355 }
356
357 void draw_item(lstate *state, litem *item)
358 {
359         GR_SIZE width, height, base, x, len;
360
361         GrDrawImageToFit(item->wid, state->gc, ICON_X_POSITION, ICON_Y_POSITION,
362                                 ICON_WIDTH, ICON_HEIGHT, item->iconid);
363
364         len = strlen(item->name);
365         GrGetGCTextSize(state->gc, item->name, len, 0, &width, &height, &base);
366         if(width >= ITEM_WIDTH) x = 0;
367         else x = (ITEM_WIDTH - width) / 2;
368
369         GrText(item->wid, state->gc, x, TEXT_Y_POSITION, item->name, len, 0);
370 }
371
372 void handle_exposure_event(lstate *state)
373 {
374         GR_EVENT_EXPOSURE *event = &state->event.exposure;
375         litem *i = state->litems;
376
377         if(event->wid == state->main_window) return;
378
379         while(i) {
380                 if(event->wid == i->wid) {
381                         draw_item(state, i);
382                         return;
383                 }
384                 i = i->next;
385         }
386
387         fprintf(stderr, "Got exposure event for unknown window %d\n",
388                                                         event->wid);
389 }
390
391 void launch_program(prog_item *prog)
392 {
393         pid_t pid;
394
395         if((pid = fork()) == -1) perror("Couldn't fork");
396         else if(!pid) {
397                 if(execvp(prog->command, prog->argv) == -1)
398                         fprintf(stderr, "Couldn't start \"%s\": %s\n",
399                                         prog->command, strerror(errno));
400                 exit(7);
401         }
402 }
403
404 void handle_mouse_event(lstate *state)
405 {
406         GR_EVENT_MOUSE *event = &state->event.mouse;
407         litem *i = state->litems;
408
409         if(event->wid == state->main_window) return;
410
411         while(i) {
412                 if(event->wid == i->wid) {
413                         launch_program(i->prog);
414                         return;
415                 }
416                 i = i->next;
417         }
418
419         fprintf(stderr, "Got mouse event for unknown window %d\n", event->wid);
420 }
421
422 void handle_screensaver_event(lstate *state)
423 {
424         GR_EVENT_SCREENSAVER *event = &state->event.screensaver;
425
426         if(event->activate != GR_TRUE) return;
427
428         if(!state->sitems) {
429                 fprintf(stderr, "Got screensaver activate event with no "
430                                 "screensavers defined\n");
431                 return;
432         }
433
434         state->cursitem = state->cursitem->next;
435         if(!state->cursitem) state->cursitem = state->sitems;
436
437         launch_program(state->cursitem->prog);
438 }
439
440 void handle_event(lstate *state)
441 {
442         switch(state->event.type) {
443                 case GR_EVENT_TYPE_EXPOSURE:
444                         handle_exposure_event(state);
445                         break;
446                 case GR_EVENT_TYPE_BUTTON_DOWN:
447                         handle_mouse_event(state);
448                         break;
449                 case GR_EVENT_TYPE_CLOSE_REQ:
450                         break;
451                 case GR_EVENT_TYPE_SCREENSAVER:
452                         handle_screensaver_event(state);
453                         break;
454                 case GR_EVENT_TYPE_NONE:
455                         break;
456                 default:
457                         fprintf(stderr, "Got unknown event type %d\n",
458                                                         state->event.type);
459                         break;
460         }
461 }
462
463 void do_event_loop(lstate *state)
464 {
465         do {
466                 GrGetNextEvent(&state->event);
467                 handle_event(state);
468         } while(state->event.type != GR_EVENT_TYPE_CLOSE_REQ);
469 }
470
471 void initialise(lstate *state)
472 {
473         GR_SCREEN_INFO si;
474         GR_IMAGE_ID back_image;
475         GR_IMAGE_INFO imageinfo;
476         int rows = 1, columns = 1, width, height, x = 0, y = 1;
477         GR_WM_PROPERTIES props;
478         litem *i;
479
480         if(GrOpen() < 0) {
481                 fprintf(stderr, "Couldn't connect to Nano-X server\n");
482                 exit(4);
483         }
484
485         state->window_background_mode = 0;
486         state->window_background_image = NULL;
487
488         read_config(state);
489
490         GrGetScreenInfo(&si);
491
492         if(si.rows > si.cols) {
493                 rows = state->numlitems;
494                 while((((rows / columns) + rows % columns) * ITEM_HEIGHT) >
495                                                                 si.rows) {
496                         columns++;
497                 }
498                 if((columns * ITEM_WIDTH) > si.cols) goto toomany;
499                 rows = (rows / columns) + (rows % columns);
500                 width = columns * ITEM_WIDTH + 1 + columns;
501                 height = rows * ITEM_HEIGHT + 1 + rows;
502         } else {
503                 columns = state->numlitems;
504                 while((((columns / rows) + (columns % rows)) * ITEM_WIDTH) >
505                                                                 si.cols) {
506                         rows++;
507                 }
508                 if((rows * ITEM_HEIGHT) > si.rows) goto toomany;
509                 columns = (columns / rows) + (columns % rows);
510                 width = columns * ITEM_WIDTH + 1 + columns;
511                 height = (rows * ITEM_HEIGHT) + 1 + rows;
512                 y = si.rows - (rows * ITEM_HEIGHT) - 1 - rows;
513         }
514
515         state->gc = GrNewGC();
516         GrSetGCForeground(state->gc, ITEM_TEXT_COLOUR);
517         GrSetGCBackground(state->gc, ITEM_BACKGROUND_COLOUR);
518
519         if(state->window_background_image) {
520                 if(!(back_image = GrLoadImageFromFile(
521                                         state->window_background_image, 0))) {
522                         fprintf(stderr, "Couldn't load background image\n");
523                 } else {
524                         GrGetImageInfo(back_image, &imageinfo);
525                         if(!(state->background_pixmap = GrNewPixmap(
526                                                         imageinfo.width,
527                                                 imageinfo.height, NULL))) {
528                                 fprintf(stderr, "Couldn't allocate pixmap "     
529                                                 "for background image\n");
530                         } else {
531                                 GrDrawImageToFit(state->background_pixmap,
532                                         state->gc, 0, 0, imageinfo.width,
533                                         imageinfo.height, back_image);
534                                 GrFreeImage(back_image);
535                                 GrSetBackgroundPixmap(GR_ROOT_WINDOW_ID,
536                                         state->background_pixmap,
537                                         state->window_background_mode);
538                                 GrClearWindow(GR_ROOT_WINDOW_ID, GR_TRUE);
539                         }
540                 }
541         }
542
543         if(state->sitems)
544                 GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_SCREENSAVER);
545
546         state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID, 0, y, width, height,
547                                                 0, ITEM_BACKGROUND_COLOUR, 0);
548         GrSelectEvents(state->main_window, GR_EVENT_MASK_CLOSE_REQ);
549         props.flags = GR_WM_FLAGS_PROPS;
550         props.props = GR_WM_PROPS_NOMOVE | GR_WM_PROPS_NODECORATE |
551                         GR_WM_PROPS_NOAUTOMOVE | GR_WM_PROPS_NOAUTORESIZE;
552         GrSetWMProperties(state->main_window, &props);
553
554         i = state->lastlitem;
555         y = 0;
556         while(i) {
557                 i->wid = GrNewWindow(state->main_window,
558                                         (x * ITEM_WIDTH) + x + 1,
559                                         (y * ITEM_HEIGHT) + y + 1, ITEM_WIDTH,
560                                         ITEM_HEIGHT, 1, ITEM_BACKGROUND_COLOUR,
561                                                         ITEM_BORDER_COLOUR);
562                 GrSelectEvents(i->wid, GR_EVENT_MASK_EXPOSURE |
563                                         GR_EVENT_MASK_BUTTON_DOWN);
564                 GrMapWindow(i->wid);
565                 i = i->prev;
566                 if(++x == columns) {
567                         x = 0;
568                         y++;
569                 }
570         }
571
572         GrMapWindow(state->main_window);
573
574         signal(SIGCHLD, &reaper);
575
576         return;
577
578 toomany:
579         fprintf(stderr, "Too many items to fit on screen\n");
580         exit(6);
581 }
582
583 int main(int argc, char *argv[])
584 {
585         lstate *state;
586
587         if(argc != 2) usage();
588
589         state = my_malloc(sizeof(lstate));
590         state->config_file = strdup(argv[1]);
591
592         initialise(state);
593
594         do_event_loop(state);
595
596         GrClose();
597
598         return 0;
599 }