Change adesklets.c behavior: shield it against unsollicited client signals
[adesklets.git] / src / adesklets.c
blob2acf4398b5df7afd00ed4bfb6e1076c8b5027bf8
1 /*--- adesklets.c --------------------------------------------------------------
2 Copyright (C) 2004, 2005 Sylvain Fourmanoit <syfou@users.sourceforge.net>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to
6 deal in the Software without restriction, including without limitation the
7 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 sell copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies of the Software and its documentation and acknowledgment shall be
13 given in the documentation and software packages that this Software was
14 used.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 ------------------------------------------------------------------------------*/
23 #include "adesklets.h" /* Application main header */
25 /*----------------------------------------------------------------------------*/
26 #define welcome(stream) fprintf(stream,\
27 "%s\n[%s]\n",WELCOME_LINE_1,WELCOME_LINE_2)
29 /*----------------------------------------------------------------------------*/
30 t_adesklets adesklets = {
31 0, /* pid_t ppid */
32 NULL, /* Display * display */
33 NULL, /* Visual * visual */
34 0, /* Window root */
35 0, /* Window window */
36 0, /* int depth */
37 0, /* int transparency */
38 X_DISPLAY_SUPPORT, /* int background_grab */
39 -1, /* int user_background_image */
40 0, /* int managed */
41 BASE_EVENT_MASK, /* long event_mask */
42 0, /* long user_event_mask */
43 NULL, /* cfgfile_item * params */
44 NULL, /* vector * menus */
45 NULL, /* vector * images */
46 NULL, /* vector * fonts */
47 NULL, /* vector * color_ranges */
48 NULL, /* vector * color_modifiers */
49 NULL, /* vector * imlib_filters */
50 NULL, /* vector * polygons */
51 NULL, /* vector * variables */
52 "", /* char * lock_filename */
53 NULL, /* FILE * lock */
54 0, /* int quit_flag */
55 0, /* int restart_flag */
56 0 /* int user_quit_flag */
59 /*----------------------------------------------------------------------------*/
60 /* Termination handler prototype for adesklets_free()
62 void termination_handler(int);
64 /*----------------------------------------------------------------------------*/
65 /* Reinstate the menus in pristine state: only one default menu with two
66 or three items: Move (if applicable), Restart (if applicable)
67 and Quit - all managed internally.
68 If an already filled menu could not get reset, returns 0 instead
69 of the successful 1.
71 int
72 adesklets_menus_reset(void)
74 int result=0;
75 xmenu * menu;
77 if (adesklets.menus)
78 adesklets.menus=vector_free(adesklets.menus);
79 if (!adesklets.menus)
80 if ((adesklets.menus=vector_init())) {
81 adesklets.menus->vector_free_item=xmenu_vector_free_item;
82 menu=xmenu_init();
83 #ifndef X_DISPLAY_MISSING
84 // if(!xwindow_window_managed(adesklets.display,adesklets.window))
85 if (!adesklets.managed)
86 #endif
87 xmenu_push_item(menu,"Move");
88 /* A lock file is needed if we want
89 the restart mechanism to work */
90 if (adesklets.lock) xmenu_push_item(menu,"Restart");
91 xmenu_push_item(menu,"Quit");
92 vector_push(adesklets.menus,menu);
93 result=1;
95 return result;
98 /*----------------------------------------------------------------------------*/
99 /* Recompute the background image based on present main window
100 width and height. Also create or resize foreground image as needed.
101 Returns 1 if both final and background images were dutifully produced,
102 0 otherwise.
104 int
105 adesklets_images_reset_background(int force_size, ...)
107 int i, j, old_width, old_height, foreground_active, background_active;
108 uint width, height;
109 int * pos;
110 vector * index;
111 va_list ap;
112 Imlib_Image image;
114 /* Get window dimension by all means necessary */
115 if (force_size) {
116 va_start(ap,force_size);
117 width=va_arg(ap,uint);
118 height=va_arg(ap,uint);
119 va_end(ap);
120 } else
121 #ifndef X_DISPLAY_MISSING
122 if (!xwindow_window_size(adesklets.display,adesklets.window,&width,&height))
123 #endif
124 width=height=1;
126 /* Save context states */
127 xwindow_context_save(IMLIB_BLEND|IMLIB_COLOR|IMLIB_IMAGE);
129 /* Record if Imlib's context image has to be changed at the end */
130 image=imlib_context_get_image();
131 foreground_active=(image && image==adesklets.images->content[0]);
132 background_active=(image && image==adesklets.images->content[1]);
134 /* Determine what images to resize */
135 if ((index=vector_init())) {
136 /* Always resize foreground */
137 if((pos=malloc(sizeof(int)))) {
138 *pos=0;
139 vector_push(index,pos);
141 /* Resize background when:
142 - We do not have X support
143 - We have X support, but there is no X connection or no window
144 - We have X support, there is a valid X connection and window,
145 but we do not grab the background
147 if(!X_DISPLAY_SUPPORT ||
148 !adesklets.background_grab ||
149 !adesklets.display || !adesklets.window) {
150 if((pos=malloc(sizeof(int)))) {
151 *pos=1;
152 vector_push(index,pos);
155 /* Resize user selected background when:
156 - It exists
158 if(adesklets.user_background_image!=-1) {
159 if ((pos=malloc(sizeof(int)))) {
160 *pos=adesklets.user_background_image;
161 vector_push(index,pos);
166 /* Create/update image(s) */
167 for(j=0;index && j<index->pos;++j) {
168 i=*((int*)index->content[j]);
169 if (!adesklets.images->content[i]) {
170 /* Create new final window image */
171 if ((adesklets.images->content[i]=imlib_create_image(width,height))) {
172 /* Select it */
173 imlib_context_set_image(adesklets.images->content[i]);
175 /* Make sure it has an alpha channel */
176 imlib_image_set_has_alpha(1);
178 /* Fill image with transparent black for foreground,
179 and opaque black for background, if applicable */
180 imlib_context_set_blend(0);
181 imlib_context_set_color(0, 0, 0, (i==0)?0:255);
182 imlib_image_fill_rectangle(0,0,width,height);
184 } else {
185 /* Update (by resizing image) */
186 imlib_context_set_image(adesklets.images->content[i]);
187 old_width=imlib_image_get_width();
188 old_height=imlib_image_get_height();
189 if((width!=old_width || height!=old_height) &&
190 (image=imlib_create_image(width,height))){
191 /* Need resizing */
192 imlib_context_set_image(image);
194 /* Make sure it has an alpha channel */
195 imlib_image_set_has_alpha(1);
197 /* Fill image with opaque black */
198 imlib_context_set_blend(0);
199 imlib_context_set_color(0,0,0,255);
200 imlib_image_fill_rectangle(0,0,width,height);
202 /* Finally, copy the original foreground image, with scaling */
203 imlib_blend_image_onto_image(adesklets.images->content[i],1,
204 0,0,old_width,old_height,
205 0,0,width,height);
207 /* Clean up : free original image */
208 imlib_context_set_image(adesklets.images->content[i]);
209 imlib_free_image();
210 adesklets.images->content[i]=image;
215 #ifndef X_DISPLAY_MISSING
216 if(adesklets.background_grab && adesklets.display && adesklets.window) {
217 /* If it exists, free background image */
218 adesklets.images->content[1]=
219 image_vector_free_item(adesklets.images->content[1]);
221 /* Create new background image */
222 adesklets.images->content[1]=
223 xwindow_grab_background(adesklets.display,adesklets.params->scr,
224 adesklets.window);
225 if (adesklets.user_event_mask&BackgroundGrabMask)
226 event("backgroundgrab\n");
228 #endif
229 /* Free index, if applicable */
230 vector_free(index);
232 /* Switch back to original context */
233 xwindow_context_restore();
235 /* Modify active image if it was originally set on foreground */
236 if(foreground_active) imlib_context_set_image(adesklets.images->content[0]);
237 if(background_active) imlib_context_set_image(adesklets.images->content[1]);
239 return adesklets.images->content[0] && adesklets.images->content[1];
242 /*----------------------------------------------------------------------------*/
243 /* Reinstate the image vector in pristine state,
244 including the regeneration of final and background image.
245 Take care of dangling context image, if applicable.
246 Returns 1 if successful, 0 in case of failure.
248 int
249 adesklets_images_reset(void)
251 int result=0;
252 if (adesklets.images)
253 adesklets.images=vector_free(adesklets.images);
254 if (!adesklets.images)
255 if((adesklets.images=vector_init())) {
256 adesklets.images->vector_free_item=image_vector_free_item;
257 adesklets.user_background_image=-1;
258 /* Recreate Final window and background images */
259 if((result=adesklets_images_reset_background(0))) {
260 adesklets.images->pos=2;
261 /* Reset current image if useful */
262 if (imlib_context_get_image()!=adesklets.images->content[0] &&
263 imlib_context_get_image()!=adesklets.images->content[1])
264 imlib_context_set_image(adesklets.images->content[0]);
267 return result;
270 /*----------------------------------------------------------------------------*/
271 /* Set/Reset main window. Also call adesklets_menu_reset and
272 adeslets_images_reset as needed. */
274 adesklets_window_reset(int managed)
276 int result=0;
277 #ifndef X_DISPLAY_MISSING
278 int mapped;
279 uint width, height;
280 XWindowAttributes attr;
281 XTextProperty text_prop_name;
282 Atom atom;
283 const char * name = PACKAGE;
284 const long valuemask = CWBackPixmap;
286 /* Determine if the old window was mapped, then destroy it as needed */
287 if(adesklets.display) {
288 if(adesklets.window) {
289 mapped=(XGetWindowAttributes(adesklets.display,
290 adesklets.window,&attr))?
291 (attr.map_state!=IsUnmapped):0;
292 XDestroyWindow(adesklets.display,adesklets.window);
293 } else
294 mapped=0;
296 /* Determine new window dimensions */
297 width=(adesklets.window)?attr.width:1;
298 height=(adesklets.window)?attr.height:1;
300 xwindow_error_reset();
301 /* Create main desklet window */
302 adesklets.root=(managed)?
303 RootWindow(adesklets.display,adesklets.params->scr):
304 xwindow_get_root_window(adesklets.display,
305 adesklets.params->scr);
307 adesklets.window=
308 XCreateWindow(adesklets.display,
309 adesklets.root,
310 adesklets.params->x, adesklets.params->y,
311 width, height, 0,
312 DefaultDepth(adesklets.display,
313 adesklets.params->scr),
314 InputOutput,
315 adesklets.visual,
316 (managed)?valuemask:(valuemask|CWOverrideRedirect),
317 &XDefaultWindowAttributes);
319 if (xwindow_error_check()) {
320 /* Set this window size */
321 xwindow_resize_window(adesklets.display,adesklets.window,
322 adesklets.params,width,height,1);
323 /* Set this window event mask */
324 XSelectInput(adesklets.display,adesklets.window,adesklets.event_mask);
326 /* Set this window as imlib2's default drawable */
327 imlib_context_set_drawable(adesklets.window);
329 /* Set window stacking order, and various properties if applicable */
330 if(managed) {
331 XRaiseWindow(adesklets.display,adesklets.window);
332 /* Window name */
333 if (XmbTextListToTextProperty(adesklets.display,
334 (char**)&name,1,
335 XCompoundTextStyle,
336 &text_prop_name)==Success)
337 XSetWMName(adesklets.display, adesklets.window, &text_prop_name);
339 /* Window delete protocol registration */
340 if ((atom=XInternAtom(adesklets.display,
341 "WM_DELETE_WINDOW",False))!=None)
342 XSetWMProtocols(adesklets.display,
343 adesklets.window, &atom, 1);
345 else
346 XLowerWindow(adesklets.display,adesklets.window);
348 /* Map the window if needed */
349 if (mapped) XMapWindow(adesklets.display,adesklets.window);
351 /* Eventually add capture of PropertyNotify on root window:
352 used for dynamic background reinitialisation */
353 XSelectInput(adesklets.display,
354 adesklets.root,
355 ((adesklets.background_grab)?PropertyChangeMask:0));
357 /* Store new value */
358 adesklets.managed = managed;
360 result=1;
361 } else
362 adesklets.window=(Window)0;
363 } else
364 adesklets.window=(Window)0;
365 #endif
366 return result;
369 /*----------------------------------------------------------------------------*/
370 /* Reste to nothing the vector of fonts, color_ranges and color_modifiers.
371 Returns 1 if successful, 0 otherwise.
373 #define ADESKLETS_RESET_FUNCTION(name)\
374 int \
375 adesklets_ ## name ## s_reset(void)\
377 int result=0;\
378 if(adesklets.name ## s)\
379 adesklets.name ## s=vector_free(adesklets.name ## s);\
380 if(!adesklets.name ## s) {\
381 if((adesklets.name ## s=vector_init())) {\
382 adesklets.name## s->vector_free_item=\
383 name ## _vector_free_item;\
384 imlib_context_set_ ## name(NULL);\
385 result=1;\
388 return result;\
391 ADESKLETS_RESET_FUNCTION(font)
392 ADESKLETS_RESET_FUNCTION(color_range)
393 ADESKLETS_RESET_FUNCTION(color_modifier)
394 ADESKLETS_RESET_FUNCTION(filter)
395 #undef ADESKLETS_RESET_FUNCTION
397 /*----------------------------------------------------------------------------*/
398 /* Reset to nothing a generic vector of something; you need
399 to provide a reference to the vector and another to a
400 vector_free_item_func function
403 adesklets_generic_reset(vector ** vec, vector_free_item_func func)
405 int result=0;
406 if(*vec)
407 *vec=vector_free(*vec);
408 if(!(*vec)) {
409 if((*vec=vector_init())) {
410 (*vec)->vector_free_item=func;
411 result=1;
414 return result;
417 /*----------------------------------------------------------------------------*/
418 /* Generate placeholder function using preceeding generic function
420 #define ADESKLETS_RESET_FUNCTION(name) \
421 int \
422 adesklets_ ## name ## s_reset(void) \
424 return adesklets_generic_reset(&adesklets.name ## s,\
425 name ## _vector_free_item);\
428 ADESKLETS_RESET_FUNCTION(polygon)
429 ADESKLETS_RESET_FUNCTION(variable)
430 #undef ADESKLETS_RESET_FUNCTION
432 /*----------------------------------------------------------------------------*/
433 /* Wrapper for xmenu_fire() that intercepts non-maskable events
434 from default menu ("Move", "Restart" and "Quit" events)
437 adesklets_menu_fire(int index, char ** return_str)
439 #ifndef X_DISPLAY_MISSING
440 int result=0;
441 if(index>=0 && index<adesklets.menus->pos) {
442 *return_str=xmenu_fire(adesklets.display,adesklets.params->scr,
443 adesklets.window,
444 adesklets.images->content[
445 (adesklets.user_background_image==-1)?
446 1:adesklets.user_background_image],
447 adesklets.images->content[0],
448 adesklets.transparency,
449 MENU(index));
450 /* Intercept default actions move and quit on the way back */
451 if(index==0 && *return_str) {
452 /* For move: verify the main window is not managed,
453 to avoid false move due to user-added "Move" */
454 if (
455 #ifndef X_DISPLAY_MISSING
456 !adesklets.managed &&
457 #endif
458 strcmp(*return_str,"Move")==0) {
459 if(xwindow_move_window(adesklets.display,
460 adesklets.root, adesklets.window,
461 adesklets.params)) {
462 XMapWindow(adesklets.display,adesklets.window);
463 if(!adesklets.params->no_update)
464 cfgfile_update(adesklets.params);
466 *return_str=NULL;
467 } else {
468 /* For restart: verify there is a lock file open,
469 to avoid false restart due to user-added "Restart"
470 item in default menu */
471 if(adesklets.lock && strcmp(*return_str,"Restart")==0) {
472 debug("Restart!\n");
473 adesklets.restart_flag=1;
474 *return_str=NULL;
475 } else {
476 if(strcmp(*return_str,"Quit")==0) {
477 adesklets.user_quit_flag=adesklets.quit_flag=1;
478 debug("Quit!\n");
479 *return_str=NULL;
484 result=1;
486 return result;
487 #else
488 return 0;
489 #endif
492 /*----------------------------------------------------------------------------*/
493 /* Return 1 if current image is potentially shown on screen, 0 otherwise.
494 Mainly used to determine needs for screen updates */
496 image_is_shown()
498 Imlib_Image image;
499 image = imlib_context_get_image();
501 return (image==adesklets.images->content[0]) ||
502 (adesklets.transparency &&
503 ((adesklets.user_background_image!=-1 &&
504 image==adesklets.images->content[adesklets.user_background_image]) ||
505 (image==adesklets.images->content[1])));
508 /*----------------------------------------------------------------------------*/
509 void usage(const char * name)
511 printf("Usage: %s [OPTIONS] [script_id]\n", name);
512 printf("adesklets interpreter and desklets launcher\n\
514 Options:\n\
515 -h, --help Display this help message\n\
516 -v, --version Get package version\n\
517 -f, --file In interpreter mode, use file as\n\
518 input stream instead of stdin\n\n");
521 /*----------------------------------------------------------------------------*/
523 adesklets_init(int argc, char ** argv)
525 int pos=1, result=0;
526 char * adesklets_id;
527 char str[CFGFILE_NAME_SIZE];
528 FILE * file;
529 struct flock lock;
530 struct sigaction new_action, old_action;
532 const char * OPTIONS[] = {"-h", "--help", "-f", "--file", "-v", "--version" };
534 /* Seek --help string: otherwise, it is either a script name of junk */
535 if(argc>=2) {
536 if(strncmp(argv[1],OPTIONS[0],strlen(OPTIONS[0]))==0 ||
537 strncmp(argv[1],OPTIONS[1],strlen(OPTIONS[1]))==0) {
538 usage(argv[0]);
539 return 0;
540 } else {
541 if (strncmp(argv[1],OPTIONS[4],strlen(OPTIONS[4]))==0 ||
542 strncmp(argv[1],OPTIONS[5],strlen(OPTIONS[5]))==0) {
543 printf("%s %s\n",PACKAGE,VERSION);
544 return 0;
545 } else {
546 if (strncmp(argv[1],OPTIONS[2],strlen(OPTIONS[2]))==0 ||
547 strncmp(argv[1],OPTIONS[3],strlen(OPTIONS[3]))==0) {
548 if(argc>=3) {
549 if (!((file=fopen(argv[2],"r"))&&
550 dup2(fileno(file),fileno(stdin))>=0)) {
551 welcome(stderr);
552 fprintf(stderr,"Could not open file '%s' for reading\n",
553 argv[2]);
554 return 0;
556 } else {
557 usage(argv[0]);
558 return 0;
560 pos+=2;
566 /* Get original parent process id */
567 adesklets.ppid=getppid();
569 /* Get desklet ID from environment */
570 adesklets_id = getenv("ADESKLETS_ID");
572 /* Set stdout and stderr to be unbuffered: this is needed
573 for proper pipe operation. stderr is always
574 unbuffered */
575 if (setvbuf(stdout,NULL,_IONBF,0)!=0) {
576 fprintf(stderr,"Could not remove stdout buffer\n");
577 return 0;
579 if (setvbuf(stderr,NULL,_IONBF,0)!=0) {
580 fprintf(stderr,"Could not remove stderr buffer\n");
581 return 0;
584 /* Determine if interactive use */
585 command.interactive=isatty(fileno(stdin));
587 /* Retrieve all parameters from config file */
588 adesklets.params = cfgfile_getinfo((!command.interactive)?argv[pos]:NULL,
589 ((uint)(adesklets_id)?
590 atoi(adesklets_id):-1));
592 /* Make sure ADESKLETS_ID is set in current environment */
593 if(!adesklets_id)
594 if (sprintf(str,"%u",adesklets.params->id)>0)
595 setenv("ADESKLETS_ID",str,1);
597 /* If interactive use, print welcome message */
598 if(command.interactive) {
599 welcome(stdout);
600 printf("Press TAB for hints.\n");
601 /* But if not, build and acquire lock file name */
602 } else if (adesklets_valid_desklet(argv[pos],0)) {
603 strncpy(str,argv[1],CFGFILE_NAME_SIZE-1);
604 str[CFGFILE_NAME_SIZE-1]=0;
605 if (snprintf(adesklets.lock_filename,CFGFILE_NAME_SIZE-1,
606 "%s/%s_uid%u_%s_%u.lock",
607 LOCKFILES_DIR,
608 PACKAGE,
609 getuid(),
610 (char*)basename(str),
611 adesklets.params->id)<CFGFILE_NAME_SIZE)
612 adesklets.lock_filename[CFGFILE_NAME_SIZE-1]=0;
613 /* Now, lock the file: this will wait forever */
614 if ((adesklets.lock=fdopen(open(adesklets.lock_filename,
615 O_CREAT|O_TRUNC|O_WRONLY,
616 S_IRUSR|S_IWUSR),
617 "w"))) {
618 lock.l_type=F_WRLCK;
619 lock.l_whence=SEEK_SET;
620 lock.l_start=0;
621 lock.l_len=0;
622 debug("Lock file: acquiring %s\n",adesklets.lock_filename);
623 TRY_RESET;
624 TRY(fcntl(fileno(adesklets.lock),F_SETLKW,&lock));
625 if (TRY_SUCCESS) {
626 /* Write PPID and PID to lock file */
627 fprintf(adesklets.lock,"%d %d\n",adesklets.ppid,getpid());
628 fflush(adesklets.lock);
629 } else {
630 debug("Lock file: could not get lock\n");
631 fclose(adesklets.lock);
632 adesklets.lock=NULL;
637 /* Force config file entry removal (or, at least, no registration)
638 at next update if invalid */
639 adesklets.params->no_update=!
640 adesklets_valid_desklet(adesklets.params->applet,1);
642 #ifndef X_DISPLAY_MISSING
643 /* Perform X Windows initialisation */
644 if ((adesklets.display=XOpenDisplay(NULL))) {
645 /* Correct screen determination */
646 adesklets.params->scr=(adesklets.params->scr>=0 &&
647 adesklets.params->scr<
648 ScreenCount(adesklets.display))?
649 adesklets.params->scr:
650 DefaultScreen(adesklets.display);
652 /* X related imlib2 settings */
653 adesklets.visual=imlib_get_best_visual(adesklets.display,
654 adesklets.params->scr,
655 &adesklets.depth);
656 imlib_context_set_display(adesklets.display);
657 imlib_context_set_visual(adesklets.visual);
658 imlib_context_set_colormap(DefaultColormap(adesklets.display,
659 adesklets.params->scr));
661 /* Create main desklet window: managed if interactive,
662 unmanaged if not */
663 adesklets_window_reset(command.interactive);
664 /* Install custom error handler */
665 XSetErrorHandler(xwindow_non_fatal_error_handler);
667 #ifdef DEBUG
668 else
669 debug("Could not connect to X server '%s'\n",XDisplayName(NULL));
670 #endif
671 #endif
673 /* Locate true type fonts system-wide */
674 xwindow_locate_truetype_fonts();
676 /* Various Others imlib2 settings */
677 imlib_set_cache_size(2048*1024);
678 imlib_set_font_cache_size(512*1024);
679 imlib_set_color_usage(128);
680 imlib_context_set_dither(1);
681 imlib_context_set_blend(1);
682 imlib_context_set_color(255,255,255,255);
684 /* Set events in proper echo mode: no echo if interactive, echo otherwise. */
685 events_echo=!command.interactive;
687 /* Initial settings */
688 if (adesklets_menus_reset()) {
689 if (adesklets_images_reset()) {
690 if (adesklets_fonts_reset()) {
691 if (adesklets_color_ranges_reset()) {
692 if (adesklets_color_modifiers_reset()) {
693 if (adesklets_filters_reset()) {
694 if (adesklets_polygons_reset()) {
695 if (adesklets_variables_reset()) {
696 /* Setup command interpreter */
697 if(command_interpreter_reset()) {
698 #ifdef FORCE_EXTENDED_CHARACTERS_INPUT
699 rl_variable_bind("input-meta", "on");
700 rl_variable_bind("convert-meta", "off");
701 rl_variable_bind("output-meta", "on");
702 #endif
703 /* Finally, set up event handler. This code snipset
704 was copied verbatim from the GNU C Library
705 Reference Manual (sigaction Function
706 Example section) */
707 new_action.sa_handler = termination_handler;
708 sigemptyset (&new_action.sa_mask);
709 new_action.sa_flags = 0;
710 sigaction (SIGINT, NULL, &old_action);
711 if (old_action.sa_handler != SIG_IGN)
712 sigaction (SIGINT, &new_action, NULL);
713 sigaction (SIGHUP, NULL, &old_action);
714 if (old_action.sa_handler != SIG_IGN)
715 sigaction (SIGHUP, &new_action, NULL);
716 sigaction (SIGTERM, NULL, &old_action);
717 if (old_action.sa_handler != SIG_IGN)
718 sigaction (SIGTERM, &new_action, NULL);
719 /* If applicable, make an initial setup of
720 config file, just in case */
721 if (X_DISPLAY_SUPPORT &&
722 adesklets.display && adesklets.window)
723 cfgfile_update(adesklets.params);
724 result=1;
725 event("ready!\n");
726 } else
727 fprintf(stderr, "Cannot initialize command interpreter\n");
728 } else
729 fprintf(stderr, "Cannot initialize variables\n");
730 } else
731 fprintf(stderr, "Cannot initialize imlib polygons\n");
732 } else
733 fprintf(stderr, "Cannot initialize imlib filters\n");
734 } else
735 fprintf(stderr, "Cannot initialize imlib color modifiers\n");
736 } else
737 fprintf(stderr, "Cannot initialize imlib color ranges\n");
738 } else
739 fprintf(stderr, "Cannot initialize imlib fonts\n");
740 } else
741 fprintf(stderr, "Cannot initialize imlib images\n");
742 } else
743 fprintf(stderr, "Cannot initialize menus\n");
745 return result;
748 /*----------------------------------------------------------------------------*/
749 void
750 adesklets_events_loop(void)
752 char *menu_str;
753 var_item * variable;
754 char ** list;
755 int x,y,i,j,k;
756 uint width, height;
757 #ifndef X_DISPLAY_MISSING
758 long mask;
759 #endif
760 double angle;
761 struct timespec sleep_time;
762 command_enum command_type;
763 vector * params;
764 #ifndef X_DISPLAY_MISSING
765 XEvent ev;
766 #endif
767 #ifdef HAVE_READLINE_HISTORY_H
768 HIST_ENTRY ** history;
769 FILE * file;
770 #endif
771 #ifdef HAVE_ICONV_H
772 iconv_t cd;
773 #endif
774 Imlib_Updates updates;
775 Imlib_Image image;
776 Imlib_Color color;
777 Imlib_Font font;
778 Imlib_Color_Range color_range;
779 Imlib_Color_Modifier color_modifier;
780 Imlib_Filter filter;
781 ImlibPolygon polygon;
782 Imlib_Load_Error error;
783 DATA32 * data;
784 DATA8 * tables[4];
786 debug("---------------------------------------------------------------\n");
787 do {
788 updates = imlib_updates_init();
789 if (command.ready) {
790 if (command.line) {
791 command.message_out=0;
792 variable_expansion(adesklets.variables,&command.line);
793 params=command_splitter(command.line,&command_type);
795 if (!command.recording ||
796 command_type==CMD_PLAY ||
797 command_type==CMD_START_RECORDING ||
798 command_type==CMD_STOP_RECORDING) {
799 switch(command_type) {
800 case CMD_TIME_GATE:
801 /* NOTE : for semi-automated generation of an adesklets'
802 API for scripting languages, you should include
803 a prototype declaration similar to this one
804 in a comment (multi-lines comments allowed)
805 directly below case declaration. Look at protoize.sh
806 for further details. Commands that are also
807 Imlib2 primitives do not need to have prototypes
808 most of the time.
810 prototype(double gate) */
811 if (command.replay_pos) {
812 if (params->pos>=2) {
813 angle=atof(params->content[1]);
814 #ifndef X_DISPLAY_MISSING
815 if (command.replay_abort_on_events) {
816 sleep_time.tv_sec=0; sleep_time.tv_nsec=X_POLLING_PERIOD/10;
817 while (angle>command_gate_chronometer())
818 if (adesklets.display && adesklets.window &&
819 (XCheckWindowEvent(adesklets.display,
820 adesklets.root,
821 PropertyChangeMask, &ev) ||
822 XCheckWindowEvent(adesklets.display,adesklets.window,
823 adesklets.event_mask,&ev) ||
824 XCheckTypedWindowEvent(adesklets.display,adesklets.window,
825 ClientMessage,&ev))) {
826 XPutBackEvent(adesklets.display,&ev);
827 break;
828 } else
829 nanosleep(&sleep_time,NULL);
830 } else {
831 #endif
832 if ((angle-=command_gate_chronometer())>0) {
833 sleep_time.tv_sec=(time_t)angle;
834 sleep_time.tv_nsec=(long)((angle-floor(angle))*1E9);
836 debug("Sleep time: %f, or %d %d\n",
837 angle,sleep_time.tv_sec,sleep_time.tv_nsec);
839 nanosleep(&sleep_time,NULL);
841 #ifndef X_DISPLAY_MISSING
843 #endif
844 } else
845 command_error("time gate not given\n");
846 } else
847 command_error("ignoring timer gate, interpreter not replaying\n");
848 break;
849 case CMD_HELP:
850 /* prototype([const char * command]) */
851 if(params->pos>=2) {
852 for(i=0;
853 COMMANDS[i].name &&
854 strcmp(params->content[1],COMMANDS[i].name);
855 ++i);
856 if (COMMANDS[i].name)
857 command_ok("%s - %s\n",COMMANDS[i].name, COMMANDS[i].doc);
858 else
859 command_error("no help on '%s'\n", (char*)params->content[1]);
860 } else {
861 for(i=0;COMMANDS[i].name;++i)
862 command_printf("%-25s -\t%s\n",COMMANDS[i].name, COMMANDS[i].doc);
864 break;
865 case CMD_PING:
866 /* prototype(void) */
867 command_ok("pong!\n");
868 break;
869 case CMD_PAUSE:
870 /* prototype([int delay]) */
871 i=(params->pos>=2)?
872 (((i=atoi(params->content[1]))>0)?i:5):5;
873 debug("Pausing for %d seconds.\n",i);
874 sleep(i);
875 break;
876 case CMD_VERSION:
877 /* prototype(void) */
878 command_ok("%s %s\n",PACKAGE,VERSION);
879 break;
880 case CMD_GET_ID:
881 /* prototype(void) */
882 command_ok("adesklets id %u\n", adesklets.params->id);
883 break;
884 case CMD_HISTORY:
885 /* prototype([const char * filename]) */
886 #ifdef HAVE_READLINE_HISTORY_H
887 if ((history=history_list())) {
888 for(i=0;history[i];++i);
889 command_printf("%d commands in history\n",i);
890 if((file=(params->pos>=2)?
891 fopen(command_subsplitter(command.line,1),"w"):stdout)) {
892 for(i=0;history[i];++i)
893 if (params->pos>=2 || !command.interactive)
894 fprintf(file,"%s\n",history[i]->line);
895 else
896 fprintf(file,"%d\t%s\n",i,history[i]->line);
897 if(file!=stdout) fclose(file);
898 } else
899 command_error("could not open output file for writing\n");
900 } else
901 command_error("could not retrieve history list\n");
902 #else
903 command_error("history support not compiled in\n");
904 #endif
905 break;
906 case CMD_SET:
907 /* prototype([const * char name, const * char value]) */
908 if ((i=params->pos)>1) {
909 /* Verify variable name does not include a dollar character */
910 for(j=0;
911 ((char*)params->content[1])[j] &&
912 ((char*)params->content[1])[j]!='$';
913 ++j);
914 if (j==strlen((char*)params->content[1])) {
915 /* First, search for existing variable */
916 variable=(var_item*)
917 vector_find(adesklets.variables,(uint*)&j,
918 variable_search_func,(void*)params->content[1]);
920 /* Then, if it exists, just delete it */
921 if (variable)
922 vector_delete(adesklets.variables,(uint)j);
923 else
924 if (i==2)
925 command_error("variable '%s' does not exist\n",
926 params->content[1]);
928 if (i>2) {
929 /* Then, set it back if there is a new content */
930 vector_push(adesklets.variables,
931 (void*)variable_create(
932 (char*)params->content[1],
933 (char*)command_subsplitter(command.line,2)));
935 } else
936 command_error("variable name contains '$'\n");
937 } else {
938 /* Print out all variables */
939 command_printf("%d variable(s)\n", adesklets.variables->pos);
940 for (i=0;i<adesklets.variables->pos;++i)
941 command_printf("%s=%s\n",
942 ((var_item*)adesklets.variables->content[i])->name,
943 ((var_item*)adesklets.variables->content[i])->value);
945 break;
946 case CMD_UNSET_ALL:
947 /* prototype(void) */
948 adesklets_variables_reset();
949 break;
950 case CMD_ECHO:
951 /* prototype(const char * string) */
952 break;
953 case CMD_START_RECORDING:
954 /* prototype(void) */
955 #ifdef HAVE_READLINE_HISTORY_H
956 /* This is a special case: you have to make sure to abort
957 current macro recording if called recursively from direct mode.
959 But this is not enough: you also need to ckeck we are not inside
960 a replay loop (indirect mode) because it would still be possible
961 to insert hidden calls to 'start_recording' inside a macro using
962 textual expansion (text variables) */
963 if (!command.recording && !command.replay_pos)
964 command.recording=history_size()+1;
965 else {
966 /* In non interactive mode, purge newly created history
967 entries */
968 if (command.recording && !command.interactive)
969 for(i=history_size()-1;i>=command.recording-1;--i)
970 free_history_entry(remove_history(i));
971 command.recording=command.replay_pos=0;
972 command_error("cannot call this while already recording or \
973 replaying, aborded\n");
975 #else
976 command_error("compiled without GNU history support\n");
977 #endif
978 break;
979 case CMD_STOP_RECORDING:
980 /* prototype(void) */
981 #ifdef HAVE_READLINE_HISTORY_H
982 if (!command.replay_pos) {
983 if (command.recording) {
984 --command.recording;
985 j=history_size()-1;
986 if(!command.interactive)
987 /* In case of non interactive use, remove
988 the reference to the 'stop_record' command */
989 free_history_entry(remove_history(j));
990 if (command.recording!=j)
991 command_ok("recorded_commands %d %d\n",
992 command.recording,
993 j-1);
994 else
995 command_error("no command recorded\n");
996 } else
997 command_error("no recording taking place right now\n");
998 } else
999 command_error("cannot call stop while replaying, replay aborded\n");
1000 command.recording=0;
1001 #else
1002 command_error("compiled without GNU history support\n");
1003 #endif
1004 break;
1005 case CMD_PLAY_GET_ABORT_ON_EVENTS:
1006 /* prototype(void) */
1007 command_ok("abort_on_event %d\n",command.replay_abort_on_events);
1008 break;
1009 case CMD_PLAY_SET_ABORT_ON_EVENTS:
1010 /* prototype(bool abort) */
1011 if (!command.replay_pos) {
1012 if (params->pos>=2)
1013 command.replay_abort_on_events=atoi((char*)params->content[1]);
1014 else
1015 command_error("abort on event value not given\n");
1016 } else
1017 command_error("cannot be called inside a replay\n");
1018 break;
1019 case CMD_PLAY:
1020 /* prototype(int beginning, int end) */
1021 #ifdef HAVE_READLINE_HISTORY_H
1022 if (!command.recording && !command.replay_pos) {
1023 if (params->pos>=3) {
1024 if (((i=atoi(params->content[1]))<(j=history_size())) &&
1025 ((k=atoi(params->content[2]))<j)) {
1026 if (i>=0 && k>=0 && (i<=k)) {
1027 gettimeofday(&command.replay_time,NULL);
1028 command.replay_pos=i+1;
1029 command.replay_stop=k;
1030 events_delay=1;
1031 } else
1032 command_error("invalid limits\n");
1033 } else
1034 command_error("limits out of range\n");
1035 } else
1036 command_error("missing start and stop limits\n");
1037 } else {
1038 command.recording=command.replay_pos=0;
1039 command_error("cannot call this now, aborded\n");
1041 #else
1042 command_error("compiled without GNU history support\n");
1043 #endif
1044 break;
1045 case CMD_CONTEXT_GET_DITHER:
1046 command_ok("context dither %hhu\n",imlib_context_get_dither());
1047 break;
1048 case CMD_CONTEXT_GET_ANTI_ALIAS:
1049 command_ok("context antialias %hhu\n",imlib_context_get_anti_alias());
1050 break;
1051 case CMD_CONTEXT_GET_BLEND:
1052 command_ok("context blend %hhu\n",imlib_context_get_blend());
1053 break;
1054 case CMD_CONTEXT_GET_OPERATION:
1055 i=imlib_context_get_operation();
1056 command_ok("context operation %d (%s)\n",
1057 i, OPERATIONS[i]);
1058 break;
1059 case CMD_CONTEXT_GET_CLIPRECT:
1060 /* prototype(void) */
1061 imlib_context_get_cliprect(&x,&y,&i,&j);
1062 command_ok("context cliprect %d %d %d %d\n",x,y,i,j);
1063 break;
1064 case CMD_CONTEXT_GET_IMAGE:
1065 image=imlib_context_get_image();
1066 for(i=0;i<adesklets.images->pos;++i)
1067 if(adesklets.images->content[i]==image)
1068 command_ok("context image %d\n",i);
1069 break;
1070 case CMD_CONTEXT_GET_FONT:
1071 if ((font=imlib_context_get_font())) {
1072 for(i=0;i<adesklets.fonts->pos;++i)
1073 if(adesklets.fonts->content[i]==font)
1074 command_ok("context font %d\n",i);
1075 } else
1076 command_ok("context font -1 (unset)\n");
1077 break;
1078 case CMD_CONTEXT_GET_COLOR_RANGE:
1079 if ((color_range=imlib_context_get_color_range())) {
1080 for(i=0;i<adesklets.color_ranges->pos;++i)
1081 if(adesklets.color_ranges->content[i]==color_range)
1082 command_ok("context colorrange %d\n",i);
1083 } else
1084 command_ok("context colorrange -1 (unset)\n");
1085 break;
1086 case CMD_CONTEXT_GET_COLOR_MODIFIER:
1087 if ((color_modifier=imlib_context_get_color_modifier())) {
1088 for(i=0;i<adesklets.color_modifiers->pos;++i)
1089 if(adesklets.color_modifiers->content[i]==color_modifier)
1090 command_ok("context colormodifier %d\n",i);
1091 } else
1092 command_ok("context colormodifier -1 (unset)\n");
1093 break;
1094 case CMD_CONTEXT_GET_FILTER:
1095 if ((filter=imlib_context_get_filter())) {
1096 for(i=0;i<adesklets.filters->pos;++i)
1097 if(adesklets.filters->content[i]==filter)
1098 command_ok("context filter %d\n",i);
1099 } else
1100 command_ok("context filter -1 (unset)\n");
1101 break;
1102 case CMD_CONTEXT_GET_COLOR:
1103 /* prototype(void) */
1104 imlib_context_get_color(&x,&y,&i,&j);
1105 command_ok("context color %hhu %hhu %hhu %hhu\n",
1106 x&255,y&255,i&255,j&255);
1107 break;
1108 case CMD_CONTEXT_GET_ANGLE:
1109 angle=imlib_context_get_angle();
1110 command_ok("context angle %4.2f\n",angle);
1111 break;
1112 case CMD_CONTEXT_GET_DIRECTION:
1113 i=imlib_context_get_direction();
1114 command_ok("context direction %d (%s)\n",
1115 i, DIRECTIONS[i]);
1116 break;
1117 case CMD_CONTEXT_SET_DITHER:
1118 /* prototype(bool dither) */
1119 if (params->pos>=2)
1120 imlib_context_set_dither((char)atoi(params->content[1]));
1121 else
1122 command_error("dither value not given\n");
1123 break;
1124 case CMD_CONTEXT_SET_ANTI_ALIAS:
1125 /* prototype(bool anti_alias) */
1126 if (params->pos>=2)
1127 imlib_context_set_anti_alias((char)atoi(params->content[1]));
1128 else
1129 command_error("anti alias value not given\n");
1130 break;
1131 case CMD_CONTEXT_SET_BLEND:
1132 /* prototype(bool blend) */
1133 if (params->pos>=2)
1134 imlib_context_set_blend((char)atoi(params->content[1]));
1135 else
1136 command_error("blend value not given\n");
1137 break;
1138 case CMD_CONTEXT_SET_OPERATION:
1139 /* prototype(enum OPERATIONS operation) */
1140 if(params->pos>=2) {
1141 for(i=0;OPERATIONS[i];++i)
1142 if(strncmp(OPERATIONS[i],params->content[1],
1143 strlen(params->content[1]))==0)
1144 break;
1145 imlib_context_set_operation((OPERATIONS[i])?
1146 i:((j=atoi(params->content[1])))<4?j:0);
1147 } else
1148 command_error("operation not given\n");
1149 break;
1150 case CMD_CONTEXT_SET_CLIPRECT:
1151 if (params->pos>=5) {
1152 if ((x=atoi((char*)params->content[1]))>=0 &&
1153 (y=atoi((char*)params->content[2]))>=0 &&
1154 (i=atoi((char*)params->content[3]))>=0 &&
1155 (j=atoi((char*)params->content[4]))>=0) {
1156 imlib_context_set_cliprect(x,y,i,j);
1157 } else
1158 command_error("clipping rectangle coordinates out of range\n");
1159 } else
1160 command_error("clipping rectangle description not given\n");
1161 break;
1162 case CMD_CONTEXT_SET_IMAGE:
1163 if (params->pos>=2) {
1164 if ((i=atoi((char*)params->content[1]))>=0 &&
1165 i<adesklets.images->pos) {
1166 imlib_context_set_image(adesklets.images->content[i]);
1167 } else
1168 command_error("image ID %d out of range\n",i);
1169 } else
1170 command_error("image ID not given\n");
1171 break;
1172 case CMD_CONTEXT_SET_FONT:
1173 /* prototype([int font]) */
1174 j=0;
1175 if (params->pos>=2) {
1176 if ((i=atoi((char*)params->content[1]))>=0 &&
1177 i<adesklets.fonts->pos) {
1178 imlib_context_set_font(adesklets.fonts->content[i]);
1179 } else {
1180 if(i==-1) {
1181 j=1;
1182 imlib_context_set_font(NULL);
1183 } else
1184 command_error("font ID %d out of range\n",i);
1186 } else {
1187 j=1;
1188 imlib_context_set_font(NULL);
1190 if(j) command_ok("context font unset\n");
1191 break;
1192 case CMD_CONTEXT_SET_COLOR_RANGE:
1193 /* prototype([int color_range]) */
1194 j=0;
1195 if (params->pos>=2) {
1196 if ((i=atoi((char*)params->content[1]))>=0 &&
1197 i<adesklets.color_ranges->pos) {
1198 imlib_context_set_color_range(adesklets.color_ranges->content[i]);
1199 } else {
1200 if(i==-1) {
1201 j=1;
1202 imlib_context_set_color_range(NULL);
1203 } else
1204 command_error("color range ID %d out of range\n",i);
1206 } else {
1207 j=1;
1208 imlib_context_set_color_range(NULL);
1210 if(j) command_ok("context color range unset\n");
1211 break;
1212 case CMD_CONTEXT_SET_COLOR_MODIFIER:
1213 /* prototype([int color_modifier]) */
1214 j=0;
1215 if (params->pos>=2) {
1216 if ((i=atoi((char*)params->content[1]))>=0 &&
1217 i<adesklets.color_modifiers->pos) {
1218 imlib_context_set_color_modifier(
1219 adesklets.color_modifiers->content[i]);
1220 } else {
1221 if(i==-1) {
1222 j=1;
1223 imlib_context_set_color_modifier(NULL);
1224 } else
1225 command_error("color modifier ID %d out of range\n",i);
1227 } else {
1228 j=1;
1229 imlib_context_set_color_modifier(NULL);
1231 if(j) command_ok("context color modifier unset\n");
1232 break;
1233 case CMD_CONTEXT_SET_FILTER:
1234 /* prototype([int filter]) */
1235 j=0;
1236 if (params->pos>=2) {
1237 if ((i=atoi((char*)params->content[1]))>=0 &&
1238 i<adesklets.filters->pos) {
1239 imlib_context_set_filter(adesklets.filters->content[i]);
1240 } else {
1241 if(i==-1) {
1242 j=1;
1243 imlib_context_set_filter(NULL);
1244 } else
1245 command_error("filter ID %d out of range\n",i);
1247 } else {
1248 j=1;
1249 imlib_context_set_filter(NULL);
1251 if(j) command_ok("context filter unset\n");
1252 break;
1253 case CMD_CONTEXT_SET_COLOR:
1254 if (params->pos>=5)
1255 imlib_context_set_color(atoi(params->content[1]),
1256 atoi(params->content[2]),
1257 atoi(params->content[3]),
1258 atoi(params->content[4]));
1259 else
1260 command_error("color RGBA description not given\n");
1261 break;
1262 case CMD_CONTEXT_SET_ANGLE:
1263 if (params->pos>=2) {
1264 imlib_context_set_angle(atof(params->content[1]));
1265 } else
1266 command_error("angle not given\n");
1267 break;
1268 case CMD_CONTEXT_SET_DIRECTION:
1269 /* prototype(enum DIRECTIONS direction) */
1270 if(params->pos>=2) {
1271 for(i=0;DIRECTIONS[i];++i)
1272 if(strncmp(DIRECTIONS[i],params->content[1],
1273 strlen(params->content[1]))==0)
1274 break;
1275 imlib_context_set_direction((DIRECTIONS[i])?
1276 i:((j=atoi(params->content[1])))<5?j:0);
1277 } else
1278 command_error("direction not given\n");
1279 break;
1280 case CMD_ADD_COLOR_TO_COLOR_RANGE:
1281 if(imlib_context_get_color_range()) {
1282 i=(params->pos>=2)?atoi(params->content[1]):0;
1283 imlib_add_color_to_color_range(i);
1284 } else
1285 command_error("no color range selected\n");
1286 break;
1287 case CMD_BLEND_IMAGE_ONTO_IMAGE:
1288 if (params->pos>=11) {
1289 if((i=atoi((char*)params->content[1]))>=0 &&
1290 i<adesklets.images->pos) {
1291 imlib_blend_image_onto_image(adesklets.images->content[i],
1292 atoi(params->content[2]),
1293 atoi(params->content[3]),
1294 atoi(params->content[4]),
1295 atoi(params->content[5]),
1296 atoi(params->content[6]),
1297 atoi(params->content[7]),
1298 atoi(params->content[8]),
1299 atoi(params->content[9]),
1300 atoi(params->content[10]));
1301 if (image_is_shown())
1302 updates = imlib_update_append_rect(updates,
1303 atoi(params->content[7]),
1304 atoi(params->content[8]),
1305 atoi(params->content[9]),
1306 atoi(params->content[10]));
1307 } else
1308 command_error("image ID %d out of range\n",i);
1309 } else
1310 command_error("not enough parameters given - need ten\n");
1311 break;
1312 case CMD_BLEND_IMAGE_ONTO_IMAGE_AT_ANGLE:
1313 if (params->pos>=11) {
1314 if((i=atoi((char*)params->content[1]))>=0 &&
1315 i<adesklets.images->pos) {
1316 imlib_blend_image_onto_image_at_angle(
1317 adesklets.images->content[i],
1318 atoi(params->content[2]),
1319 atoi(params->content[3]),
1320 atoi(params->content[4]),
1321 atoi(params->content[5]),
1322 atoi(params->content[6]),
1323 atoi(params->content[7]),
1324 atoi(params->content[8]),
1325 atoi(params->content[9]),
1326 atoi(params->content[10]));
1327 if (image_is_shown())
1328 /* We do not bother: we update everything */
1329 updates = imlib_update_append_rect(updates,
1330 0,0,
1331 imlib_image_get_width(),
1332 imlib_image_get_height());
1333 } else
1334 command_error("image ID %d out of range\n",i);
1335 } else
1336 command_error("not enough parameters given - need ten\n");
1337 break;
1338 case CMD_BLEND_IMAGE_ONTO_IMAGE_SKEWED:
1339 if (params->pos>=12) {
1340 if((i=atoi((char*)params->content[1]))>=0 &&
1341 i<adesklets.images->pos) {
1342 imlib_blend_image_onto_image_skewed(adesklets.images->content[i],
1343 atoi(params->content[2]),
1344 atoi(params->content[3]),
1345 atoi(params->content[4]),
1346 atoi(params->content[5]),
1347 atoi(params->content[6]),
1348 atoi(params->content[7]),
1349 atoi(params->content[8]),
1350 atoi(params->content[9]),
1351 atoi(params->content[10]),
1352 atoi(params->content[11]),
1353 atoi(params->content[12]));
1354 if (image_is_shown())
1355 /* We do not bother: we update everything */
1356 updates = imlib_update_append_rect(updates,
1357 0,0,
1358 imlib_image_get_width(),
1359 imlib_image_get_height());
1360 } else
1361 command_error("image ID %d out of range\n",i);
1362 } else
1363 command_error("not enough parameters given - need twelve\n");
1364 break;
1365 case CMD_APPLY_FILTER:
1366 /* WARNING: there is a initialisation bug in imlib2 prior
1367 version 1.2.0 (cvs of 11/20/04) that sets the dynamic filters
1368 never to work if an image loader is not used
1369 at least once before (this has to do with
1370 lt_dlinit() being called at the wrong place...).
1371 We can do nothing about this: upgrade your imlib2 lib!
1373 prototype(const char * script)
1375 if(params->pos>=2) {
1376 menu_str=command_subsplitter(command.line,1);
1377 if(!strstr(menu_str,"[]")) {
1378 imlib_apply_filter(menu_str);
1379 if (image_is_shown())
1380 updates=imlib_update_append_rect(updates,0,0,
1381 imlib_image_get_width(),
1382 imlib_image_get_height());
1384 else
1385 command_error("variadic filters forbidden\n");
1386 } else
1387 command_error("filter description not given\n");
1390 "tint(x=0,y=0,w=100,h=100,alpha=100,red=155,green=25,blue=25);"
1392 break;
1393 case CMD_GET_TEXT_SIZE:
1394 /* prototype(const char * text) */
1395 if(imlib_context_get_font()) {
1396 if(params->pos>=2) {
1397 menu_str=dupstr_utf8(command_subsplitter(command.line,1));
1398 imlib_get_text_size(menu_str,
1399 &i,&j);
1400 free(menu_str);
1401 command_ok("text size %d %d\n",i,j);
1402 } else
1403 command_error("text string not given or blank\n");
1404 } else
1405 command_error("no font selected.\n");
1406 break;
1407 case CMD_GET_TEXT_ADVANCE:
1408 /* prototype(const char * text) */
1409 if(imlib_context_get_font()) {
1410 if(params->pos>=2) {
1411 menu_str=dupstr_utf8(command_subsplitter(command.line,1));
1412 imlib_get_text_advance(menu_str,&i,&j);
1413 free(menu_str);
1414 command_ok("text advance %d %d\n",i,j);
1415 } else
1416 command_error("text string not given or blank\n");
1417 } else
1418 command_error("no font selected.\n");
1419 break;
1420 case CMD_TEXT_DRAW:
1421 if(imlib_context_get_font()) {
1422 if(params->pos>=4) {
1423 menu_str=dupstr_utf8(command_subsplitter(command.line,3));
1424 imlib_text_draw(atoi(params->content[1]),
1425 atoi(params->content[2]),
1426 menu_str);
1427 if (image_is_shown()) {
1428 imlib_get_text_size(menu_str,&x,&y);
1429 updates = imlib_update_append_rect(updates,
1430 atoi(params->content[1]),
1431 atoi(params->content[2]),
1432 x,y);
1434 free(menu_str);
1435 } else
1436 command_error("text string not given or blank\n");
1437 } else
1438 command_error("no font selected.\n");
1439 break;
1440 case CMD_MODIFY_COLOR_MODIFIER_GAMMA:
1441 if(imlib_context_get_color_modifier()) {
1442 if(params->pos>=2) {
1443 imlib_modify_color_modifier_gamma(atof(params->content[1]));
1444 } else
1445 command_error("gamma value not given\n");
1446 } else
1447 command_error("no context color modifier selected\n");
1448 break;
1449 case CMD_MODIFY_COLOR_MODIFIER_BRIGHTNESS:
1450 if(imlib_context_get_color_modifier()) {
1451 if(params->pos>=2) {
1452 imlib_modify_color_modifier_brightness(atof(params->content[1]));
1453 } else
1454 command_error("brightness value not given\n");
1455 } else
1456 command_error("no context color modifier selected\n");
1457 break;
1458 case CMD_MODIFY_COLOR_MODIFIER_CONTRAST:
1459 if(imlib_context_get_color_modifier()) {
1460 if(params->pos>=2) {
1461 imlib_modify_color_modifier_contrast(atof(params->content[1]));
1462 } else
1463 command_error("contrast value not given\n");
1464 } else
1465 command_error("no context color modifier selected\n");
1466 break;
1467 case CMD_GET_COLOR_MODIFIER_TABLES:
1468 /* prototype(void) */
1469 /* Throw all 1024 table entries in RGBA orders */
1470 if(imlib_context_get_color_modifier()) {
1471 if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1472 (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1473 (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1474 (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
1475 imlib_get_color_modifier_tables(tables[0],tables[1],
1476 tables[2],tables[3]);
1477 for(i=0;i<4;++i)
1478 for(j=0;j<256;++j)
1479 command_printf("%hhu ", tables[i][j]);
1480 command_printf("\n");
1481 } else
1482 command_error("memory allocation problem\n");
1483 for(i=0;i<4;++i)
1484 if(tables[i]) free(tables[i]);
1485 } else
1486 command_error("no context color modifier selected\n");
1487 break;
1488 break;
1489 case CMD_SET_COLOR_MODIFIER_TABLES:
1490 /* prototype(unsigned char * table) */
1491 if(imlib_context_get_color_modifier()) {
1492 if (params->pos==1025) {
1493 if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1494 (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1495 (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1496 (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
1497 for(i=0;i<4;++i)
1498 for(j=0;j<256;++j)
1499 tables[i][j]=(DATA8)atoi(params->content[(i*256)+j+1]);
1500 imlib_set_color_modifier_tables(tables[0],tables[1],
1501 tables[2],tables[3]);
1502 command_ok("set_color_modifier_tables\n");
1503 } else
1504 command_error("memory allocation problem");
1505 for(i=0;i<4;++i)
1506 if(tables[i]) free(tables[i]);
1507 } else
1508 command_error("Invalid number of entries - need 1024\n");
1509 } else
1510 command_error("no context color modifier selected\n");
1511 break;
1512 case CMD_GET_COLOR_MODIFIER_VALUE:
1513 /* prototype(enum RGBA_TABLES table, int index) */
1514 /* NOTE: this is not an original imlib2 function.
1515 it was included as a convenience for
1516 interactive use. */
1517 if(imlib_context_get_color_modifier()) {
1518 if (params->pos>=3) {
1519 for(i=0;RGBA_TABLES[i];++i)
1520 if(strncmp(RGBA_TABLES[i],
1521 params->content[1],
1522 strlen(params->content[1]))==0)
1523 break;
1524 i=(RGBA_TABLES[i])?i:atoi(params->content[1])%4;
1526 if((j=atoi(params->content[2]))<256 && j>=0) {
1527 if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1528 (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1529 (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1530 (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
1531 imlib_get_color_modifier_tables(tables[0],tables[1],
1532 tables[2],tables[3]);
1533 command_ok("value %s %hhu\n",
1534 RGBA_TABLES[i],
1535 (char)tables[i][j]&255);
1537 } else
1538 command_error("memory allocation problem\n");
1539 for(i=0;i<4;++i)
1540 if(tables[i]) free(tables[i]);
1541 } else
1542 command_error("index value %d out of range\n",j);
1543 } else
1544 command_error("parameters not given - need two\n");
1545 } else
1546 command_error("no context color modifier selected\n");
1547 break;
1548 case CMD_SET_COLOR_MODIFIER_VALUE:
1549 /* prototype(enum RGBA_TABLES table, int index, int value) */
1550 /* NOTE: this is not an original imlib2 function.
1551 it was included as a convenience for
1552 interactive use. */
1553 if(imlib_context_get_color_modifier()) {
1554 if (params->pos>=4) {
1555 for(i=0;RGBA_TABLES[i];++i)
1556 if(strncmp(RGBA_TABLES[i],
1557 params->content[1],
1558 strlen(params->content[1]))==0)
1559 break;
1560 i=(RGBA_TABLES[i])?i:atoi(params->content[1])%4;
1562 if((j=atoi(params->content[2]))<256 && j>=0) {
1563 if ((x=atoi(params->content[3]))<256 && x>=0) {
1564 if((tables[0]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1565 (tables[1]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1566 (tables[2]=(DATA8*)malloc(sizeof(DATA8)*256))&&
1567 (tables[3]=(DATA8*)malloc(sizeof(DATA8)*256))) {
1568 imlib_get_color_modifier_tables(tables[0],tables[1],
1569 tables[2],tables[3]);
1570 tables[i][j]=x;
1571 imlib_set_color_modifier_tables(tables[0],tables[1],
1572 tables[2],tables[3]);
1573 } else
1574 command_error("memory allocation problem\n");
1575 for(i=0;i<4;++i)
1576 if(tables[i]) free(tables[i]);
1577 } else
1578 command_error("value %d out of range\n",x);
1579 } else
1580 command_error("index value %d out of range\n",j);
1581 } else
1582 command_error("parameters not given - need three\n");
1583 } else
1584 command_error("no context color modifier selected\n");
1585 break;
1586 case CMD_APPLY_COLOR_MODIFIER:
1587 if(imlib_context_get_color_modifier()) {
1588 imlib_apply_color_modifier();
1589 if(image_is_shown())
1590 updates=imlib_update_append_rect(updates,0,0,
1591 imlib_image_get_width(),
1592 imlib_image_get_height());
1593 } else
1594 command_error("no context color modifier selected\n");
1595 break;
1596 case CMD_APPLY_COLOR_MODIFIER_TO_RECTANGLE:
1597 if(imlib_context_get_color_modifier()) {
1598 if (params->pos>=5) {
1599 imlib_apply_color_modifier_to_rectangle(
1600 (x=atoi(params->content[1])),
1601 (y=atoi(params->content[2])),
1602 (i=atoi(params->content[3])),
1603 (j=atoi(params->content[4])));
1604 if (image_is_shown())
1605 updates=imlib_update_append_rect(updates,x,y,i,j);
1606 } else
1607 command_error("rectangles coordinates not given\n");
1608 } else
1609 command_error("no context color modifier selected\n");
1610 break;
1611 case CMD_LOAD_IMAGE_WITHOUT_CACHE:
1612 if (params->pos>=2) {
1613 menu_str=command_subsplitter(command.line,1);
1614 if ((image=imlib_load_image_without_cache(menu_str))) {
1615 if (vector_push(adesklets.images,image))
1616 command_ok("new image %d\n",adesklets.images->pos-1);
1617 else
1618 command_error("memory allocation problem\n");
1619 } else
1620 command_error("could not load image '%s'\n", menu_str);
1621 } else
1622 command_error("image file name not given\n");
1623 break;
1624 case CMD_LOAD_IMAGE:
1625 if (params->pos>=2) {
1626 menu_str=command_subsplitter(command.line,1);
1627 if ((image=imlib_load_image_with_error_return(menu_str,&error))) {
1628 if (vector_push(adesklets.images,image))
1629 command_ok("new image %d\n",adesklets.images->pos-1);
1630 else
1631 command_error("memory allocation problem\n");
1632 } else
1633 command_error("could not load image '%s' - %s\n",
1634 menu_str,LOAD_ERRORS[(int)error]);
1635 } else
1636 command_error("image file name not given\n");
1637 break;
1638 case CMD_SAVE_IMAGE:
1639 if (params->pos>=2) {
1640 menu_str=command_subsplitter(command.line,1);
1641 imlib_save_image_with_error_return(menu_str,&error);
1642 if(error!=IMLIB_LOAD_ERROR_NONE)
1643 command_error("%s\n",LOAD_ERRORS[(int)error]);
1644 } else
1645 command_error("image file name not given\n");
1646 break;
1647 case CMD_CREATE_IMAGE:
1648 if (params->pos>=3) {
1649 if((i=atoi(params->content[1]))>0 &&
1650 (j=atoi(params->content[2]))>0) {
1651 if((image=imlib_create_image(i,j))) {
1652 xwindow_context_save(IMLIB_IMAGE|IMLIB_BLEND|IMLIB_COLOR);
1653 imlib_context_set_image(image);
1654 imlib_image_set_has_alpha(1);
1655 imlib_context_set_blend(0);
1656 imlib_context_set_color(0,0,0,0);
1657 imlib_image_fill_rectangle(0,0,i,j);
1658 xwindow_context_restore();
1659 if (vector_push(adesklets.images,image))
1660 command_ok("new image %d\n",adesklets.images->pos-1);
1661 else
1662 command_error("memory allocation problem\n");
1663 } else
1664 command_error("imlib image allocation error\n");
1665 } else
1666 command_error("image dimensions out of range\n");
1667 } else
1668 command_error("image dimensions were not given\n");
1669 break;
1670 case CMD_CREATE_IMAGE_USING_DATA:
1671 /* This uses imlib_create_image_using_copied_data(),
1672 so DATA * data can be freed afterward.
1673 As in CMD_IMAGE_GET_DATA, data is expected to be
1674 RGBA ordered. */
1675 if (params->pos>=3) {
1676 if ((width=atoi(params->content[1]))>0 &&
1677 (height=atoi(params->content[2]))>0) {
1678 if(width*height*4==params->pos-3) {
1679 if((data=(DATA32*)malloc(sizeof(DATA32)*width*height))) {
1680 for(i=0;i<width*height;++i)
1681 data[i]=
1682 ((atoi((char*)params->content[i*4+3])&255)<<16)|
1683 ((atoi((char*)params->content[i*4+4])&255)<<8)|
1684 ((atoi((char*)params->content[i*4+5])&255)<<0)|
1685 ((atoi((char*)params->content[i*4+6])&255)<<24);
1686 if ((image=imlib_create_image_using_copied_data(width,
1687 height,
1688 data))) {
1689 xwindow_context_save(IMLIB_IMAGE);
1690 imlib_context_set_image(image);
1691 imlib_image_set_has_alpha(1);
1692 xwindow_context_restore();
1693 if(vector_push(adesklets.images,image))
1694 command_ok("new image %d\n",adesklets.images->pos-1);
1695 else
1696 command_error("memory allocation problem");
1697 } else
1698 command_error("imlib image allocation error\n");
1699 free(data);
1701 else
1702 command_error("memory allocation problem\n");
1703 } else
1704 command_error("image dimensions and data lenght mismatch\n");
1705 } else
1706 command_error("image dimensions out of range\n");
1707 } else
1708 command_error("image dimensions were not given\n");
1709 break;
1710 case CMD_CLONE_IMAGE:
1711 if((image=imlib_clone_image())) {
1712 if (vector_push(adesklets.images,image))
1713 command_ok("cloned image %d\n",adesklets.images->pos-1);
1714 else
1715 command_error("memory allocation problem");
1716 } else
1717 command_error("imlib image allocation error\n");
1718 break;
1719 case CMD_FREE_IMAGE:
1720 /* This does not react as imlib_free_image:
1721 - image ID has to be given
1722 - If current context image is freed, context
1723 is put back on foreground image
1724 - If image corresponding to user_background_image
1725 is freed, user_background_image is reset.
1727 prototype(int image)
1729 if(params->pos>=2) {
1730 if((i=atoi((char*)params->content[1]))<adesklets.images->pos &&
1731 i>=0) {
1732 if(i>=2) {
1733 j=(imlib_context_get_image()==adesklets.images->content[i]);
1734 if (vector_delete(adesklets.images,i)) {
1735 if(i==adesklets.user_background_image) {
1736 adesklets.user_background_image=-1;
1737 xwindow_context_save(IMLIB_IMAGE);
1738 imlib_context_set_image(adesklets.images->content[0]);
1739 updates=imlib_update_append_rect(updates,0,0,
1740 imlib_image_get_width(),
1741 imlib_image_get_height());
1742 xwindow_context_restore();
1744 else
1745 if(i<adesklets.user_background_image)
1746 --adesklets.user_background_image;
1747 if (j)
1748 imlib_context_set_image(adesklets.images->content[0]);
1749 } else
1750 command_error("memory desallocation problem\n");
1751 } else
1752 command_error("it is forbidden to unload image %d\n",i);
1753 } else
1754 command_error("image ID %d out of range\n",i);
1755 } else
1756 command_error("image ID not given\n");
1757 break;
1758 case CMD_LOAD_FONT:
1759 if(params->pos>=2) {
1760 if (strlen(params->content[1])>=3 &&
1761 index(params->content[1],'/')) {
1762 if ((font=imlib_load_font(params->content[1]))) {
1763 if(vector_push(adesklets.fonts,font))
1764 command_ok("new font %d\n", adesklets.fonts->pos-1);
1765 else
1766 command_error("memory allocation problem");
1767 } else
1768 command_error("font '%s' could not be loaded\n",
1769 (char*)params->content[1]);
1770 } else
1771 command_error(
1772 "font description incorrect - should be `name/size'\n");
1773 } else
1774 command_error("font description not given\n");
1775 break;
1776 case CMD_FREE_FONT:
1777 /* This does not react as imlib_free_font:
1778 - font ID has to be given
1779 - If current font is freed, context
1780 is put back on NULL
1782 prototype(int font)
1784 if(params->pos>=2) {
1785 if((i=atoi((char*)params->content[1]))
1786 <adesklets.fonts->pos &&
1787 i>=0) {
1788 j=(imlib_context_get_font()==
1789 adesklets.fonts->content[i]);
1790 if (vector_delete(adesklets.fonts,i)) {
1791 if (j)
1792 imlib_context_set_font(NULL);
1793 } else
1794 command_error("memory desallocation problem\n");
1795 } else
1796 command_error("font ID %d out of range\n",i);
1797 } else
1798 command_error("font ID not given\n");
1799 break;
1800 case CMD_LIST_FONTS:
1801 /* prototype(void) */
1802 list=imlib_list_fonts(&j);
1803 command_printf("%d fonts found\n",j);
1804 for(i=0;i<j;++i)
1805 command_printf("%s ",list[i]);
1806 command_printf("\n");
1807 imlib_free_font_list(list,j);
1808 break;
1809 case CMD_LIST_FONT_PATH:
1810 /* prototype(void) */
1811 list=imlib_list_font_path(&j);
1812 command_printf("%d font_path found\n",j);
1813 for(i=0;i<j;++i)
1814 command_printf("%s\n",list[i]);
1815 break;
1816 case CMD_ADD_PATH_TO_FONT_PATH:
1817 if(params->pos>=2) {
1818 imlib_add_path_to_font_path(command_subsplitter(command.line,1));
1819 } else
1820 command_error("font path not given\n");
1821 break;
1822 case CMD_REMOVE_PATH_FROM_FONT_PATH:
1823 if(params->pos>=2) {
1824 imlib_remove_path_from_font_path(
1825 command_subsplitter(command.line,1));
1826 debug("%s\n",command_subsplitter(command.line,1));
1827 } else
1828 command_error("font path not given\n");
1829 break;
1830 case CMD_CREATE_COLOR_RANGE:
1831 if((color_range=imlib_create_color_range())) {
1832 if(vector_push(adesklets.color_ranges,color_range))
1833 command_ok("new colorrange %d\n",adesklets.color_ranges->pos-1);
1834 else
1835 command_error("memory allocation problem\n");
1836 } else
1837 command_error("imlib allocation problem\n");
1838 break;
1839 case CMD_FREE_COLOR_RANGE:
1840 /* This does not react as imlib_free_color_range:
1841 - color_range ID has to be given
1842 - If current color range is freed, context
1843 is put back on NULL
1845 prototype(int color_range)
1847 if(params->pos>=2) {
1848 if((i=atoi((char*)params->content[1]))
1849 <adesklets.color_ranges->pos &&
1850 i>=0) {
1851 j=(imlib_context_get_color_range()==
1852 adesklets.color_ranges->content[i]);
1853 if (vector_delete(adesklets.color_ranges,i)) {
1854 if (j)
1855 imlib_context_set_color_range(NULL);
1856 } else
1857 command_error("memory desallocation problem\n");
1858 } else
1859 command_error("color range ID %d out of range\n",i);
1860 } else
1861 command_error("color range ID not given\n");
1862 break;
1863 case CMD_CREATE_FILTER:
1864 /* prototype(void) */
1865 if((filter=imlib_create_filter(0))) {
1866 if(vector_push(adesklets.filters,filter))
1867 command_ok("new filter %d\n",adesklets.filters->pos-1);
1868 else
1869 command_error("memory allocation problem\n");
1870 } else
1871 command_error("imlib allocation problem\n");
1872 break;
1873 case CMD_FREE_FILTER:
1874 /* This does not react as imlib_free_filter:
1875 - filter ID has to be given
1876 - If current filter is freed, context
1877 is put back on NULL
1879 prototype(int filter)
1881 if(params->pos>=2) {
1882 if((i=atoi((char*)params->content[1]))
1883 <adesklets.filters->pos &&
1884 i>=0) {
1885 j=(imlib_context_get_filter()==
1886 adesklets.filters->content[i]);
1887 if (vector_delete(adesklets.filters,i)) {
1888 if (j)
1889 imlib_context_set_filter(NULL);
1890 } else
1891 command_error("memory desallocation problem\n");
1892 } else
1893 command_error("filter ID %d out of range\n",i);
1894 } else
1895 command_error("filter ID not given\n");
1896 break;
1897 case CMD_CREATE_COLOR_MODIFIER:
1898 if((color_modifier=imlib_create_color_modifier())) {
1899 if(vector_push(adesklets.color_modifiers,color_modifier))
1900 command_ok("new colormodifier %d\n",
1901 adesklets.color_modifiers->pos-1);
1902 else
1903 command_error("memory allocation problem\n");
1904 } else
1905 command_error("imlib allocation problem\n");
1906 break;
1907 case CMD_FREE_COLOR_MODIFIER:
1908 /* This does not react as imlib_free_color_modifier:
1909 - color_range ID has to be given
1910 - If current color modifier is freed, context
1911 is put back on NULL
1913 prototype(int color_modifier)
1915 if(params->pos>=2) {
1916 if((i=atoi((char*)params->content[1]))
1917 <adesklets.color_modifiers->pos &&
1918 i>=0) {
1919 j=(imlib_context_get_color_modifier()==
1920 adesklets.color_modifiers->content[i]);
1921 if (vector_delete(adesklets.color_modifiers,i)) {
1922 if (j)
1923 imlib_context_set_color_modifier(NULL);
1924 } else
1925 command_error("memory desallocation problem\n");
1926 } else
1927 command_error("color modifier ID %d out of range\n",i);
1928 } else
1929 command_error("color modifier ID not given\n");
1930 break;
1931 case CMD_POLYGON_NEW:
1932 if((polygon=imlib_polygon_new())) {
1933 if(vector_push(adesklets.polygons,polygon))
1934 command_ok("new polygon %d\n",adesklets.polygons->pos-1);
1935 else
1936 command_error("memory allocation problem\n");
1937 } else
1938 command_error("imlib allocation problem\n");
1939 break;
1940 case CMD_POLYGON_FREE:
1941 if(params->pos>=2) {
1942 if((i=atoi(params->content[1]))>=0 &&
1943 i<adesklets.polygons->pos) {
1944 if(!vector_delete(adesklets.polygons,i))
1945 command_error("memory desallocation problem\n");
1946 } else
1947 command_error("polygon ID %d out of range\n",i);
1948 } else
1949 command_error("polygon ID not given\n");
1950 break;
1951 case CMD_POLYGON_ADD_POINT:
1952 if(params->pos>=4) {
1953 if((i=atoi(params->content[1]))>=0 && i<adesklets.polygons->pos) {
1954 imlib_polygon_add_point(adesklets.polygons->content[i],
1955 atoi(params->content[2]),
1956 atoi(params->content[3]));
1957 } else
1958 command_error("polygon ID %d out of range\n",i);
1959 } else
1960 command_error("not enough parameters given - need 3\n");
1961 break;
1962 case CMD_IMAGES_RESET_ALL:
1963 /* prototype(void) */
1964 adesklets_images_reset();
1965 break;
1966 case CMD_IMAGES_INFO:
1967 /* prototype(void) */
1968 xwindow_context_save(IMLIB_IMAGE);
1969 command_printf("%d images\n",adesklets.images->pos);
1970 for(i=0;i<adesklets.images->pos;++i) {
1971 imlib_context_set_image(adesklets.images->content[i]);
1972 command_printf("id %d width %d height %d alpha %hhu filename %s\n",
1974 imlib_image_get_width(), imlib_image_get_height(),
1975 imlib_image_has_alpha(), imlib_image_get_filename());
1977 xwindow_context_restore();
1978 break;
1979 case CMD_FONTS_RESET_ALL:
1980 /* prototype(void) */
1981 adesklets_fonts_reset();
1982 break;
1983 case CMD_FONTS_INFO:
1984 /* prototype(void) */
1985 command_printf("%d fonts\n",adesklets.fonts->pos);
1986 break;
1987 case CMD_COLOR_RANGES_RESET_ALL:
1988 /* prototype(void) */
1989 adesklets_color_ranges_reset();
1990 break;
1991 case CMD_COLOR_RANGES_INFO:
1992 /* prototype(void) */
1993 command_printf("%d color ranges\n",adesklets.color_ranges->pos);
1994 break;
1995 case CMD_COLOR_MODIFIERS_RESET_ALL:
1996 /* prototype(void) */
1997 adesklets_color_modifiers_reset();
1998 break;
1999 case CMD_COLOR_MODIFIERS_INFO:
2000 /* prototype(void) */
2001 command_printf("%d color modifiers\n",adesklets.color_modifiers->pos);
2002 break;
2003 case CMD_FILTERS_RESET_ALL:
2004 /* prototype(void) */
2005 adesklets_filters_reset();
2006 break;
2007 case CMD_FILTERS_INFO:
2008 /* prototype(void) */
2009 command_printf("%d filters\n",adesklets.filters->pos);
2010 break;
2011 case CMD_POLYGONS_RESET_ALL:
2012 /* prototype(void) */
2013 adesklets_polygons_reset();
2014 break;
2015 case CMD_POLYGONS_INFO:
2016 /* prototype(void) */
2017 command_printf("%d polygons\n",adesklets.polygons->pos);
2018 break;
2019 case CMD_IMAGE_HAS_ALPHA:
2020 command_ok("image alpha %hhu\n",imlib_image_has_alpha());
2021 break;
2022 case CMD_IMAGE_GET_WIDTH:
2023 command_ok("image width %d\n",imlib_image_get_width());
2024 break;
2025 case CMD_IMAGE_GET_HEIGHT:
2026 command_ok("image height %d\n",imlib_image_get_height());
2027 break;
2028 case CMD_IMAGE_GET_FILENAME:
2029 command_ok("image filename %s\n",imlib_image_get_filename());
2030 break;
2031 case CMD_IMAGE_GET_DATA:
2032 /* This uses imlib_image_get_data_for_reading_only(),
2033 so there is no need to invalidate image. Print final result
2034 in rgba format */
2035 if((data=imlib_image_get_data_for_reading_only())) {
2036 width=imlib_image_get_width();
2037 height=imlib_image_get_height();
2038 command_printf("image data - %d %d\n",width,height);
2039 for(i=0;i<width*height;++i)
2040 command_printf("%hhu %hhu %hhu %hhu ",
2041 ((data[i]&(255<<16))>>16),
2042 ((data[i]&(255<<8))>>8),
2043 (data[i]&255),
2044 ((data[i]&(255<<24))>>24));
2045 command_printf("\n");
2046 } else
2047 command_error("imlib data fetch problem\n");
2048 break;
2049 case CMD_IMAGE_QUERY_PIXEL:
2050 /* prototype(int x, int y) */
2051 if (params->pos>=2) {
2052 imlib_image_query_pixel(atoi(params->content[1]),
2053 atoi(params->content[2]),
2054 &color);
2055 command_ok("pixel value %hhu %hhu %hhu %hhu\n",
2056 (char)color.red&255,(char)color.green&255,
2057 (char)color.blue&255,(char)color.alpha&255);
2058 } else
2059 command_error("pixel coordinates not given\n");
2060 break;
2061 case CMD_IMAGE_SET_HAS_ALPHA:
2062 /* prototype(bool has_alpha) */
2063 if (params->pos>=2)
2064 imlib_image_set_has_alpha((char)atoi(params->content[1]));
2065 else
2066 command_error("alpha value not given\n");
2067 break;
2068 case CMD_IMAGE_SET_CHANGES_ON_DISK:
2069 /* prototype(void) */
2070 imlib_image_set_changes_on_disk();
2071 break;
2072 case CMD_IMAGE_SET_FORMAT:
2073 if (params->pos>=2)
2074 imlib_image_set_format(params->content[1]);
2075 else
2076 command_error("format string not given\n");
2077 break;
2078 case CMD_IMAGE_FILTER_RECURSE:
2079 /* prototype(void) */
2080 if(imlib_context_get_filter()) {
2081 for(i=0,j=imlib_image_get_width();i<j;++i) {
2082 imlib_image_filter();
2083 #ifdef DEBUG
2084 if(i%(j/10)==(j/10)-1)
2085 debug("We are %d0 percents through.\n", (i+1)*10/j);
2086 #endif
2088 if(image_is_shown())
2089 updates=imlib_update_append_rect(updates,0,0,
2090 imlib_image_get_width(),
2091 imlib_image_get_height());
2093 else
2094 command_error("no filter selected\n");
2095 break;
2096 case CMD_IMAGE_DRAW_LINE:
2097 if(params->pos>=5) {
2098 imlib_image_draw_line(atoi(params->content[1]),
2099 atoi(params->content[2]),
2100 atoi(params->content[3]),
2101 atoi(params->content[4]),0);
2102 if (image_is_shown())
2103 updates = imlib_update_append_rect(updates,
2104 atoi(params->content[1]),
2105 atoi(params->content[2]),
2106 atoi(params->content[3])-
2107 atoi(params->content[1]),
2108 atoi(params->content[4])-
2109 atoi(params->content[2]));
2110 } else
2111 command_error("line coordinates not given\n");
2112 break;
2113 case CMD_IMAGE_DRAW_RECTANGLE:
2114 if(params->pos>=5) {
2115 imlib_image_draw_rectangle(atoi(params->content[1]),
2116 atoi(params->content[2]),
2117 atoi(params->content[3]),
2118 atoi(params->content[4]));
2119 if (image_is_shown())
2120 updates = imlib_update_append_rect(updates,
2121 atoi(params->content[1]),
2122 atoi(params->content[2]),
2123 atoi(params->content[3]),
2124 atoi(params->content[4]));
2125 } else
2126 command_error("rectangle description not given\n");
2127 break;
2128 case CMD_IMAGE_FILL_RECTANGLE:
2129 if(params->pos>=5) {
2130 imlib_image_fill_rectangle(atoi(params->content[1]),
2131 atoi(params->content[2]),
2132 atoi(params->content[3]),
2133 atoi(params->content[4]));
2134 if (image_is_shown())
2135 updates = imlib_update_append_rect(updates,
2136 atoi(params->content[1]),
2137 atoi(params->content[2]),
2138 atoi(params->content[3]),
2139 atoi(params->content[4]));
2140 } else
2141 command_error("rectangle description not given\n");
2142 break;
2143 case CMD_IMAGE_FILL_COLOR_RANGE_RECTANGLE:
2144 if (imlib_context_get_color_range()) {
2145 if(params->pos>=6) {
2146 imlib_image_fill_color_range_rectangle(atoi(params->content[1]),
2147 atoi(params->content[2]),
2148 atoi(params->content[3]),
2149 atoi(params->content[4]),
2150 atof(params->content[5]));
2151 if (image_is_shown())
2152 updates = imlib_update_append_rect(updates,
2153 atoi(params->content[1]),
2154 atoi(params->content[2]),
2155 atoi(params->content[3]),
2156 atoi(params->content[4]));
2157 } else
2158 command_error("not enough parameters given - need five\n");
2159 } else
2160 command_error("no color range selected\n");
2161 break;
2162 case CMD_IMAGE_DRAW_ELLIPSE:
2163 if(params->pos>=5) {
2164 imlib_image_draw_ellipse(atoi(params->content[1]),
2165 atoi(params->content[2]),
2166 atoi(params->content[3]),
2167 atoi(params->content[4]));
2168 if (image_is_shown())
2169 updates = imlib_update_append_rect(updates,
2170 atoi(params->content[1])-
2171 atoi(params->content[3]),
2172 atoi(params->content[2])-
2173 atoi(params->content[4]),
2174 2*atoi(params->content[3]),
2175 2*atoi(params->content[4]));
2176 } else
2177 command_error("ellipse description not given\n");
2178 break;
2179 case CMD_IMAGE_FILL_ELLIPSE:
2180 if(params->pos>=5) {
2181 imlib_image_fill_ellipse(atoi(params->content[1]),
2182 atoi(params->content[2]),
2183 atoi(params->content[3]),
2184 atoi(params->content[4]));
2185 if (image_is_shown())
2186 updates = imlib_update_append_rect(updates,
2187 atoi(params->content[1])-
2188 atoi(params->content[3]),
2189 atoi(params->content[2])-
2190 atoi(params->content[4]),
2191 2*atoi(params->content[3]),
2192 2*atoi(params->content[4]));
2193 } else
2194 command_error("ellipse description not given\n");
2195 break;
2196 case CMD_IMAGE_COPY_ALPHA_TO_IMAGE:
2197 if(params->pos>=4) {
2198 if((i=atoi(params->content[1]))>=0 &&
2199 i<adesklets.images->pos) {
2200 imlib_image_copy_alpha_to_image(adesklets.images->content[i],
2201 atoi(params->content[2]),
2202 atoi(params->content[3]));
2203 if(image_is_shown()) {
2204 xwindow_context_save(IMLIB_IMAGE);
2205 imlib_context_set_image(adesklets.images->content[i]);
2206 updates = imlib_update_append_rect(updates,
2207 atoi(params->content[2]),
2208 atoi(params->content[3]),
2209 imlib_image_get_width(),
2210 imlib_image_get_height());
2211 xwindow_context_restore();
2213 } else
2214 command_error("image ID out of range\n");
2215 } else
2216 command_error("parameters not given\n");
2217 break;
2218 case CMD_IMAGE_COPY_ALPHA_RECTANGLE_TO_IMAGE:
2219 if(params->pos>=8) {
2220 if((i=atoi(params->content[1]))>=0 &&
2221 i<adesklets.images->pos) {
2222 imlib_image_copy_alpha_rectangle_to_image(
2223 adesklets.images->content[i],
2224 atoi(params->content[2]),
2225 atoi(params->content[3]),
2226 atoi(params->content[4]),
2227 atoi(params->content[5]),
2228 atoi(params->content[6]),
2229 atoi(params->content[7]));
2231 if(image_is_shown())
2232 updates= imlib_update_append_rect(updates,
2233 atoi(params->content[6]),
2234 atoi(params->content[7]),
2235 atoi(params->content[4]),
2236 atoi(params->content[5]));
2237 } else
2238 command_error("image ID out of range\n");
2239 } else
2240 command_error("parameters not given - need height\n");
2241 break;
2242 case CMD_IMAGE_DRAW_POLYGON:
2243 if (params->pos>=3) {
2244 if ((i=atoi(params->content[1]))>=0 && i<adesklets.polygons->pos) {
2245 imlib_image_draw_polygon(adesklets.polygons->content[i],
2246 ((char*)params->content[2])[0]);
2247 if(image_is_shown()) {
2248 imlib_polygon_get_bounds(adesklets.polygons->content[i],
2249 &x, &y, &i, &j);
2250 updates= imlib_update_append_rect(updates,x,y,i-x,j-y);
2252 } else
2253 command_error("polygon ID %d out of range\n",i);
2254 } else
2255 command_error("parameters not given\n");
2256 break;
2257 case CMD_IMAGE_FILL_POLYGON:
2258 if (params->pos>=2) {
2259 if ((i=atoi(params->content[1]))>=0 && i<adesklets.polygons->pos) {
2260 imlib_image_fill_polygon(adesklets.polygons->content[i]);
2261 if(image_is_shown()) {
2262 imlib_polygon_get_bounds(adesklets.polygons->content[i],
2263 &x, &y, &i, &j);
2264 updates= imlib_update_append_rect(updates,x,y,i-x,j-y);
2266 } else
2267 command_error("polygon ID %d out of range\n",i);
2268 } else
2269 command_error("polygon ID not given\n");
2270 break;
2271 case CMD_IMAGE_FLIP_HORIZONTAL:
2272 imlib_image_flip_horizontal();
2273 if (image_is_shown())
2274 updates=imlib_update_append_rect(updates,0,0,
2275 imlib_image_get_width(),
2276 imlib_image_get_height());
2277 break;
2278 case CMD_IMAGE_FLIP_VERTICAL:
2279 imlib_image_flip_vertical();
2280 if (image_is_shown())
2281 updates=imlib_update_append_rect(updates,0,0,
2282 imlib_image_get_width(),
2283 imlib_image_get_height());
2284 break;
2285 case CMD_IMAGE_FLIP_DIAGONAL:
2286 if(((image=imlib_context_get_image()))!=
2287 adesklets.images->content[0] &&
2288 image != adesklets.images->content[1] &&
2289 (adesklets.user_background_image==-1 ||
2290 image != adesklets.images->content[
2291 adesklets.user_background_image]))
2292 imlib_image_flip_diagonal();
2293 else
2294 command_error("operation forbidden on this image\n");
2295 break;
2296 case CMD_IMAGE_ORIENTATE:
2297 if (params->pos>=2) {
2298 if((i=atoi(params->content[1])%4)%2==0 ||
2299 (((image=imlib_context_get_image())!=
2300 adesklets.images->content[0] &&
2301 image != adesklets.images->content[1])))
2302 imlib_image_orientate(i);
2303 else
2304 command_error("operation forbidden on this image\n");
2305 } else
2306 command_error("orientation not given\n");
2307 break;
2308 case CMD_IMAGE_BLUR:
2309 if (params->pos>=2) {
2310 imlib_image_blur(atof(params->content[1]));
2311 updates=imlib_update_append_rect(updates,0,0,
2312 imlib_image_get_width(),
2313 imlib_image_get_height());
2314 } else
2315 command_error("Blur radius not given\n");
2316 break;
2317 case CMD_IMAGE_SHARPEN:
2318 if (params->pos>=2) {
2319 imlib_image_sharpen(atof(params->content[1]));
2320 updates=imlib_update_append_rect(updates,0,0,
2321 imlib_image_get_width(),
2322 imlib_image_get_height());
2323 } else
2324 command_error("Sharpen radius not given\n");
2325 break;
2326 #define FILTER_SET(op)\
2327 if(imlib_context_get_filter()) {\
2328 if (params->pos>=7)\
2329 imlib_filter_set ## op(atoi(params->content[1]),\
2330 atoi(params->content[2]),\
2331 atoi(params->content[3]),\
2332 atoi(params->content[4]),\
2333 atoi(params->content[5]),\
2334 atoi(params->content[6]));\
2335 else\
2336 command_error("missing parameters - need six\n");\
2337 } else\
2338 command_error("no filter selected\n")
2339 case CMD_FILTER_SET:
2340 /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
2341 FILTER_SET( );
2342 break;
2343 case CMD_FILTER_SET_RED:
2344 /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
2345 FILTER_SET(_red);
2346 break;
2347 case CMD_FILTER_SET_GREEN:
2348 /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
2349 FILTER_SET(_green);
2350 break;
2351 case CMD_FILTER_SET_BLUE:
2352 /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
2353 FILTER_SET(_blue);
2354 break;
2355 case CMD_FILTER_SET_ALPHA:
2356 /* prototype(int xoff, int yoff, int a, int r, int g, int b) */
2357 FILTER_SET(_alpha);
2358 break;
2359 #undef FILTER_SET
2360 #define FILTER_SET(op)\
2361 if(imlib_context_get_filter()) {\
2362 if (params->pos>=5)\
2363 imlib_filter_ ## op(atoi(params->content[1]),\
2364 atoi(params->content[2]),\
2365 atoi(params->content[3]),\
2366 atoi(params->content[4]));\
2367 else\
2368 command_error("missing parameters - need four\n");\
2369 } else\
2370 command_error("no filter selected\n")
2371 case CMD_FILTER_CONSTANTS:
2372 /* prototype(int a, int r, int g, int b) */
2373 FILTER_SET(constants);
2374 break;
2375 case CMD_FILTER_DIVISORS:
2376 /* prototype(int a, int r, int g, int b) */
2377 FILTER_SET(divisors);
2378 break;
2379 #undef FILTER_SET
2380 case CMD_MENU_FIRE:
2381 /* prototype(int menu) */
2382 #ifndef X_DISPLAY_MISSING
2383 if (adesklets.display && adesklets.window) {
2384 if(params->pos>=2) {
2385 i=atoi((char*)params->content[1]);
2386 if (adesklets_menu_fire(i,(char**)&menu_str)) {
2387 if (adesklets.user_event_mask&MenuFireMask)
2388 event("menufire %d %s\n",i,menu_str);
2389 } else
2390 command_error("menu fire error\n");
2392 else
2393 command_error("menu ID not given\n");
2394 } else
2395 #endif
2396 command_error("X connection or window missing\n");
2397 break;
2398 case CMD_MENU_RESET_ALL:
2399 /* prototype(void) */
2400 if (!adesklets_menus_reset())
2401 command_error("internal consistency problem with menu\n");
2402 break;
2403 case CMD_MENU_ADD_MENU:
2404 /* prototype(void) */
2405 if (!vector_push(adesklets.menus,xmenu_init()))
2406 command_error("could not add a new menu\n");
2407 else
2408 command_ok("new menu %d\n",adesklets.menus->pos-1);
2409 break;
2410 case CMD_MENU_ADD_SUBMENU:
2411 /* prototype(const char * submenu) */
2412 if (params->pos>=2) {
2413 if (!xmenu_push_submenu(MENU(adesklets.menus->pos-1),
2414 command.line+1+
2415 strlen(COMMANDS[CMD_MENU_ADD_SUBMENU].name)))
2416 command_error("could not create submenu\n");
2418 if ((menu_str=dupstr_utf8(command_subsplitter(command.line,1)))) {
2419 if (!xmenu_push_submenu(MENU(adesklets.menus->pos-1),menu_str))
2420 command_error("could not create submenu\n");
2421 free(menu_str);
2424 } else
2425 command_error("submenu description not given\n");
2426 break;
2427 case CMD_MENU_ADD_ITEM:
2428 /* prototype(const char * add_item) */
2429 if(params->pos>=2) {
2430 if(!xmenu_push_item(MENU(adesklets.menus->pos-1),
2431 command.line+1+
2432 strlen(COMMANDS[CMD_MENU_ADD_ITEM].name)))
2433 command_error("could not create item\n");
2434 } else
2435 command_error("item description not given\n");
2436 break;
2437 case CMD_MENU_ADD_SEPARATOR:
2438 /* prototype(void) */
2439 if(!xmenu_push_item(MENU(adesklets.menus->pos-1),"-"))
2440 command_error("could not add separator\n");
2441 break;
2442 case CMD_MENU_END_SUBMENU:
2443 /* prototype(void) */
2444 if(!xmenu_end_submenu(MENU(adesklets.menus->pos-1)))
2445 command_error("could not end submenu\n");
2446 break;
2447 case CMD_EVENT_CATCH:
2448 /* prototype(voidvoid) */
2449 #ifndef X_DISPLAY_MISSING
2450 if (adesklets.display && adesklets.window) {
2451 if(params->pos>=2) {
2452 for(i=0;X_WINDOW_EVENTS[i].name;++i)
2453 if(strncmp(X_WINDOW_EVENTS[i].name,params->content[1],
2454 strlen(X_WINDOW_EVENTS[i].name))==0)
2455 break;
2456 adesklets.user_event_mask|=
2457 X_WINDOW_EVENTS[(X_WINDOW_EVENTS[i].name)?
2458 i:atoi(params->content[1])%i].mask;
2459 adesklets.event_mask=(BASE_EVENT_MASK)|
2460 (adesklets.user_event_mask&
2461 ~(BackgroundGrabMask|MenuFireMask));
2462 XSelectInput(adesklets.display,adesklets.window,
2463 adesklets.event_mask);
2464 } else
2465 command_error("event to catch not given\n");
2466 } else
2467 #endif
2468 command_error("X connection or window missing\n");
2469 break;
2470 case CMD_EVENT_UNCATCH:
2471 /* prototype(voidvoid) */
2472 #ifndef X_DISPLAY_MISSING
2473 if(adesklets.display && adesklets.window) {
2474 if(params->pos>=2) {
2475 for(i=0;X_WINDOW_EVENTS[i].name;++i)
2476 if(strncmp(X_WINDOW_EVENTS[i].name,params->content[1],
2477 strlen(X_WINDOW_EVENTS[i].name))==0)
2478 break;
2479 mask=X_WINDOW_EVENTS[(X_WINDOW_EVENTS[i].name)?
2480 i:atoi(params->content[1])%i].mask;
2481 /* If event was already selected, purge all remaining
2482 events of that type if applicable */
2483 if(mask!=BackgroundGrabMask &&
2484 mask!=MenuFireMask &&
2485 (adesklets.event_mask&mask) &&
2486 !((BASE_EVENT_MASK)&mask))
2487 while(XCheckWindowEvent(adesklets.display,
2488 adesklets.window,mask,&ev));
2489 adesklets.user_event_mask&=~mask;
2490 adesklets.event_mask=(BASE_EVENT_MASK)|
2491 (adesklets.user_event_mask
2492 &~(BackgroundGrabMask|MenuFireMask));
2493 XSelectInput(adesklets.display,adesklets.window,
2494 adesklets.event_mask);
2495 } else
2496 command_error("event to uncatch not given\n");
2497 } else
2498 #endif
2499 command_error("X connection or window missing\n");
2500 break;
2501 case CMD_EVENTS_RESET_ALL:
2502 /* prototype(voidvoid) */
2503 #ifndef X_DISPLAY_MISSING
2504 if(adesklets.display && adesklets.window) {
2505 XSelectInput(adesklets.display,adesklets.window,
2506 BASE_EVENT_MASK);
2507 while(XCheckWindowEvent(adesklets.display,adesklets.window,
2508 adesklets.user_event_mask&
2509 ~(BASE_EVENT_MASK)&~BackgroundGrabMask&
2510 ~MenuFireMask,
2511 &ev));
2512 adesklets.user_event_mask=0;
2513 adesklets.event_mask=BASE_EVENT_MASK;
2514 } else
2515 #endif
2516 command_error("X connection or window missing\n");
2517 break;
2518 case CMD_EVENTS_INFO:
2519 /* prototype(void) */
2520 #ifndef X_DISPLAY_MISSING
2521 if (adesklets.display && adesklets.window) {
2522 for(i=0,j=0;X_WINDOW_EVENTS[i].name;++i)
2523 if(adesklets.user_event_mask&X_WINDOW_EVENTS[i].mask)
2524 ++j;
2525 command_printf("%d events caught\n",j);
2526 for(i=0;X_WINDOW_EVENTS[i].name;++i)
2527 if(adesklets.user_event_mask&X_WINDOW_EVENTS[i].mask)
2528 command_printf("%d (%s)\n",i , X_WINDOW_EVENTS[i].name);
2529 } else
2530 #endif
2531 command_error("X connection or window missing\n");
2532 break;
2533 case CMD_EVENTS_GET_ECHO:
2534 /* prototype(void) */
2535 command_ok("events echo %d\n", events_echo);
2536 break;
2537 case CMD_EVENTS_SET_ECHO:
2538 /* prototype(voidvoid) */
2539 if(params->pos>=2) {
2540 if (events_echo!=(i=atoi(params->content[1]))) {
2541 events_echo=i;
2542 if(i)
2543 events_purge();
2546 else
2547 command_error("echo value not given\n");
2548 break;
2549 case CMD_EVENTS_GET_SEND_SIGUSR1:
2550 /* prototype(void) */
2551 command_ok("events send_sigusr1 %d\n",(events_ppid)?1:0);
2552 break;
2553 case CMD_EVENTS_SET_SEND_SIGUSR1:
2554 /* prototype(voidvoid) */
2555 if (params->pos>=2)
2556 events_ppid=(atoi(params->content[1]))?adesklets.ppid:0;
2557 else
2558 command_error("send SIGUSR1 status not given\n");
2559 break;
2560 case CMD_EVENTS_PURGE:
2561 /* prototype(voidvoid) */
2562 command_printf("%d events to purge\n",(events)?events->pos:0);
2563 events_purge();
2564 break;
2565 case CMD_WINDOW_RESET:
2566 /* prototype(enum WINDOW_MANAGER manager) */
2567 if(params->pos>=2) {
2568 for(i=0;WINDOW_MANAGER[i];++i)
2569 if(strncmp(WINDOW_MANAGER[i],params->content[1],
2570 strlen(params->content[1]))==0)
2571 break;
2572 if (adesklets_window_reset((WINDOW_MANAGER[i])?i:
2573 atoi(params->content[1]))) {
2574 if (adesklets_menus_reset()) {
2575 if (!adesklets_images_reset_background(0))
2576 command_error("could not reset background images\n");
2577 } else
2578 command_error("could not reset menus\n");
2579 } else
2580 command_error("could not reset main window\n");
2581 } else
2582 command_error("Window manager status not given\n");
2583 break;
2584 case CMD_WINDOW_SHOW:
2585 /* prototype(void) */
2586 #ifndef X_DISPLAY_MISSING
2587 if (adesklets.display && adesklets.window) {
2588 if (!XMapWindow(adesklets.display,adesklets.window))
2589 command_error("could not map the window\n");
2590 } else
2591 #endif
2592 command_error("X connection or window missing\n");
2593 break;
2594 case CMD_WINDOW_HIDE:
2595 /* prototype(void) */
2596 #ifndef X_DISPLAY_MISSING
2597 if (adesklets.display && adesklets.window) {
2598 if(!XUnmapWindow(adesklets.display,adesklets.window))
2599 command_error("could not unmap the window\n");
2600 } else
2601 #endif
2602 command_error("X connection or window missing\n");
2603 break;
2604 case CMD_WINDOW_RESIZE:
2605 /* prototype(int width, int height) */
2606 if (params->pos>=3) {
2607 if((i=atoi(params->content[1]))>0 &&
2608 (j=atoi(params->content[2]))>0) {
2609 #ifndef X_DISPLAY_MISSING
2610 if (adesklets.display && adesklets.window) {
2611 if (!xwindow_resize_window(adesklets.display,adesklets.window,
2612 adesklets.params,i,j,0))
2613 command_error("did not resize window\n");
2614 } else {
2615 #endif
2616 if (!adesklets_images_reset_background(1,i,j))
2617 command_error("no window, and could not resize images\n");
2618 #ifndef X_DISPLAY_MISSING
2620 #endif
2621 } else command_error("resize out of range\n");
2622 } else command_error("resize dimensions no given\n");
2623 break;
2624 case CMD_WINDOW_GET_TRANSPARENCY:
2625 /* prototype(void) */
2626 command_ok("window transparency %d\n",adesklets.transparency);
2627 break;
2628 case CMD_WINDOW_GET_BACKGROUND_GRAB:
2629 /* prototype(void) */
2630 if(X_DISPLAY_SUPPORT && adesklets.display && adesklets.window)
2631 command_ok("window backgroundgrab %d\n",adesklets.background_grab);
2632 else
2633 command_error(
2634 "background grab irrelevant - no X window connection or window\n");
2635 break;
2636 case CMD_WINDOW_GET_BACKGROUND_IMAGE:
2637 /* prototype(void) */
2638 if(X_DISPLAY_SUPPORT && adesklets.display && adesklets.window)
2639 command_ok("background image %d\n",
2640 (adesklets.user_background_image!=-1)?
2641 adesklets.user_background_image:1);
2642 else
2643 command_error(
2644 "background window irrelevant - no X window connection or window\n");
2645 break;
2646 case CMD_WINDOW_GET_MANAGED_STATUS:
2647 /* prototype(void) */
2648 #ifndef X_DISPLAY_MISSING
2649 if(adesklets.display && adesklets.window) {
2650 command_ok("window managedstatus %d (%s)\n",
2651 adesklets.managed,
2652 WINDOW_MANAGER[adesklets.managed]);
2653 } else
2654 command_error("X connection or window missing\n");
2655 #else
2656 command_error("X connection or window missing\n");
2657 #endif
2658 break;
2659 case CMD_WINDOW_SET_TRANSPARENCY:
2660 /* prototype(bool transparency) */
2661 if (params->pos>=2) {
2662 i=atoi((char*)params->content[1]);
2663 if (adesklets.transparency!=i) {
2664 adesklets.transparency=i;
2665 /* If there is a chance, invalidate the entire window */
2666 #ifndef X_DISPLAY_MISSING
2667 xwindow_window_size(adesklets.display,adesklets.window,
2668 &width,&height);
2669 updates = imlib_update_append_rect(updates,
2670 0,0,(int)width,(int)height);
2671 #endif
2673 } else command_error("transparency value not given\n");
2674 break;
2675 case CMD_WINDOW_SET_BACKGROUND_GRAB:
2676 /* prototype(bool grab) */
2677 if (params->pos>=2) {
2678 if (adesklets.background_grab!=(i=atoi(params->content[1]))) {
2679 if ((adesklets.background_grab=i))
2680 adesklets_images_reset_background(0);
2681 else {
2682 xwindow_context_save(IMLIB_IMAGE|IMLIB_BLEND|IMLIB_COLOR);
2683 imlib_context_set_image(adesklets.images->content[1]);
2684 imlib_context_set_color(0,0,0,255);
2685 imlib_context_set_blend(0);
2686 imlib_image_fill_rectangle(0,0,
2687 imlib_image_get_width(),
2688 imlib_image_get_height());
2689 xwindow_context_restore();
2692 #ifndef X_DISPLAY_MISSING
2693 xwindow_window_size(adesklets.display,adesklets.window,
2694 &width,&height);
2695 updates = imlib_update_append_rect(updates,
2696 0,0,(int)width,(int)height);
2697 #endif
2699 } else
2700 command_error("background grab value not given\n");
2701 break;
2702 case CMD_WINDOW_SET_BACKGROUND_IMAGE:
2703 /* prototype(int image) */
2704 if (X_DISPLAY_SUPPORT && adesklets.display && adesklets.window) {
2705 if(params->pos>=2) {
2706 if((i=atoi(params->content[1]))>=0 && i<adesklets.images->pos) {
2707 if(i!=0) {
2708 xwindow_context_save(IMLIB_IMAGE);
2709 imlib_context_set_image(adesklets.images->content[0]);
2710 j=imlib_image_get_width();
2711 k=imlib_image_get_height();
2712 if(i!=1) {
2713 imlib_context_set_image(adesklets.images->content[i]);
2714 x=imlib_image_get_width();
2715 y=imlib_image_get_height();
2716 if (x==j && y==k) {
2717 adesklets.user_background_image=i;
2718 updates = imlib_update_append_rect(updates,
2719 0,0,x,y);
2721 else
2722 command_error("incorrect dimensions image\n");
2723 } else {
2724 /* Drop silently reset to actual foreground */
2725 adesklets.user_background_image=-1;
2726 updates = imlib_update_append_rect(updates,
2727 0,0,j,k);
2729 xwindow_context_restore();
2730 } else
2731 command_error(
2732 "foreground image cannot be selected as background\n");
2733 } else
2734 command_error("image ID %d out of range\n",i);
2735 } else
2736 command_error("background image ID not given\n");
2737 } else
2738 command_error(
2739 "background window irrelevant - no X window connection or window\n");
2740 break;
2741 case CMD_SCREEN_GET_WIDTH:
2742 /* prototype(void) */
2743 #ifndef X_DISPLAY_MISSING
2744 if (adesklets.display) {
2745 command_ok("screen width %d\n",
2746 WidthOfScreen(ScreenOfDisplay(adesklets.display,
2747 adesklets.params->scr)));
2748 } else
2749 command_error("X connection missing\n");
2750 #else
2751 command_error("X connection missing\n");
2752 #endif
2753 break;
2754 case CMD_SCREEN_GET_HEIGHT:
2755 /* prototype(void) */
2756 #ifndef X_DISPLAY_MISSING
2757 if(adesklets.display) {
2758 command_ok("screen height %d\n",
2759 HeightOfScreen(ScreenOfDisplay(adesklets.display,
2760 adesklets.params->scr)));
2761 } else
2762 command_error("X connection missing\n");
2763 #else
2764 command_error("X connection missing\n");
2765 #endif
2766 break;
2767 case CMD_SCREEN_GET_DEPTH:
2768 /* prototype(void) */
2769 if(adesklets.display)
2770 command_ok("screen depth %d\n",adesklets.depth);
2771 else
2772 command_error("X connection missing\n");
2773 break;
2774 case CMD_GET_CHARSET:
2775 /* prototype(void) */
2776 #ifdef HAVE_ICONV_H
2777 if (command.from_page)
2778 command_ok("charset %s\n",command.from_page);
2779 else
2780 #endif
2781 command_ok("charset -1 (unset)\n");
2782 break;
2783 case CMD_SET_CHARSET:
2784 /* prototype(const char * charset) */
2785 #ifdef HAVE_ICONV_H
2786 if (params->pos>=2) {
2787 if ((cd=iconv_open("UTF8",params->content[1]))!=(iconv_t)(-1)) {
2788 if (command.cd) {
2789 iconv_close(command.cd);
2790 command.cd=NULL;
2792 if (command.from_page) {
2793 free(command.from_page);
2794 command.from_page=NULL;
2796 command.from_page=dupstr(params->content[1]);
2797 command.cd=cd;
2798 } else
2799 command_error("could not establish conversion from '%s' to 'UTF8'\n",
2800 params->content[1]);
2801 } else {
2802 if (command.cd) {
2803 iconv_close(command.cd);
2804 command.cd=NULL;
2806 if (command.from_page) {
2807 free(command.from_page);
2808 command.from_page=NULL;
2810 command_ok("charset -1 (unset)\n");
2812 #else
2813 command_error("charset conversion not compiled in\n");
2814 #endif
2815 break;
2816 case CMD_CHARSET_STATUS:
2817 /* prototype(void) */
2818 #ifdef HAVE_ICONV_H
2819 command_ok("charset_status 1\n");
2820 #else
2821 command_ok("charset_status 0 (charset conversion not compiled in)\n");
2822 #endif
2823 break;
2824 case CMD_X_STATUS:
2825 /* prototype(void) */
2826 #ifndef X_DISPLAY_MISSING
2827 command_ok("x_status %d (%s%s')\n",(adesklets.display)?1:0,
2828 (adesklets.display)?"connected to '":"disconnected from '",
2829 XDisplayName(NULL));
2830 #else
2831 command_ok("x_status 0 (X Window support not compiled in)\n");
2832 #endif
2833 break;
2834 case CMD_QUIT:
2835 /* prototype(void) */
2836 command_ok("quitting...\n");
2837 adesklets.quit_flag=1;
2838 break;
2839 default:
2840 if(blank_line(command.line))
2841 command.message_out=1;
2842 else
2843 command_error("syntax error\n");
2844 } /* switch(command_type) */
2845 } /* if command.recording */
2846 if (!command.message_out) command_ok("%s\n",command.line);
2847 vector_free(params);
2848 free(command.line);
2849 command.ready=0; ++command.rank;
2850 if (command.interactive && !command.replay_pos &&
2851 !adesklets.quit_flag && !adesklets.restart_flag)
2852 command_interpreter_reset();
2853 } else {printf("\n"); adesklets.quit_flag=1;} /* if (command.line) */
2854 } /* if(command.ready) */
2856 #ifndef X_DISPLAY_MISSING
2857 while(adesklets.display && adesklets.window &&
2858 (XCheckWindowEvent(adesklets.display,
2859 adesklets.root,
2860 PropertyChangeMask, &ev) ||
2861 XCheckWindowEvent(adesklets.display,adesklets.window,
2862 adesklets.event_mask,&ev) ||
2863 XCheckTypedWindowEvent(adesklets.display,adesklets.window,
2864 ClientMessage,&ev))) {
2865 switch(ev.type) {
2866 case Expose:
2867 /* Refresh updates list */
2868 updates = imlib_update_append_rect(updates,
2869 ev.xexpose.x,ev.xexpose.y,
2870 ev.xexpose.width,ev.xexpose.height);
2871 break;
2872 case PropertyNotify:
2873 /* This event is generated from root window only:
2874 we use it to check for dynamic root window background change,
2875 as enlightment has used it for years. Look at
2876 xwindow_updated_background() for details */
2877 if (ev.xproperty.atom != None &&
2878 ev.xproperty.atom == XInternAtom (adesklets.display,
2879 "_XROOTPMAP_ID", True) &&
2880 adesklets.background_grab &&
2881 xwindow_updated_background(adesklets.display,
2882 ev.xproperty.window,
2883 ev.xproperty.atom))
2884 /* Recompute the background images */
2885 adesklets_images_reset_background(0);
2887 /* Because the setting of background_pixmap as ParentRelative
2888 on the main window, there is no need to invalidate
2889 it here: an Expose event will be automatically generated. */
2890 break;
2891 case ButtonPress:
2892 /* Fire default menu on left button click */
2893 if(ev.xbutton.button==3) {
2894 if (
2895 #ifdef CONTROL_ON_CONTEXT_MENU
2896 (ev.xbutton.state & ControlMask) &&
2897 #endif
2898 (adesklets_menu_fire(0,&menu_str)) &&
2899 (adesklets.user_event_mask&MenuFireMask))
2900 event("menufire 0 %s\n",menu_str);
2901 } else
2902 if(adesklets.user_event_mask&ButtonPressMask)
2903 event("buttonpress %d %d %d\n",
2904 ev.xbutton.x,ev.xbutton.y,ev.xbutton.button);
2906 break;
2907 case ButtonRelease:
2908 if(ev.xbutton.button!=3)
2909 event("buttonrelease %d %d %d\n",
2910 ev.xbutton.x,ev.xbutton.y,ev.xbutton.button);
2911 break;
2912 case MotionNotify:
2913 event("motionnotify %d %d\n",
2914 ev.xmotion.x, ev.xmotion.y);
2915 break;
2916 case EnterNotify:
2917 event("enternotify %d %d\n",
2918 ev.xcrossing.x, ev.xcrossing.y);
2919 break;
2920 case LeaveNotify:
2921 event("leavenotify %d %d\n",
2922 ev.xcrossing.x, ev.xcrossing.y);
2923 break;
2924 case ConfigureNotify:
2925 if (ev.xconfigure.window==adesklets.window)
2926 if (xwindow_window_moved_or_resized(ev.xconfigure.x,
2927 ev.xconfigure.y,
2928 ev.xconfigure.width,
2929 ev.xconfigure.height))
2930 adesklets_images_reset_background(0);
2931 break;
2932 case ClientMessage:
2933 /* Check for the "WM_WINDOW_DELETE" protocol */
2934 if (ev.xclient.data.l[0] == XInternAtom(adesklets.display,
2935 "WM_WINDOW_DELETE",
2936 False)) {
2937 debug("Message from window manager: quitting!\n");
2938 adesklets.user_quit_flag=adesklets.quit_flag=1;
2939 } else
2940 debug("Unknown client message sent.");
2941 break;
2942 default:
2943 /* Untreated cases */
2944 break;
2948 /* Now, performs main window updates as needed */
2949 xwindow_update_window(adesklets.window, &updates,
2950 adesklets.images->content[
2951 (adesklets.user_background_image!=-1)?
2952 adesklets.user_background_image:1],
2953 adesklets.images->content[0],
2954 adesklets.transparency);
2955 #endif
2956 if(updates) imlib_updates_free(updates);
2958 } while(!adesklets.quit_flag && !adesklets.restart_flag &&
2959 (command_replayer() || command_interpreter()));
2962 /*----------------------------------------------------------------------------*/
2963 int adesklets_free(void)
2965 int i, fd_null;
2966 struct flock lock;
2968 debug("---------------------------------------------------------------\n");
2969 /* Ultimate update : take care of potential applet removal
2970 if user asked for it. */
2971 adesklets.params->no_update|=adesklets.user_quit_flag;
2972 cfgfile_update(adesklets.params);
2974 /* X Windows cleanup */
2975 #ifndef X_DISPLAY_MISSING
2976 if(adesklets.display) {
2977 if(adesklets.window) {
2978 XUnmapWindow(adesklets.display,adesklets.window);
2979 XDestroyWindow(adesklets.display,adesklets.window);
2981 XCloseDisplay(adesklets.display);
2983 #endif
2985 /* For terminal reset, if it was not cleanly performed
2986 (will happen when quitting from the default left click
2987 menu, for instance) */
2988 rl_callback_handler_remove();
2990 /* Send SIGTERM notification signal to parent process:
2991 in all case but restart, adesklets do not
2992 go further to ensure parent termination. */
2993 kill(adesklets.ppid,SIGTERM);
2995 /* if Lock exist: handle possible restart */
2996 if(adesklets.lock) {
2997 if(adesklets.restart_flag) {
2998 /* Wait for adesklets parent process to exit
2999 SIGKILL_TIMEOUT seconds, then send a SIGKILL. */
3000 for(i=0;i<SIGKILL_TIMEOUT && adesklets.ppid==getppid();++i)
3001 sleep(1);
3002 if (i==SIGKILL_TIMEOUT) kill(adesklets.ppid,SIGKILL);
3003 while(adesklets.ppid==getppid()) sleep(1);
3004 if (fork()==0) {
3005 /* Redirect stdout and stderr to /dev/null to avoid
3006 output buffer overflow */
3007 if ((fd_null=open("/dev/null",O_WRONLY))>=0) {
3008 dup2(fd_null,1);
3009 dup2(fd_null,2);
3010 close(fd_null);
3012 execl(adesklets.params->applet,
3013 adesklets.params->applet,
3014 NULL);
3015 /* debug("Restart: could not exec `%s'",adesklets.params->applet); */
3016 exit(EXIT_FAILURE);
3020 /* Release the lock */
3021 lock.l_type=F_UNLCK;
3022 lock.l_whence=SEEK_SET;
3023 lock.l_start=0;
3024 lock.l_len=0;
3025 fcntl(fileno(adesklets.lock),F_SETLK,&lock);
3026 fclose(adesklets.lock);
3028 /* Try to unlink the lock file:
3029 thanks to POSIX, this will fail gracefully
3030 if a process is still using the file */
3031 unlink(adesklets.lock_filename);
3034 /* Free structures */
3035 if(events) vector_free(events);
3036 adesklets.menus=vector_free(adesklets.menus);
3037 adesklets.images=vector_free(adesklets.images);
3038 adesklets.fonts=vector_free(adesklets.fonts);
3039 adesklets.color_ranges=vector_free(adesklets.color_ranges);
3040 adesklets.color_modifiers=vector_free(adesklets.color_modifiers);
3041 adesklets.filters=vector_free(adesklets.filters);
3042 adesklets.polygons=vector_free(adesklets.polygons);
3043 adesklets.variables=vector_free(adesklets.variables);
3045 return !adesklets.menus &&
3046 !adesklets.images &&
3047 !adesklets.fonts &&
3048 !adesklets.color_ranges &&
3049 !adesklets.color_modifiers &&
3050 !adesklets.filters &&
3051 !adesklets.polygons &&
3052 !adesklets.variables;
3055 /*----------------------------------------------------------------------------*/
3056 /* Signal wrapper for adesklets_free()
3058 void
3059 termination_handler(int signum)
3061 exit((adesklets_free())?EXIT_SUCCESS:EXIT_FAILURE);
3064 /*----------------------------------------------------------------------------*/
3065 /* Since we cannot verify if applet is a script of a binary without trying
3066 to execute it, we require it to have both read and execute permissions for
3067 the current user... Better _portable_ solution is welcomed.
3069 int
3070 adesklets_valid_desklet(char * applet, int register_flag)
3072 int result = 0;
3074 if(applet)
3075 if((register_flag && applet[0]=='/') || !register_flag)
3076 result=(access(applet,R_OK|X_OK)==0);
3077 return result;
3080 /*----------------------------------------------------------------------------*/
3081 /* Our image generator function (have a look at command.c) */
3082 char *
3083 image_generator(const char * text, int state)
3085 return generic_index_generator(text,state,adesklets.images->pos);
3088 /*----------------------------------------------------------------------------*/
3089 /* Our font name generator function (have a look at command.c) */
3090 char *
3091 base_font_generator(const char * text, int state)
3093 char * result;
3094 static int number;
3095 static char ** fonts;
3097 if (!state) {
3098 fonts=imlib_list_fonts(&number);
3100 if(!(result=generic_generator(text,state,fonts,number))) {
3101 imlib_free_font_list(fonts,number);
3103 return result;
3106 /*----------------------------------------------------------------------------*/
3107 char *
3108 base_font_path_generator(const char * text, int state)
3110 static int number;
3111 static char ** font_path;
3113 if (!state) {
3114 font_path=imlib_list_font_path(&number);
3116 return generic_generator(text,state,font_path,number);
3119 /*----------------------------------------------------------------------------*/
3120 char *
3121 font_generator (const char * text, int state)
3123 return generic_index_generator(text,state,adesklets.fonts->pos);
3126 /*----------------------------------------------------------------------------*/
3127 char *
3128 font_generator_with_null (const char * text, int state)
3130 return generic_index_generator_with_null(text,state,adesklets.fonts->pos);
3133 /*----------------------------------------------------------------------------*/
3134 /* Our menu generator function (have a look at command.c) */
3135 char *
3136 menu_generator(const char * text, int state)
3138 return generic_index_generator(text,state,adesklets.menus->pos);
3141 /*----------------------------------------------------------------------------*/
3142 /* Our color ranges generator function (have a look at command.c) */
3143 char *
3144 color_range_generator(const char * text, int state)
3146 return generic_index_generator(text,state,adesklets.color_ranges->pos);
3149 /*----------------------------------------------------------------------------*/
3150 /* Our color ranges generator function (have a look at command.c) */
3151 char *
3152 color_range_generator_with_null(const char * text, int state)
3154 return generic_index_generator_with_null(text,state,
3155 adesklets.color_ranges->pos);
3158 /*----------------------------------------------------------------------------*/
3159 /* Our color modifiers generator function (have a look at command.c) */
3160 char *
3161 color_modifier_generator(const char * text, int state)
3163 return generic_index_generator(text,state,adesklets.color_modifiers->pos);
3166 /*----------------------------------------------------------------------------*/
3167 /* Our color modifiers generator function (have a look at command.c) */
3168 char *
3169 color_modifier_generator_with_null(const char * text, int state)
3171 return generic_index_generator_with_null(text,state,
3172 adesklets.color_modifiers->pos);
3175 /*----------------------------------------------------------------------------*/
3176 /* Our filters generator function (have a look at command.c) */
3177 char *
3178 filter_generator(const char * text, int state)
3180 return generic_index_generator(text,state,adesklets.filters->pos);
3183 /*----------------------------------------------------------------------------*/
3184 /* Our filters generator function (have a look at command.c) */
3185 char *
3186 filter_generator_with_null(const char * text, int state)
3188 return generic_index_generator_with_null(text,state,
3189 adesklets.filters->pos);
3192 /*----------------------------------------------------------------------------*/
3193 /* Our polygon generator function (have a look at command.c) */
3194 char *
3195 polygon_generator(const char * text, int state)
3197 return generic_index_generator(text,state,adesklets.polygons->pos);
3200 /*----------------------------------------------------------------------------*/
3201 /* We have to put this generator here because variables vector is part of
3202 the adesklets structure */
3203 char *
3204 variable_generator(const char * text, int state)
3206 static int list_index, len;
3207 char * name;
3209 if(!state) {
3210 list_index=0;
3211 len=strlen(text);
3214 while (list_index<adesklets.variables->pos) {
3215 name=((var_item*)adesklets.variables->content[list_index])->name;
3216 ++list_index;
3217 if(strncmp(name,text,len)==0)
3218 return dupstr(name);
3221 return NULL;
3224 /*----------------------------------------------------------------------------*/
3226 /* Generic generator mecanism: used for different wrappers.*/
3228 char * generic_generator(const char * text, int state,
3229 char ** names, int number)
3231 static int list_index, len;
3232 char * name;
3234 if(!state) {
3235 list_index=0;
3236 len=strlen(text);
3239 while((number==-1 || list_index<number) &&
3240 (name=names[list_index])) {
3241 ++list_index;
3242 if(strncmp(name,text,len)==0)
3243 return(dupstr(name));
3246 return NULL;