Close fd in CMD_Exec
[fvwm.git] / fvwm / builtins.c
blob7197aff6cb2146ccb3ea3cd2252d3e6751f50bed
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all original code
19 * by Rob Nation
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
25 /* ---------------------------- included header files ---------------------- */
27 #include "config.h"
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <X11/keysym.h>
37 #include "libs/fvwmlib.h"
38 #include "libs/fvwmsignal.h"
39 #include "libs/setpgrp.h"
40 #include "libs/Grab.h"
41 #include "libs/Parse.h"
42 #include "libs/ColorUtils.h"
43 #include "libs/Graphics.h"
44 #include "libs/wild.h"
45 #include "libs/envvar.h"
46 #include "libs/ClientMsg.h"
47 #include "libs/Picture.h"
48 #include "libs/PictureUtils.h"
49 #include "libs/FGettext.h"
50 #include "libs/charmap.h"
51 #include "libs/wcontext.h"
52 #include "libs/Flocale.h"
53 #include "libs/Ficonv.h"
54 #include "fvwm.h"
55 #include "externs.h"
56 #include "colorset.h"
57 #include "bindings.h"
58 #include "misc.h"
59 #include "cursor.h"
60 #include "functions.h"
61 #include "commands.h"
62 #include "screen.h"
63 #include "builtins.h"
64 #include "module_interface.h"
65 #include "borders.h"
66 #include "frame.h"
67 #include "events.h"
68 #include "ewmh.h"
69 #include "virtual.h"
70 #include "decorations.h"
71 #include "add_window.h"
72 #include "update.h"
73 #include "style.h"
74 #include "move_resize.h"
75 #include "menus.h"
76 #ifdef HAVE_STROKE
77 #include "stroke.h"
78 #endif /* HAVE_STROKE */
80 /* ---------------------------- local definitions -------------------------- */
82 /* ---------------------------- local macros ------------------------------- */
84 /* ---------------------------- imports ------------------------------------ */
86 extern float rgpctMovementDefault[32];
87 extern int cpctMovementDefault;
88 extern int cmsDelayDefault;
90 /* ---------------------------- included code files ------------------------ */
92 /* ---------------------------- local types -------------------------------- */
93 typedef enum {FakeMouseEvent, FakeKeyEvent} FakeEventType;
94 /* ---------------------------- forward declarations ----------------------- */
96 /* ---------------------------- local variables ---------------------------- */
98 static char *exec_shell_name="/bin/sh";
100 /* button state strings must match the enumerated states */
101 static char *button_states[BS_MaxButtonStateName + 1] =
103 "ActiveUp",
104 "ActiveDown",
105 "InactiveUp",
106 "InactiveDown",
107 "ToggledActiveUp",
108 "ToggledActiveDown",
109 "ToggledInactiveUp",
110 "ToggledInactiveDown",
111 "Active",
112 "Inactive",
113 "ToggledActive",
114 "ToggledInactive",
115 "AllNormal",
116 "AllToggled",
117 "AllActive",
118 "AllInactive",
119 "AllUp",
120 "AllDown",
121 "AllActiveUp",
122 "AllActiveDown",
123 "AllInactiveUp",
124 "AllInactiveDown",
125 NULL
128 /* ---------------------------- exported variables (globals) --------------- */
130 char *ModulePath = FVWM_MODULEDIR;
131 int moduleTimeout = DEFAULT_MODULE_TIMEOUT;
133 /* ---------------------------- local functions ---------------------------- */
135 /** Prepend rather than replace the image path.
136 Used for obsolete PixmapPath and IconPath **/
137 static void obsolete_imagepaths( const char* pre_path )
139 char* tmp = stripcpy( pre_path );
140 char* path = alloca(strlen( tmp ) + strlen(PictureGetImagePath()) + 2 );
142 strcpy( path, tmp );
143 free( tmp );
145 strcat( path, ":" );
146 strcat( path, PictureGetImagePath() );
148 PictureSetImagePath( path );
150 return;
155 * Reads a title button description (veliaa@rpi.edu)
158 static char *ReadTitleButton(
159 char *s, TitleButton *tb, Boolean append, int button)
161 char *end = NULL;
162 char *spec;
163 char *t;
164 int i;
165 int bs;
166 int bs_start, bs_end;
167 int pstyle = 0;
168 DecorFace tmpdf;
170 Bool multiple;
171 int use_mask = 0;
172 int set_mask = 0;
174 s = SkipSpaces(s, NULL, 0);
175 t = GetNextTokenIndex(s, button_states, 0, &bs);
176 if (bs != BS_All)
178 s = SkipSpaces(t, NULL, 0);
181 if (bs == BS_All)
183 use_mask = 0;
184 set_mask = 0;
186 else if (bs == BS_Active)
188 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
189 set_mask = 0;
191 else if (bs == BS_Inactive)
193 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
194 set_mask = BS_MASK_INACTIVE;
196 else if (bs == BS_ToggledActive)
198 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
199 set_mask = BS_MASK_TOGGLED;
201 else if (bs == BS_ToggledInactive)
203 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
204 set_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
206 else if (bs == BS_AllNormal)
208 use_mask = BS_MASK_TOGGLED;
209 set_mask = 0;
211 else if (bs == BS_AllToggled)
213 use_mask = BS_MASK_TOGGLED;
214 set_mask = BS_MASK_TOGGLED;
216 else if (bs == BS_AllActive)
218 use_mask = BS_MASK_INACTIVE;
219 set_mask = 0;
221 else if (bs == BS_AllInactive)
223 use_mask = BS_MASK_INACTIVE;
224 set_mask = BS_MASK_INACTIVE;
226 else if (bs == BS_AllUp)
228 use_mask = BS_MASK_DOWN;
229 set_mask = 0;
231 else if (bs == BS_AllDown)
233 use_mask = BS_MASK_DOWN;
234 set_mask = BS_MASK_DOWN;
236 else if (bs == BS_AllActiveUp)
238 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
239 set_mask = 0;
241 else if (bs == BS_AllActiveDown)
243 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
244 set_mask = BS_MASK_DOWN;
246 else if (bs == BS_AllInactiveUp)
248 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
249 set_mask = BS_MASK_INACTIVE;
251 else if (bs == BS_AllInactiveDown)
253 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
254 set_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
257 if ((bs & BS_MaxButtonStateMask) == bs)
259 multiple = False;
260 bs_start = bs;
261 bs_end = bs;
263 else
265 multiple = True;
266 bs_start = 0;
267 bs_end = BS_MaxButtonState - 1;
268 for (i = bs_start; (i & use_mask) != set_mask && i <= bs_end;
269 i++)
271 bs_start++;
275 if (*s == '(')
277 int len;
278 pstyle = 1;
279 if (!(end = strchr(++s, ')')))
281 fvwm_msg(
282 ERR, "ReadTitleButton",
283 "missing parenthesis: %s", s);
284 return NULL;
286 s = SkipSpaces(s, NULL, 0);
287 len = end - s + 1;
288 spec = safemalloc(len);
289 strncpy(spec, s, len - 1);
290 spec[len - 1] = 0;
292 else
294 spec = s;
297 spec = SkipSpaces(spec, NULL, 0);
298 /* setup temporary in case button read fails */
299 memset(&tmpdf, 0, sizeof(DecorFace));
300 DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
302 if (strncmp(spec, "--", 2) == 0)
304 /* only change flags */
305 Bool verbose = True;
306 for (i = bs_start; i <= bs_end; ++i)
308 if (multiple && (i & use_mask) != set_mask)
310 continue;
312 ReadDecorFace(spec, &TB_STATE(*tb)[i], button, verbose);
313 verbose = False;
316 else if (ReadDecorFace(spec, &tmpdf, button, True))
318 if (append)
320 DecorFace *head = &TB_STATE(*tb)[bs_start];
321 DecorFace *tail = head;
322 DecorFace *next;
324 while (tail->next)
326 tail = tail->next;
328 tail->next = (DecorFace *)safemalloc(sizeof(DecorFace));
329 memcpy(tail->next, &tmpdf, sizeof(DecorFace));
330 if (DFS_FACE_TYPE(tail->next->style) == VectorButton &&
331 DFS_FACE_TYPE((&TB_STATE(*tb)[bs_start])->style) ==
332 DefaultVectorButton)
334 /* override the default vector style */
335 memcpy(
336 &tail->next->style, &head->style,
337 sizeof(DecorFaceStyle));
338 DFS_FACE_TYPE(tail->next->style) = VectorButton;
339 next = head->next;
340 head->next = NULL;
341 FreeDecorFace(dpy, head);
342 memcpy(head, next, sizeof(DecorFace));
343 free(next);
345 for (i = bs_start + 1; i <= bs_end; ++i)
347 if (multiple && (i & use_mask) != set_mask)
349 continue;
351 head = &TB_STATE(*tb)[i];
352 tail = head;
353 while (tail->next)
355 tail = tail->next;
357 tail->next = (DecorFace *)safemalloc(
358 sizeof(DecorFace));
359 memset(
360 &DFS_FLAGS(tail->next->style), 0,
361 sizeof(DFS_FLAGS(tail->next->style)));
362 DFS_FACE_TYPE(tail->next->style) =
363 SimpleButton;
364 tail->next->next = NULL;
365 ReadDecorFace(spec, tail->next, button, False);
366 if (DFS_FACE_TYPE(tail->next->style) ==
367 VectorButton &&
368 DFS_FACE_TYPE((&TB_STATE(*tb)[i])->style) ==
369 DefaultVectorButton)
371 /* override the default vector style */
372 memcpy(
373 &tail->next->style,
374 &head->style,
375 sizeof(DecorFaceStyle));
376 DFS_FACE_TYPE(tail->next->style) =
377 VectorButton;
378 next = head->next;
379 head->next = NULL;
380 FreeDecorFace(dpy, head);
381 memcpy(head, next, sizeof(DecorFace));
382 free(next);
386 else
388 FreeDecorFace(dpy, &TB_STATE(*tb)[bs_start]);
389 memcpy(
390 &(TB_STATE(*tb)[bs_start]), &tmpdf,
391 sizeof(DecorFace));
392 for (i = bs_start + 1; i <= bs_end; ++i)
394 if (multiple && (i & use_mask) != set_mask)
396 continue;
398 ReadDecorFace(
399 spec, &TB_STATE(*tb)[i], button, False);
403 if (pstyle)
405 free(spec);
406 end++;
407 end = SkipSpaces(end, NULL, 0);
410 return end;
413 /* Remove the given decor from all windows */
414 static void __remove_window_decors(F_CMD_ARGS, FvwmDecor *d)
416 const exec_context_t *exc2;
417 exec_context_changes_t ecc;
418 FvwmWindow *t;
420 for (t = Scr.FvwmRoot.next; t; t = t->next)
422 if (t->decor == d)
424 /* remove the extra title height now because we delete
425 * the current decor before calling ChangeDecor(). */
426 t->g.frame.height -= t->decor->title_height;
427 t->decor = NULL;
428 ecc.w.fw = t;
429 ecc.w.wcontext = C_WINDOW;
430 exc2 = exc_clone_context(
431 exc, &ecc, ECC_FW | ECC_WCONTEXT);
432 execute_function(
433 cond_rc, exc2, "ChangeDecor Default", 0);
434 exc_destroy_context(exc2);
438 return;
441 static void do_title_style(F_CMD_ARGS, Bool do_add)
443 char *parm;
444 char *prev;
445 #ifdef USEDECOR
446 FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
447 #else
448 FvwmDecor *decor = &Scr.DefaultDecor;
449 #endif
451 Scr.flags.do_need_window_update = 1;
452 decor->flags.has_changed = 1;
453 decor->titlebar.flags.has_changed = 1;
455 for (prev = action ; (parm = PeekToken(action, &action)); prev = action)
457 if (!do_add && StrEquals(parm,"centered"))
459 TB_JUSTIFICATION(decor->titlebar) = JUST_CENTER;
461 else if (!do_add && StrEquals(parm,"leftjustified"))
463 TB_JUSTIFICATION(decor->titlebar) = JUST_LEFT;
465 else if (!do_add && StrEquals(parm,"rightjustified"))
467 TB_JUSTIFICATION(decor->titlebar) = JUST_RIGHT;
469 else if (!do_add && StrEquals(parm,"height"))
471 int height = 0;
472 int next = 0;
474 if (!action ||
475 sscanf(action, "%d%n", &height, &next) <= 0 ||
476 height < MIN_FONT_HEIGHT ||
477 height > MAX_FONT_HEIGHT)
479 if (height != 0)
481 fvwm_msg(ERR, "do_title_style",
482 "bad height argument (height"
483 " must be from 5 to 256)");
484 height = 0;
487 if (decor->title_height != height ||
488 decor->min_title_height != 0)
490 decor->title_height = height;
491 decor->min_title_height = 0;
492 decor->flags.has_title_height_changed = 1;
494 if (action)
495 action += next;
497 else if (!do_add && StrEquals(parm,"MinHeight"))
499 int height = 0;
500 int next = 0;
502 if (!action ||
503 sscanf(action, "%d%n", &height, &next) <= 0 ||
504 height < MIN_FONT_HEIGHT ||
505 height > MAX_FONT_HEIGHT)
507 if (height < MIN_FONT_HEIGHT)
508 height = MIN_FONT_HEIGHT;
509 else if (height > MAX_FONT_HEIGHT)
510 height = 0;
512 if (decor->min_title_height != height)
514 decor->title_height = 0;
515 decor->min_title_height = height;
516 decor->flags.has_title_height_changed = 1;
518 if (action)
519 action += next;
521 else
523 action = ReadTitleButton(
524 prev, &decor->titlebar, do_add, -1);
528 return;
533 * Reads a multi-pixmap titlebar config. (tril@igs.net)
536 static char *ReadMultiPixmapDecor(char *s, DecorFace *df)
538 static char *pm_names[TBMP_NUM_PIXMAPS+1] =
540 "Main",
541 "LeftMain",
542 "RightMain",
543 "LeftButtons",
544 "RightButtons",
545 "UnderText",
546 "LeftOfText",
547 "RightOfText",
548 "LeftEnd",
549 "RightEnd",
550 "Buttons",
551 NULL
553 FvwmPicture **pm;
554 FvwmAcs *acs;
555 Pixel *pixels;
556 char *token;
557 Bool stretched;
558 Bool load_pixmap = False;
559 int pm_id, i = 0;
560 FvwmPictureAttributes fpa;
562 df->style.face_type = MultiPixmap;
563 df->u.mp.pixmaps = pm =
564 (FvwmPicture**)safecalloc(
565 TBMP_NUM_PIXMAPS, sizeof(FvwmPicture*));
566 df->u.mp.acs = acs =
567 (FvwmAcs *)safemalloc(TBMP_NUM_PIXMAPS * sizeof(FvwmAcs));
568 df->u.mp.pixels = pixels =
569 (Pixel *)safemalloc(TBMP_NUM_PIXMAPS * sizeof(Pixel));
570 for(i=0; i < TBMP_NUM_PIXMAPS; i++)
572 acs[i].cs = -1;
573 acs[i].alpha_percent = 100;
575 s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
576 while (pm_id >= 0)
578 stretched = False;
579 load_pixmap = False;
580 s = DoPeekToken(s, &token, ",()", NULL, NULL);
581 if (StrEquals(token, "stretched"))
583 stretched = True;
584 s = DoPeekToken(s, &token, ",", NULL, NULL);
586 else if (StrEquals(token, "tiled"))
588 s = DoPeekToken(s, &token, ",", NULL, NULL);
590 if (!token)
592 break;
594 if (pm[pm_id] || acs[pm_id].cs >= 0 ||
595 (df->u.mp.solid_flags & (1 << pm_id)))
597 fvwm_msg(WARN, "ReadMultiPixmapDecor",
598 "Ignoring: already-specified %s",
599 pm_names[i]);
600 continue;
602 if (stretched)
604 df->u.mp.stretch_flags |= (1 << pm_id);
606 if (strncasecmp (token, "Colorset", 8) == 0)
608 int val;
609 char *tmp;
611 tmp = DoPeekToken(s, &token, ",", NULL, NULL);
612 if (!GetIntegerArguments(token, NULL, &val, 1) ||
613 val < 0)
615 fvwm_msg(
616 ERR, "ReadMultiPixmapDecor",
617 "Colorset shoule take one or two "
618 "positive integers as argument");
620 else
622 acs[pm_id].cs = val;
623 alloc_colorset(val);
624 s = tmp;
625 tmp = DoPeekToken(s, &token, ",", NULL, NULL);
626 if (GetIntegerArguments(token, NULL, &val, 1))
628 acs[pm_id].alpha_percent =
629 max(0, min(100,val));
630 s = tmp;
634 else if (strncasecmp(token, "TiledPixmap", 11) == 0)
636 s = DoPeekToken(s, &token, ",", NULL, NULL);
637 load_pixmap = True;
639 else if (strncasecmp(token, "AdjustedPixmap", 14) == 0)
641 s = DoPeekToken(s, &token, ",", NULL, NULL);
642 load_pixmap = True;
643 df->u.mp.stretch_flags |= (1 << pm_id);
645 else if (strncasecmp(token, "Solid", 5) == 0)
647 s = DoPeekToken(s, &token, ",", NULL, NULL);
648 if (token)
650 df->u.mp.pixels[pm_id] = GetColor(token);
651 df->u.mp.solid_flags |= (1 << pm_id);
654 else
656 load_pixmap = True;
658 if (load_pixmap && token)
660 fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
661 pm[pm_id] = PCacheFvwmPicture(
662 dpy, Scr.NoFocusWin, NULL, token, fpa);
663 if (!pm[pm_id])
665 fvwm_msg(ERR, "ReadMultiPixmapDecor",
666 "Pixmap '%s' could not be loaded",
667 token);
670 if (pm_id == TBMP_BUTTONS)
672 if (pm[TBMP_LEFT_BUTTONS])
674 PDestroyFvwmPicture(dpy, pm[TBMP_LEFT_BUTTONS]);
676 if (pm[TBMP_RIGHT_BUTTONS])
678 PDestroyFvwmPicture(dpy, pm[TBMP_RIGHT_BUTTONS]);
680 df->u.mp.stretch_flags &= ~(1 << TBMP_LEFT_BUTTONS);
681 df->u.mp.stretch_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
682 df->u.mp.solid_flags &= ~(1 << TBMP_LEFT_BUTTONS);
683 df->u.mp.solid_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
684 if (pm[TBMP_BUTTONS])
686 pm[TBMP_LEFT_BUTTONS] =
687 PCloneFvwmPicture(pm[TBMP_BUTTONS]);
688 acs[TBMP_LEFT_BUTTONS].cs = -1;
689 pm[TBMP_RIGHT_BUTTONS] =
690 PCloneFvwmPicture(pm[TBMP_BUTTONS]);
691 acs[TBMP_RIGHT_BUTTONS].cs = -1;
693 else
695 pm[TBMP_RIGHT_BUTTONS] =
696 pm[TBMP_LEFT_BUTTONS] = NULL;
697 acs[TBMP_RIGHT_BUTTONS].cs =
698 acs[TBMP_LEFT_BUTTONS].cs =
699 acs[TBMP_BUTTONS].cs;
700 acs[TBMP_RIGHT_BUTTONS].alpha_percent =
701 acs[TBMP_LEFT_BUTTONS].alpha_percent =
702 acs[TBMP_BUTTONS].alpha_percent;
703 pixels[TBMP_LEFT_BUTTONS] =
704 pixels[TBMP_RIGHT_BUTTONS] =
705 pixels[TBMP_BUTTONS];
707 if (stretched)
709 df->u.mp.stretch_flags |=
710 (1 << TBMP_LEFT_BUTTONS) |
711 (1 << TBMP_RIGHT_BUTTONS);
713 if (df->u.mp.solid_flags & (1 << TBMP_BUTTONS))
715 df->u.mp.solid_flags |=
716 (1 << TBMP_LEFT_BUTTONS);
717 df->u.mp.solid_flags |=
718 (1 << TBMP_RIGHT_BUTTONS);
720 if (pm[TBMP_BUTTONS])
722 PDestroyFvwmPicture(dpy, pm[TBMP_BUTTONS]);
723 pm[TBMP_BUTTONS] = NULL;
725 acs[TBMP_BUTTONS].cs = -1;
726 df->u.mp.solid_flags &= ~(1 << TBMP_BUTTONS);
728 s = SkipSpaces(s, NULL, 0);
729 s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
732 if (!(pm[TBMP_MAIN] || acs[TBMP_MAIN].cs >= 0 ||
733 (df->u.mp.solid_flags & TBMP_MAIN))
735 !(pm[TBMP_LEFT_MAIN] || acs[TBMP_LEFT_MAIN].cs >= 0 ||
736 (df->u.mp.solid_flags & TBMP_LEFT_MAIN))
738 !(pm[TBMP_RIGHT_MAIN] || acs[TBMP_RIGHT_MAIN].cs >= 0 ||
739 (df->u.mp.solid_flags & TBMP_RIGHT_MAIN)))
741 fvwm_msg(ERR, "ReadMultiPixmapDecor",
742 "No Main pixmap/colorset/solid found for TitleStyle "
743 "MultiPixmap (you must specify either Main, "
744 "or both LeftMain and RightMain)");
745 for (i=0; i < TBMP_NUM_PIXMAPS; i++)
747 if (pm[i])
749 PDestroyFvwmPicture(dpy, pm[i]);
751 else if (!!(df->u.mp.solid_flags & i))
753 PictureFreeColors(
754 dpy, Pcmap, &df->u.mp.pixels[i], 1, 0,
755 False);
758 free(pm);
759 free(acs);
760 free(pixels);
761 return NULL;
764 return s;
769 * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
770 * structure, but does not free the FvwmDecor itself
773 static void DestroyFvwmDecor(FvwmDecor *decor)
775 int i;
776 /* reset to default button set (frees allocated mem) */
777 DestroyAllButtons(decor);
778 for (i = 0; i < BS_MaxButtonState; ++i)
780 FreeDecorFace(dpy, &TB_STATE(decor->titlebar)[i]);
782 FreeDecorFace(dpy, &decor->BorderStyle.active);
783 FreeDecorFace(dpy, &decor->BorderStyle.inactive);
784 #ifdef USEDECOR
785 if (decor->tag)
787 free(decor->tag);
788 decor->tag = NULL;
790 #endif
792 return;
795 static void SetLayerButtonFlag(
796 int layer, int multi, int set, FvwmDecor *decor, TitleButton *tb)
798 int i;
799 int start = 0;
800 int add = 2;
802 if (multi)
804 if (multi == 2)
806 start = 1;
808 else if (multi == 3)
810 add = 1;
812 for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
814 if (set)
816 TB_FLAGS(decor->buttons[i]).has_layer = 1;
817 TB_LAYER(decor->buttons[i]) = layer;
819 else
821 TB_FLAGS(decor->buttons[i]).has_layer = 0;
825 else
827 if (set)
829 TB_FLAGS(*tb).has_layer = 1;
830 TB_LAYER(*tb) = layer;
832 else
834 TB_FLAGS(*tb).has_layer = 0;
838 return;
843 * Changes a button decoration style (changes by veliaa@rpi.edu)
846 static void SetMWMButtonFlag(
847 mwm_flags flag, int multi, int set, FvwmDecor *decor, TitleButton *tb)
849 int i;
850 int start = 0;
851 int add = 2;
853 if (multi)
855 if (multi == 2)
857 start = 1;
859 else if (multi == 3)
861 add = 1;
863 for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
865 if (set)
867 TB_MWM_DECOR_FLAGS(decor->buttons[i]) |= flag;
869 else
871 TB_MWM_DECOR_FLAGS(decor->buttons[i]) &= ~flag;
875 else
877 if (set)
879 TB_MWM_DECOR_FLAGS(*tb) |= flag;
881 else
883 TB_MWM_DECOR_FLAGS(*tb) &= ~flag;
887 return;
890 static void do_button_style(F_CMD_ARGS, Bool do_add)
892 int i;
893 int multi = 0;
894 int button = 0;
895 int do_return;
896 char *text = NULL;
897 char *prev = NULL;
898 char *parm = NULL;
899 TitleButton *tb = NULL;
900 #ifdef USEDECOR
901 FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
902 #else
903 FvwmDecor *decor = &Scr.DefaultDecor;
904 #endif
906 parm = PeekToken(action, &text);
907 if (parm && isdigit(*parm))
909 button = atoi(parm);
910 button = BUTTON_INDEX(button);
913 if (parm == NULL || button >= NUMBER_OF_TITLE_BUTTONS || button < 0)
915 fvwm_msg(
916 ERR, "ButtonStyle", "Bad button style (1) in line %s",
917 action);
918 return;
921 Scr.flags.do_need_window_update = 1;
923 do_return = 0;
924 if (!isdigit(*parm))
926 if (StrEquals(parm,"left"))
928 multi = 1; /* affect all left buttons */
930 else if (StrEquals(parm,"right"))
932 multi = 2; /* affect all right buttons */
934 else if (StrEquals(parm,"all"))
936 multi = 3; /* affect all buttons */
938 else
940 /* we're either resetting buttons or an invalid button
941 * set was specified */
942 if (StrEquals(parm,"reset"))
944 ResetAllButtons(decor);
946 else
948 fvwm_msg(
949 ERR, "ButtonStyle",
950 "Bad button style (2) in line %s",
951 action);
953 multi = 3;
954 do_return = 1;
957 /* mark button style and decor as changed */
958 decor->flags.has_changed = 1;
959 if (multi == 0)
961 /* a single button was specified */
962 tb = &decor->buttons[button];
963 TB_FLAGS(*tb).has_changed = 1;
965 else
967 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
969 if (((multi & 1) && !(i & 1)) ||
970 ((multi & 2) && (i & 1)))
972 TB_FLAGS(decor->buttons[i]).has_changed = 1;
976 if (do_return == 1)
978 return;
980 for (prev = text; (parm = PeekToken(text, &text)); prev = text)
982 if (!do_add && strcmp(parm,"-") == 0)
984 char *tok;
985 text = GetNextToken(text, &tok);
986 while (tok)
988 int set = 1;
989 char *old_tok = NULL;
991 if (*tok == '!')
993 /* flag negate */
994 set = 0;
995 old_tok = tok;
996 tok++;
998 if (StrEquals(tok,"Clear"))
1000 if (multi)
1002 for (i = 0;
1003 i < NUMBER_OF_TITLE_BUTTONS; ++i)
1005 if (((multi & 1) &&
1006 !(i & 1)) ||
1007 ((multi & 2) &&
1008 (i & 1)))
1010 TB_JUSTIFICATION(decor->buttons[i]) =
1011 (set) ? JUST_CENTER : JUST_RIGHT;
1012 memset(&TB_FLAGS(decor->buttons[i]), (set) ? 0 : 0xff,
1013 sizeof(TB_FLAGS(decor->buttons[i])));
1014 /* ? not very useful if set == 0 ? */
1018 else
1020 TB_JUSTIFICATION(*tb) = (set) ?
1021 JUST_CENTER :
1022 JUST_RIGHT;
1023 memset(&TB_FLAGS(*tb), (set) ?
1024 0 : 0xff,
1025 sizeof(TB_FLAGS(*tb)));
1026 /* ? not very useful if
1027 * set == 0 ? */
1030 else if (StrEquals(tok, "MWMDecorMenu"))
1032 SetMWMButtonFlag(
1033 MWM_DECOR_MENU, multi, set,
1034 decor, tb);
1036 else if (StrEquals(tok, "MWMDecorMin"))
1038 SetMWMButtonFlag(
1039 MWM_DECOR_MINIMIZE, multi, set,
1040 decor, tb);
1042 else if (StrEquals(tok, "MWMDecorMax"))
1044 SetMWMButtonFlag(
1045 MWM_DECOR_MAXIMIZE, multi, set,
1046 decor, tb);
1048 else if (StrEquals(tok, "MWMDecorShade"))
1050 SetMWMButtonFlag(
1051 MWM_DECOR_SHADE, multi, set,
1052 decor, tb);
1054 else if (StrEquals(tok, "MWMDecorStick"))
1056 SetMWMButtonFlag(
1057 MWM_DECOR_STICK, multi, set,
1058 decor, tb);
1060 else if (StrEquals(tok, "MwmDecorLayer"))
1062 int layer, got_number;
1063 char *ltok;
1064 text = GetNextToken(text, &ltok);
1065 if (ltok)
1067 got_number =
1068 (sscanf(ltok, "%d",
1069 &layer) == 1);
1070 free (ltok);
1072 else
1074 got_number = 0;
1076 if (!ltok || !got_number)
1078 fvwm_msg(ERR, "ButtonStyle",
1079 "could not read"
1080 " integer value for"
1081 " layer -- line: %s",
1082 text);
1084 else
1086 SetLayerButtonFlag(
1087 layer, multi, set,
1088 decor, tb);
1092 else
1094 fvwm_msg(ERR, "ButtonStyle",
1095 "unknown title button flag"
1096 " %s -- line: %s", tok, text);
1098 if (set)
1100 free(tok);
1102 else
1104 free(old_tok);
1106 text = GetNextToken(text, &tok);
1108 break;
1110 else
1112 if (multi)
1114 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
1116 if (((multi & 1) && !(i & 1)) ||
1117 ((multi & 2) && (i & 1)))
1119 text = ReadTitleButton(
1120 prev,
1121 &decor->buttons[i],
1122 do_add, i);
1126 else if (!(text = ReadTitleButton(
1127 prev, tb, do_add, button)))
1129 break;
1134 return;
1137 static
1138 int update_decorface_colorset(DecorFace *df, int cset)
1140 DecorFace *tdf;
1141 int has_changed = 0;
1143 for(tdf = df; tdf != NULL; tdf = tdf->next)
1145 if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
1146 tdf->u.acs.cs == cset)
1148 tdf->flags.has_changed = 1;
1149 has_changed = 1;
1151 else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
1153 int i;
1155 for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
1157 if (tdf->u.mp.acs[i].cs == cset)
1159 tdf->flags.has_changed = 1;
1160 has_changed = 1;
1166 return has_changed;
1169 static
1170 int update_titlebutton_colorset(TitleButton *tb, int cset)
1172 int i;
1173 int has_changed = 0;
1175 for(i = 0; i < BS_MaxButtonState; i++)
1177 tb->state[i].flags.has_changed =
1178 update_decorface_colorset(&(tb->state[i]), cset);
1179 has_changed |= tb->state[i].flags.has_changed;
1181 return has_changed;
1184 static
1185 void update_decors_colorset(int cset)
1187 int i;
1188 int has_changed;
1189 FvwmDecor *decor = &Scr.DefaultDecor;
1191 #ifdef USEDECOR
1192 for(decor = &Scr.DefaultDecor; decor != NULL; decor = decor->next)
1193 #endif
1195 has_changed = 0;
1196 for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
1198 decor->flags.has_changed |= update_titlebutton_colorset(
1199 &(decor->buttons[i]), cset);
1201 decor->flags.has_changed |= update_titlebutton_colorset(
1202 &(decor->titlebar), cset);
1203 decor->flags.has_changed |= update_decorface_colorset(
1204 &(decor->BorderStyle.active), cset);
1205 decor->flags.has_changed |= update_decorface_colorset(
1206 &(decor->BorderStyle.inactive), cset);
1207 if (decor->flags.has_changed)
1209 Scr.flags.do_need_window_update = 1;
1214 static Bool __parse_vector_line_one_coord(
1215 char **ret_action, int *pcoord, int *poff, char *action)
1217 int offset;
1218 int n;
1220 *ret_action = action;
1221 n = sscanf(action, "%d%n", pcoord, &offset);
1222 if (n < 1)
1224 return False;
1226 action += offset;
1227 /* check for offest */
1228 if (*action == '+' || *action == '-')
1230 n = sscanf(action, "%dp%n", poff, &offset);
1231 if (n < 1)
1233 return False;
1235 if (*poff < -128)
1237 *poff = -128;
1239 else if (*poff > 127)
1241 *poff = 127;
1243 action += offset;
1245 else
1247 *poff = 0;
1249 *ret_action = action;
1251 return True;
1254 static Bool __parse_vector_line(
1255 char **ret_action, int *px, int *py, int *pxoff, int *pyoff, int *pc,
1256 char *action)
1258 Bool is_valid = True;
1259 int offset;
1260 int n;
1262 *ret_action = action;
1263 if (__parse_vector_line_one_coord(&action, px, pxoff, action) == False)
1265 return False;
1267 if (*action != 'x')
1269 return False;
1271 action++;
1272 if (__parse_vector_line_one_coord(&action, py, pyoff, action) == False)
1274 return False;
1276 if (*action != '@')
1278 return False;
1280 action++;
1281 /* read the line style */
1282 n = sscanf(action, "%d%n", pc, &offset);
1283 if (n < 1)
1285 return False;
1287 action += offset;
1288 *ret_action = action;
1290 return is_valid;
1293 /* ---------------------------- interface functions ------------------------ */
1295 void refresh_window(Window w, Bool window_update)
1297 XSetWindowAttributes attributes;
1298 unsigned long valuemask;
1300 valuemask = CWOverrideRedirect | CWBackingStore | CWSaveUnder |
1301 CWBackPixmap;
1302 attributes.override_redirect = True;
1303 attributes.save_under = False;
1304 attributes.background_pixmap = None;
1305 attributes.backing_store = NotUseful;
1306 w = XCreateWindow(
1307 dpy, w, 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight, 0,
1308 CopyFromParent, CopyFromParent, CopyFromParent, valuemask,
1309 &attributes);
1310 XMapWindow(dpy, w);
1311 if (Scr.flags.do_need_window_update && window_update)
1313 flush_window_updates();
1315 XDestroyWindow(dpy, w);
1316 XSync(dpy, 0);
1317 handle_all_expose();
1319 return;
1322 void ApplyDefaultFontAndColors(void)
1324 XGCValues gcv;
1325 unsigned long gcm;
1326 int cset = Scr.DefaultColorset;
1328 /* make GC's */
1329 gcm = GCFunction|GCLineWidth|GCForeground|GCBackground;
1330 gcv.function = GXcopy;
1331 if (Scr.DefaultFont->font)
1333 gcm |= GCFont;
1334 gcv.font = Scr.DefaultFont->font->fid;
1336 gcv.line_width = 0;
1337 if (cset >= 0)
1339 gcv.foreground = Colorset[cset].fg;
1340 gcv.background = Colorset[cset].bg;
1342 else
1344 gcv.foreground = Scr.StdFore;
1345 gcv.background = Scr.StdBack;
1347 if (Scr.StdGC)
1349 XChangeGC(dpy, Scr.StdGC, gcm, &gcv);
1351 else
1353 Scr.StdGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1356 gcm = GCFunction|GCLineWidth|GCForeground;
1357 if (cset >= 0)
1359 gcv.foreground = Colorset[cset].hilite;
1361 else
1363 gcv.foreground = Scr.StdHilite;
1365 if (Scr.StdReliefGC)
1367 XChangeGC(dpy, Scr.StdReliefGC, gcm, &gcv);
1369 else
1371 Scr.StdReliefGC = fvwmlib_XCreateGC(
1372 dpy, Scr.NoFocusWin, gcm, &gcv);
1374 if (cset >= 0)
1376 gcv.foreground = Colorset[cset].shadow;
1378 else
1380 gcv.foreground = Scr.StdShadow;
1382 if (Scr.StdShadowGC)
1384 XChangeGC(dpy, Scr.StdShadowGC, gcm, &gcv);
1386 else
1388 Scr.StdShadowGC = fvwmlib_XCreateGC(
1389 dpy, Scr.NoFocusWin, gcm, &gcv);
1391 /* update the geometry window for move/resize */
1392 if (Scr.SizeWindow != None)
1394 resize_geometry_window();
1396 UpdateAllMenuStyles();
1398 return;
1401 void FreeDecorFace(Display *dpy, DecorFace *df)
1403 int i;
1405 switch (DFS_FACE_TYPE(df->style))
1407 case GradientButton:
1408 if (df->u.grad.d_pixels != NULL && df->u.grad.d_npixels)
1410 PictureFreeColors(
1411 dpy, Pcmap, df->u.grad.d_pixels,
1412 df->u.grad.d_npixels, 0, False);
1413 free(df->u.grad.d_pixels);
1415 else if (Pdepth <= 8 && df->u.grad.xcs != NULL &&
1416 df->u.grad.npixels > 0 && !df->u.grad.do_dither)
1418 Pixel *p;
1419 int i;
1421 p = (Pixel *)safemalloc(
1422 df->u.grad.npixels * sizeof(Pixel));
1423 for(i=0; i < df->u.grad.npixels; i++)
1425 p[i] = df->u.grad.xcs[i].pixel;
1427 PictureFreeColors(
1428 dpy, Pcmap, p, df->u.grad.npixels, 0, False);
1429 free(p);
1431 if (df->u.grad.xcs != NULL)
1433 free(df->u.grad.xcs);
1435 break;
1437 case PixmapButton:
1438 case TiledPixmapButton:
1439 case StretchedPixmapButton:
1440 case AdjustedPixmapButton:
1441 case ShrunkPixmapButton:
1442 if (df->u.p)
1444 PDestroyFvwmPicture(dpy, df->u.p);
1446 break;
1448 case MultiPixmap:
1449 if (df->u.mp.pixmaps)
1451 for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
1453 if (df->u.mp.pixmaps[i])
1455 PDestroyFvwmPicture(
1456 dpy, df->u.mp.pixmaps[i]);
1458 else if (!!(df->u.mp.solid_flags & i))
1460 PictureFreeColors(
1461 dpy, Pcmap, &df->u.mp.pixels[i],
1462 1, 0, False);
1465 free(df->u.mp.pixmaps);
1467 if (df->u.mp.acs)
1469 free(df->u.mp.acs);
1471 if (df->u.mp.pixels)
1473 free(df->u.mp.pixels);
1475 break;
1476 case VectorButton:
1477 case DefaultVectorButton:
1478 if (df->u.vector.x)
1480 free (df->u.vector.x);
1482 if (df->u.vector.y)
1484 free (df->u.vector.y);
1486 /* free offsets for coord */
1487 if (df->u.vector.xoff)
1489 free(df->u.vector.xoff);
1491 if (df->u.vector.yoff)
1493 free(df->u.vector.yoff);
1495 if (df->u.vector.c)
1497 free (df->u.vector.c);
1499 break;
1500 default:
1501 /* see below */
1502 break;
1504 /* delete any compound styles */
1505 if (df->next)
1507 FreeDecorFace(dpy, df->next);
1508 free(df->next);
1510 df->next = NULL;
1511 memset(&df->style, 0, sizeof(df->style));
1512 memset(&df->u, 0, sizeof(df->u));
1513 DFS_FACE_TYPE(df->style) = SimpleButton;
1515 return;
1520 * Reads a button face line into a structure (veliaa@rpi.edu)
1523 Bool ReadDecorFace(char *s, DecorFace *df, int button, int verbose)
1525 int offset;
1526 char style[256], *file;
1527 char *action = s;
1529 /* some variants of scanf do not increase the assign count when %n is
1530 * used, so a return value of 1 is no error. */
1531 if (sscanf(s, "%255s%n", style, &offset) < 1)
1533 if (verbose)
1535 fvwm_msg(ERR, "ReadDecorFace", "error in face `%s'", s);
1537 return False;
1539 style[255] = 0;
1541 if (strncasecmp(style, "--", 2) != 0)
1543 s += offset;
1545 FreeDecorFace(dpy, df);
1547 /* determine button style */
1548 if (strncasecmp(style,"Simple",6)==0)
1550 memset(&df->style, 0, sizeof(df->style));
1551 DFS_FACE_TYPE(df->style) = SimpleButton;
1553 else if (strncasecmp(style,"Default",7)==0)
1555 int b = -1, n = sscanf(s, "%d%n", &b, &offset);
1557 if (n < 1)
1559 if (button == -1)
1561 if (verbose)
1563 fvwm_msg(
1564 ERR,"ReadDecorFace",
1565 "need default button"
1566 " number to load");
1568 return False;
1570 b = button;
1572 else
1574 b = BUTTON_INDEX(b);
1575 s += offset;
1577 if (b >= 0 && b < NUMBER_OF_TITLE_BUTTONS)
1579 LoadDefaultButton(df, b);
1581 else
1583 if (verbose)
1585 fvwm_msg(
1586 ERR, "ReadDecorFace",
1587 "button number out of range:"
1588 " %d", b);
1590 return False;
1593 else if (strncasecmp(style,"Vector",6)==0 ||
1594 (strlen(style)<=2 && isdigit(*style)))
1596 /* normal coordinate list button style */
1597 int i, num_coords, num;
1598 struct vector_coords *vc = &df->u.vector;
1600 /* get number of points */
1601 if (strncasecmp(style,"Vector",6)==0)
1603 num = sscanf(s,"%d%n",&num_coords,&offset);
1604 s += offset;
1606 else
1608 num = sscanf(style,"%d",&num_coords);
1611 if (num < 1 || num_coords<2 ||
1612 num_coords > MAX_TITLE_BUTTON_VECTOR_LINES)
1614 if (verbose)
1616 fvwm_msg(
1617 ERR, "ReadDecorFace",
1618 "Bad button style (2) in line:"
1619 " %s",action);
1621 return False;
1624 vc->num = num_coords;
1625 vc->use_fgbg = 0;
1626 vc->x = (signed char*)safemalloc(sizeof(char) *
1627 num_coords);
1628 vc->y = (signed char*)safemalloc(sizeof(char) *
1629 num_coords);
1630 vc->xoff = (signed char*)safemalloc(sizeof(char) *
1631 num_coords);
1632 vc->yoff = (signed char*)safemalloc(sizeof(char) *
1633 num_coords);
1634 vc->c = (signed char*)safemalloc(sizeof(char) *
1635 num_coords);
1637 /* get the points */
1638 for (i = 0; i < vc->num; ++i)
1640 int x;
1641 int y;
1642 int xoff = 0;
1643 int yoff = 0;
1644 int c;
1646 if (__parse_vector_line(
1647 &s, &x, &y, &xoff, &yoff, &c, s) ==
1648 False)
1650 break;
1652 if (x < 0)
1654 x = 0;
1656 if (x > 100)
1658 x = 100;
1660 if (y < 0)
1662 y = 0;
1664 if (y > 100)
1666 y = 100;
1668 if (c < 0 || c > 4)
1670 c = 4;
1672 vc->x[i] = x;
1673 vc->y[i] = y;
1674 vc->c[i] = c;
1675 vc->xoff[i] = xoff;
1676 vc->yoff[i] = yoff;
1677 if (c == 2 || c == 3)
1679 vc->use_fgbg = 1;
1682 if (i < vc->num)
1684 if (verbose)
1686 fvwm_msg(
1687 ERR, "ReadDecorFace",
1688 "Bad button style (3) in line"
1689 " %s", action);
1691 free(vc->x);
1692 free(vc->y);
1693 free(vc->c);
1694 free(vc->xoff);
1695 free(vc->yoff);
1696 vc->x = NULL;
1697 vc->y = NULL;
1698 vc->c = NULL;
1699 vc->xoff = NULL;
1700 vc->yoff = NULL;
1701 return False;
1703 memset(&df->style, 0, sizeof(df->style));
1704 DFS_FACE_TYPE(df->style) = VectorButton;
1706 else if (strncasecmp(style,"Solid",5)==0)
1708 s = GetNextToken(s, &file);
1709 if (file)
1711 memset(&df->style, 0, sizeof(df->style));
1712 DFS_FACE_TYPE(df->style) = SolidButton;
1713 df->u.back = GetColor(file);
1714 free(file);
1716 else
1718 if (verbose)
1720 fvwm_msg(
1721 ERR, "ReadDecorFace",
1722 "no color given for Solid"
1723 " face type: %s", action);
1725 return False;
1728 else if (strncasecmp(style+1, "Gradient", 8)==0)
1730 char **s_colors;
1731 int npixels, nsegs, *perc;
1732 XColor *xcs;
1733 Bool do_dither = False;
1735 if (!IsGradientTypeSupported(style[0]))
1737 return False;
1739 /* translate the gradient string into an array of
1740 * colors etc */
1741 npixels = ParseGradient(
1742 s, &s, &s_colors, &perc, &nsegs);
1743 while (*s && isspace(*s))
1745 s++;
1747 if (npixels <= 0)
1749 return False;
1751 /* grab the colors */
1752 if (Pdepth <= 16)
1754 do_dither = True;
1756 xcs = AllocAllGradientColors(
1757 s_colors, perc, nsegs, npixels, do_dither);
1758 if (xcs == None)
1759 return False;
1760 df->u.grad.xcs = xcs;
1761 df->u.grad.npixels = npixels;
1762 df->u.grad.do_dither = do_dither;
1763 df->u.grad.d_pixels = NULL;
1764 memset(&df->style, 0, sizeof(df->style));
1765 DFS_FACE_TYPE(df->style) = GradientButton;
1766 df->u.grad.gradient_type = toupper(style[0]);
1768 else if (strncasecmp(style,"Pixmap",6)==0
1769 || strncasecmp(style,"TiledPixmap",11)==0
1770 || strncasecmp(style,"StretchedPixmap",15)==0
1771 || strncasecmp(style,"AdjustedPixmap",14)==0
1772 || strncasecmp(style,"ShrunkPixmap",12)==0)
1774 FvwmPictureAttributes fpa;
1776 s = GetNextToken(s, &file);
1777 fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
1778 df->u.p = PCacheFvwmPicture(
1779 dpy, Scr.NoFocusWin, NULL, file, fpa);
1780 if (df->u.p == NULL)
1782 if (file)
1784 if (verbose)
1786 fvwm_msg(
1787 ERR, "ReadDecorFace",
1788 "couldn't load pixmap"
1789 " %s", file);
1791 free(file);
1793 return False;
1795 if (file)
1797 free(file);
1798 file = NULL;
1801 memset(&df->style, 0, sizeof(df->style));
1802 if (strncasecmp(style,"Tiled",5)==0)
1804 DFS_FACE_TYPE(df->style) = TiledPixmapButton;
1806 else if (strncasecmp(style,"Stretched",9)==0)
1808 DFS_FACE_TYPE(df->style) =
1809 StretchedPixmapButton;
1811 else if (strncasecmp(style,"Adjusted",8)==0)
1813 DFS_FACE_TYPE(df->style) =
1814 AdjustedPixmapButton;
1816 else if (strncasecmp(style,"Shrunk",6)==0)
1818 DFS_FACE_TYPE(df->style) =
1819 ShrunkPixmapButton;
1821 else
1823 DFS_FACE_TYPE(df->style) = PixmapButton;
1826 else if (strncasecmp(style,"MultiPixmap",11)==0)
1828 if (button != -1)
1830 if (verbose)
1832 fvwm_msg(
1833 ERR, "ReadDecorFace",
1834 "MultiPixmap is only valid"
1835 " for TitleStyle");
1837 return False;
1839 s = ReadMultiPixmapDecor(s, df);
1840 if (!s)
1842 return False;
1845 else if (FMiniIconsSupported &&
1846 strncasecmp (style, "MiniIcon", 8) == 0)
1848 memset(&df->style, 0, sizeof(df->style));
1849 DFS_FACE_TYPE(df->style) = MiniIconButton;
1850 /* pixmap read in when the window is created */
1851 df->u.p = NULL;
1853 else if (strncasecmp (style, "Colorset", 8) == 0)
1855 int val[2];
1856 int n;
1858 n = GetIntegerArguments(s, NULL, val, 2);
1859 if (n == 0)
1862 memset(&df->style, 0, sizeof(df->style));
1863 if (n > 0 && val[0] >= 0)
1866 df->u.acs.cs = val[0];
1867 alloc_colorset(val[0]);
1868 DFS_FACE_TYPE(df->style) = ColorsetButton;
1870 df->u.acs.alpha_percent = 100;
1871 if (n > 1)
1873 df->u.acs.alpha_percent =
1874 max(0, min(100,val[1]));
1876 s = SkipNTokens(s, n);
1878 else
1880 if (verbose)
1882 fvwm_msg(
1883 ERR, "ReadDecorFace",
1884 "unknown style %s: %s", style, action);
1886 return False;
1890 /* Process button flags ("--" signals start of flags,
1891 it is also checked for above) */
1892 s = GetNextToken(s, &file);
1893 if (file && (strcmp(file,"--")==0))
1895 char *tok;
1896 s = GetNextToken(s, &tok);
1897 while (tok && *tok)
1899 int set = 1;
1900 char *old_tok = NULL;
1902 if (*tok == '!')
1903 { /* flag negate */
1904 set = 0;
1905 old_tok = tok;
1906 tok++;
1908 if (StrEquals(tok,"Clear"))
1910 memset(&DFS_FLAGS(df->style), (set) ? 0 : 0xff,
1911 sizeof(DFS_FLAGS(df->style)));
1912 /* ? what is set == 0 good for ? */
1914 else if (StrEquals(tok,"Left"))
1916 if (set)
1918 DFS_H_JUSTIFICATION(df->style) =
1919 JUST_LEFT;
1921 else
1923 DFS_H_JUSTIFICATION(df->style) =
1924 JUST_RIGHT;
1927 else if (StrEquals(tok,"Right"))
1929 if (set)
1931 DFS_H_JUSTIFICATION(df->style) =
1932 JUST_RIGHT;
1934 else
1936 DFS_H_JUSTIFICATION(df->style) =
1937 JUST_LEFT;
1940 else if (StrEquals(tok,"Centered"))
1942 DFS_H_JUSTIFICATION(df->style) = JUST_CENTER;
1943 DFS_V_JUSTIFICATION(df->style) = JUST_CENTER;
1945 else if (StrEquals(tok,"Top"))
1947 if (set)
1949 DFS_V_JUSTIFICATION(df->style) =
1950 JUST_TOP;
1952 else
1954 DFS_V_JUSTIFICATION(df->style) =
1955 JUST_BOTTOM;
1958 else if (StrEquals(tok,"Bottom"))
1960 if (set)
1962 DFS_V_JUSTIFICATION(df->style) =
1963 JUST_BOTTOM;
1965 else
1967 DFS_V_JUSTIFICATION(df->style) =
1968 JUST_TOP;
1971 else if (StrEquals(tok,"Flat"))
1973 if (set)
1975 DFS_BUTTON_RELIEF(df->style) =
1976 DFS_BUTTON_IS_FLAT;
1978 else if (DFS_BUTTON_RELIEF(df->style) ==
1979 DFS_BUTTON_IS_FLAT)
1981 DFS_BUTTON_RELIEF(df->style) =
1982 DFS_BUTTON_IS_UP;
1985 else if (StrEquals(tok,"Sunk"))
1987 if (set)
1989 DFS_BUTTON_RELIEF(df->style) =
1990 DFS_BUTTON_IS_SUNK;
1992 else if (DFS_BUTTON_RELIEF(df->style) ==
1993 DFS_BUTTON_IS_SUNK)
1995 DFS_BUTTON_RELIEF(df->style) =
1996 DFS_BUTTON_IS_UP;
1999 else if (StrEquals(tok,"Raised"))
2001 if (set)
2003 DFS_BUTTON_RELIEF(df->style) =
2004 DFS_BUTTON_IS_UP;
2006 else
2008 DFS_BUTTON_RELIEF(df->style) =
2009 DFS_BUTTON_IS_SUNK;
2012 else if (StrEquals(tok,"UseTitleStyle"))
2014 if (set)
2016 DFS_USE_TITLE_STYLE(df->style) = 1;
2017 DFS_USE_BORDER_STYLE(df->style) = 0;
2019 else
2020 DFS_USE_TITLE_STYLE(df->style) = 0;
2022 else if (StrEquals(tok,"HiddenHandles"))
2024 DFS_HAS_HIDDEN_HANDLES(df->style) = !!set;
2026 else if (StrEquals(tok,"NoInset"))
2028 DFS_HAS_NO_INSET(df->style) = !!set;
2030 else if (StrEquals(tok,"UseBorderStyle"))
2032 if (set)
2034 DFS_USE_BORDER_STYLE(df->style) = 1;
2035 DFS_USE_TITLE_STYLE(df->style) = 0;
2037 else
2039 DFS_USE_BORDER_STYLE(df->style) = 0;
2042 else if (verbose)
2044 fvwm_msg(
2045 ERR, "ReadDecorFace",
2046 "unknown button face flag '%s'"
2047 " -- line: %s", tok, action);
2049 if (set)
2051 free(tok);
2053 else
2055 free(old_tok);
2057 s = GetNextToken(s, &tok);
2060 if (file)
2062 free(file);
2065 return True;
2068 #ifdef USEDECOR
2071 * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
2074 void AddToDecor(F_CMD_ARGS, FvwmDecor *decor)
2076 if (!action)
2078 return;
2080 while (*action && isspace((unsigned char)*action))
2082 ++action;
2084 if (!*action)
2086 return;
2088 Scr.cur_decor = decor;
2089 execute_function(cond_rc, exc, action, 0);
2090 Scr.cur_decor = NULL;
2092 return;
2097 * InitFvwmDecor -- initializes an FvwmDecor structure to defaults
2100 void InitFvwmDecor(FvwmDecor *decor)
2102 int i;
2103 DecorFace tmpdf;
2105 /* zero out the structures */
2106 memset(decor, 0, sizeof (FvwmDecor));
2107 memset(&tmpdf, 0, sizeof(DecorFace));
2109 /* initialize title-bar button styles */
2110 DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
2111 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
2113 int j = 0;
2114 for (; j < BS_MaxButtonState; ++j)
2116 TB_STATE(decor->buttons[i])[j] = tmpdf;
2119 /* reset to default button set */
2120 ResetAllButtons(decor);
2121 /* initialize title-bar styles */
2122 for (i = 0; i < BS_MaxButtonState; ++i)
2124 DFS_FACE_TYPE(
2125 TB_STATE(decor->titlebar)[i].style) = SimpleButton;
2128 /* initialize border texture styles */
2129 DFS_FACE_TYPE(decor->BorderStyle.active.style) = SimpleButton;
2130 DFS_FACE_TYPE(decor->BorderStyle.inactive.style) = SimpleButton;
2132 return;
2135 void reset_decor_changes(void)
2137 #ifndef USEDECOR
2138 Scr.DefaultDecor.flags.has_changed = 0;
2139 Scr.DefaultDecor.flags.has_title_height_changed = 0;
2140 #else
2141 FvwmDecor *decor;
2142 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
2144 decor->flags.has_changed = 0;
2145 decor->flags.has_title_height_changed = 0;
2147 /* todo: must reset individual change flags too */
2148 #endif
2150 return;
2153 void update_fvwm_colorset(int cset)
2155 if (cset == Scr.DefaultColorset)
2157 Scr.flags.do_need_window_update = 1;
2158 Scr.flags.has_default_color_changed = 1;
2160 UpdateMenuColorset(cset);
2161 update_style_colorset(cset);
2162 update_decors_colorset(cset);
2164 return;
2167 /* ---------------------------- builtin commands --------------------------- */
2169 void CMD_Beep(F_CMD_ARGS)
2171 #if 1 /*!!!*/
2172 parse_colorset(11, "RootTransparent");
2173 #endif
2174 XBell(dpy, 0);
2176 return;
2179 void CMD_Nop(F_CMD_ARGS)
2181 return;
2184 void CMD_EscapeFunc(F_CMD_ARGS)
2186 return;
2189 void CMD_CursorMove(F_CMD_ARGS)
2191 int x = 0, y = 0;
2192 int val1, val2, val1_unit, val2_unit;
2193 int virtual_x, virtual_y;
2194 int pan_x, pan_y;
2195 int x_pages, y_pages;
2197 if (GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit) != 2)
2199 fvwm_msg(ERR, "movecursor", "CursorMove needs 2 arguments");
2200 return;
2202 if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
2203 &x, &y, &JunkX, &JunkY, &JunkMask) == False)
2205 /* pointer is on a different screen */
2206 return;
2208 x = x + val1 * val1_unit / 100;
2209 y = y + val2 * val2_unit / 100;
2210 virtual_x = Scr.Vx;
2211 virtual_y = Scr.Vy;
2212 if (x >= 0)
2214 x_pages = x / Scr.MyDisplayWidth;
2216 else
2218 x_pages = ((x + 1) / Scr.MyDisplayWidth) - 1;
2220 virtual_x += x_pages * Scr.MyDisplayWidth;
2221 x -= x_pages * Scr.MyDisplayWidth;
2222 if (virtual_x < 0)
2224 x += virtual_x;
2225 virtual_x = 0;
2227 else if (virtual_x > Scr.VxMax)
2229 x += virtual_x - Scr.VxMax;
2230 virtual_x = Scr.VxMax;
2233 if (y >= 0)
2235 y_pages = y / Scr.MyDisplayHeight;
2237 else
2239 y_pages = ((y + 1) / Scr.MyDisplayHeight) - 1;
2241 virtual_y += y_pages * Scr.MyDisplayHeight;
2242 y -= y_pages * Scr.MyDisplayHeight;
2243 if (virtual_y < 0)
2245 y += virtual_y;
2246 virtual_y = 0;
2248 else if (virtual_y > Scr.VyMax)
2250 y += virtual_y - Scr.VyMax;
2251 virtual_y = Scr.VyMax;
2253 if (virtual_x != Scr.Vx || virtual_y != Scr.Vy)
2254 MoveViewport(virtual_x, virtual_y, True);
2255 pan_x = (Scr.EdgeScrollX != 0) ? 2 : 0;
2256 pan_y = (Scr.EdgeScrollY != 0) ? 2 : 0;
2257 /* prevent paging if EdgeScroll is active */
2258 if (x >= Scr.MyDisplayWidth - pan_x)
2260 x = Scr.MyDisplayWidth - pan_x -1;
2262 else if (x < pan_x)
2264 x = pan_x;
2266 if (y >= Scr.MyDisplayHeight - pan_y)
2268 y = Scr.MyDisplayHeight - pan_y - 1;
2270 else if (y < pan_y)
2272 y = pan_y;
2274 FWarpPointerUpdateEvpos(
2275 exc->x.elast, dpy, None, Scr.Root, 0, 0, Scr.MyDisplayWidth,
2276 Scr.MyDisplayHeight, x, y);
2278 return;
2281 void CMD_Delete(F_CMD_ARGS)
2283 FvwmWindow * const fw = exc->w.fw;
2285 if (!is_function_allowed(F_DELETE, NULL, fw, RQORIG_PROGRAM_US, True))
2287 XBell(dpy, 0);
2289 return;
2291 if (IS_TEAR_OFF_MENU(fw))
2293 /* 'soft' delete tear off menus. Note: we can't send the
2294 * message to the menu window directly because it was created
2295 * using a different display. The client message would never
2296 * be read from there. */
2297 send_clientmessage(
2298 dpy, FW_W_PARENT(fw), _XA_WM_DELETE_WINDOW,
2299 CurrentTime);
2301 return;
2303 if (WM_DELETES_WINDOW(fw))
2305 send_clientmessage(
2306 dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2308 return;
2310 else
2312 XBell(dpy, 0);
2314 XFlush(dpy);
2316 return;
2319 void CMD_Destroy(F_CMD_ARGS)
2321 FvwmWindow * const fw = exc->w.fw;
2323 if (IS_TEAR_OFF_MENU(fw))
2325 CMD_Delete(F_PASS_ARGS);
2326 return;
2328 if (!is_function_allowed(F_DESTROY, NULL, fw, True, True))
2330 XBell(dpy, 0);
2331 return;
2333 if (
2334 XGetGeometry(
2335 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2336 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2337 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2338 != 0)
2340 XKillClient(dpy, FW_W(fw));
2342 destroy_window(fw);
2343 XFlush(dpy);
2345 return;
2348 void CMD_Close(F_CMD_ARGS)
2350 FvwmWindow * const fw = exc->w.fw;
2352 if (IS_TEAR_OFF_MENU(fw))
2354 CMD_Delete(F_PASS_ARGS);
2355 return;
2357 if (!is_function_allowed(F_CLOSE, NULL, fw, True, True))
2359 XBell(dpy, 0);
2360 return;
2362 if (WM_DELETES_WINDOW(fw))
2364 send_clientmessage(
2365 dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2366 return;
2368 if (
2369 XGetGeometry(
2370 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2371 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2372 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2373 != 0)
2375 XKillClient(dpy, FW_W(fw));
2378 destroy_window(fw);
2379 XFlush(dpy);
2381 return;
2384 void CMD_Restart(F_CMD_ARGS)
2386 Done(1, action);
2388 return;
2391 void CMD_ExecUseShell(F_CMD_ARGS)
2393 char *arg=NULL;
2394 static char shell_set = 0;
2396 if (shell_set)
2398 free(exec_shell_name);
2400 shell_set = 1;
2401 action = GetNextToken(action,&arg);
2402 if (arg) /* specific shell was specified */
2404 exec_shell_name = arg;
2406 else /* no arg, so use $SHELL -- not working??? */
2408 if (getenv("SHELL"))
2410 exec_shell_name = safestrdup(getenv("SHELL"));
2412 else
2414 /* if $SHELL not set, use default */
2415 exec_shell_name = safestrdup("/bin/sh");
2420 void CMD_Exec(F_CMD_ARGS)
2422 char *cmd=NULL;
2424 /* if it doesn't already have an 'exec' as the first word, add that
2425 * to keep down number of procs started */
2426 /* need to parse string better to do this right though, so not doing
2427 * this for now... */
2428 #if 0
2429 if (strncasecmp(action,"exec",4)!=0)
2431 cmd = (char *)safemalloc(strlen(action)+6);
2432 strcpy(cmd,"exec ");
2433 strcat(cmd,action);
2435 else
2436 #endif
2438 cmd = safestrdup(action);
2440 if (!cmd)
2442 return;
2444 /* Use to grab the pointer here, but the fork guarantees that
2445 * we wont be held up waiting for the function to finish,
2446 * so the pointer-gram just caused needless delay and flashing
2447 * on the screen */
2448 /* Thought I'd try vfork and _exit() instead of regular fork().
2449 * The man page says that its better. */
2450 /* Not everyone has vfork! */
2451 /* According to the man page, vfork should never be used at all.
2454 if (!(fork())) /* child process */
2456 /* This is for fixing a problem with rox filer */
2457 int fd;
2459 fvmm_deinstall_signals();
2460 fd = open("/dev/null", O_RDONLY, 0);
2461 dup2(fd,STDIN_FILENO);
2463 if (fd != STDIN_FILENO)
2464 close(fd);
2466 if (fvwm_setpgrp() == -1)
2468 fvwm_msg(ERR, "exec_function", "setpgrp failed (%s)",
2469 strerror(errno));
2470 exit(100);
2472 if (execl(exec_shell_name, exec_shell_name, "-c", cmd, NULL) ==
2475 fvwm_msg(ERR, "exec_function", "execl failed (%s)",
2476 strerror(errno));
2477 exit(100);
2480 free(cmd);
2482 return;
2485 void CMD_Refresh(F_CMD_ARGS)
2487 refresh_window(Scr.Root, True);
2489 return;
2492 void CMD_RefreshWindow(F_CMD_ARGS)
2494 FvwmWindow * const fw = exc->w.fw;
2496 refresh_window(
2497 (exc->w.wcontext == C_ICON) ?
2498 FW_W_ICON_TITLE(fw) : FW_W_FRAME(fw), True);
2500 return;
2503 void CMD_Wait(F_CMD_ARGS)
2505 Bool done = False;
2506 Bool redefine_cursor = False;
2507 Bool is_ungrabbed;
2508 char *escape;
2509 Window nonewin = None;
2510 char *wait_string, *rest;
2511 FvwmWindow *t;
2513 /* try to get a single token */
2514 rest = GetNextToken(action, &wait_string);
2515 if (wait_string)
2517 while (*rest && isspace((unsigned char)*rest))
2519 rest++;
2521 if (*rest)
2523 int i;
2524 char *temp;
2526 /* nope, multiple tokens - try old syntax */
2528 /* strip leading and trailing whitespace */
2529 temp = action;
2530 while (*temp && isspace((unsigned char)*temp))
2532 temp++;
2534 wait_string = safestrdup(temp);
2535 for (i = strlen(wait_string) - 1; i >= 0 &&
2536 isspace(wait_string[i]); i--)
2538 wait_string[i] = 0;
2542 else
2544 wait_string = safestrdup("");
2547 is_ungrabbed = UngrabEm(GRAB_NORMAL);
2548 while (!done && !isTerminated)
2550 XEvent e;
2551 if (BUSY_WAIT & Scr.BusyCursor)
2553 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_WAIT]);
2554 redefine_cursor = True;
2556 if (My_XNextEvent(dpy, &e))
2558 dispatch_event(&e);
2559 if (XFindContext(
2560 dpy, e.xmap.window, FvwmContext,
2561 (caddr_t *)&t) == XCNOENT)
2563 t = NULL;
2566 if (e.type == MapNotify && e.xmap.event == Scr.Root)
2568 if (!*wait_string)
2570 done = True;
2572 if (t && matchWildcards(
2573 wait_string, t->name.name) == True)
2575 done = True;
2577 else if (t && t->class.res_class &&
2578 matchWildcards(
2579 wait_string,
2580 t->class.res_class) == True)
2582 done = True;
2584 else if (t && t->class.res_name &&
2585 matchWildcards(
2586 wait_string,
2587 t->class.res_name) == True)
2589 done = True;
2592 else if (e.type == KeyPress)
2594 /* should I be using <t> or <exc->w.fw>?
2595 * DV: t
2597 int context;
2598 XClassHint *class;
2599 char *name;
2601 context = GetContext(&t, t, &e, &nonewin);
2602 if (t != NULL)
2604 class = &(t->class);
2605 name = t->name.name;
2607 else
2609 class = NULL;
2610 name = NULL;
2612 escape = CheckBinding(
2613 Scr.AllBindings, STROKE_ARG(0)
2614 e.xkey.keycode, e.xkey.state,
2615 GetUnusedModifiers(), context,
2616 BIND_KEYPRESS, class, name);
2617 if (escape != NULL)
2619 if (!strcasecmp(escape,"escapefunc"))
2621 done = True;
2627 if (redefine_cursor)
2629 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
2631 if (is_ungrabbed)
2633 GrabEm(CRS_NONE, GRAB_NORMAL);
2635 free(wait_string);
2637 return;
2640 void CMD_Quit(F_CMD_ARGS)
2642 if (master_pid != getpid())
2644 kill(master_pid, SIGTERM);
2646 Done(0,NULL);
2648 return;
2651 void CMD_QuitScreen(F_CMD_ARGS)
2653 Done(0,NULL);
2655 return;
2658 void CMD_Echo(F_CMD_ARGS)
2660 int len;
2662 if (!action)
2664 action = "";
2666 len = strlen(action);
2667 if (len != 0)
2669 if (action[len-1]=='\n')
2671 action[len-1]='\0';
2674 fvwm_msg(ECHO,"Echo",action);
2676 return;
2679 void CMD_PrintInfo(F_CMD_ARGS)
2681 int verbose;
2682 char *rest, *subject = NULL;
2684 rest = GetNextToken(action, &subject);
2685 if (!rest || GetIntegerArguments(rest, NULL, &verbose, 1) != 1)
2687 verbose = 0;
2689 if (StrEquals(subject, "Colors"))
2691 PicturePrintColorInfo(verbose);
2693 else if (StrEquals(subject, "Locale"))
2695 FlocalePrintLocaleInfo(dpy, verbose);
2697 else if (StrEquals(subject, "NLS"))
2699 FGettextPrintLocalePath(verbose);
2701 else if (StrEquals(subject, "style"))
2703 print_styles(verbose);
2705 else if (StrEquals(subject, "ImageCache"))
2707 PicturePrintImageCache(verbose);
2709 else if (StrEquals(subject, "Bindings"))
2711 print_bindings();
2713 else
2715 fvwm_msg(ERR, "PrintInfo",
2716 "Unknown subject '%s'", action);
2718 if (subject)
2720 free(subject);
2722 return;
2725 void CMD_ColormapFocus(F_CMD_ARGS)
2727 if (MatchToken(action,"FollowsFocus"))
2729 Scr.ColormapFocus = COLORMAP_FOLLOWS_FOCUS;
2731 else if (MatchToken(action,"FollowsMouse"))
2733 Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
2735 else
2737 fvwm_msg(ERR, "SetColormapFocus",
2738 "ColormapFocus requires 1 arg: FollowsFocus or"
2739 " FollowsMouse");
2740 return;
2743 return;
2746 void CMD_ClickTime(F_CMD_ARGS)
2748 int val;
2750 if (GetIntegerArguments(action, NULL, &val, 1) != 1)
2752 Scr.ClickTime = DEFAULT_CLICKTIME;
2754 else
2756 Scr.ClickTime = (val < 0)? 0 : val;
2759 /* Use a negative value during startup and change sign afterwards. This
2760 * speeds things up quite a bit. */
2761 if (fFvwmInStartup)
2763 Scr.ClickTime = -Scr.ClickTime;
2766 return;
2770 void CMD_ImagePath(F_CMD_ARGS)
2772 PictureSetImagePath( action );
2774 return;
2777 void CMD_IconPath(F_CMD_ARGS)
2779 fvwm_msg(ERR, "iconPath_function",
2780 "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2781 obsolete_imagepaths( action );
2783 return;
2786 void CMD_PixmapPath(F_CMD_ARGS)
2788 fvwm_msg(ERR, "pixmapPath_function",
2789 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2790 " instead." );
2791 obsolete_imagepaths( action );
2793 return;
2796 void CMD_LocalePath(F_CMD_ARGS)
2798 FGettextSetLocalePath( action );
2800 return;
2803 void CMD_ModulePath(F_CMD_ARGS)
2805 static int need_to_free = 0;
2807 setPath( &ModulePath, action, need_to_free );
2808 need_to_free = 1;
2810 return;
2813 void CMD_ModuleTimeout(F_CMD_ARGS)
2815 int timeout;
2817 moduleTimeout = DEFAULT_MODULE_TIMEOUT;
2818 if (GetIntegerArguments(action, NULL, &timeout, 1) == 1 && timeout > 0)
2820 moduleTimeout = timeout;
2823 return;
2826 void CMD_HilightColor(F_CMD_ARGS)
2828 char *fore;
2829 char *back;
2830 #ifdef USEDECOR
2831 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2833 fvwm_msg(
2834 ERR, "SetHiColor",
2835 "Decors do not support the HilightColor command"
2836 " anymore. Please use"
2837 " 'Style <stylename> HilightFore <forecolor>' and"
2838 " 'Style <stylename> HilightBack <backcolor>' instead."
2839 " Sorry for the inconvenience.");
2840 return;
2842 #endif
2843 action = GetNextToken(action, &fore);
2844 GetNextToken(action, &back);
2845 if (fore && back)
2847 action = safemalloc(strlen(fore) + strlen(back) + 29);
2848 sprintf(action, "* HilightFore %s, HilightBack %s", fore, back);
2849 CMD_Style(F_PASS_ARGS);
2851 if (fore)
2853 free(fore);
2855 if (back)
2857 free(back);
2860 return;
2863 void CMD_HilightColorset(F_CMD_ARGS)
2865 char *newaction;
2867 #ifdef USEDECOR
2868 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2870 fvwm_msg(
2871 ERR, "SetHiColorset",
2872 "Decors do not support the HilightColorset command "
2873 "anymore. Please use "
2874 "'Style <stylename> HilightColorset <colorset>'"
2875 " instead. Sorry for the inconvenience.");
2876 return;
2878 #endif
2879 if (action)
2881 newaction = safemalloc(strlen(action) + 32);
2882 sprintf(newaction, "* HilightColorset %s", action);
2883 action = newaction;
2884 CMD_Style(F_PASS_ARGS);
2885 free(newaction);
2888 return;
2891 void CMD_TitleStyle(F_CMD_ARGS)
2893 do_title_style(F_PASS_ARGS, False);
2895 return;
2896 } /* SetTitleStyle */
2900 * Appends a titlestyle (veliaa@rpi.edu)
2903 void CMD_AddTitleStyle(F_CMD_ARGS)
2905 do_title_style(F_PASS_ARGS, True);
2907 return;
2910 void CMD_PropertyChange(F_CMD_ARGS)
2912 char string[256];
2913 char *token;
2914 char *rest;
2915 int ret;
2916 unsigned long argument;
2917 unsigned long data1;
2918 unsigned long data2;
2920 /* argument */
2921 token = PeekToken(action, &rest);
2922 if (token == NULL)
2924 return;
2926 ret = sscanf(token, "%lu", &argument);
2927 if (ret < 1)
2929 return;
2931 /* data1 */
2932 data1 = 0;
2933 token = PeekToken(rest, &rest);
2934 if (token != NULL)
2936 ret = sscanf(token, "%lu", &data1);
2937 if (ret < 1)
2939 rest = NULL;
2942 /* data2 */
2943 data2 = 0;
2944 token = PeekToken(rest, &rest);
2945 if (token != NULL)
2947 ret = sscanf(token, "%lu", &data2);
2948 if (ret < 1)
2950 rest = NULL;
2953 /* string */
2954 memset(string, 0, 256);
2955 if (rest != NULL)
2957 ret = sscanf(rest, "%255c", &(string[0]));
2959 BroadcastPropertyChange(argument, data1, data2, string);
2961 return;
2964 void CMD_DefaultIcon(F_CMD_ARGS)
2966 if (Scr.DefaultIcon)
2968 free(Scr.DefaultIcon);
2970 GetNextToken(action, &Scr.DefaultIcon);
2972 return;
2975 void CMD_DefaultColorset(F_CMD_ARGS)
2977 int cset;
2979 if (GetIntegerArguments(action, NULL, &cset, 1) != 1)
2981 return;
2983 Scr.DefaultColorset = cset;
2984 if (Scr.DefaultColorset < 0)
2986 Scr.DefaultColorset = -1;
2988 alloc_colorset(Scr.DefaultColorset);
2989 Scr.flags.do_need_window_update = 1;
2990 Scr.flags.has_default_color_changed = 1;
2992 return;
2995 void CMD_DefaultColors(F_CMD_ARGS)
2997 char *fore = NULL;
2998 char *back = NULL;
3000 action = GetNextToken(action, &fore);
3001 if (action)
3003 action = GetNextToken(action, &back);
3005 if (!back)
3007 back = safestrdup(DEFAULT_BACK_COLOR);
3009 if (!fore)
3011 fore = safestrdup(DEFAULT_FORE_COLOR);
3013 if (!StrEquals(fore, "-"))
3015 PictureFreeColors(dpy, Pcmap, &Scr.StdFore, 1, 0, True);
3016 Scr.StdFore = GetColor(fore);
3018 if (!StrEquals(back, "-"))
3020 PictureFreeColors(dpy, Pcmap, &Scr.StdBack, 3, 0, True);
3021 Scr.StdBack = GetColor(back);
3022 Scr.StdHilite = GetHilite(Scr.StdBack);
3023 Scr.StdShadow = GetShadow(Scr.StdBack);
3025 free(fore);
3026 free(back);
3028 Scr.DefaultColorset = -1;
3029 Scr.flags.do_need_window_update = 1;
3030 Scr.flags.has_default_color_changed = 1;
3032 return;
3035 void CMD_DefaultFont(F_CMD_ARGS)
3037 char *font;
3038 FlocaleFont *new_font;
3039 FvwmWindow *t;
3041 font = PeekToken(action, &action);
3042 if (!font)
3044 /* Try 'fixed', pass NULL font name */
3046 if (!(new_font = FlocaleLoadFont(dpy, font, "fvwm")))
3048 if (Scr.DefaultFont == NULL)
3050 exit(1);
3052 else
3054 return;
3057 FlocaleUnloadFont(dpy, Scr.DefaultFont);
3058 Scr.DefaultFont = new_font;
3059 /* we should do that here because a redraw can happen before
3060 flush_window_updates is called ... */
3061 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
3063 if (USING_DEFAULT_ICON_FONT(t))
3065 t->icon_font = Scr.DefaultFont;
3067 if (USING_DEFAULT_WINDOW_FONT(t))
3069 t->title_font = Scr.DefaultFont;
3072 /* set flags to indicate that the font has changed */
3073 Scr.flags.do_need_window_update = 1;
3074 Scr.flags.has_default_font_changed = 1;
3076 return;
3079 void CMD_IconFont(F_CMD_ARGS)
3081 char *newaction;
3083 #ifdef USEDECOR
3084 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3086 fvwm_msg(
3087 ERR, "LoadIconFont",
3088 "Decors do not support the IconFont command anymore."
3089 " Please use 'Style <stylename> IconFont <fontname>'"
3090 " instead. Sorry for the inconvenience.");
3091 return;
3093 #endif
3094 if (action)
3096 newaction = safemalloc(strlen(action) + 16);
3097 sprintf(newaction, "* IconFont %s", action);
3098 action = newaction;
3099 CMD_Style(F_PASS_ARGS);
3100 free(newaction);
3103 return;
3106 void CMD_WindowFont(F_CMD_ARGS)
3108 char *newaction;
3110 #ifdef USEDECOR
3111 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3113 fvwm_msg(
3114 ERR, "LoadWindowFont",
3115 "Decors do not support the WindowFont command anymore."
3116 " Please use 'Style <stylename> Font <fontname>'"
3117 " instead. Sorry for the inconvenience.");
3118 return;
3120 #endif
3121 if (action)
3123 newaction = safemalloc(strlen(action) + 16);
3124 sprintf(newaction, "* Font %s", action);
3125 action = newaction;
3126 CMD_Style(F_PASS_ARGS);
3127 free(newaction);
3130 return;
3135 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3138 void CMD_ChangeDecor(F_CMD_ARGS)
3140 char *item;
3141 int old_height;
3142 FvwmDecor *decor = &Scr.DefaultDecor;
3143 FvwmDecor *found = NULL;
3144 FvwmWindow * const fw = exc->w.fw;
3146 item = PeekToken(action, &action);
3147 if (!action || !item)
3149 return;
3151 /* search for tag */
3152 for (; decor; decor = decor->next)
3154 if (decor->tag && StrEquals(item, decor->tag))
3156 found = decor;
3157 break;
3160 if (!found)
3162 XBell(dpy, 0);
3163 return;
3165 SET_DECOR_CHANGED(fw, 1);
3166 old_height = (fw->decor) ? fw->decor->title_height : 0;
3167 fw->decor = found;
3168 apply_decor_change(fw);
3170 return;
3175 * Destroys an FvwmDecor (veliaa@rpi.edu)
3178 void CMD_DestroyDecor(F_CMD_ARGS)
3180 char *item;
3181 FvwmDecor *decor = Scr.DefaultDecor.next;
3182 FvwmDecor *prev = &Scr.DefaultDecor, *found = NULL;
3183 Bool do_recreate = False;
3185 item = PeekToken(action, &action);
3186 if (!item)
3188 return;
3190 if (StrEquals(item, "recreate"))
3192 do_recreate = True;
3193 item = PeekToken(action, NULL);
3195 if (!item)
3197 return;
3200 /* search for tag */
3201 for (; decor; decor = decor->next)
3203 if (decor->tag && StrEquals(item, decor->tag))
3205 found = decor;
3206 break;
3208 prev = decor;
3211 if (found && (found != &Scr.DefaultDecor || do_recreate))
3213 if (!do_recreate)
3215 __remove_window_decors(F_PASS_ARGS, found);
3217 DestroyFvwmDecor(found);
3218 if (do_recreate)
3220 int i;
3222 InitFvwmDecor(found);
3223 found->tag = safestrdup(item);
3224 Scr.flags.do_need_window_update = 1;
3225 found->flags.has_changed = 1;
3226 found->flags.has_title_height_changed = 0;
3227 found->titlebar.flags.has_changed = 1;
3228 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
3230 TB_FLAGS(found->buttons[i]).has_changed = 1;
3233 else
3235 prev->next = found->next;
3236 free(found);
3240 return;
3245 * Initiates an AddToDecor (veliaa@rpi.edu)
3248 void CMD_AddToDecor(F_CMD_ARGS)
3250 FvwmDecor *decor;
3251 FvwmDecor *found = NULL;
3252 char *item = NULL;
3254 action = GetNextToken(action, &item);
3255 if (!item)
3257 return;
3259 if (!action)
3261 free(item);
3262 return;
3264 /* search for tag */
3265 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3267 if (decor->tag && StrEquals(item, decor->tag))
3269 found = decor;
3270 break;
3273 if (!found)
3275 /* then make a new one */
3276 found = (FvwmDecor *)safemalloc(sizeof( FvwmDecor ));
3277 InitFvwmDecor(found);
3278 found->tag = item; /* tag it */
3279 /* add it to list */
3280 for (decor = &Scr.DefaultDecor; decor->next;
3281 decor = decor->next)
3283 /* nop */
3285 decor->next = found;
3287 else
3289 free(item);
3292 if (found)
3294 AddToDecor(F_PASS_ARGS, found);
3295 /* Set + state to last decor */
3296 set_last_added_item(ADDED_DECOR, found);
3299 return;
3301 #endif /* USEDECOR */
3306 * Updates window decoration styles (veliaa@rpi.edu)
3309 void CMD_UpdateDecor(F_CMD_ARGS)
3311 FvwmWindow *fw2;
3312 #ifdef USEDECOR
3313 FvwmDecor *decor, *found = NULL;
3314 FvwmWindow *hilight = Scr.Hilite;
3315 char *item = NULL;
3317 action = GetNextToken(action, &item);
3318 if (item)
3320 /* search for tag */
3321 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3323 if (decor->tag && StrEquals(item, decor->tag))
3325 found = decor;
3326 break;
3329 free(item);
3331 #endif
3333 for (fw2 = Scr.FvwmRoot.next; fw2; fw2 = fw2->next)
3335 #ifdef USEDECOR
3336 /* update specific decor, or all */
3337 if (found)
3339 if (fw2->decor == found)
3341 border_draw_decorations(
3342 fw2, PART_ALL, True, True, CLEAR_ALL,
3343 NULL, NULL);
3344 border_draw_decorations(
3345 fw2, PART_ALL, False, True, CLEAR_ALL,
3346 NULL, NULL);
3349 else
3350 #endif
3352 border_draw_decorations(
3353 fw2, PART_ALL, True, True, CLEAR_ALL, NULL,
3354 NULL);
3355 border_draw_decorations(
3356 fw2, PART_ALL, False, True, CLEAR_ALL, NULL,
3357 NULL);
3360 border_draw_decorations(
3361 hilight, PART_ALL, True, True, CLEAR_ALL, NULL, NULL);
3364 void CMD_ButtonStyle(F_CMD_ARGS)
3366 do_button_style(F_PASS_ARGS, False);
3368 return;
3373 * Appends a button decoration style (veliaa@rpi.edu)
3376 void CMD_AddButtonStyle(F_CMD_ARGS)
3378 do_button_style(F_PASS_ARGS, True);
3380 return;
3383 void CMD_SetEnv(F_CMD_ARGS)
3385 char *szVar = NULL;
3386 char *szValue = NULL;
3387 char *szPutenv = NULL;
3389 action = GetNextToken(action, &szVar);
3390 if (!szVar)
3392 return;
3394 action = GetNextToken(action, &szValue);
3395 if (!szValue)
3397 szValue = safestrdup("");
3399 szPutenv = safemalloc(strlen(szVar) + strlen(szValue) + 2);
3400 sprintf(szPutenv,"%s=%s", szVar, szValue);
3401 flib_putenv(szVar, szPutenv);
3402 free(szVar);
3403 free(szPutenv);
3404 free(szValue);
3406 return;
3409 void CMD_UnsetEnv(F_CMD_ARGS)
3411 char *szVar = NULL;
3413 szVar = PeekToken(action, &action);
3414 if (!szVar)
3416 return;
3418 flib_unsetenv(szVar);
3420 return;
3423 void CMD_GlobalOpts(F_CMD_ARGS)
3425 char *opt;
3426 char *replace;
3427 char buf[64];
3428 int i;
3429 Bool is_bugopt;
3430 char *optlist[] = {
3431 "WindowShadeShrinks",
3432 "WindowShadeScrolls",
3433 "SmartPlacementIsReallySmart",
3434 "SmartPlacementIsNormal",
3435 "ClickToFocusDoesntPassClick",
3436 "ClickToFocusPassesClick",
3437 "ClickToFocusDoesntRaise",
3438 "ClickToFocusRaises",
3439 "MouseFocusClickDoesntRaise",
3440 "MouseFocusClickRaises",
3441 "NoStipledTitles",
3442 "StipledTitles",
3443 "CaptureHonorsStartsOnPage",
3444 "CaptureIgnoresStartsOnPage",
3445 "RecaptureHonorsStartsOnPage",
3446 "RecaptureIgnoresStartsOnPage",
3447 "ActivePlacementHonorsStartsOnPage",
3448 "ActivePlacementIgnoresStartsOnPage",
3449 "RaiseOverNativeWindows",
3450 "IgnoreNativeWindows",
3451 NULL
3453 char *replacelist[] = {
3454 /* These options are mapped to the Style * command */
3455 NULL, /* NULL means to use "Style * <optionname>" */
3456 NULL,
3457 "* MinOverlapPlacement",
3458 "* TileCascadePlacement",
3459 "* ClickToFocusPassesClickOff",
3460 "* ClickToFocusPassesClick",
3461 "* ClickToFocusRaisesOff",
3462 "* ClickToFocusRaises",
3463 "* MouseFocusClickRaisesOff",
3464 "* MouseFocusClickRaises",
3465 "* StippledTitleOff",
3466 "* StippledTitle",
3467 NULL,
3468 NULL,
3469 NULL,
3470 NULL,
3471 "* ManualPlacementHonorsStartsOnPage",
3472 "* ManualPlacementIgnoresStartsOnPage",
3473 /* These options are mapped to the BugOpts command */
3474 "RaiseOverNativeWindows on",
3475 "RaiseOverNativeWindows off"
3478 fvwm_msg(ERR, "SetGlobalOptions",
3479 "The GlobalOpts command is obsolete.");
3480 for (action = GetNextSimpleOption(action, &opt); opt;
3481 action = GetNextSimpleOption(action, &opt))
3483 replace = NULL;
3484 is_bugopt = False;
3486 i = GetTokenIndex(opt, optlist, 0, NULL);
3487 if (i > -1)
3489 char *cmd;
3490 char *tmp;
3492 replace = replacelist[i];
3493 if (replace == NULL)
3495 replace = &(buf[0]);
3496 sprintf(buf, "* %s", opt);
3498 else if (*replace != '*')
3500 is_bugopt = True;
3502 tmp = action;
3503 action = replace;
3504 if (!is_bugopt)
3506 CMD_Style(F_PASS_ARGS);
3507 cmd = "Style";
3509 else
3511 CMD_BugOpts(F_PASS_ARGS);
3512 cmd = "BugOpts";
3514 action = tmp;
3515 fvwm_msg(
3516 ERR, "SetGlobalOptions",
3517 "Please replace 'GlobalOpts %s' with '%s %s'.",
3518 opt, cmd, replace);
3520 else
3522 fvwm_msg(ERR, "SetGlobalOptions",
3523 "Unknown Global Option '%s'", opt);
3525 /* should never be null, but checking anyways... */
3526 if (opt)
3528 free(opt);
3531 if (opt)
3533 free(opt);
3536 return;
3539 void CMD_BugOpts(F_CMD_ARGS)
3541 char *opt;
3542 int toggle;
3543 char *optstring;
3545 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3546 while (action && *action && *action != '\n')
3548 action = GetNextFullOption(action, &optstring);
3549 if (!optstring)
3551 /* no more options */
3552 return;
3554 toggle = ParseToggleArgument(
3555 SkipNTokens(optstring,1), NULL, 2, False);
3556 opt = PeekToken(optstring, NULL);
3557 free(optstring);
3559 if (!opt)
3561 return;
3563 /* toggle = ParseToggleArgument(rest, &rest, 2, False);*/
3565 if (StrEquals(opt, "FlickeringMoveWorkaround"))
3567 switch (toggle)
3569 case -1:
3570 Scr.bo.do_disable_configure_notify ^= 1;
3571 break;
3572 case 0:
3573 case 1:
3574 Scr.bo.do_disable_configure_notify = toggle;
3575 break;
3576 default:
3577 Scr.bo.do_disable_configure_notify = 0;
3578 break;
3581 else if (StrEquals(opt, "MixedVisualWorkaround"))
3583 switch (toggle)
3585 case -1:
3586 Scr.bo.do_install_root_cmap ^= 1;
3587 break;
3588 case 0:
3589 case 1:
3590 Scr.bo.do_install_root_cmap = toggle;
3591 break;
3592 default:
3593 Scr.bo.do_install_root_cmap = 0;
3594 break;
3597 else if (StrEquals(opt, "ModalityIsEvil"))
3599 switch (toggle)
3601 case -1:
3602 Scr.bo.is_modality_evil ^= 1;
3603 break;
3604 case 0:
3605 case 1:
3606 Scr.bo.is_modality_evil = toggle;
3607 break;
3608 default:
3609 Scr.bo.is_modality_evil = 0;
3610 break;
3612 if (Scr.bo.is_modality_evil)
3614 SetMWM_INFO(Scr.NoFocusWin);
3617 else if (StrEquals(opt, "RaiseOverNativeWindows"))
3619 switch (toggle)
3621 case -1:
3622 Scr.bo.is_raise_hack_needed ^= 1;
3623 break;
3624 case 0:
3625 case 1:
3626 Scr.bo.is_raise_hack_needed = toggle;
3627 break;
3628 default:
3629 Scr.bo.is_raise_hack_needed = 0;
3630 break;
3633 else if (StrEquals(opt, "RaiseOverUnmanaged"))
3635 switch (toggle)
3637 case -1:
3638 Scr.bo.do_raise_over_unmanaged ^= 1;
3639 break;
3640 case 0:
3641 case 1:
3642 Scr.bo.do_raise_over_unmanaged = toggle;
3643 break;
3644 default:
3645 Scr.bo.do_raise_over_unmanaged = 0;
3646 break;
3649 else if (StrEquals(opt, "FlickeringQtDialogsWorkaround"))
3651 switch (toggle)
3653 case -1:
3654 Scr.bo.do_enable_flickering_qt_dialogs_workaround ^= 1;
3655 break;
3656 case 0:
3657 case 1:
3658 Scr.bo.do_enable_flickering_qt_dialogs_workaround = toggle;
3659 break;
3660 default:
3661 Scr.bo.do_enable_flickering_qt_dialogs_workaround = 0;
3662 break;
3665 else if (StrEquals(opt, "QtDragnDropWorkaround") )
3667 switch (toggle)
3669 case -1:
3670 Scr.bo.do_enable_qt_drag_n_drop_workaround ^= 1;
3671 break;
3672 case 0:
3673 case 1:
3674 Scr.bo.do_enable_qt_drag_n_drop_workaround = toggle;
3675 break;
3676 default:
3677 Scr.bo.do_enable_qt_drag_n_drop_workaround = 0;
3678 break;
3681 else if (EWMH_BugOpts(opt, toggle))
3683 /* work is done in EWMH_BugOpts */
3685 else if (StrEquals(opt, "DisplayNewWindowNames"))
3687 switch (toggle)
3689 case -1:
3690 Scr.bo.do_display_new_window_names ^= 1;
3691 break;
3692 case 0:
3693 case 1:
3694 Scr.bo.do_display_new_window_names = toggle;
3695 break;
3696 default:
3697 Scr.bo.do_display_new_window_names = 0;
3698 break;
3701 else if (StrEquals(opt, "ExplainWindowPlacement"))
3703 switch (toggle)
3705 case -1:
3706 Scr.bo.do_explain_window_placement ^= 1;
3707 break;
3708 case 0:
3709 case 1:
3710 Scr.bo.do_explain_window_placement = toggle;
3711 break;
3712 default:
3713 Scr.bo.do_explain_window_placement = 0;
3714 break;
3717 else if (StrEquals(opt, "DebugCRMotionMethod"))
3719 switch (toggle)
3721 case -1:
3722 Scr.bo.do_debug_cr_motion_method ^= 1;
3723 break;
3724 case 0:
3725 case 1:
3726 Scr.bo.do_debug_cr_motion_method = toggle;
3727 break;
3728 default:
3729 Scr.bo.do_debug_cr_motion_method = 0;
3730 break;
3733 else if (StrEquals(opt, "TransliterateUtf8"))
3735 FiconvSetTransliterateUtf8(toggle);
3737 else
3739 fvwm_msg(ERR, "SetBugOptions",
3740 "Unknown Bug Option '%s'", opt);
3744 return;
3747 void CMD_Emulate(F_CMD_ARGS)
3749 char *style;
3751 style = PeekToken(action, NULL);
3752 if (!style || StrEquals(style, "fvwm"))
3754 Scr.gs.do_emulate_mwm = False;
3755 Scr.gs.do_emulate_win = False;
3757 else if (StrEquals(style, "mwm"))
3759 Scr.gs.do_emulate_mwm = True;
3760 Scr.gs.do_emulate_win = False;
3762 else if (StrEquals(style, "win"))
3764 Scr.gs.do_emulate_mwm = False;
3765 Scr.gs.do_emulate_win = True;
3767 else
3769 fvwm_msg(ERR, "Emulate", "Unknown style '%s'", style);
3770 return;
3772 Scr.flags.do_need_window_update = 1;
3773 Scr.flags.has_default_font_changed = 1;
3774 Scr.flags.has_default_color_changed = 1;
3776 return;
3779 void CMD_ColorLimit(F_CMD_ARGS)
3781 fvwm_msg(
3782 WARN, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3783 "fvwm -color-limit option");
3785 return;
3789 /* set animation parameters */
3790 void CMD_SetAnimation(F_CMD_ARGS)
3792 char *opt;
3793 int delay;
3794 float pct;
3795 int i = 0;
3797 opt = PeekToken(action, &action);
3798 if (!opt || sscanf(opt,"%d",&delay) != 1)
3800 fvwm_msg(ERR,"SetAnimation",
3801 "Improper milli-second delay as first argument");
3802 return;
3804 if (delay > 500)
3806 fvwm_msg(WARN,"SetAnimation",
3807 "Using longer than .5 seconds as between frame"
3808 " animation delay");
3810 cmsDelayDefault = delay;
3811 for (opt = PeekToken(action, &action); opt;
3812 opt = PeekToken(action, &action))
3814 if (sscanf(opt,"%f",&pct) != 1)
3816 fvwm_msg(ERR,"SetAnimation",
3817 "Use fractional values ending in 1.0 as args"
3818 " 2 and on");
3819 return;
3821 rgpctMovementDefault[i++] = pct;
3823 /* No pct entries means don't change them at all */
3824 if (i > 0 && rgpctMovementDefault[i-1] != 1.0)
3826 rgpctMovementDefault[i++] = 1.0;
3829 return;
3832 /* Determine which modifiers are required with a keycode to make <keysym>. */
3833 static Bool FKeysymToKeycode (Display *dpy, KeySym keysym,
3834 unsigned int *keycode, unsigned int *modifiers)
3836 int m;
3838 *keycode = XKeysymToKeycode(dpy, keysym);
3839 *modifiers = 0;
3841 for (m = 0; m <= 8; ++m)
3843 KeySym ks = XKeycodeToKeysym(dpy, *keycode, m);
3844 if (ks == keysym)
3846 switch (m)
3848 case 0: /* No modifiers */
3849 break;
3850 case 1: /* Shift modifier */
3851 *modifiers |= ShiftMask;
3852 break;
3853 default:
3854 fvwm_msg(ERR, "FKeysymToKeycode",
3855 "Unhandled modifier %d", m);
3856 break;
3858 return True;
3861 return False;
3864 static void __fake_event(F_CMD_ARGS, FakeEventType type)
3866 char *token;
3867 char *optlist[] = {
3868 "press", "p",
3869 "release", "r",
3870 "wait", "w",
3871 "modifiers", "m",
3872 "depth", "d",
3873 NULL
3875 unsigned int mask = 0;
3876 Window root = Scr.Root;
3877 int maxdepth = 0;
3878 static char args[128];
3879 strncpy(args, action, sizeof(args) - 1);
3881 /* get the mask of pressed/released buttons/keys */
3882 FQueryPointer(
3883 dpy, Scr.Root, &root, &JunkRoot, &JunkX, &JunkY, &JunkX,
3884 &JunkY, &mask);
3886 token = PeekToken(action, &action);
3887 while (token && action)
3889 int index = GetTokenIndex(token, optlist, 0, NULL);
3890 int val, depth;
3891 XEvent e;
3892 Window w;
3893 Window child_w;
3894 int x = 0;
3895 int y = 0;
3896 int rx = 0;
3897 int ry = 0;
3898 Bool do_unset;
3899 long add_mask = 0;
3900 KeySym keysym = NoSymbol;
3902 XFlush(dpy);
3903 do_unset = True;
3904 switch (index)
3906 case 0:
3907 case 1:
3908 do_unset = False;
3909 /* fall through */
3910 case 2:
3911 case 3:
3912 /* key/button press or release */
3913 if (type == FakeMouseEvent)
3915 if ((GetIntegerArguments(
3916 action, &action, &val, 1) != 1) ||
3917 val < 1 ||
3918 val > NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
3920 fvwm_msg(
3921 ERR, "__fake_event",
3922 "Invalid button specifier in"
3923 " \"%s\" for FakeClick.", args);
3924 return; /* error */
3927 else /* type == FakeKeyEvent */
3929 char *key = PeekToken(action, &action);
3930 if (key == NULL)
3932 fvwm_msg(
3933 ERR, "__fake_event",
3934 "No keysym specifier in \"%s\""
3935 " for FakeKeypress.", args);
3936 return;
3939 /* Do *NOT* use FvwmStringToKeysym() as it is
3940 * case insensitive. */
3941 keysym = XStringToKeysym(key);
3942 if (keysym == NoSymbol)
3944 fvwm_msg(
3945 ERR, "__fake_event",
3946 "Invalid keysym specifier (%s)"
3947 " in \"%s\" for FakeKeypress.",
3948 key, args);
3949 return;
3953 w = None;
3954 child_w = root;
3955 for (depth = 1;
3956 depth != maxdepth &&
3957 w != child_w && child_w != None;
3958 depth++)
3960 w = child_w;
3961 if (FQueryPointer(
3962 dpy, w, &root, &child_w,
3963 &rx, &ry, &x, &y,
3964 &JunkMask) == False)
3966 /* pointer is on a different
3967 * screen - that's okay here */
3971 if (type == FakeMouseEvent)
3973 e.type = (do_unset) ?
3974 ButtonRelease : ButtonPress;
3975 e.xbutton.display = dpy;
3976 e.xbutton.window = w;
3977 e.xbutton.subwindow = None;
3978 e.xbutton.root = root;
3979 e.xbutton.time = fev_get_evtime();
3980 e.xbutton.x = x;
3981 e.xbutton.y = y;
3982 e.xbutton.x_root = rx;
3983 e.xbutton.y_root = ry;
3984 e.xbutton.button = val;
3985 e.xbutton.state = mask;
3986 e.xbutton.same_screen = (Scr.Root == root);
3987 /* SS: I think this mask handling code is
3988 * buggy.
3989 * The value of <mask> is overridden during a
3990 * "wait" operation. Also why are we only using
3991 * Button1Mask? What if the user has requested
3992 * a FakeClick using some other button? */
3993 /* DV: Button1Mask is actually a bit. Shifting
3994 * it by (val -1) bits to the left gives
3995 * Button2Mask, Button3Mask etc. */
3996 if (do_unset)
3998 mask &= ~(Button1Mask << (val - 1));
4000 else
4002 mask |= (Button1Mask << (val - 1));
4004 add_mask = (do_unset) ?
4005 ButtonPressMask : ButtonReleaseMask;
4007 else
4009 /* type == FakeKeyEvent */
4010 e.type = (do_unset ? KeyRelease : KeyPress);
4011 e.xkey.display = dpy;
4012 e.xkey.subwindow = None;
4013 e.xkey.root = root;
4014 e.xkey.time = fev_get_evtime();
4015 e.xkey.x = x;
4016 e.xkey.y = y;
4017 e.xkey.x_root = rx;
4018 e.xkey.y_root = ry;
4019 e.xkey.same_screen = (Scr.Root == root);
4021 w = e.xkey.window = exc->w.w;
4023 if (FKeysymToKeycode(
4024 dpy, keysym, &(e.xkey.keycode),
4025 &(e.xkey.state)) != True)
4027 fvwm_msg(DBG, "__fake_event",
4028 "FKeysymToKeycode failed");
4029 return;
4031 e.xkey.state |= mask;
4032 add_mask = (do_unset) ?
4033 KeyReleaseMask : KeyPressMask;
4035 FSendEvent(dpy, w, True,
4036 SubstructureNotifyMask | add_mask, &e);
4037 XFlush(dpy);
4038 break;
4039 case 4:
4040 case 5:
4041 /* wait */
4042 if ((GetIntegerArguments(
4043 action, &action, &val, 1) != 1) ||
4044 val <= 0 || val > 1000000)
4046 fvwm_msg(ERR, "__fake_event",
4047 "Invalid wait value in \"%s\"", args);
4048 return;
4051 usleep(1000 * val);
4052 if (FQueryPointer(
4053 dpy, Scr.Root, &root, &JunkRoot,
4054 &JunkX, &JunkY, &JunkX, &JunkY,
4055 &mask) == False)
4057 /* pointer is on a different screen -
4058 * that's okay here */
4060 break;
4061 case 6:
4062 case 7:
4063 /* set modifier */
4064 if (GetIntegerArguments(action, &action, &val, 1) != 1)
4066 fvwm_msg(
4067 ERR, "__fake_event",
4068 "Invalid modifier value in \"%s\"",
4069 args);
4070 return;
4072 do_unset = False;
4073 if (val < 0)
4075 do_unset = True;
4076 val = -val;
4078 if (val == 6)
4080 val = ShiftMask;
4082 else if (val == 7)
4084 val = LockMask;
4086 else if (val == 8)
4088 val = ControlMask;
4090 else if (val >=1 && val <= 5)
4092 val = (Mod1Mask << (val - 1));
4094 else
4096 /* error */
4097 return;
4099 /* SS: Could be buggy if a "modifier" operation
4100 * preceeds a "wait" operation. */
4101 if (do_unset)
4103 mask &= ~val;
4105 else
4107 mask |= val;
4109 break;
4110 case 8:
4111 case 9:
4112 /* new max depth */
4113 if (GetIntegerArguments(action, &action, &val, 1) != 1)
4115 fvwm_msg(ERR, "__fake_event",
4116 "Invalid depth value in \"%s\"", args);
4117 return;
4119 maxdepth = val;
4120 break;
4121 default:
4122 fvwm_msg(ERR, "__fake_event",
4123 "Invalid command (%s) in \"%s\"", token, args);
4124 return;
4126 if (action)
4128 token = PeekToken(action, &action);
4132 return;
4135 void CMD_FakeClick(F_CMD_ARGS)
4137 __fake_event(F_PASS_ARGS, FakeMouseEvent);
4139 return;
4142 void CMD_FakeKeypress(F_CMD_ARGS)
4144 __fake_event(F_PASS_ARGS, FakeKeyEvent);
4146 return;
4149 /* A function to handle stroke (olicha Nov 11, 1999) */
4150 #ifdef HAVE_STROKE
4151 void CMD_StrokeFunc(F_CMD_ARGS)
4153 int finished = 0;
4154 int abort = 0;
4155 int modifiers = exc->x.etrigger->xbutton.state;
4156 int start_event_type = exc->x.etrigger->type;
4157 char sequence[STROKE_MAX_SEQUENCE + 1];
4158 char *stroke_action, *name;
4159 char *opt = NULL;
4160 Bool finish_on_release = True;
4161 KeySym keysym;
4162 Bool restore_repeat = False;
4163 Bool echo_sequence = False;
4164 Bool draw_motion = False;
4165 int i = 0;
4166 int *x = NULL;
4167 int *y = NULL;
4168 const int STROKE_CHUNK_SIZE = 0xff;
4169 int coords_size = STROKE_CHUNK_SIZE;
4170 Window JunkRoot, JunkChild;
4171 int JunkX, JunkY;
4172 int tmpx, tmpy;
4173 unsigned int JunkMask;
4174 Bool feed_back = False;
4175 int stroke_width = 1;
4176 XEvent e;
4177 XClassHint *class;
4181 if (!GrabEm(CRS_STROKE, GRAB_NORMAL))
4183 XBell(dpy, 0);
4184 return;
4186 x = (int*)safemalloc(coords_size * sizeof(int));
4187 y = (int*)safemalloc(coords_size * sizeof(int));
4188 e = *exc->x.etrigger;
4189 /* set the default option */
4190 if (e.type == KeyPress || e.type == ButtonPress)
4192 finish_on_release = True;
4194 else
4196 finish_on_release = False;
4199 /* parse the option */
4200 for (action = GetNextSimpleOption(action, &opt); opt;
4201 action = GetNextSimpleOption(action, &opt))
4203 if (StrEquals("NotStayPressed",opt))
4205 finish_on_release = False;
4207 else if (StrEquals("EchoSequence",opt))
4209 echo_sequence = True;
4211 else if (StrEquals("DrawMotion",opt))
4213 draw_motion = True;
4215 else if (StrEquals("FeedBack",opt))
4217 feed_back = True;
4219 else if (StrEquals("StrokeWidth",opt))
4221 /* stroke width takes a positive integer argument */
4222 if (opt)
4224 free(opt);
4226 action = GetNextToken(action, &opt);
4227 if (!opt)
4229 fvwm_msg(
4230 WARN, "StrokeWidth",
4231 "needs an integer argument");
4233 /* we allow stroke_width == 0 which means drawing a
4234 * `fast' line of width 1; the upper level of 100 is
4235 * arbitrary */
4236 else if (!sscanf(opt, "%d", &stroke_width) ||
4237 stroke_width < 0 || stroke_width > 100)
4239 fvwm_msg(
4240 WARN, "StrokeWidth",
4241 "Bad integer argument %d",
4242 stroke_width);
4243 stroke_width = 1;
4246 else
4248 fvwm_msg(WARN,"StrokeFunc","Unknown option %s", opt);
4250 if (opt)
4252 free(opt);
4255 if (opt)
4257 free(opt);
4260 /* Force auto repeat off and grab the Keyboard to get proper
4261 * KeyRelease events if we need it.
4262 * Some computers do not support KeyRelease events, can we
4263 * check this here ? No ? */
4264 if (start_event_type == KeyPress && finish_on_release)
4266 XKeyboardState kstate;
4268 XGetKeyboardControl(dpy, &kstate);
4269 if (kstate.global_auto_repeat == AutoRepeatModeOn)
4271 XAutoRepeatOff(dpy);
4272 restore_repeat = True;
4274 MyXGrabKeyboard(dpy);
4277 /* be ready to get a stroke sequence */
4278 stroke_init();
4280 if (draw_motion)
4282 MyXGrabServer(dpy);
4283 if (FQueryPointer(
4284 dpy, Scr.Root, &JunkRoot, &JunkChild, &x[0], &y[0],
4285 &JunkX, &JunkY, &JunkMask) == False)
4287 /* pointer is on a different screen */
4288 x[0] = 0;
4289 y[0] = 0;
4291 XSetLineAttributes(
4292 dpy,Scr.XorGC,stroke_width,LineSolid,CapButt,JoinMiter);
4295 while (!finished && !abort)
4297 /* block until there is an event */
4298 FMaskEvent(
4299 dpy, ButtonPressMask | ButtonReleaseMask |
4300 KeyPressMask | KeyReleaseMask | ButtonMotionMask |
4301 PointerMotionMask, &e);
4302 switch (e.type)
4304 case MotionNotify:
4305 if (e.xmotion.same_screen == False)
4307 continue;
4309 if (e.xany.window != Scr.Root)
4311 if (FQueryPointer(
4312 dpy, Scr.Root, &JunkRoot,
4313 &JunkChild, &tmpx, &tmpy, &JunkX,
4314 &JunkY, &JunkMask) == False)
4316 /* pointer is on a different screen */
4317 tmpx = 0;
4318 tmpy = 0;
4321 else
4323 tmpx = e.xmotion.x;
4324 tmpy = e.xmotion.y;
4326 stroke_record(tmpx,tmpy);
4327 if (draw_motion && (x[i] != tmpx || y[i] != tmpy))
4329 i++;
4330 if (i >= coords_size)
4332 coords_size += STROKE_CHUNK_SIZE;
4333 x = (int*)saferealloc(
4334 (void *)x, coords_size *
4335 sizeof(int));
4336 y = (int*)saferealloc(
4337 (void *)y, coords_size *
4338 sizeof(int));
4340 x[i] = tmpx;
4341 y[i] = tmpy;
4342 XDrawLine(
4343 dpy, Scr.Root, Scr.XorGC, x[i-1],
4344 y[i-1], x[i], y[i]);
4346 break;
4347 case ButtonRelease:
4348 if (finish_on_release && start_event_type ==
4349 ButtonPress)
4351 finished = 1;
4353 break;
4354 case KeyRelease:
4355 if (finish_on_release && start_event_type == KeyPress)
4357 finished = 1;
4359 break;
4360 case KeyPress:
4361 keysym = XLookupKeysym(&e.xkey, 0);
4362 /* abort if Escape or Delete is pressed (as in menus.c)
4364 if (keysym == XK_Escape || keysym == XK_Delete ||
4365 keysym == XK_KP_Separator)
4367 abort = 1;
4369 /* finish on enter or space (as in menus.c) */
4370 if (keysym == XK_Return || keysym == XK_KP_Enter ||
4371 keysym == XK_space)
4373 finished = 1;
4375 break;
4376 case ButtonPress:
4377 if (!finish_on_release)
4379 finished = 1;
4381 break;
4382 default:
4383 break;
4387 if (draw_motion)
4389 while (i > 0)
4391 XDrawLine(
4392 dpy, Scr.Root, Scr.XorGC, x[i-1], y[i-1], x[i],
4393 y[i]);
4394 i--;
4396 XSetLineAttributes(dpy,Scr.XorGC,0,LineSolid,CapButt,JoinMiter);
4397 MyXUngrabServer(dpy);
4399 if (x != NULL)
4401 free(x);
4402 free(y);
4404 if (start_event_type == KeyPress && finish_on_release)
4406 MyXUngrabKeyboard(dpy);
4408 UngrabEm(GRAB_NORMAL);
4409 if (restore_repeat)
4411 XAutoRepeatOn(dpy);
4414 /* get the stroke sequence */
4415 stroke_trans(sequence);
4417 if (echo_sequence)
4419 char num_seq[STROKE_MAX_SEQUENCE + 1];
4421 for (i = 0; sequence[i] != '\0';i++)
4423 /* Telephone to numeric pad */
4424 if ('7' <= sequence[i] && sequence[i] <= '9')
4426 num_seq[i] = sequence[i]-6;
4428 else if ('1' <= sequence[i] && sequence[i] <= '3')
4430 num_seq[i] = sequence[i]+6;
4432 else
4434 num_seq[i] = sequence[i];
4437 num_seq[i++] = '\0';
4438 fvwm_msg(INFO, "StrokeFunc", "stroke sequence: %s (N%s)",
4439 sequence, num_seq);
4441 if (abort)
4443 return;
4445 if (exc->w.fw == NULL)
4447 class = NULL;
4448 name = NULL;
4450 else
4452 class = &exc->w.fw->class;
4453 name = exc->w.fw->name.name;
4455 /* check for a binding */
4456 stroke_action = CheckBinding(
4457 Scr.AllBindings, sequence, 0, modifiers, GetUnusedModifiers(),
4458 exc->w.wcontext, BIND_STROKE, class, name);
4460 /* execute the action */
4461 if (stroke_action != NULL)
4463 const exec_context_t *exc2;
4464 exec_context_changes_t ecc;
4466 if (feed_back && atoi(sequence) != 0)
4468 GrabEm(CRS_WAIT, GRAB_BUSY);
4469 usleep(200000);
4470 UngrabEm(GRAB_BUSY);
4472 ecc.x.etrigger = &e;
4473 exc2 = exc_clone_context(exc, &ecc, ECC_ETRIGGER);
4474 execute_function(cond_rc, exc2, stroke_action, 0);
4475 exc_destroy_context(exc2);
4478 return;
4480 #endif /* HAVE_STROKE */
4482 void CMD_State(F_CMD_ARGS)
4484 unsigned int state;
4485 int toggle;
4486 int n;
4487 FvwmWindow * const fw = exc->w.fw;
4489 n = GetIntegerArguments(action, &action, (int *)&state, 1);
4490 if (n <= 0)
4492 return;
4494 if (state < 0 || state > 31)
4496 fvwm_msg(ERR, "CMD_State", "Illegal state %d\n", state);
4497 return;
4499 toggle = ParseToggleArgument(action, NULL, -1, 0);
4500 state = (1 << state);
4501 switch (toggle)
4503 case -1:
4504 TOGGLE_USER_STATES(fw, state);
4505 break;
4506 case 0:
4507 CLEAR_USER_STATES(fw, state);
4508 break;
4509 case 1:
4510 default:
4511 SET_USER_STATES(fw, state);
4512 break;
4515 return;