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