Correct typo of dates in Changelog.
[fvwm.git] / fvwm / builtins.c
blob31b248c0a9091ba5cb98897eb1587182431fc713
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 "fvwm.h"
53 #include "externs.h"
54 #include "colorset.h"
55 #include "bindings.h"
56 #include "misc.h"
57 #include "cursor.h"
58 #include "functions.h"
59 #include "commands.h"
60 #include "screen.h"
61 #include "builtins.h"
62 #include "module_interface.h"
63 #include "borders.h"
64 #include "frame.h"
65 #include "events.h"
66 #include "ewmh.h"
67 #include "virtual.h"
68 #include "decorations.h"
69 #include "add_window.h"
70 #include "update.h"
71 #include "style.h"
72 #include "move_resize.h"
73 #include "menus.h"
74 #ifdef HAVE_STROKE
75 #include "stroke.h"
76 #endif /* HAVE_STROKE */
78 /* ---------------------------- local definitions -------------------------- */
80 /* ---------------------------- local macros ------------------------------- */
82 /* ---------------------------- imports ------------------------------------ */
84 extern float rgpctMovementDefault[32];
85 extern int cpctMovementDefault;
86 extern int cmsDelayDefault;
88 /* ---------------------------- included code files ------------------------ */
90 /* ---------------------------- local types -------------------------------- */
91 typedef enum {FakeMouseEvent, FakeKeyEvent} FakeEventType;
92 /* ---------------------------- forward declarations ----------------------- */
94 /* ---------------------------- local variables ---------------------------- */
96 static char *exec_shell_name="/bin/sh";
98 /* button state strings must match the enumerated states */
99 static char *button_states[BS_MaxButtonStateName + 1] =
101 "ActiveUp",
102 "ActiveDown",
103 "InactiveUp",
104 "InactiveDown",
105 "ToggledActiveUp",
106 "ToggledActiveDown",
107 "ToggledInactiveUp",
108 "ToggledInactiveDown",
109 "Active",
110 "Inactive",
111 "ToggledActive",
112 "ToggledInactive",
113 "AllNormal",
114 "AllToggled",
115 "AllActive",
116 "AllInactive",
117 "AllUp",
118 "AllDown",
119 "AllActiveUp",
120 "AllActiveDown",
121 "AllInactiveUp",
122 "AllInactiveDown",
123 NULL
126 /* ---------------------------- exported variables (globals) --------------- */
128 char *ModulePath = FVWM_MODULEDIR;
129 int moduleTimeout = DEFAULT_MODULE_TIMEOUT;
131 /* ---------------------------- local functions ---------------------------- */
133 /** Prepend rather than replace the image path.
134 Used for obsolete PixmapPath and IconPath **/
135 static void obsolete_imagepaths( const char* pre_path )
137 char* tmp = stripcpy( pre_path );
138 char* path = alloca(strlen( tmp ) + strlen(PictureGetImagePath()) + 2 );
140 strcpy( path, tmp );
141 free( tmp );
143 strcat( path, ":" );
144 strcat( path, PictureGetImagePath() );
146 PictureSetImagePath( path );
148 return;
153 * Reads a title button description (veliaa@rpi.edu)
156 static char *ReadTitleButton(
157 char *s, TitleButton *tb, Boolean append, int button)
159 char *end = NULL;
160 char *spec;
161 char *t;
162 int i;
163 int bs;
164 int bs_start, bs_end;
165 int pstyle = 0;
166 DecorFace tmpdf;
168 Bool multiple;
169 int use_mask = 0;
170 int set_mask = 0;
172 s = SkipSpaces(s, NULL, 0);
173 t = GetNextTokenIndex(s, button_states, 0, &bs);
174 if (bs != BS_All)
176 s = SkipSpaces(t, NULL, 0);
179 if (bs == BS_All)
181 use_mask = 0;
182 set_mask = 0;
184 else if (bs == BS_Active)
186 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
187 set_mask = 0;
189 else if (bs == BS_Inactive)
191 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
192 set_mask = BS_MASK_INACTIVE;
194 else if (bs == BS_ToggledActive)
196 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
197 set_mask = BS_MASK_TOGGLED;
199 else if (bs == BS_ToggledInactive)
201 use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
202 set_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
204 else if (bs == BS_AllNormal)
206 use_mask = BS_MASK_TOGGLED;
207 set_mask = 0;
209 else if (bs == BS_AllToggled)
211 use_mask = BS_MASK_TOGGLED;
212 set_mask = BS_MASK_TOGGLED;
214 else if (bs == BS_AllActive)
216 use_mask = BS_MASK_INACTIVE;
217 set_mask = 0;
219 else if (bs == BS_AllInactive)
221 use_mask = BS_MASK_INACTIVE;
222 set_mask = BS_MASK_INACTIVE;
224 else if (bs == BS_AllUp)
226 use_mask = BS_MASK_DOWN;
227 set_mask = 0;
229 else if (bs == BS_AllDown)
231 use_mask = BS_MASK_DOWN;
232 set_mask = BS_MASK_DOWN;
234 else if (bs == BS_AllActiveUp)
236 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
237 set_mask = 0;
239 else if (bs == BS_AllActiveDown)
241 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
242 set_mask = BS_MASK_DOWN;
244 else if (bs == BS_AllInactiveUp)
246 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
247 set_mask = BS_MASK_INACTIVE;
249 else if (bs == BS_AllInactiveDown)
251 use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
252 set_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
255 if ((bs & BS_MaxButtonStateMask) == bs)
257 multiple = False;
258 bs_start = bs;
259 bs_end = bs;
261 else
263 multiple = True;
264 bs_start = 0;
265 bs_end = BS_MaxButtonState - 1;
266 for (i = bs_start; (i & use_mask) != set_mask && i <= bs_end;
267 i++)
269 bs_start++;
273 if (*s == '(')
275 int len;
276 pstyle = 1;
277 if (!(end = strchr(++s, ')')))
279 fvwm_msg(
280 ERR, "ReadTitleButton",
281 "missing parenthesis: %s", s);
282 return NULL;
284 s = SkipSpaces(s, NULL, 0);
285 len = end - s + 1;
286 spec = safemalloc(len);
287 strncpy(spec, s, len - 1);
288 spec[len - 1] = 0;
290 else
292 spec = s;
295 spec = SkipSpaces(spec, NULL, 0);
296 /* setup temporary in case button read fails */
297 memset(&tmpdf, 0, sizeof(DecorFace));
298 DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
300 if (strncmp(spec, "--", 2) == 0)
302 /* only change flags */
303 Bool verbose = True;
304 for (i = bs_start; i <= bs_end; ++i)
306 if (multiple && (i & use_mask) != set_mask)
308 continue;
310 ReadDecorFace(spec, &TB_STATE(*tb)[i], button, verbose);
311 verbose = False;
314 else if (ReadDecorFace(spec, &tmpdf, button, True))
316 if (append)
318 DecorFace *head = &TB_STATE(*tb)[bs_start];
319 DecorFace *tail = head;
320 DecorFace *next;
322 while (tail->next)
324 tail = tail->next;
326 tail->next = (DecorFace *)safemalloc(sizeof(DecorFace));
327 memcpy(tail->next, &tmpdf, sizeof(DecorFace));
328 if (DFS_FACE_TYPE(tail->next->style) == VectorButton &&
329 DFS_FACE_TYPE((&TB_STATE(*tb)[bs_start])->style) ==
330 DefaultVectorButton)
332 /* override the default vector style */
333 memcpy(
334 &tail->next->style, &head->style,
335 sizeof(DecorFaceStyle));
336 DFS_FACE_TYPE(tail->next->style) = VectorButton;
337 next = head->next;
338 head->next = NULL;
339 FreeDecorFace(dpy, head);
340 memcpy(head, next, sizeof(DecorFace));
341 free(next);
343 for (i = bs_start + 1; i <= bs_end; ++i)
345 if (multiple && (i & use_mask) != set_mask)
347 continue;
349 head = &TB_STATE(*tb)[i];
350 tail = head;
351 while (tail->next)
353 tail = tail->next;
355 tail->next = (DecorFace *)safemalloc(
356 sizeof(DecorFace));
357 memset(
358 &DFS_FLAGS(tail->next->style), 0,
359 sizeof(DFS_FLAGS(tail->next->style)));
360 DFS_FACE_TYPE(tail->next->style) =
361 SimpleButton;
362 tail->next->next = NULL;
363 ReadDecorFace(spec, tail->next, button, False);
364 if (DFS_FACE_TYPE(tail->next->style) ==
365 VectorButton &&
366 DFS_FACE_TYPE((&TB_STATE(*tb)[i])->style) ==
367 DefaultVectorButton)
369 /* override the default vector style */
370 memcpy(
371 &tail->next->style,
372 &head->style,
373 sizeof(DecorFaceStyle));
374 DFS_FACE_TYPE(tail->next->style) =
375 VectorButton;
376 next = head->next;
377 head->next = NULL;
378 FreeDecorFace(dpy, head);
379 memcpy(head, next, sizeof(DecorFace));
380 free(next);
384 else
386 FreeDecorFace(dpy, &TB_STATE(*tb)[bs_start]);
387 memcpy(
388 &(TB_STATE(*tb)[bs_start]), &tmpdf,
389 sizeof(DecorFace));
390 for (i = bs_start + 1; i <= bs_end; ++i)
392 if (multiple && (i & use_mask) != set_mask)
394 continue;
396 ReadDecorFace(
397 spec, &TB_STATE(*tb)[i], button, False);
401 if (pstyle)
403 free(spec);
404 end++;
405 end = SkipSpaces(end, NULL, 0);
408 return end;
411 /* Remove the given decor from all windows */
412 static void __remove_window_decors(F_CMD_ARGS, FvwmDecor *d)
414 const exec_context_t *exc2;
415 exec_context_changes_t ecc;
416 FvwmWindow *t;
418 for (t = Scr.FvwmRoot.next; t; t = t->next)
420 if (t->decor == d)
422 /* remove the extra title height now because we delete
423 * the current decor before calling ChangeDecor(). */
424 t->g.frame.height -= t->decor->title_height;
425 t->decor = NULL;
426 ecc.w.fw = t;
427 ecc.w.wcontext = C_WINDOW;
428 exc2 = exc_clone_context(
429 exc, &ecc, ECC_FW | ECC_WCONTEXT);
430 execute_function(
431 cond_rc, exc2, "ChangeDecor Default", 0);
432 exc_destroy_context(exc2);
436 return;
439 static void do_title_style(F_CMD_ARGS, Bool do_add)
441 char *parm;
442 char *prev;
443 #ifdef USEDECOR
444 FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
445 #else
446 FvwmDecor *decor = &Scr.DefaultDecor;
447 #endif
449 Scr.flags.do_need_window_update = 1;
450 decor->flags.has_changed = 1;
451 decor->titlebar.flags.has_changed = 1;
453 for (prev = action ; (parm = PeekToken(action, &action)); prev = action)
455 if (!do_add && StrEquals(parm,"centered"))
457 TB_JUSTIFICATION(decor->titlebar) = JUST_CENTER;
459 else if (!do_add && StrEquals(parm,"leftjustified"))
461 TB_JUSTIFICATION(decor->titlebar) = JUST_LEFT;
463 else if (!do_add && StrEquals(parm,"rightjustified"))
465 TB_JUSTIFICATION(decor->titlebar) = JUST_RIGHT;
467 else if (!do_add && StrEquals(parm,"height"))
469 int height = 0;
470 int next = 0;
472 if (!action ||
473 sscanf(action, "%d%n", &height, &next) <= 0 ||
474 height < MIN_FONT_HEIGHT ||
475 height > MAX_FONT_HEIGHT)
477 if (height != 0)
479 fvwm_msg(ERR, "do_title_style",
480 "bad height argument (height"
481 " must be from 5 to 256)");
482 height = 0;
485 if (decor->title_height != height ||
486 decor->min_title_height != 0)
488 decor->title_height = height;
489 decor->min_title_height = 0;
490 decor->flags.has_title_height_changed = 1;
492 if (action)
493 action += next;
495 else if (!do_add && StrEquals(parm,"MinHeight"))
497 int height = 0;
498 int next = 0;
500 if (!action ||
501 sscanf(action, "%d%n", &height, &next) <= 0 ||
502 height < MIN_FONT_HEIGHT ||
503 height > MAX_FONT_HEIGHT)
505 if (height < MIN_FONT_HEIGHT)
506 height = MIN_FONT_HEIGHT;
507 else if (height > MAX_FONT_HEIGHT)
508 height = 0;
510 if (decor->min_title_height != height)
512 decor->title_height = 0;
513 decor->min_title_height = height;
514 decor->flags.has_title_height_changed = 1;
516 if (action)
517 action += next;
519 else
521 action = ReadTitleButton(
522 prev, &decor->titlebar, do_add, -1);
526 return;
531 * Reads a multi-pixmap titlebar config. (tril@igs.net)
534 static char *ReadMultiPixmapDecor(char *s, DecorFace *df)
536 static char *pm_names[TBMP_NUM_PIXMAPS+1] =
538 "Main",
539 "LeftMain",
540 "RightMain",
541 "LeftButtons",
542 "RightButtons",
543 "UnderText",
544 "LeftOfText",
545 "RightOfText",
546 "LeftEnd",
547 "RightEnd",
548 "Buttons",
549 NULL
551 FvwmPicture **pm;
552 FvwmAcs *acs;
553 Pixel *pixels;
554 char *token;
555 Bool stretched;
556 Bool load_pixmap = False;
557 int pm_id, i = 0;
558 FvwmPictureAttributes fpa;
560 df->style.face_type = MultiPixmap;
561 df->u.mp.pixmaps = pm =
562 (FvwmPicture**)safecalloc(
563 TBMP_NUM_PIXMAPS, sizeof(FvwmPicture*));
564 df->u.mp.acs = acs =
565 (FvwmAcs *)safemalloc(TBMP_NUM_PIXMAPS * sizeof(FvwmAcs));
566 df->u.mp.pixels = pixels =
567 (Pixel *)safemalloc(TBMP_NUM_PIXMAPS * sizeof(Pixel));
568 for(i=0; i < TBMP_NUM_PIXMAPS; i++)
570 acs[i].cs = -1;
571 acs[i].alpha_percent = 100;
573 s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
574 while (pm_id >= 0)
576 stretched = False;
577 load_pixmap = False;
578 s = DoPeekToken(s, &token, ",()", NULL, NULL);
579 if (StrEquals(token, "stretched"))
581 stretched = True;
582 s = DoPeekToken(s, &token, ",", NULL, NULL);
584 else if (StrEquals(token, "tiled"))
586 s = DoPeekToken(s, &token, ",", NULL, NULL);
588 if (!token)
590 break;
592 if (pm[pm_id] || acs[pm_id].cs >= 0 ||
593 (df->u.mp.solid_flags & (1 << pm_id)))
595 fvwm_msg(WARN, "ReadMultiPixmapDecor",
596 "Ignoring: already-specified %s",
597 pm_names[i]);
598 continue;
600 if (stretched)
602 df->u.mp.stretch_flags |= (1 << pm_id);
604 if (strncasecmp (token, "Colorset", 8) == 0)
606 int val;
607 char *tmp;
609 tmp = DoPeekToken(s, &token, ",", NULL, NULL);
610 if (!GetIntegerArguments(token, NULL, &val, 1) ||
611 val < 0)
613 fvwm_msg(
614 ERR, "ReadMultiPixmapDecor",
615 "Colorset shoule take one or two "
616 "positive integers as argument");
618 else
620 acs[pm_id].cs = val;
621 alloc_colorset(val);
622 s = tmp;
623 tmp = DoPeekToken(s, &token, ",", NULL, NULL);
624 if (GetIntegerArguments(token, NULL, &val, 1))
626 acs[pm_id].alpha_percent =
627 max(0, min(100,val));
628 s = tmp;
632 else if (strncasecmp(token, "TiledPixmap", 11) == 0)
634 s = DoPeekToken(s, &token, ",", NULL, NULL);
635 load_pixmap = True;
637 else if (strncasecmp(token, "AdjustedPixmap", 14) == 0)
639 s = DoPeekToken(s, &token, ",", NULL, NULL);
640 load_pixmap = True;
641 df->u.mp.stretch_flags |= (1 << pm_id);
643 else if (strncasecmp(token, "Solid", 5) == 0)
645 s = DoPeekToken(s, &token, ",", NULL, NULL);
646 if (token)
648 df->u.mp.pixels[pm_id] = GetColor(token);
649 df->u.mp.solid_flags |= (1 << pm_id);
652 else
654 load_pixmap = True;
656 if (load_pixmap && token)
658 fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
659 pm[pm_id] = PCacheFvwmPicture(
660 dpy, Scr.NoFocusWin, NULL, token, fpa);
661 if (!pm[pm_id])
663 fvwm_msg(ERR, "ReadMultiPixmapDecor",
664 "Pixmap '%s' could not be loaded",
665 token);
668 if (pm_id == TBMP_BUTTONS)
670 if (pm[TBMP_LEFT_BUTTONS])
672 PDestroyFvwmPicture(dpy, pm[TBMP_LEFT_BUTTONS]);
674 if (pm[TBMP_RIGHT_BUTTONS])
676 PDestroyFvwmPicture(dpy, pm[TBMP_RIGHT_BUTTONS]);
678 df->u.mp.stretch_flags &= ~(1 << TBMP_LEFT_BUTTONS);
679 df->u.mp.stretch_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
680 df->u.mp.solid_flags &= ~(1 << TBMP_LEFT_BUTTONS);
681 df->u.mp.solid_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
682 if (pm[TBMP_BUTTONS])
684 pm[TBMP_LEFT_BUTTONS] =
685 PCloneFvwmPicture(pm[TBMP_BUTTONS]);
686 acs[TBMP_LEFT_BUTTONS].cs = -1;
687 pm[TBMP_RIGHT_BUTTONS] =
688 PCloneFvwmPicture(pm[TBMP_BUTTONS]);
689 acs[TBMP_RIGHT_BUTTONS].cs = -1;
691 else
693 pm[TBMP_RIGHT_BUTTONS] =
694 pm[TBMP_LEFT_BUTTONS] = NULL;
695 acs[TBMP_RIGHT_BUTTONS].cs =
696 acs[TBMP_LEFT_BUTTONS].cs =
697 acs[TBMP_BUTTONS].cs;
698 acs[TBMP_RIGHT_BUTTONS].alpha_percent =
699 acs[TBMP_LEFT_BUTTONS].alpha_percent =
700 acs[TBMP_BUTTONS].alpha_percent;
701 pixels[TBMP_LEFT_BUTTONS] =
702 pixels[TBMP_RIGHT_BUTTONS] =
703 pixels[TBMP_BUTTONS];
705 if (stretched)
707 df->u.mp.stretch_flags |=
708 (1 << TBMP_LEFT_BUTTONS) |
709 (1 << TBMP_RIGHT_BUTTONS);
711 if (df->u.mp.solid_flags & (1 << TBMP_BUTTONS))
713 df->u.mp.solid_flags |=
714 (1 << TBMP_LEFT_BUTTONS);
715 df->u.mp.solid_flags |=
716 (1 << TBMP_RIGHT_BUTTONS);
718 if (pm[TBMP_BUTTONS])
720 PDestroyFvwmPicture(dpy, pm[TBMP_BUTTONS]);
721 pm[TBMP_BUTTONS] = NULL;
723 acs[TBMP_BUTTONS].cs = -1;
724 df->u.mp.solid_flags &= ~(1 << TBMP_BUTTONS);
726 s = SkipSpaces(s, NULL, 0);
727 s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
730 if (!(pm[TBMP_MAIN] || acs[TBMP_MAIN].cs >= 0 ||
731 (df->u.mp.solid_flags & TBMP_MAIN))
733 !(pm[TBMP_LEFT_MAIN] || acs[TBMP_LEFT_MAIN].cs >= 0 ||
734 (df->u.mp.solid_flags & TBMP_LEFT_MAIN))
736 !(pm[TBMP_RIGHT_MAIN] || acs[TBMP_RIGHT_MAIN].cs >= 0 ||
737 (df->u.mp.solid_flags & TBMP_RIGHT_MAIN)))
739 fvwm_msg(ERR, "ReadMultiPixmapDecor",
740 "No Main pixmap/colorset/solid found for TitleStyle "
741 "MultiPixmap (you must specify either Main, "
742 "or both LeftMain and RightMain)");
743 for (i=0; i < TBMP_NUM_PIXMAPS; i++)
745 if (pm[i])
747 PDestroyFvwmPicture(dpy, pm[i]);
749 else if (!!(df->u.mp.solid_flags & i))
751 PictureFreeColors(
752 dpy, Pcmap, &df->u.mp.pixels[i], 1, 0,
753 False);
756 free(pm);
757 free(acs);
758 free(pixels);
759 return NULL;
762 return s;
767 * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
768 * structure, but does not free the FvwmDecor itself
771 static void DestroyFvwmDecor(FvwmDecor *decor)
773 int i;
774 /* reset to default button set (frees allocated mem) */
775 DestroyAllButtons(decor);
776 for (i = 0; i < BS_MaxButtonState; ++i)
778 FreeDecorFace(dpy, &TB_STATE(decor->titlebar)[i]);
780 FreeDecorFace(dpy, &decor->BorderStyle.active);
781 FreeDecorFace(dpy, &decor->BorderStyle.inactive);
782 #ifdef USEDECOR
783 if (decor->tag)
785 free(decor->tag);
786 decor->tag = NULL;
788 #endif
790 return;
793 static void SetLayerButtonFlag(
794 int layer, int multi, int set, FvwmDecor *decor, TitleButton *tb)
796 int i;
797 int start = 0;
798 int add = 2;
800 if (multi)
802 if (multi == 2)
804 start = 1;
806 else if (multi == 3)
808 add = 1;
810 for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
812 if (set)
814 TB_FLAGS(decor->buttons[i]).has_layer = 1;
815 TB_LAYER(decor->buttons[i]) = layer;
817 else
819 TB_FLAGS(decor->buttons[i]).has_layer = 0;
823 else
825 if (set)
827 TB_FLAGS(*tb).has_layer = 1;
828 TB_LAYER(*tb) = layer;
830 else
832 TB_FLAGS(*tb).has_layer = 0;
836 return;
841 * Changes a button decoration style (changes by veliaa@rpi.edu)
844 static void SetMWMButtonFlag(
845 mwm_flags flag, int multi, int set, FvwmDecor *decor, TitleButton *tb)
847 int i;
848 int start = 0;
849 int add = 2;
851 if (multi)
853 if (multi == 2)
855 start = 1;
857 else if (multi == 3)
859 add = 1;
861 for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
863 if (set)
865 TB_MWM_DECOR_FLAGS(decor->buttons[i]) |= flag;
867 else
869 TB_MWM_DECOR_FLAGS(decor->buttons[i]) &= ~flag;
873 else
875 if (set)
877 TB_MWM_DECOR_FLAGS(*tb) |= flag;
879 else
881 TB_MWM_DECOR_FLAGS(*tb) &= ~flag;
885 return;
888 static void do_button_style(F_CMD_ARGS, Bool do_add)
890 int i;
891 int multi = 0;
892 int button = 0;
893 int do_return;
894 char *text = NULL;
895 char *prev = NULL;
896 char *parm = NULL;
897 TitleButton *tb = NULL;
898 #ifdef USEDECOR
899 FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
900 #else
901 FvwmDecor *decor = &Scr.DefaultDecor;
902 #endif
904 parm = PeekToken(action, &text);
905 if (parm && isdigit(*parm))
907 button = atoi(parm);
908 button = BUTTON_INDEX(button);
911 if (parm == NULL || button >= NUMBER_OF_TITLE_BUTTONS || button < 0)
913 fvwm_msg(
914 ERR, "ButtonStyle", "Bad button style (1) in line %s",
915 action);
916 return;
919 Scr.flags.do_need_window_update = 1;
921 do_return = 0;
922 if (!isdigit(*parm))
924 if (StrEquals(parm,"left"))
926 multi = 1; /* affect all left buttons */
928 else if (StrEquals(parm,"right"))
930 multi = 2; /* affect all right buttons */
932 else if (StrEquals(parm,"all"))
934 multi = 3; /* affect all buttons */
936 else
938 /* we're either resetting buttons or an invalid button
939 * set was specified */
940 if (StrEquals(parm,"reset"))
942 ResetAllButtons(decor);
944 else
946 fvwm_msg(
947 ERR, "ButtonStyle",
948 "Bad button style (2) in line %s",
949 action);
951 multi = 3;
952 do_return = 1;
955 /* mark button style and decor as changed */
956 decor->flags.has_changed = 1;
957 if (multi == 0)
959 /* a single button was specified */
960 tb = &decor->buttons[button];
961 TB_FLAGS(*tb).has_changed = 1;
963 else
965 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
967 if (((multi & 1) && !(i & 1)) ||
968 ((multi & 2) && (i & 1)))
970 TB_FLAGS(decor->buttons[i]).has_changed = 1;
974 if (do_return == 1)
976 return;
978 for (prev = text; (parm = PeekToken(text, &text)); prev = text)
980 if (!do_add && strcmp(parm,"-") == 0)
982 char *tok;
983 text = GetNextToken(text, &tok);
984 while (tok)
986 int set = 1;
987 char *old_tok = NULL;
989 if (*tok == '!')
991 /* flag negate */
992 set = 0;
993 old_tok = tok;
994 tok++;
996 if (StrEquals(tok,"Clear"))
998 if (multi)
1000 for (i = 0;
1001 i < NUMBER_OF_TITLE_BUTTONS; ++i)
1003 if (((multi & 1) &&
1004 !(i & 1)) ||
1005 ((multi & 2) &&
1006 (i & 1)))
1008 TB_JUSTIFICATION(decor->buttons[i]) =
1009 (set) ? JUST_CENTER : JUST_RIGHT;
1010 memset(&TB_FLAGS(decor->buttons[i]), (set) ? 0 : 0xff,
1011 sizeof(TB_FLAGS(decor->buttons[i])));
1012 /* ? not very useful if set == 0 ? */
1016 else
1018 TB_JUSTIFICATION(*tb) = (set) ?
1019 JUST_CENTER :
1020 JUST_RIGHT;
1021 memset(&TB_FLAGS(*tb), (set) ?
1022 0 : 0xff,
1023 sizeof(TB_FLAGS(*tb)));
1024 /* ? not very useful if
1025 * set == 0 ? */
1028 else if (StrEquals(tok, "MWMDecorMenu"))
1030 SetMWMButtonFlag(
1031 MWM_DECOR_MENU, multi, set,
1032 decor, tb);
1034 else if (StrEquals(tok, "MWMDecorMin"))
1036 SetMWMButtonFlag(
1037 MWM_DECOR_MINIMIZE, multi, set,
1038 decor, tb);
1040 else if (StrEquals(tok, "MWMDecorMax"))
1042 SetMWMButtonFlag(
1043 MWM_DECOR_MAXIMIZE, multi, set,
1044 decor, tb);
1046 else if (StrEquals(tok, "MWMDecorShade"))
1048 SetMWMButtonFlag(
1049 MWM_DECOR_SHADE, multi, set,
1050 decor, tb);
1052 else if (StrEquals(tok, "MWMDecorStick"))
1054 SetMWMButtonFlag(
1055 MWM_DECOR_STICK, multi, set,
1056 decor, tb);
1058 else if (StrEquals(tok, "MwmDecorLayer"))
1060 int layer, got_number;
1061 char *ltok;
1062 text = GetNextToken(text, &ltok);
1063 if (ltok)
1065 got_number =
1066 (sscanf(ltok, "%d",
1067 &layer) == 1);
1068 free (ltok);
1070 else
1072 got_number = 0;
1074 if (!ltok || !got_number)
1076 fvwm_msg(ERR, "ButtonStyle",
1077 "could not read"
1078 " integer value for"
1079 " layer -- line: %s",
1080 text);
1082 else
1084 SetLayerButtonFlag(
1085 layer, multi, set,
1086 decor, tb);
1090 else
1092 fvwm_msg(ERR, "ButtonStyle",
1093 "unknown title button flag"
1094 " %s -- line: %s", tok, text);
1096 if (set)
1098 free(tok);
1100 else
1102 free(old_tok);
1104 text = GetNextToken(text, &tok);
1106 break;
1108 else
1110 if (multi)
1112 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
1114 if (((multi & 1) && !(i & 1)) ||
1115 ((multi & 2) && (i & 1)))
1117 text = ReadTitleButton(
1118 prev,
1119 &decor->buttons[i],
1120 do_add, i);
1124 else if (!(text = ReadTitleButton(
1125 prev, tb, do_add, button)))
1127 break;
1132 return;
1135 static
1136 int update_decorface_colorset(DecorFace *df, int cset)
1138 DecorFace *tdf;
1139 int has_changed = 0;
1141 for(tdf = df; tdf != NULL; tdf = tdf->next)
1143 if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
1144 tdf->u.acs.cs == cset)
1146 tdf->flags.has_changed = 1;
1147 has_changed = 1;
1149 else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
1151 int i;
1153 for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
1155 if (tdf->u.mp.acs[i].cs == cset)
1157 tdf->flags.has_changed = 1;
1158 has_changed = 1;
1164 return has_changed;
1167 static
1168 int update_titlebutton_colorset(TitleButton *tb, int cset)
1170 int i;
1171 int has_changed = 0;
1173 for(i = 0; i < BS_MaxButtonState; i++)
1175 tb->state[i].flags.has_changed =
1176 update_decorface_colorset(&(tb->state[i]), cset);
1177 has_changed |= tb->state[i].flags.has_changed;
1179 return has_changed;
1182 static
1183 void update_decors_colorset(int cset)
1185 int i;
1186 int has_changed;
1187 FvwmDecor *decor = &Scr.DefaultDecor;
1189 #ifdef USEDECOR
1190 for(decor = &Scr.DefaultDecor; decor != NULL; decor = decor->next)
1191 #endif
1193 has_changed = 0;
1194 for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
1196 decor->flags.has_changed |= update_titlebutton_colorset(
1197 &(decor->buttons[i]), cset);
1199 decor->flags.has_changed |= update_titlebutton_colorset(
1200 &(decor->titlebar), cset);
1201 decor->flags.has_changed |= update_decorface_colorset(
1202 &(decor->BorderStyle.active), cset);
1203 decor->flags.has_changed |= update_decorface_colorset(
1204 &(decor->BorderStyle.inactive), cset);
1205 if (decor->flags.has_changed)
1207 Scr.flags.do_need_window_update = 1;
1212 static Bool __parse_vector_line_one_coord(
1213 char **ret_action, int *pcoord, int *poff, char *action)
1215 int offset;
1216 int n;
1218 *ret_action = action;
1219 n = sscanf(action, "%d%n", pcoord, &offset);
1220 if (n < 1)
1222 return False;
1224 action += offset;
1225 /* check for offest */
1226 if (*action == '+' || *action == '-')
1228 n = sscanf(action, "%dp%n", poff, &offset);
1229 if (n < 1)
1231 return False;
1233 if (*poff < -128)
1235 *poff = -128;
1237 else if (*poff > 127)
1239 *poff = 127;
1241 action += offset;
1243 else
1245 *poff = 0;
1247 *ret_action = action;
1249 return True;
1252 static Bool __parse_vector_line(
1253 char **ret_action, int *px, int *py, int *pxoff, int *pyoff, int *pc,
1254 char *action)
1256 Bool is_valid = True;
1257 int offset;
1258 int n;
1260 *ret_action = action;
1261 if (__parse_vector_line_one_coord(&action, px, pxoff, action) == False)
1263 return False;
1265 if (*action != 'x')
1267 return False;
1269 action++;
1270 if (__parse_vector_line_one_coord(&action, py, pyoff, action) == False)
1272 return False;
1274 if (*action != '@')
1276 return False;
1278 action++;
1279 /* read the line style */
1280 n = sscanf(action, "%d%n", pc, &offset);
1281 if (n < 1)
1283 return False;
1285 action += offset;
1286 *ret_action = action;
1288 return is_valid;
1291 /* ---------------------------- interface functions ------------------------ */
1293 void refresh_window(Window w, Bool window_update)
1295 XSetWindowAttributes attributes;
1296 unsigned long valuemask;
1298 valuemask = CWOverrideRedirect | CWBackingStore | CWSaveUnder |
1299 CWBackPixmap;
1300 attributes.override_redirect = True;
1301 attributes.save_under = False;
1302 attributes.background_pixmap = None;
1303 attributes.backing_store = NotUseful;
1304 w = XCreateWindow(
1305 dpy, w, 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight, 0,
1306 CopyFromParent, CopyFromParent, CopyFromParent, valuemask,
1307 &attributes);
1308 XMapWindow(dpy, w);
1309 if (Scr.flags.do_need_window_update && window_update)
1311 flush_window_updates();
1313 XDestroyWindow(dpy, w);
1314 XSync(dpy, 0);
1315 handle_all_expose();
1317 return;
1320 void ApplyDefaultFontAndColors(void)
1322 XGCValues gcv;
1323 unsigned long gcm;
1324 int cset = Scr.DefaultColorset;
1326 /* make GC's */
1327 gcm = GCFunction|GCLineWidth|GCForeground|GCBackground;
1328 gcv.function = GXcopy;
1329 if (Scr.DefaultFont->font)
1331 gcm |= GCFont;
1332 gcv.font = Scr.DefaultFont->font->fid;
1334 gcv.line_width = 0;
1335 if (cset >= 0)
1337 gcv.foreground = Colorset[cset].fg;
1338 gcv.background = Colorset[cset].bg;
1340 else
1342 gcv.foreground = Scr.StdFore;
1343 gcv.background = Scr.StdBack;
1345 if (Scr.StdGC)
1347 XChangeGC(dpy, Scr.StdGC, gcm, &gcv);
1349 else
1351 Scr.StdGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1354 gcm = GCFunction|GCLineWidth|GCForeground;
1355 if (cset >= 0)
1357 gcv.foreground = Colorset[cset].hilite;
1359 else
1361 gcv.foreground = Scr.StdHilite;
1363 if (Scr.StdReliefGC)
1365 XChangeGC(dpy, Scr.StdReliefGC, gcm, &gcv);
1367 else
1369 Scr.StdReliefGC = fvwmlib_XCreateGC(
1370 dpy, Scr.NoFocusWin, gcm, &gcv);
1372 if (cset >= 0)
1374 gcv.foreground = Colorset[cset].shadow;
1376 else
1378 gcv.foreground = Scr.StdShadow;
1380 if (Scr.StdShadowGC)
1382 XChangeGC(dpy, Scr.StdShadowGC, gcm, &gcv);
1384 else
1386 Scr.StdShadowGC = fvwmlib_XCreateGC(
1387 dpy, Scr.NoFocusWin, gcm, &gcv);
1389 /* update the geometry window for move/resize */
1390 if (Scr.SizeWindow != None)
1392 resize_geometry_window();
1394 UpdateAllMenuStyles();
1396 return;
1399 void FreeDecorFace(Display *dpy, DecorFace *df)
1401 int i;
1403 switch (DFS_FACE_TYPE(df->style))
1405 case GradientButton:
1406 if (df->u.grad.d_pixels != NULL && df->u.grad.d_npixels)
1408 PictureFreeColors(
1409 dpy, Pcmap, df->u.grad.d_pixels,
1410 df->u.grad.d_npixels, 0, False);
1411 free(df->u.grad.d_pixels);
1413 else if (Pdepth <= 8 && df->u.grad.xcs != NULL &&
1414 df->u.grad.npixels > 0 && !df->u.grad.do_dither)
1416 Pixel *p;
1417 int i;
1419 p = (Pixel *)safemalloc(
1420 df->u.grad.npixels * sizeof(Pixel));
1421 for(i=0; i < df->u.grad.npixels; i++)
1423 p[i] = df->u.grad.xcs[i].pixel;
1425 PictureFreeColors(
1426 dpy, Pcmap, p, df->u.grad.npixels, 0, False);
1427 free(p);
1429 if (df->u.grad.xcs != NULL)
1431 free(df->u.grad.xcs);
1433 break;
1435 case PixmapButton:
1436 case TiledPixmapButton:
1437 case StretchedPixmapButton:
1438 case AdjustedPixmapButton:
1439 case ShrunkPixmapButton:
1440 if (df->u.p)
1442 PDestroyFvwmPicture(dpy, df->u.p);
1444 break;
1446 case MultiPixmap:
1447 if (df->u.mp.pixmaps)
1449 for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
1451 if (df->u.mp.pixmaps[i])
1453 PDestroyFvwmPicture(
1454 dpy, df->u.mp.pixmaps[i]);
1456 else if (!!(df->u.mp.solid_flags & i))
1458 PictureFreeColors(
1459 dpy, Pcmap, &df->u.mp.pixels[i],
1460 1, 0, False);
1463 free(df->u.mp.pixmaps);
1465 if (df->u.mp.acs)
1467 free(df->u.mp.acs);
1469 if (df->u.mp.pixels)
1471 free(df->u.mp.pixels);
1473 break;
1474 case VectorButton:
1475 case DefaultVectorButton:
1476 if (df->u.vector.x)
1478 free (df->u.vector.x);
1480 if (df->u.vector.y)
1482 free (df->u.vector.y);
1484 /* free offsets for coord */
1485 if (df->u.vector.xoff)
1487 free(df->u.vector.xoff);
1489 if (df->u.vector.yoff)
1491 free(df->u.vector.yoff);
1493 if (df->u.vector.c)
1495 free (df->u.vector.c);
1497 break;
1498 default:
1499 /* see below */
1500 break;
1502 /* delete any compound styles */
1503 if (df->next)
1505 FreeDecorFace(dpy, df->next);
1506 free(df->next);
1508 df->next = NULL;
1509 memset(&df->style, 0, sizeof(df->style));
1510 memset(&df->u, 0, sizeof(df->u));
1511 DFS_FACE_TYPE(df->style) = SimpleButton;
1513 return;
1518 * Reads a button face line into a structure (veliaa@rpi.edu)
1521 Bool ReadDecorFace(char *s, DecorFace *df, int button, int verbose)
1523 int offset;
1524 char style[256], *file;
1525 char *action = s;
1527 /* some variants of scanf do not increase the assign count when %n is
1528 * used, so a return value of 1 is no error. */
1529 if (sscanf(s, "%255s%n", style, &offset) < 1)
1531 if (verbose)
1533 fvwm_msg(ERR, "ReadDecorFace", "error in face `%s'", s);
1535 return False;
1537 style[255] = 0;
1539 if (strncasecmp(style, "--", 2) != 0)
1541 s += offset;
1543 FreeDecorFace(dpy, df);
1545 /* determine button style */
1546 if (strncasecmp(style,"Simple",6)==0)
1548 memset(&df->style, 0, sizeof(df->style));
1549 DFS_FACE_TYPE(df->style) = SimpleButton;
1551 else if (strncasecmp(style,"Default",7)==0)
1553 int b = -1, n = sscanf(s, "%d%n", &b, &offset);
1555 if (n < 1)
1557 if (button == -1)
1559 if (verbose)
1561 fvwm_msg(
1562 ERR,"ReadDecorFace",
1563 "need default button"
1564 " number to load");
1566 return False;
1568 b = button;
1570 else
1572 b = BUTTON_INDEX(b);
1573 s += offset;
1575 if (b >= 0 && b < NUMBER_OF_TITLE_BUTTONS)
1577 LoadDefaultButton(df, b);
1579 else
1581 if (verbose)
1583 fvwm_msg(
1584 ERR, "ReadDecorFace",
1585 "button number out of range:"
1586 " %d", b);
1588 return False;
1591 else if (strncasecmp(style,"Vector",6)==0 ||
1592 (strlen(style)<=2 && isdigit(*style)))
1594 /* normal coordinate list button style */
1595 int i, num_coords, num;
1596 struct vector_coords *vc = &df->u.vector;
1598 /* get number of points */
1599 if (strncasecmp(style,"Vector",6)==0)
1601 num = sscanf(s,"%d%n",&num_coords,&offset);
1602 s += offset;
1604 else
1606 num = sscanf(style,"%d",&num_coords);
1609 if (num < 1 || num_coords<2 ||
1610 num_coords > MAX_TITLE_BUTTON_VECTOR_LINES)
1612 if (verbose)
1614 fvwm_msg(
1615 ERR, "ReadDecorFace",
1616 "Bad button style (2) in line:"
1617 " %s",action);
1619 return False;
1622 vc->num = num_coords;
1623 vc->use_fgbg = 0;
1624 vc->x = (signed char*)safemalloc(sizeof(char) *
1625 num_coords);
1626 vc->y = (signed char*)safemalloc(sizeof(char) *
1627 num_coords);
1628 vc->xoff = (signed char*)safemalloc(sizeof(char) *
1629 num_coords);
1630 vc->yoff = (signed char*)safemalloc(sizeof(char) *
1631 num_coords);
1632 vc->c = (signed char*)safemalloc(sizeof(char) *
1633 num_coords);
1635 /* get the points */
1636 for (i = 0; i < vc->num; ++i)
1638 int x;
1639 int y;
1640 int xoff = 0;
1641 int yoff = 0;
1642 int c;
1644 if (__parse_vector_line(
1645 &s, &x, &y, &xoff, &yoff, &c, s) ==
1646 False)
1648 break;
1650 if (x < 0)
1652 x = 0;
1654 if (x > 100)
1656 x = 100;
1658 if (y < 0)
1660 y = 0;
1662 if (y > 100)
1664 y = 100;
1666 if (c < 0 || c > 4)
1668 c = 4;
1670 vc->x[i] = x;
1671 vc->y[i] = y;
1672 vc->c[i] = c;
1673 vc->xoff[i] = xoff;
1674 vc->yoff[i] = yoff;
1675 if (c == 2 || c == 3)
1677 vc->use_fgbg = 1;
1680 if (i < vc->num)
1682 if (verbose)
1684 fvwm_msg(
1685 ERR, "ReadDecorFace",
1686 "Bad button style (3) in line"
1687 " %s", action);
1689 free(vc->x);
1690 free(vc->y);
1691 free(vc->c);
1692 free(vc->xoff);
1693 free(vc->yoff);
1694 vc->x = NULL;
1695 vc->y = NULL;
1696 vc->c = NULL;
1697 vc->xoff = NULL;
1698 vc->yoff = NULL;
1699 return False;
1701 memset(&df->style, 0, sizeof(df->style));
1702 DFS_FACE_TYPE(df->style) = VectorButton;
1704 else if (strncasecmp(style,"Solid",5)==0)
1706 s = GetNextToken(s, &file);
1707 if (file)
1709 memset(&df->style, 0, sizeof(df->style));
1710 DFS_FACE_TYPE(df->style) = SolidButton;
1711 df->u.back = GetColor(file);
1712 free(file);
1714 else
1716 if (verbose)
1718 fvwm_msg(
1719 ERR, "ReadDecorFace",
1720 "no color given for Solid"
1721 " face type: %s", action);
1723 return False;
1726 else if (strncasecmp(style+1, "Gradient", 8)==0)
1728 char **s_colors;
1729 int npixels, nsegs, *perc;
1730 XColor *xcs;
1731 Bool do_dither = False;
1733 if (!IsGradientTypeSupported(style[0]))
1735 return False;
1737 /* translate the gradient string into an array of
1738 * colors etc */
1739 npixels = ParseGradient(
1740 s, &s, &s_colors, &perc, &nsegs);
1741 while (*s && isspace(*s))
1743 s++;
1745 if (npixels <= 0)
1747 return False;
1749 /* grab the colors */
1750 if (Pdepth <= 16)
1752 do_dither = True;
1754 xcs = AllocAllGradientColors(
1755 s_colors, perc, nsegs, npixels, do_dither);
1756 if (xcs == None)
1757 return False;
1758 df->u.grad.xcs = xcs;
1759 df->u.grad.npixels = npixels;
1760 df->u.grad.do_dither = do_dither;
1761 df->u.grad.d_pixels = NULL;
1762 memset(&df->style, 0, sizeof(df->style));
1763 DFS_FACE_TYPE(df->style) = GradientButton;
1764 df->u.grad.gradient_type = toupper(style[0]);
1766 else if (strncasecmp(style,"Pixmap",6)==0
1767 || strncasecmp(style,"TiledPixmap",11)==0
1768 || strncasecmp(style,"StretchedPixmap",15)==0
1769 || strncasecmp(style,"AdjustedPixmap",14)==0
1770 || strncasecmp(style,"ShrunkPixmap",12)==0)
1772 FvwmPictureAttributes fpa;
1774 s = GetNextToken(s, &file);
1775 fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
1776 df->u.p = PCacheFvwmPicture(
1777 dpy, Scr.NoFocusWin, NULL, file, fpa);
1778 if (df->u.p == NULL)
1780 if (file)
1782 if (verbose)
1784 fvwm_msg(
1785 ERR, "ReadDecorFace",
1786 "couldn't load pixmap"
1787 " %s", file);
1789 free(file);
1791 return False;
1793 if (file)
1795 free(file);
1796 file = NULL;
1799 memset(&df->style, 0, sizeof(df->style));
1800 if (strncasecmp(style,"Tiled",5)==0)
1802 DFS_FACE_TYPE(df->style) = TiledPixmapButton;
1804 else if (strncasecmp(style,"Stretched",9)==0)
1806 DFS_FACE_TYPE(df->style) =
1807 StretchedPixmapButton;
1809 else if (strncasecmp(style,"Adjusted",8)==0)
1811 DFS_FACE_TYPE(df->style) =
1812 AdjustedPixmapButton;
1814 else if (strncasecmp(style,"Shrunk",6)==0)
1816 DFS_FACE_TYPE(df->style) =
1817 ShrunkPixmapButton;
1819 else
1821 DFS_FACE_TYPE(df->style) = PixmapButton;
1824 else if (strncasecmp(style,"MultiPixmap",11)==0)
1826 if (button != -1)
1828 if (verbose)
1830 fvwm_msg(
1831 ERR, "ReadDecorFace",
1832 "MultiPixmap is only valid"
1833 " for TitleStyle");
1835 return False;
1837 s = ReadMultiPixmapDecor(s, df);
1838 if (!s)
1840 return False;
1843 else if (FMiniIconsSupported &&
1844 strncasecmp (style, "MiniIcon", 8) == 0)
1846 memset(&df->style, 0, sizeof(df->style));
1847 DFS_FACE_TYPE(df->style) = MiniIconButton;
1848 /* pixmap read in when the window is created */
1849 df->u.p = NULL;
1851 else if (strncasecmp (style, "Colorset", 8) == 0)
1853 int val[2];
1854 int n;
1856 n = GetIntegerArguments(s, NULL, val, 2);
1857 if (n == 0)
1860 memset(&df->style, 0, sizeof(df->style));
1861 if (n > 0 && val[0] >= 0)
1864 df->u.acs.cs = val[0];
1865 alloc_colorset(val[0]);
1866 DFS_FACE_TYPE(df->style) = ColorsetButton;
1868 df->u.acs.alpha_percent = 100;
1869 if (n > 1)
1871 df->u.acs.alpha_percent =
1872 max(0, min(100,val[1]));
1874 s = SkipNTokens(s, n);
1876 else
1878 if (verbose)
1880 fvwm_msg(
1881 ERR, "ReadDecorFace",
1882 "unknown style %s: %s", style, action);
1884 return False;
1888 /* Process button flags ("--" signals start of flags,
1889 it is also checked for above) */
1890 s = GetNextToken(s, &file);
1891 if (file && (strcmp(file,"--")==0))
1893 char *tok;
1894 s = GetNextToken(s, &tok);
1895 while (tok && *tok)
1897 int set = 1;
1898 char *old_tok = NULL;
1900 if (*tok == '!')
1901 { /* flag negate */
1902 set = 0;
1903 old_tok = tok;
1904 tok++;
1906 if (StrEquals(tok,"Clear"))
1908 memset(&DFS_FLAGS(df->style), (set) ? 0 : 0xff,
1909 sizeof(DFS_FLAGS(df->style)));
1910 /* ? what is set == 0 good for ? */
1912 else if (StrEquals(tok,"Left"))
1914 if (set)
1916 DFS_H_JUSTIFICATION(df->style) =
1917 JUST_LEFT;
1919 else
1921 DFS_H_JUSTIFICATION(df->style) =
1922 JUST_RIGHT;
1925 else if (StrEquals(tok,"Right"))
1927 if (set)
1929 DFS_H_JUSTIFICATION(df->style) =
1930 JUST_RIGHT;
1932 else
1934 DFS_H_JUSTIFICATION(df->style) =
1935 JUST_LEFT;
1938 else if (StrEquals(tok,"Centered"))
1940 DFS_H_JUSTIFICATION(df->style) = JUST_CENTER;
1941 DFS_V_JUSTIFICATION(df->style) = JUST_CENTER;
1943 else if (StrEquals(tok,"Top"))
1945 if (set)
1947 DFS_V_JUSTIFICATION(df->style) =
1948 JUST_TOP;
1950 else
1952 DFS_V_JUSTIFICATION(df->style) =
1953 JUST_BOTTOM;
1956 else if (StrEquals(tok,"Bottom"))
1958 if (set)
1960 DFS_V_JUSTIFICATION(df->style) =
1961 JUST_BOTTOM;
1963 else
1965 DFS_V_JUSTIFICATION(df->style) =
1966 JUST_TOP;
1969 else if (StrEquals(tok,"Flat"))
1971 if (set)
1973 DFS_BUTTON_RELIEF(df->style) =
1974 DFS_BUTTON_IS_FLAT;
1976 else if (DFS_BUTTON_RELIEF(df->style) ==
1977 DFS_BUTTON_IS_FLAT)
1979 DFS_BUTTON_RELIEF(df->style) =
1980 DFS_BUTTON_IS_UP;
1983 else if (StrEquals(tok,"Sunk"))
1985 if (set)
1987 DFS_BUTTON_RELIEF(df->style) =
1988 DFS_BUTTON_IS_SUNK;
1990 else if (DFS_BUTTON_RELIEF(df->style) ==
1991 DFS_BUTTON_IS_SUNK)
1993 DFS_BUTTON_RELIEF(df->style) =
1994 DFS_BUTTON_IS_UP;
1997 else if (StrEquals(tok,"Raised"))
1999 if (set)
2001 DFS_BUTTON_RELIEF(df->style) =
2002 DFS_BUTTON_IS_UP;
2004 else
2006 DFS_BUTTON_RELIEF(df->style) =
2007 DFS_BUTTON_IS_SUNK;
2010 else if (StrEquals(tok,"UseTitleStyle"))
2012 if (set)
2014 DFS_USE_TITLE_STYLE(df->style) = 1;
2015 DFS_USE_BORDER_STYLE(df->style) = 0;
2017 else
2018 DFS_USE_TITLE_STYLE(df->style) = 0;
2020 else if (StrEquals(tok,"HiddenHandles"))
2022 DFS_HAS_HIDDEN_HANDLES(df->style) = !!set;
2024 else if (StrEquals(tok,"NoInset"))
2026 DFS_HAS_NO_INSET(df->style) = !!set;
2028 else if (StrEquals(tok,"UseBorderStyle"))
2030 if (set)
2032 DFS_USE_BORDER_STYLE(df->style) = 1;
2033 DFS_USE_TITLE_STYLE(df->style) = 0;
2035 else
2037 DFS_USE_BORDER_STYLE(df->style) = 0;
2040 else if (verbose)
2042 fvwm_msg(
2043 ERR, "ReadDecorFace",
2044 "unknown button face flag '%s'"
2045 " -- line: %s", tok, action);
2047 if (set)
2049 free(tok);
2051 else
2053 free(old_tok);
2055 s = GetNextToken(s, &tok);
2058 if (file)
2060 free(file);
2063 return True;
2066 #ifdef USEDECOR
2069 * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
2072 void AddToDecor(F_CMD_ARGS, FvwmDecor *decor)
2074 if (!action)
2076 return;
2078 while (*action && isspace((unsigned char)*action))
2080 ++action;
2082 if (!*action)
2084 return;
2086 Scr.cur_decor = decor;
2087 execute_function(cond_rc, exc, action, 0);
2088 Scr.cur_decor = NULL;
2090 return;
2095 * InitFvwmDecor -- initializes an FvwmDecor structure to defaults
2098 void InitFvwmDecor(FvwmDecor *decor)
2100 int i;
2101 DecorFace tmpdf;
2103 /* zero out the structures */
2104 memset(decor, 0, sizeof (FvwmDecor));
2105 memset(&tmpdf, 0, sizeof(DecorFace));
2107 /* initialize title-bar button styles */
2108 DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
2109 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
2111 int j = 0;
2112 for (; j < BS_MaxButtonState; ++j)
2114 TB_STATE(decor->buttons[i])[j] = tmpdf;
2117 /* reset to default button set */
2118 ResetAllButtons(decor);
2119 /* initialize title-bar styles */
2120 for (i = 0; i < BS_MaxButtonState; ++i)
2122 DFS_FACE_TYPE(
2123 TB_STATE(decor->titlebar)[i].style) = SimpleButton;
2126 /* initialize border texture styles */
2127 DFS_FACE_TYPE(decor->BorderStyle.active.style) = SimpleButton;
2128 DFS_FACE_TYPE(decor->BorderStyle.inactive.style) = SimpleButton;
2130 return;
2133 void reset_decor_changes(void)
2135 #ifndef USEDECOR
2136 Scr.DefaultDecor.flags.has_changed = 0;
2137 Scr.DefaultDecor.flags.has_title_height_changed = 0;
2138 #else
2139 FvwmDecor *decor;
2140 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
2142 decor->flags.has_changed = 0;
2143 decor->flags.has_title_height_changed = 0;
2145 /* todo: must reset individual change flags too */
2146 #endif
2148 return;
2151 void update_fvwm_colorset(int cset)
2153 if (cset == Scr.DefaultColorset)
2155 Scr.flags.do_need_window_update = 1;
2156 Scr.flags.has_default_color_changed = 1;
2158 UpdateMenuColorset(cset);
2159 update_style_colorset(cset);
2160 update_decors_colorset(cset);
2162 return;
2165 /* ---------------------------- builtin commands --------------------------- */
2167 void CMD_Beep(F_CMD_ARGS)
2169 #if 1 /*!!!*/
2170 parse_colorset(11, "RootTransparent");
2171 #endif
2172 XBell(dpy, 0);
2174 return;
2177 void CMD_Nop(F_CMD_ARGS)
2179 return;
2182 void CMD_EscapeFunc(F_CMD_ARGS)
2184 return;
2187 void CMD_CursorMove(F_CMD_ARGS)
2189 int x = 0, y = 0;
2190 int val1, val2, val1_unit, val2_unit;
2191 int virtual_x, virtual_y;
2192 int pan_x, pan_y;
2193 int x_pages, y_pages;
2195 if (GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit) != 2)
2197 fvwm_msg(ERR, "movecursor", "CursorMove needs 2 arguments");
2198 return;
2200 if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
2201 &x, &y, &JunkX, &JunkY, &JunkMask) == False)
2203 /* pointer is on a different screen */
2204 return;
2206 x = x + val1 * val1_unit / 100;
2207 y = y + val2 * val2_unit / 100;
2208 virtual_x = Scr.Vx;
2209 virtual_y = Scr.Vy;
2210 if (x >= 0)
2212 x_pages = x / Scr.MyDisplayWidth;
2214 else
2216 x_pages = ((x + 1) / Scr.MyDisplayWidth) - 1;
2218 virtual_x += x_pages * Scr.MyDisplayWidth;
2219 x -= x_pages * Scr.MyDisplayWidth;
2220 if (virtual_x < 0)
2222 x += virtual_x;
2223 virtual_x = 0;
2225 else if (virtual_x > Scr.VxMax)
2227 x += virtual_x - Scr.VxMax;
2228 virtual_x = Scr.VxMax;
2231 if (y >= 0)
2233 y_pages = y / Scr.MyDisplayHeight;
2235 else
2237 y_pages = ((y + 1) / Scr.MyDisplayHeight) - 1;
2239 virtual_y += y_pages * Scr.MyDisplayHeight;
2240 y -= y_pages * Scr.MyDisplayHeight;
2241 if (virtual_y < 0)
2243 y += virtual_y;
2244 virtual_y = 0;
2246 else if (virtual_y > Scr.VyMax)
2248 y += virtual_y - Scr.VyMax;
2249 virtual_y = Scr.VyMax;
2251 if (virtual_x != Scr.Vx || virtual_y != Scr.Vy)
2252 MoveViewport(virtual_x, virtual_y, True);
2253 pan_x = (Scr.EdgeScrollX != 0) ? 2 : 0;
2254 pan_y = (Scr.EdgeScrollY != 0) ? 2 : 0;
2255 /* prevent paging if EdgeScroll is active */
2256 if (x >= Scr.MyDisplayWidth - pan_x)
2258 x = Scr.MyDisplayWidth - pan_x -1;
2260 else if (x < pan_x)
2262 x = pan_x;
2264 if (y >= Scr.MyDisplayHeight - pan_y)
2266 y = Scr.MyDisplayHeight - pan_y - 1;
2268 else if (y < pan_y)
2270 y = pan_y;
2272 FWarpPointerUpdateEvpos(
2273 exc->x.elast, dpy, None, Scr.Root, 0, 0, Scr.MyDisplayWidth,
2274 Scr.MyDisplayHeight, x, y);
2276 return;
2279 void CMD_Delete(F_CMD_ARGS)
2281 FvwmWindow * const fw = exc->w.fw;
2283 if (!is_function_allowed(F_DELETE, NULL, fw, RQORIG_PROGRAM_US, True))
2285 XBell(dpy, 0);
2287 return;
2289 if (IS_TEAR_OFF_MENU(fw))
2291 /* 'soft' delete tear off menus. Note: we can't send the
2292 * message to the menu window directly because it was created
2293 * using a different display. The client message would never
2294 * be read from there. */
2295 send_clientmessage(
2296 dpy, FW_W_PARENT(fw), _XA_WM_DELETE_WINDOW,
2297 CurrentTime);
2299 return;
2301 if (WM_DELETES_WINDOW(fw))
2303 send_clientmessage(
2304 dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2306 return;
2308 else
2310 XBell(dpy, 0);
2312 XFlush(dpy);
2314 return;
2317 void CMD_Destroy(F_CMD_ARGS)
2319 FvwmWindow * const fw = exc->w.fw;
2321 if (IS_TEAR_OFF_MENU(fw))
2323 CMD_Delete(F_PASS_ARGS);
2324 return;
2326 if (!is_function_allowed(F_DESTROY, NULL, fw, True, True))
2328 XBell(dpy, 0);
2329 return;
2331 if (
2332 XGetGeometry(
2333 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2334 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2335 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2336 != 0)
2338 XKillClient(dpy, FW_W(fw));
2340 destroy_window(fw);
2341 XFlush(dpy);
2343 return;
2346 void CMD_Close(F_CMD_ARGS)
2348 FvwmWindow * const fw = exc->w.fw;
2350 if (IS_TEAR_OFF_MENU(fw))
2352 CMD_Delete(F_PASS_ARGS);
2353 return;
2355 if (!is_function_allowed(F_CLOSE, NULL, fw, True, True))
2357 XBell(dpy, 0);
2358 return;
2360 if (WM_DELETES_WINDOW(fw))
2362 send_clientmessage(
2363 dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2364 return;
2366 if (
2367 XGetGeometry(
2368 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2369 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2370 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2371 != 0)
2373 XKillClient(dpy, FW_W(fw));
2376 destroy_window(fw);
2377 XFlush(dpy);
2379 return;
2382 void CMD_Restart(F_CMD_ARGS)
2384 Done(1, action);
2386 return;
2389 void CMD_ExecUseShell(F_CMD_ARGS)
2391 char *arg=NULL;
2392 static char shell_set = 0;
2394 if (shell_set)
2396 free(exec_shell_name);
2398 shell_set = 1;
2399 action = GetNextToken(action,&arg);
2400 if (arg) /* specific shell was specified */
2402 exec_shell_name = arg;
2404 else /* no arg, so use $SHELL -- not working??? */
2406 if (getenv("SHELL"))
2408 exec_shell_name = safestrdup(getenv("SHELL"));
2410 else
2412 /* if $SHELL not set, use default */
2413 exec_shell_name = safestrdup("/bin/sh");
2418 void CMD_Exec(F_CMD_ARGS)
2420 char *cmd=NULL;
2422 /* if it doesn't already have an 'exec' as the first word, add that
2423 * to keep down number of procs started */
2424 /* need to parse string better to do this right though, so not doing
2425 * this for now... */
2426 #if 0
2427 if (strncasecmp(action,"exec",4)!=0)
2429 cmd = (char *)safemalloc(strlen(action)+6);
2430 strcpy(cmd,"exec ");
2431 strcat(cmd,action);
2433 else
2434 #endif
2436 cmd = safestrdup(action);
2438 if (!cmd)
2440 return;
2442 /* Use to grab the pointer here, but the fork guarantees that
2443 * we wont be held up waiting for the function to finish,
2444 * so the pointer-gram just caused needless delay and flashing
2445 * on the screen */
2446 /* Thought I'd try vfork and _exit() instead of regular fork().
2447 * The man page says that its better. */
2448 /* Not everyone has vfork! */
2449 /* According to the man page, vfork should never be used at all.
2452 if (!(fork())) /* child process */
2454 /* This is for fixing a problem with rox filer */
2455 int fd;
2457 fvmm_deinstall_signals();
2458 fd = open("/dev/null", O_RDONLY, 0);
2459 dup2(fd,STDIN_FILENO);
2460 if (fvwm_setpgrp() == -1)
2462 fvwm_msg(ERR, "exec_function", "setpgrp failed (%s)",
2463 strerror(errno));
2464 exit(100);
2466 if (execl(exec_shell_name, exec_shell_name, "-c", cmd, NULL) ==
2469 fvwm_msg(ERR, "exec_function", "execl failed (%s)",
2470 strerror(errno));
2471 exit(100);
2474 free(cmd);
2476 return;
2479 void CMD_Refresh(F_CMD_ARGS)
2481 refresh_window(Scr.Root, True);
2483 return;
2486 void CMD_RefreshWindow(F_CMD_ARGS)
2488 FvwmWindow * const fw = exc->w.fw;
2490 refresh_window(
2491 (exc->w.wcontext == C_ICON) ?
2492 FW_W_ICON_TITLE(fw) : FW_W_FRAME(fw), True);
2494 return;
2497 void CMD_Wait(F_CMD_ARGS)
2499 Bool done = False;
2500 Bool redefine_cursor = False;
2501 Bool is_ungrabbed;
2502 char *escape;
2503 Window nonewin = None;
2504 char *wait_string, *rest;
2505 FvwmWindow *t;
2507 /* try to get a single token */
2508 rest = GetNextToken(action, &wait_string);
2509 if (wait_string)
2511 while (*rest && isspace((unsigned char)*rest))
2513 rest++;
2515 if (*rest)
2517 int i;
2518 char *temp;
2520 /* nope, multiple tokens - try old syntax */
2522 /* strip leading and trailing whitespace */
2523 temp = action;
2524 while (*temp && isspace((unsigned char)*temp))
2526 temp++;
2528 wait_string = safestrdup(temp);
2529 for (i = strlen(wait_string) - 1; i >= 0 &&
2530 isspace(wait_string[i]); i--)
2532 wait_string[i] = 0;
2536 else
2538 wait_string = safestrdup("");
2541 is_ungrabbed = UngrabEm(GRAB_NORMAL);
2542 while (!done && !isTerminated)
2544 XEvent e;
2545 if (BUSY_WAIT & Scr.BusyCursor)
2547 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_WAIT]);
2548 redefine_cursor = True;
2550 if (My_XNextEvent(dpy, &e))
2552 dispatch_event(&e);
2553 if (XFindContext(
2554 dpy, e.xmap.window, FvwmContext,
2555 (caddr_t *)&t) == XCNOENT)
2557 t = NULL;
2560 if (e.type == MapNotify && e.xmap.event == Scr.Root)
2562 if (!*wait_string)
2564 done = True;
2566 if (t && matchWildcards(
2567 wait_string, t->name.name) == True)
2569 done = True;
2571 else if (t && t->class.res_class &&
2572 matchWildcards(
2573 wait_string,
2574 t->class.res_class) == True)
2576 done = True;
2578 else if (t && t->class.res_name &&
2579 matchWildcards(
2580 wait_string,
2581 t->class.res_name) == True)
2583 done = True;
2586 else if (e.type == KeyPress)
2588 /* should I be using <t> or <exc->w.fw>?
2589 * DV: t
2591 int context;
2592 XClassHint *class;
2593 char *name;
2595 context = GetContext(&t, t, &e, &nonewin);
2596 if (t != NULL)
2598 class = &(t->class);
2599 name = t->name.name;
2601 else
2603 class = NULL;
2604 name = NULL;
2606 escape = CheckBinding(
2607 Scr.AllBindings, STROKE_ARG(0)
2608 e.xkey.keycode, e.xkey.state,
2609 GetUnusedModifiers(), context,
2610 BIND_KEYPRESS, class, name);
2611 if (escape != NULL)
2613 if (!strcasecmp(escape,"escapefunc"))
2615 done = True;
2621 if (redefine_cursor)
2623 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
2625 if (is_ungrabbed)
2627 GrabEm(CRS_NONE, GRAB_NORMAL);
2629 free(wait_string);
2631 return;
2634 void CMD_Quit(F_CMD_ARGS)
2636 if (master_pid != getpid())
2638 kill(master_pid, SIGTERM);
2640 Done(0,NULL);
2642 return;
2645 void CMD_QuitScreen(F_CMD_ARGS)
2647 Done(0,NULL);
2649 return;
2652 void CMD_Echo(F_CMD_ARGS)
2654 int len;
2656 if (!action)
2658 action = "";
2660 len = strlen(action);
2661 if (len != 0)
2663 if (action[len-1]=='\n')
2665 action[len-1]='\0';
2668 fvwm_msg(ECHO,"Echo",action);
2670 return;
2673 void CMD_PrintInfo(F_CMD_ARGS)
2675 int verbose;
2676 char *rest, *subject = NULL;
2678 rest = GetNextToken(action, &subject);
2679 if (!rest || GetIntegerArguments(rest, NULL, &verbose, 1) != 1)
2681 verbose = 0;
2683 if (StrEquals(subject, "Colors"))
2685 PicturePrintColorInfo(verbose);
2687 else if (StrEquals(subject, "Locale"))
2689 FlocalePrintLocaleInfo(dpy, verbose);
2691 else if (StrEquals(subject, "NLS"))
2693 FGettextPrintLocalePath(verbose);
2695 else if (StrEquals(subject, "style"))
2697 print_styles(verbose);
2699 else if (StrEquals(subject, "ImageCache"))
2701 PicturePrintImageCache(verbose);
2703 else if (StrEquals(subject, "Bindings"))
2705 print_bindings();
2707 else
2709 fvwm_msg(ERR, "PrintInfo",
2710 "Unknown subject '%s'", action);
2712 if (subject)
2714 free(subject);
2716 return;
2719 void CMD_ColormapFocus(F_CMD_ARGS)
2721 if (MatchToken(action,"FollowsFocus"))
2723 Scr.ColormapFocus = COLORMAP_FOLLOWS_FOCUS;
2725 else if (MatchToken(action,"FollowsMouse"))
2727 Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
2729 else
2731 fvwm_msg(ERR, "SetColormapFocus",
2732 "ColormapFocus requires 1 arg: FollowsFocus or"
2733 " FollowsMouse");
2734 return;
2737 return;
2740 void CMD_ClickTime(F_CMD_ARGS)
2742 int val;
2744 if (GetIntegerArguments(action, NULL, &val, 1) != 1)
2746 Scr.ClickTime = DEFAULT_CLICKTIME;
2748 else
2750 Scr.ClickTime = (val < 0)? 0 : val;
2753 /* Use a negative value during startup and change sign afterwards. This
2754 * speeds things up quite a bit. */
2755 if (fFvwmInStartup)
2757 Scr.ClickTime = -Scr.ClickTime;
2760 return;
2764 void CMD_ImagePath(F_CMD_ARGS)
2766 PictureSetImagePath( action );
2768 return;
2771 void CMD_IconPath(F_CMD_ARGS)
2773 fvwm_msg(ERR, "iconPath_function",
2774 "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2775 obsolete_imagepaths( action );
2777 return;
2780 void CMD_PixmapPath(F_CMD_ARGS)
2782 fvwm_msg(ERR, "pixmapPath_function",
2783 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2784 " instead." );
2785 obsolete_imagepaths( action );
2787 return;
2790 void CMD_LocalePath(F_CMD_ARGS)
2792 FGettextSetLocalePath( action );
2794 return;
2797 void CMD_ModulePath(F_CMD_ARGS)
2799 static int need_to_free = 0;
2801 setPath( &ModulePath, action, need_to_free );
2802 need_to_free = 1;
2804 return;
2807 void CMD_ModuleTimeout(F_CMD_ARGS)
2809 int timeout;
2811 moduleTimeout = DEFAULT_MODULE_TIMEOUT;
2812 if (GetIntegerArguments(action, NULL, &timeout, 1) == 1 && timeout > 0)
2814 moduleTimeout = timeout;
2817 return;
2820 void CMD_HilightColor(F_CMD_ARGS)
2822 char *fore;
2823 char *back;
2824 #ifdef USEDECOR
2825 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2827 fvwm_msg(
2828 ERR, "SetHiColor",
2829 "Decors do not support the HilightColor command"
2830 " anymore. Please use"
2831 " 'Style <stylename> HilightFore <forecolor>' and"
2832 " 'Style <stylename> HilightBack <backcolor>' instead."
2833 " Sorry for the inconvenience.");
2834 return;
2836 #endif
2837 action = GetNextToken(action, &fore);
2838 GetNextToken(action, &back);
2839 if (fore && back)
2841 action = safemalloc(strlen(fore) + strlen(back) + 29);
2842 sprintf(action, "* HilightFore %s, HilightBack %s", fore, back);
2843 CMD_Style(F_PASS_ARGS);
2845 if (fore)
2847 free(fore);
2849 if (back)
2851 free(back);
2854 return;
2857 void CMD_HilightColorset(F_CMD_ARGS)
2859 char *newaction;
2861 #ifdef USEDECOR
2862 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2864 fvwm_msg(
2865 ERR, "SetHiColorset",
2866 "Decors do not support the HilightColorset command "
2867 "anymore. Please use "
2868 "'Style <stylename> HilightColorset <colorset>'"
2869 " instead. Sorry for the inconvenience.");
2870 return;
2872 #endif
2873 if (action)
2875 newaction = safemalloc(strlen(action) + 32);
2876 sprintf(newaction, "* HilightColorset %s", action);
2877 action = newaction;
2878 CMD_Style(F_PASS_ARGS);
2879 free(newaction);
2882 return;
2885 void CMD_TitleStyle(F_CMD_ARGS)
2887 do_title_style(F_PASS_ARGS, False);
2889 return;
2890 } /* SetTitleStyle */
2894 * Appends a titlestyle (veliaa@rpi.edu)
2897 void CMD_AddTitleStyle(F_CMD_ARGS)
2899 do_title_style(F_PASS_ARGS, True);
2901 return;
2904 void CMD_PropertyChange(F_CMD_ARGS)
2906 char string[256];
2907 char *token;
2908 char *rest;
2909 int ret;
2910 unsigned long argument;
2911 unsigned long data1;
2912 unsigned long data2;
2914 /* argument */
2915 token = PeekToken(action, &rest);
2916 if (token == NULL)
2918 return;
2920 ret = sscanf(token, "%lu", &argument);
2921 if (ret < 1)
2923 return;
2925 /* data1 */
2926 data1 = 0;
2927 token = PeekToken(rest, &rest);
2928 if (token != NULL)
2930 ret = sscanf(token, "%lu", &data1);
2931 if (ret < 1)
2933 rest = NULL;
2936 /* data2 */
2937 data2 = 0;
2938 token = PeekToken(rest, &rest);
2939 if (token != NULL)
2941 ret = sscanf(token, "%lu", &data2);
2942 if (ret < 1)
2944 rest = NULL;
2947 /* string */
2948 memset(string, 0, 256);
2949 if (rest != NULL)
2951 ret = sscanf(rest, "%255c", &(string[0]));
2953 BroadcastPropertyChange(argument, data1, data2, string);
2955 return;
2958 void CMD_DefaultIcon(F_CMD_ARGS)
2960 if (Scr.DefaultIcon)
2962 free(Scr.DefaultIcon);
2964 GetNextToken(action, &Scr.DefaultIcon);
2966 return;
2969 void CMD_DefaultColorset(F_CMD_ARGS)
2971 int cset;
2973 if (GetIntegerArguments(action, NULL, &cset, 1) != 1)
2975 return;
2977 Scr.DefaultColorset = cset;
2978 if (Scr.DefaultColorset < 0)
2980 Scr.DefaultColorset = -1;
2982 alloc_colorset(Scr.DefaultColorset);
2983 Scr.flags.do_need_window_update = 1;
2984 Scr.flags.has_default_color_changed = 1;
2986 return;
2989 void CMD_DefaultColors(F_CMD_ARGS)
2991 char *fore = NULL;
2992 char *back = NULL;
2994 action = GetNextToken(action, &fore);
2995 if (action)
2997 action = GetNextToken(action, &back);
2999 if (!back)
3001 back = safestrdup(DEFAULT_BACK_COLOR);
3003 if (!fore)
3005 fore = safestrdup(DEFAULT_FORE_COLOR);
3007 if (!StrEquals(fore, "-"))
3009 PictureFreeColors(dpy, Pcmap, &Scr.StdFore, 1, 0, True);
3010 Scr.StdFore = GetColor(fore);
3012 if (!StrEquals(back, "-"))
3014 PictureFreeColors(dpy, Pcmap, &Scr.StdBack, 3, 0, True);
3015 Scr.StdBack = GetColor(back);
3016 Scr.StdHilite = GetHilite(Scr.StdBack);
3017 Scr.StdShadow = GetShadow(Scr.StdBack);
3019 free(fore);
3020 free(back);
3022 Scr.DefaultColorset = -1;
3023 Scr.flags.do_need_window_update = 1;
3024 Scr.flags.has_default_color_changed = 1;
3026 return;
3029 void CMD_DefaultFont(F_CMD_ARGS)
3031 char *font;
3032 FlocaleFont *new_font;
3033 FvwmWindow *t;
3035 font = PeekToken(action, &action);
3036 if (!font)
3038 /* Try 'fixed', pass NULL font name */
3040 if (!(new_font = FlocaleLoadFont(dpy, font, "fvwm")))
3042 if (Scr.DefaultFont == NULL)
3044 exit(1);
3046 else
3048 return;
3051 FlocaleUnloadFont(dpy, Scr.DefaultFont);
3052 Scr.DefaultFont = new_font;
3053 /* we should do that here because a redraw can happen before
3054 flush_window_updates is called ... */
3055 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
3057 if (USING_DEFAULT_ICON_FONT(t))
3059 t->icon_font = Scr.DefaultFont;
3061 if (USING_DEFAULT_WINDOW_FONT(t))
3063 t->title_font = Scr.DefaultFont;
3066 /* set flags to indicate that the font has changed */
3067 Scr.flags.do_need_window_update = 1;
3068 Scr.flags.has_default_font_changed = 1;
3070 return;
3073 void CMD_IconFont(F_CMD_ARGS)
3075 char *newaction;
3077 #ifdef USEDECOR
3078 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3080 fvwm_msg(
3081 ERR, "LoadIconFont",
3082 "Decors do not support the IconFont command anymore."
3083 " Please use 'Style <stylename> IconFont <fontname>'"
3084 " instead. Sorry for the inconvenience.");
3085 return;
3087 #endif
3088 if (action)
3090 newaction = safemalloc(strlen(action) + 16);
3091 sprintf(newaction, "* IconFont %s", action);
3092 action = newaction;
3093 CMD_Style(F_PASS_ARGS);
3094 free(newaction);
3097 return;
3100 void CMD_WindowFont(F_CMD_ARGS)
3102 char *newaction;
3104 #ifdef USEDECOR
3105 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3107 fvwm_msg(
3108 ERR, "LoadWindowFont",
3109 "Decors do not support the WindowFont command anymore."
3110 " Please use 'Style <stylename> Font <fontname>'"
3111 " instead. Sorry for the inconvenience.");
3112 return;
3114 #endif
3115 if (action)
3117 newaction = safemalloc(strlen(action) + 16);
3118 sprintf(newaction, "* Font %s", action);
3119 action = newaction;
3120 CMD_Style(F_PASS_ARGS);
3121 free(newaction);
3124 return;
3129 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3132 void CMD_ChangeDecor(F_CMD_ARGS)
3134 char *item;
3135 int old_height;
3136 FvwmDecor *decor = &Scr.DefaultDecor;
3137 FvwmDecor *found = NULL;
3138 FvwmWindow * const fw = exc->w.fw;
3140 item = PeekToken(action, &action);
3141 if (!action || !item)
3143 return;
3145 /* search for tag */
3146 for (; decor; decor = decor->next)
3148 if (decor->tag && StrEquals(item, decor->tag))
3150 found = decor;
3151 break;
3154 if (!found)
3156 XBell(dpy, 0);
3157 return;
3159 SET_DECOR_CHANGED(fw, 1);
3160 old_height = (fw->decor) ? fw->decor->title_height : 0;
3161 fw->decor = found;
3162 apply_decor_change(fw);
3164 return;
3169 * Destroys an FvwmDecor (veliaa@rpi.edu)
3172 void CMD_DestroyDecor(F_CMD_ARGS)
3174 char *item;
3175 FvwmDecor *decor = Scr.DefaultDecor.next;
3176 FvwmDecor *prev = &Scr.DefaultDecor, *found = NULL;
3177 Bool do_recreate = False;
3179 item = PeekToken(action, &action);
3180 if (!item)
3182 return;
3184 if (StrEquals(item, "recreate"))
3186 do_recreate = True;
3187 item = PeekToken(action, NULL);
3189 if (!item)
3191 return;
3194 /* search for tag */
3195 for (; decor; decor = decor->next)
3197 if (decor->tag && StrEquals(item, decor->tag))
3199 found = decor;
3200 break;
3202 prev = decor;
3205 if (found && (found != &Scr.DefaultDecor || do_recreate))
3207 if (!do_recreate)
3209 __remove_window_decors(F_PASS_ARGS, found);
3211 DestroyFvwmDecor(found);
3212 if (do_recreate)
3214 int i;
3216 InitFvwmDecor(found);
3217 found->tag = safestrdup(item);
3218 Scr.flags.do_need_window_update = 1;
3219 found->flags.has_changed = 1;
3220 found->flags.has_title_height_changed = 0;
3221 found->titlebar.flags.has_changed = 1;
3222 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
3224 TB_FLAGS(found->buttons[i]).has_changed = 1;
3227 else
3229 prev->next = found->next;
3230 free(found);
3234 return;
3239 * Initiates an AddToDecor (veliaa@rpi.edu)
3242 void CMD_AddToDecor(F_CMD_ARGS)
3244 FvwmDecor *decor;
3245 FvwmDecor *found = NULL;
3246 char *item = NULL;
3248 action = GetNextToken(action, &item);
3249 if (!item)
3251 return;
3253 if (!action)
3255 free(item);
3256 return;
3258 /* search for tag */
3259 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3261 if (decor->tag && StrEquals(item, decor->tag))
3263 found = decor;
3264 break;
3267 if (!found)
3269 /* then make a new one */
3270 found = (FvwmDecor *)safemalloc(sizeof( FvwmDecor ));
3271 InitFvwmDecor(found);
3272 found->tag = item; /* tag it */
3273 /* add it to list */
3274 for (decor = &Scr.DefaultDecor; decor->next;
3275 decor = decor->next)
3277 /* nop */
3279 decor->next = found;
3281 else
3283 free(item);
3286 if (found)
3288 AddToDecor(F_PASS_ARGS, found);
3289 /* Set + state to last decor */
3290 set_last_added_item(ADDED_DECOR, found);
3293 return;
3295 #endif /* USEDECOR */
3300 * Updates window decoration styles (veliaa@rpi.edu)
3303 void CMD_UpdateDecor(F_CMD_ARGS)
3305 FvwmWindow *fw2;
3306 #ifdef USEDECOR
3307 FvwmDecor *decor, *found = NULL;
3308 FvwmWindow *hilight = Scr.Hilite;
3309 char *item = NULL;
3311 action = GetNextToken(action, &item);
3312 if (item)
3314 /* search for tag */
3315 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3317 if (decor->tag && StrEquals(item, decor->tag))
3319 found = decor;
3320 break;
3323 free(item);
3325 #endif
3327 for (fw2 = Scr.FvwmRoot.next; fw2; fw2 = fw2->next)
3329 #ifdef USEDECOR
3330 /* update specific decor, or all */
3331 if (found)
3333 if (fw2->decor == found)
3335 border_draw_decorations(
3336 fw2, PART_ALL, True, True, CLEAR_ALL,
3337 NULL, NULL);
3338 border_draw_decorations(
3339 fw2, PART_ALL, False, True, CLEAR_ALL,
3340 NULL, NULL);
3343 else
3344 #endif
3346 border_draw_decorations(
3347 fw2, PART_ALL, True, True, CLEAR_ALL, NULL,
3348 NULL);
3349 border_draw_decorations(
3350 fw2, PART_ALL, False, True, CLEAR_ALL, NULL,
3351 NULL);
3354 border_draw_decorations(
3355 hilight, PART_ALL, True, True, CLEAR_ALL, NULL, NULL);
3358 void CMD_ButtonStyle(F_CMD_ARGS)
3360 do_button_style(F_PASS_ARGS, False);
3362 return;
3367 * Appends a button decoration style (veliaa@rpi.edu)
3370 void CMD_AddButtonStyle(F_CMD_ARGS)
3372 do_button_style(F_PASS_ARGS, True);
3374 return;
3377 void CMD_SetEnv(F_CMD_ARGS)
3379 char *szVar = NULL;
3380 char *szValue = NULL;
3381 char *szPutenv = NULL;
3383 action = GetNextToken(action, &szVar);
3384 if (!szVar)
3386 return;
3388 action = GetNextToken(action, &szValue);
3389 if (!szValue)
3391 szValue = safestrdup("");
3393 szPutenv = safemalloc(strlen(szVar) + strlen(szValue) + 2);
3394 sprintf(szPutenv,"%s=%s", szVar, szValue);
3395 flib_putenv(szVar, szPutenv);
3396 free(szVar);
3397 free(szPutenv);
3398 free(szValue);
3400 return;
3403 void CMD_UnsetEnv(F_CMD_ARGS)
3405 char *szVar = NULL;
3407 szVar = PeekToken(action, &action);
3408 if (!szVar)
3410 return;
3412 flib_unsetenv(szVar);
3414 return;
3417 void CMD_GlobalOpts(F_CMD_ARGS)
3419 char *opt;
3420 char *replace;
3421 char buf[64];
3422 int i;
3423 Bool is_bugopt;
3424 char *optlist[] = {
3425 "WindowShadeShrinks",
3426 "WindowShadeScrolls",
3427 "SmartPlacementIsReallySmart",
3428 "SmartPlacementIsNormal",
3429 "ClickToFocusDoesntPassClick",
3430 "ClickToFocusPassesClick",
3431 "ClickToFocusDoesntRaise",
3432 "ClickToFocusRaises",
3433 "MouseFocusClickDoesntRaise",
3434 "MouseFocusClickRaises",
3435 "NoStipledTitles",
3436 "StipledTitles",
3437 "CaptureHonorsStartsOnPage",
3438 "CaptureIgnoresStartsOnPage",
3439 "RecaptureHonorsStartsOnPage",
3440 "RecaptureIgnoresStartsOnPage",
3441 "ActivePlacementHonorsStartsOnPage",
3442 "ActivePlacementIgnoresStartsOnPage",
3443 "RaiseOverNativeWindows",
3444 "IgnoreNativeWindows",
3445 NULL
3447 char *replacelist[] = {
3448 /* These options are mapped to the Style * command */
3449 NULL, /* NULL means to use "Style * <optionname>" */
3450 NULL,
3451 "* MinOverlapPlacement",
3452 "* TileCascadePlacement",
3453 "* ClickToFocusPassesClickOff",
3454 "* ClickToFocusPassesClick",
3455 "* ClickToFocusRaisesOff",
3456 "* ClickToFocusRaises",
3457 "* MouseFocusClickRaisesOff",
3458 "* MouseFocusClickRaises",
3459 "* StippledTitleOff",
3460 "* StippledTitle",
3461 NULL,
3462 NULL,
3463 NULL,
3464 NULL,
3465 "* ManualPlacementHonorsStartsOnPage",
3466 "* ManualPlacementIgnoresStartsOnPage",
3467 /* These options are mapped to the BugOpts command */
3468 "RaiseOverNativeWindows on",
3469 "RaiseOverNativeWindows off"
3472 fvwm_msg(ERR, "SetGlobalOptions",
3473 "The GlobalOpts command is obsolete.");
3474 for (action = GetNextSimpleOption(action, &opt); opt;
3475 action = GetNextSimpleOption(action, &opt))
3477 replace = NULL;
3478 is_bugopt = False;
3480 i = GetTokenIndex(opt, optlist, 0, NULL);
3481 if (i > -1)
3483 char *cmd;
3484 char *tmp;
3486 replace = replacelist[i];
3487 if (replace == NULL)
3489 replace = &(buf[0]);
3490 sprintf(buf, "* %s", opt);
3492 else if (*replace != '*')
3494 is_bugopt = True;
3496 tmp = action;
3497 action = replace;
3498 if (!is_bugopt)
3500 CMD_Style(F_PASS_ARGS);
3501 cmd = "Style";
3503 else
3505 CMD_BugOpts(F_PASS_ARGS);
3506 cmd = "BugOpts";
3508 action = tmp;
3509 fvwm_msg(
3510 ERR, "SetGlobalOptions",
3511 "Please replace 'GlobalOpts %s' with '%s %s'.",
3512 opt, cmd, replace);
3514 else
3516 fvwm_msg(ERR, "SetGlobalOptions",
3517 "Unknown Global Option '%s'", opt);
3519 /* should never be null, but checking anyways... */
3520 if (opt)
3522 free(opt);
3525 if (opt)
3527 free(opt);
3530 return;
3533 void CMD_BugOpts(F_CMD_ARGS)
3535 char *opt;
3536 char delim;
3537 int toggle;
3539 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3540 while (action)
3542 action = DoGetNextToken(action, &opt, NULL, ",", &delim);
3543 if (!opt)
3545 /* no more options */
3546 return;
3548 if (delim == '\n' || delim == ',')
3550 /* missing toggle argument */
3551 toggle = 2;
3553 else
3555 toggle = ParseToggleArgument(action, &action, 1, False);
3558 if (StrEquals(opt, "FlickeringMoveWorkaround"))
3560 switch (toggle)
3562 case -1:
3563 Scr.bo.do_disable_configure_notify ^= 1;
3564 break;
3565 case 0:
3566 case 1:
3567 Scr.bo.do_disable_configure_notify = toggle;
3568 break;
3569 default:
3570 Scr.bo.do_disable_configure_notify = 0;
3571 break;
3574 else if (StrEquals(opt, "MixedVisualWorkaround"))
3576 switch (toggle)
3578 case -1:
3579 Scr.bo.do_install_root_cmap ^= 1;
3580 break;
3581 case 0:
3582 case 1:
3583 Scr.bo.do_install_root_cmap = toggle;
3584 break;
3585 default:
3586 Scr.bo.do_install_root_cmap = 0;
3587 break;
3590 else if (StrEquals(opt, "ModalityIsEvil"))
3592 switch (toggle)
3594 case -1:
3595 Scr.bo.is_modality_evil ^= 1;
3596 break;
3597 case 0:
3598 case 1:
3599 Scr.bo.is_modality_evil = toggle;
3600 break;
3601 default:
3602 Scr.bo.is_modality_evil = 0;
3603 break;
3605 if (Scr.bo.is_modality_evil)
3607 SetMWM_INFO(Scr.NoFocusWin);
3610 else if (StrEquals(opt, "RaiseOverNativeWindows"))
3612 switch (toggle)
3614 case -1:
3615 Scr.bo.is_raise_hack_needed ^= 1;
3616 break;
3617 case 0:
3618 case 1:
3619 Scr.bo.is_raise_hack_needed = toggle;
3620 break;
3621 default:
3622 Scr.bo.is_raise_hack_needed = 0;
3623 break;
3626 else if (StrEquals(opt, "RaiseOverUnmanaged"))
3628 switch (toggle)
3630 case -1:
3631 Scr.bo.do_raise_over_unmanaged ^= 1;
3632 break;
3633 case 0:
3634 case 1:
3635 Scr.bo.do_raise_over_unmanaged = toggle;
3636 break;
3637 default:
3638 Scr.bo.do_raise_over_unmanaged = 0;
3639 break;
3642 else if (StrEquals(opt, "FlickeringQtDialogsWorkaround"))
3644 switch (toggle)
3646 case -1:
3647 Scr.bo.do_enable_flickering_qt_dialogs_workaround ^= 1;
3648 break;
3649 case 0:
3650 case 1:
3651 Scr.bo.do_enable_flickering_qt_dialogs_workaround = toggle;
3652 break;
3653 default:
3654 Scr.bo.do_enable_flickering_qt_dialogs_workaround = 0;
3655 break;
3658 else if (EWMH_BugOpts(opt, toggle))
3660 /* work is done in EWMH_BugOpts */
3662 else if (StrEquals(opt, "DisplayNewWindowNames"))
3664 switch (toggle)
3666 case -1:
3667 Scr.bo.do_display_new_window_names ^= 1;
3668 break;
3669 case 0:
3670 case 1:
3671 Scr.bo.do_display_new_window_names = toggle;
3672 break;
3673 default:
3674 Scr.bo.do_display_new_window_names = 0;
3675 break;
3678 else if (StrEquals(opt, "ExplainWindowPlacement"))
3680 switch (toggle)
3682 case -1:
3683 Scr.bo.do_explain_window_placement ^= 1;
3684 break;
3685 case 0:
3686 case 1:
3687 Scr.bo.do_explain_window_placement = toggle;
3688 break;
3689 default:
3690 Scr.bo.do_explain_window_placement = 0;
3691 break;
3694 else if (StrEquals(opt, "DebugCRMotionMethod"))
3696 switch (toggle)
3698 case -1:
3699 Scr.bo.do_debug_cr_motion_method ^= 1;
3700 break;
3701 case 0:
3702 case 1:
3703 Scr.bo.do_debug_cr_motion_method = toggle;
3704 break;
3705 default:
3706 Scr.bo.do_debug_cr_motion_method = 0;
3707 break;
3710 else
3712 fvwm_msg(ERR, "SetBugOptions",
3713 "Unknown Bug Option '%s'", opt);
3715 free(opt);
3718 return;
3721 void CMD_Emulate(F_CMD_ARGS)
3723 char *style;
3725 style = PeekToken(action, NULL);
3726 if (!style || StrEquals(style, "fvwm"))
3728 Scr.gs.do_emulate_mwm = False;
3729 Scr.gs.do_emulate_win = False;
3731 else if (StrEquals(style, "mwm"))
3733 Scr.gs.do_emulate_mwm = True;
3734 Scr.gs.do_emulate_win = False;
3736 else if (StrEquals(style, "win"))
3738 Scr.gs.do_emulate_mwm = False;
3739 Scr.gs.do_emulate_win = True;
3741 else
3743 fvwm_msg(ERR, "Emulate", "Unknown style '%s'", style);
3744 return;
3746 Scr.flags.do_need_window_update = 1;
3747 Scr.flags.has_default_font_changed = 1;
3748 Scr.flags.has_default_color_changed = 1;
3750 return;
3753 void CMD_ColorLimit(F_CMD_ARGS)
3755 fvwm_msg(
3756 WARN, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3757 "fvwm -color-limit option");
3759 return;
3763 /* set animation parameters */
3764 void CMD_SetAnimation(F_CMD_ARGS)
3766 char *opt;
3767 int delay;
3768 float pct;
3769 int i = 0;
3771 opt = PeekToken(action, &action);
3772 if (!opt || sscanf(opt,"%d",&delay) != 1)
3774 fvwm_msg(ERR,"SetAnimation",
3775 "Improper milli-second delay as first argument");
3776 return;
3778 if (delay > 500)
3780 fvwm_msg(WARN,"SetAnimation",
3781 "Using longer than .5 seconds as between frame"
3782 " animation delay");
3784 cmsDelayDefault = delay;
3785 for (opt = PeekToken(action, &action); opt;
3786 opt = PeekToken(action, &action))
3788 if (sscanf(opt,"%f",&pct) != 1)
3790 fvwm_msg(ERR,"SetAnimation",
3791 "Use fractional values ending in 1.0 as args"
3792 " 2 and on");
3793 return;
3795 rgpctMovementDefault[i++] = pct;
3797 /* No pct entries means don't change them at all */
3798 if (i > 0 && rgpctMovementDefault[i-1] != 1.0)
3800 rgpctMovementDefault[i++] = 1.0;
3803 return;
3806 /* Determine which modifiers are required with a keycode to make <keysym>. */
3807 static Bool FKeysymToKeycode (Display *dpy, KeySym keysym,
3808 unsigned int *keycode, unsigned int *modifiers)
3810 int m;
3812 *keycode = XKeysymToKeycode(dpy, keysym);
3813 *modifiers = 0;
3815 for (m = 0; m <= 8; ++m)
3817 KeySym ks = XKeycodeToKeysym(dpy, *keycode, m);
3818 if (ks == keysym)
3820 switch (m)
3822 case 0: /* No modifiers */
3823 break;
3824 case 1: /* Shift modifier */
3825 *modifiers |= ShiftMask;
3826 break;
3827 default:
3828 fvwm_msg(ERR, "FKeysymToKeycode",
3829 "Unhandled modifier %d", m);
3830 break;
3832 return True;
3835 return False;
3838 static void __fake_event(F_CMD_ARGS, FakeEventType type)
3840 char *token;
3841 char *optlist[] = {
3842 "press", "p",
3843 "release", "r",
3844 "wait", "w",
3845 "modifiers", "m",
3846 "depth", "d",
3847 NULL
3849 unsigned int mask = 0;
3850 Window root = Scr.Root;
3851 int maxdepth = 0;
3852 static char args[128];
3853 strncpy(args, action, sizeof(args) - 1);
3855 /* get the mask of pressed/released buttons/keys */
3856 FQueryPointer(
3857 dpy, Scr.Root, &root, &JunkRoot, &JunkX, &JunkY, &JunkX,
3858 &JunkY, &mask);
3860 token = PeekToken(action, &action);
3861 while (token && action)
3863 int index = GetTokenIndex(token, optlist, 0, NULL);
3864 int val, depth;
3865 XEvent e;
3866 Window w;
3867 Window child_w;
3868 int x = 0;
3869 int y = 0;
3870 int rx = 0;
3871 int ry = 0;
3872 Bool do_unset;
3873 long add_mask = 0;
3874 KeySym keysym = NoSymbol;
3876 XFlush(dpy);
3877 do_unset = True;
3878 switch (index)
3880 case 0:
3881 case 1:
3882 do_unset = False;
3883 /* fall through */
3884 case 2:
3885 case 3:
3886 /* key/button press or release */
3887 if (type == FakeMouseEvent)
3889 if ((GetIntegerArguments(
3890 action, &action, &val, 1) != 1) ||
3891 val < 1 ||
3892 val > NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
3894 fvwm_msg(
3895 ERR, "__fake_event",
3896 "Invalid button specifier in"
3897 " \"%s\" for FakeClick.", args);
3898 return; /* error */
3901 else /* type == FakeKeyEvent */
3903 char *key = PeekToken(action, &action);
3904 if (key == NULL)
3906 fvwm_msg(
3907 ERR, "__fake_event",
3908 "No keysym specifier in \"%s\""
3909 " for FakeKeypress.", args);
3910 return;
3913 /* Do *NOT* use FvwmStringToKeysym() as it is
3914 * case insensitive. */
3915 keysym = XStringToKeysym(key);
3916 if (keysym == NoSymbol)
3918 fvwm_msg(
3919 ERR, "__fake_event",
3920 "Invalid keysym specifier (%s)"
3921 " in \"%s\" for FakeKeypress.",
3922 key, args);
3923 return;
3927 w = None;
3928 child_w = root;
3929 for (depth = 1;
3930 depth != maxdepth &&
3931 w != child_w && child_w != None;
3932 depth++)
3934 w = child_w;
3935 if (FQueryPointer(
3936 dpy, w, &root, &child_w,
3937 &rx, &ry, &x, &y,
3938 &JunkMask) == False)
3940 /* pointer is on a different
3941 * screen - that's okay here */
3945 if (type == FakeMouseEvent)
3947 e.type = (do_unset) ?
3948 ButtonRelease : ButtonPress;
3949 e.xbutton.display = dpy;
3950 e.xbutton.window = w;
3951 e.xbutton.subwindow = None;
3952 e.xbutton.root = root;
3953 e.xbutton.time = fev_get_evtime();
3954 e.xbutton.x = x;
3955 e.xbutton.y = y;
3956 e.xbutton.x_root = rx;
3957 e.xbutton.y_root = ry;
3958 e.xbutton.button = val;
3959 e.xbutton.state = mask;
3960 e.xbutton.same_screen = (Scr.Root == root);
3961 /* SS: I think this mask handling code is
3962 * buggy.
3963 * The value of <mask> is overridden during a
3964 * "wait" operation. Also why are we only using
3965 * Button1Mask? What if the user has requested
3966 * a FakeClick using some other button? */
3967 /* DV: Button1Mask is actually a bit. Shifting
3968 * it by (val -1) bits to the left gives
3969 * Button2Mask, Button3Mask etc. */
3970 if (do_unset)
3972 mask &= ~(Button1Mask << (val - 1));
3974 else
3976 mask |= (Button1Mask << (val - 1));
3978 add_mask = (do_unset) ?
3979 ButtonPressMask : ButtonReleaseMask;
3981 else
3983 /* type == FakeKeyEvent */
3984 e.type = (do_unset ? KeyRelease : KeyPress);
3985 e.xkey.display = dpy;
3986 e.xkey.subwindow = None;
3987 e.xkey.root = root;
3988 e.xkey.time = fev_get_evtime();
3989 e.xkey.x = x;
3990 e.xkey.y = y;
3991 e.xkey.x_root = rx;
3992 e.xkey.y_root = ry;
3993 e.xkey.same_screen = (Scr.Root == root);
3995 w = e.xkey.window = exc->w.w;
3997 if (FKeysymToKeycode(
3998 dpy, keysym, &(e.xkey.keycode),
3999 &(e.xkey.state)) != True)
4001 fvwm_msg(DBG, "__fake_event",
4002 "FKeysymToKeycode failed");
4003 return;
4005 e.xkey.state |= mask;
4006 add_mask = (do_unset) ?
4007 KeyReleaseMask : KeyPressMask;
4009 FSendEvent(dpy, w, True,
4010 SubstructureNotifyMask | add_mask, &e);
4011 XFlush(dpy);
4012 break;
4013 case 4:
4014 case 5:
4015 /* wait */
4016 if ((GetIntegerArguments(
4017 action, &action, &val, 1) != 1) ||
4018 val <= 0 || val > 1000000)
4020 fvwm_msg(ERR, "__fake_event",
4021 "Invalid wait value in \"%s\"", args);
4022 return;
4025 usleep(1000 * val);
4026 if (FQueryPointer(
4027 dpy, Scr.Root, &root, &JunkRoot,
4028 &JunkX, &JunkY, &JunkX, &JunkY,
4029 &mask) == False)
4031 /* pointer is on a different screen -
4032 * that's okay here */
4034 break;
4035 case 6:
4036 case 7:
4037 /* set modifier */
4038 if (GetIntegerArguments(action, &action, &val, 1) != 1)
4040 fvwm_msg(
4041 ERR, "__fake_event",
4042 "Invalid modifier value in \"%s\"",
4043 args);
4044 return;
4046 do_unset = False;
4047 if (val < 0)
4049 do_unset = True;
4050 val = -val;
4052 if (val == 6)
4054 val = ShiftMask;
4056 else if (val == 7)
4058 val = LockMask;
4060 else if (val == 8)
4062 val = ControlMask;
4064 else if (val >=1 && val <= 5)
4066 val = (Mod1Mask << (val - 1));
4068 else
4070 /* error */
4071 return;
4073 /* SS: Could be buggy if a "modifier" operation
4074 * preceeds a "wait" operation. */
4075 if (do_unset)
4077 mask &= ~val;
4079 else
4081 mask |= val;
4083 break;
4084 case 8:
4085 case 9:
4086 /* new max depth */
4087 if (GetIntegerArguments(action, &action, &val, 1) != 1)
4089 fvwm_msg(ERR, "__fake_event",
4090 "Invalid depth value in \"%s\"", args);
4091 return;
4093 maxdepth = val;
4094 break;
4095 default:
4096 fvwm_msg(ERR, "__fake_event",
4097 "Invalid command (%s) in \"%s\"", token, args);
4098 return;
4100 if (action)
4102 token = PeekToken(action, &action);
4106 return;
4109 void CMD_FakeClick(F_CMD_ARGS)
4111 __fake_event(F_PASS_ARGS, FakeMouseEvent);
4113 return;
4116 void CMD_FakeKeypress(F_CMD_ARGS)
4118 __fake_event(F_PASS_ARGS, FakeKeyEvent);
4120 return;
4123 /* A function to handle stroke (olicha Nov 11, 1999) */
4124 #ifdef HAVE_STROKE
4125 void CMD_StrokeFunc(F_CMD_ARGS)
4127 int finished = 0;
4128 int abort = 0;
4129 int modifiers = exc->x.etrigger->xbutton.state;
4130 int start_event_type = exc->x.etrigger->type;
4131 char sequence[STROKE_MAX_SEQUENCE + 1];
4132 char *stroke_action, *name;
4133 char *opt = NULL;
4134 Bool finish_on_release = True;
4135 KeySym keysym;
4136 Bool restore_repeat = False;
4137 Bool echo_sequence = False;
4138 Bool draw_motion = False;
4139 int i = 0;
4140 int *x = NULL;
4141 int *y = NULL;
4142 const int STROKE_CHUNK_SIZE = 0xff;
4143 int coords_size = STROKE_CHUNK_SIZE;
4144 Window JunkRoot, JunkChild;
4145 int JunkX, JunkY;
4146 int tmpx, tmpy;
4147 unsigned int JunkMask;
4148 Bool feed_back = False;
4149 int stroke_width = 1;
4150 XEvent e;
4151 XClassHint *class;
4155 if (!GrabEm(CRS_STROKE, GRAB_NORMAL))
4157 XBell(dpy, 0);
4158 return;
4160 x = (int*)safemalloc(coords_size * sizeof(int));
4161 y = (int*)safemalloc(coords_size * sizeof(int));
4162 e = *exc->x.etrigger;
4163 /* set the default option */
4164 if (e.type == KeyPress || e.type == ButtonPress)
4166 finish_on_release = True;
4168 else
4170 finish_on_release = False;
4173 /* parse the option */
4174 for (action = GetNextSimpleOption(action, &opt); opt;
4175 action = GetNextSimpleOption(action, &opt))
4177 if (StrEquals("NotStayPressed",opt))
4179 finish_on_release = False;
4181 else if (StrEquals("EchoSequence",opt))
4183 echo_sequence = True;
4185 else if (StrEquals("DrawMotion",opt))
4187 draw_motion = True;
4189 else if (StrEquals("FeedBack",opt))
4191 feed_back = True;
4193 else if (StrEquals("StrokeWidth",opt))
4195 /* stroke width takes a positive integer argument */
4196 if (opt)
4198 free(opt);
4200 action = GetNextToken(action, &opt);
4201 if (!opt)
4203 fvwm_msg(
4204 WARN, "StrokeWidth",
4205 "needs an integer argument");
4207 /* we allow stroke_width == 0 which means drawing a
4208 * `fast' line of width 1; the upper level of 100 is
4209 * arbitrary */
4210 else if (!sscanf(opt, "%d", &stroke_width) ||
4211 stroke_width < 0 || stroke_width > 100)
4213 fvwm_msg(
4214 WARN, "StrokeWidth",
4215 "Bad integer argument %d",
4216 stroke_width);
4217 stroke_width = 1;
4220 else
4222 fvwm_msg(WARN,"StrokeFunc","Unknown option %s", opt);
4224 if (opt)
4226 free(opt);
4229 if (opt)
4231 free(opt);
4234 /* Force auto repeat off and grab the Keyboard to get proper
4235 * KeyRelease events if we need it.
4236 * Some computers do not support KeyRelease events, can we
4237 * check this here ? No ? */
4238 if (start_event_type == KeyPress && finish_on_release)
4240 XKeyboardState kstate;
4242 XGetKeyboardControl(dpy, &kstate);
4243 if (kstate.global_auto_repeat == AutoRepeatModeOn)
4245 XAutoRepeatOff(dpy);
4246 restore_repeat = True;
4248 MyXGrabKeyboard(dpy);
4251 /* be ready to get a stroke sequence */
4252 stroke_init();
4254 if (draw_motion)
4256 MyXGrabServer(dpy);
4257 if (FQueryPointer(
4258 dpy, Scr.Root, &JunkRoot, &JunkChild, &x[0], &y[0],
4259 &JunkX, &JunkY, &JunkMask) == False)
4261 /* pointer is on a different screen */
4262 x[0] = 0;
4263 y[0] = 0;
4265 XSetLineAttributes(
4266 dpy,Scr.XorGC,stroke_width,LineSolid,CapButt,JoinMiter);
4269 while (!finished && !abort)
4271 /* block until there is an event */
4272 FMaskEvent(
4273 dpy, ButtonPressMask | ButtonReleaseMask |
4274 KeyPressMask | KeyReleaseMask | ButtonMotionMask |
4275 PointerMotionMask, &e);
4276 switch (e.type)
4278 case MotionNotify:
4279 if (e.xmotion.same_screen == False)
4281 continue;
4283 if (e.xany.window != Scr.Root)
4285 if (FQueryPointer(
4286 dpy, Scr.Root, &JunkRoot,
4287 &JunkChild, &tmpx, &tmpy, &JunkX,
4288 &JunkY, &JunkMask) == False)
4290 /* pointer is on a different screen */
4291 tmpx = 0;
4292 tmpy = 0;
4295 else
4297 tmpx = e.xmotion.x;
4298 tmpy = e.xmotion.y;
4300 stroke_record(tmpx,tmpy);
4301 if (draw_motion && (x[i] != tmpx || y[i] != tmpy))
4303 i++;
4304 if (i >= coords_size)
4306 coords_size += STROKE_CHUNK_SIZE;
4307 x = (int*)saferealloc(
4308 (void *)x, coords_size *
4309 sizeof(int));
4310 y = (int*)saferealloc(
4311 (void *)y, coords_size *
4312 sizeof(int));
4314 x[i] = tmpx;
4315 y[i] = tmpy;
4316 XDrawLine(
4317 dpy, Scr.Root, Scr.XorGC, x[i-1],
4318 y[i-1], x[i], y[i]);
4320 break;
4321 case ButtonRelease:
4322 if (finish_on_release && start_event_type ==
4323 ButtonPress)
4325 finished = 1;
4327 break;
4328 case KeyRelease:
4329 if (finish_on_release && start_event_type == KeyPress)
4331 finished = 1;
4333 break;
4334 case KeyPress:
4335 keysym = XLookupKeysym(&e.xkey, 0);
4336 /* abort if Escape or Delete is pressed (as in menus.c)
4338 if (keysym == XK_Escape || keysym == XK_Delete ||
4339 keysym == XK_KP_Separator)
4341 abort = 1;
4343 /* finish on enter or space (as in menus.c) */
4344 if (keysym == XK_Return || keysym == XK_KP_Enter ||
4345 keysym == XK_space)
4347 finished = 1;
4349 break;
4350 case ButtonPress:
4351 if (!finish_on_release)
4353 finished = 1;
4355 break;
4356 default:
4357 break;
4361 if (draw_motion)
4363 while (i > 0)
4365 XDrawLine(
4366 dpy, Scr.Root, Scr.XorGC, x[i-1], y[i-1], x[i],
4367 y[i]);
4368 i--;
4370 XSetLineAttributes(dpy,Scr.XorGC,0,LineSolid,CapButt,JoinMiter);
4371 MyXUngrabServer(dpy);
4373 if (x != NULL)
4375 free(x);
4376 free(y);
4378 if (start_event_type == KeyPress && finish_on_release)
4380 MyXUngrabKeyboard(dpy);
4382 UngrabEm(GRAB_NORMAL);
4383 if (restore_repeat)
4385 XAutoRepeatOn(dpy);
4388 /* get the stroke sequence */
4389 stroke_trans(sequence);
4391 if (echo_sequence)
4393 char num_seq[STROKE_MAX_SEQUENCE + 1];
4395 for (i = 0; sequence[i] != '\0';i++)
4397 /* Telephone to numeric pad */
4398 if ('7' <= sequence[i] && sequence[i] <= '9')
4400 num_seq[i] = sequence[i]-6;
4402 else if ('1' <= sequence[i] && sequence[i] <= '3')
4404 num_seq[i] = sequence[i]+6;
4406 else
4408 num_seq[i] = sequence[i];
4411 num_seq[i++] = '\0';
4412 fvwm_msg(INFO, "StrokeFunc", "stroke sequence: %s (N%s)",
4413 sequence, num_seq);
4415 if (abort)
4417 return;
4419 if (exc->w.fw == NULL)
4421 class = NULL;
4422 name = NULL;
4424 else
4426 class = &exc->w.fw->class;
4427 name = exc->w.fw->name.name;
4429 /* check for a binding */
4430 stroke_action = CheckBinding(
4431 Scr.AllBindings, sequence, 0, modifiers, GetUnusedModifiers(),
4432 exc->w.wcontext, BIND_STROKE, class, name);
4434 /* execute the action */
4435 if (stroke_action != NULL)
4437 const exec_context_t *exc2;
4438 exec_context_changes_t ecc;
4440 if (feed_back && atoi(sequence) != 0)
4442 GrabEm(CRS_WAIT, GRAB_BUSY);
4443 usleep(200000);
4444 UngrabEm(GRAB_BUSY);
4446 ecc.x.etrigger = &e;
4447 exc2 = exc_clone_context(exc, &ecc, ECC_ETRIGGER);
4448 execute_function(cond_rc, exc2, stroke_action, 0);
4449 exc_destroy_context(exc2);
4452 return;
4454 #endif /* HAVE_STROKE */
4456 void CMD_State(F_CMD_ARGS)
4458 unsigned int state;
4459 int toggle;
4460 int n;
4461 FvwmWindow * const fw = exc->w.fw;
4463 n = GetIntegerArguments(action, &action, (int *)&state, 1);
4464 if (n <= 0)
4466 return;
4468 if (state < 0 || state > 31)
4470 fvwm_msg(ERR, "CMD_State", "Illegal state %d\n", state);
4471 return;
4473 toggle = ParseToggleArgument(action, NULL, -1, 0);
4474 state = (1 << state);
4475 switch (toggle)
4477 case -1:
4478 TOGGLE_USER_STATES(fw, state);
4479 break;
4480 case 0:
4481 CLEAR_USER_STATES(fw, state);
4482 break;
4483 case 1:
4484 default:
4485 SET_USER_STATES(fw, state);
4486 break;
4489 return;