Fix CursorMove command to correctly honour EdgeScroll settings.
[fvwm.git] / fvwm / builtins.c
blobe23fbec20f23ab01ae7b8e99956e22fc649e675d
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 x_unit, y_unit;
2194 int virtual_x, virtual_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;
2209 x_unit = val1 * val1_unit / 100;
2210 y_unit = val2 * val2_unit / 100;
2212 x += x_unit;
2213 y += y_unit;
2215 virtual_x = Scr.Vx;
2216 virtual_y = Scr.Vy;
2217 if (x >= 0)
2219 x_pages = x / Scr.MyDisplayWidth;
2221 else
2223 x_pages = ((x + 1) / Scr.MyDisplayWidth) - 1;
2225 virtual_x += x_pages * Scr.MyDisplayWidth;
2226 x -= x_pages * Scr.MyDisplayWidth;
2227 if (virtual_x < 0)
2229 x += virtual_x;
2230 virtual_x = 0;
2232 else if (virtual_x > Scr.VxMax)
2234 x += virtual_x - Scr.VxMax;
2235 virtual_x = Scr.VxMax;
2238 if (y >= 0)
2240 y_pages = y / Scr.MyDisplayHeight;
2242 else
2244 y_pages = ((y + 1) / Scr.MyDisplayHeight) - 1;
2246 virtual_y += y_pages * Scr.MyDisplayHeight;
2247 y -= y_pages * Scr.MyDisplayHeight;
2249 if (virtual_y < 0)
2251 y += virtual_y;
2252 virtual_y = 0;
2254 else if (virtual_y > Scr.VyMax)
2256 y += virtual_y - Scr.VyMax;
2257 virtual_y = Scr.VyMax;
2260 /* TA: (2010/12/19): Only move to the new page if scrolling is
2261 * enabled and the viewport is able to change based on where the
2262 * pointer is.
2264 if ((virtual_x != Scr.Vx && Scr.EdgeScrollX != 0) ||
2265 (virtual_y != Scr.Vy && Scr.EdgeScrollY != 0))
2267 MoveViewport(virtual_x, virtual_y, True);
2270 /* TA: (2010/12/19): If the cursor is about to enter a pan-window, or
2271 * is one, or the cursor's next step is to go beyond the page
2272 * boundary, stop the cursor from moving in that direction, *if* we've
2273 * disallowed edge scrolling.
2275 * Whilst this stops the cursor short of the edge of the screen in a
2276 * given direction, this is the desired behaviour.
2278 if (Scr.EdgeScrollX == 0 && (x >= Scr.MyDisplayWidth ||
2279 x + x_unit >= Scr.MyDisplayWidth))
2280 return;
2282 if (Scr.EdgeScrollY == 0 && (y >= Scr.MyDisplayHeight ||
2283 y + y_unit >= Scr.MyDisplayHeight))
2284 return;
2286 FWarpPointerUpdateEvpos(
2287 exc->x.elast, dpy, None, Scr.Root, 0, 0, Scr.MyDisplayWidth,
2288 Scr.MyDisplayHeight, x, y);
2290 return;
2293 void CMD_Delete(F_CMD_ARGS)
2295 FvwmWindow * const fw = exc->w.fw;
2297 if (!is_function_allowed(F_DELETE, NULL, fw, RQORIG_PROGRAM_US, True))
2299 XBell(dpy, 0);
2301 return;
2303 if (IS_TEAR_OFF_MENU(fw))
2305 /* 'soft' delete tear off menus. Note: we can't send the
2306 * message to the menu window directly because it was created
2307 * using a different display. The client message would never
2308 * be read from there. */
2309 send_clientmessage(
2310 dpy, FW_W_PARENT(fw), _XA_WM_DELETE_WINDOW,
2311 CurrentTime);
2313 return;
2315 if (WM_DELETES_WINDOW(fw))
2317 send_clientmessage(
2318 dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2320 return;
2322 else
2324 XBell(dpy, 0);
2326 XFlush(dpy);
2328 return;
2331 void CMD_Destroy(F_CMD_ARGS)
2333 FvwmWindow * const fw = exc->w.fw;
2335 if (IS_TEAR_OFF_MENU(fw))
2337 CMD_Delete(F_PASS_ARGS);
2338 return;
2340 if (!is_function_allowed(F_DESTROY, NULL, fw, True, True))
2342 XBell(dpy, 0);
2343 return;
2345 if (
2346 XGetGeometry(
2347 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2348 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2349 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2350 != 0)
2352 XKillClient(dpy, FW_W(fw));
2354 destroy_window(fw);
2355 XFlush(dpy);
2357 return;
2360 void CMD_Close(F_CMD_ARGS)
2362 FvwmWindow * const fw = exc->w.fw;
2364 if (IS_TEAR_OFF_MENU(fw))
2366 CMD_Delete(F_PASS_ARGS);
2367 return;
2369 if (!is_function_allowed(F_CLOSE, NULL, fw, True, True))
2371 XBell(dpy, 0);
2372 return;
2374 if (WM_DELETES_WINDOW(fw))
2376 send_clientmessage(
2377 dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2378 return;
2380 if (
2381 XGetGeometry(
2382 dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2383 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2384 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2385 != 0)
2387 XKillClient(dpy, FW_W(fw));
2390 destroy_window(fw);
2391 XFlush(dpy);
2393 return;
2396 void CMD_Restart(F_CMD_ARGS)
2398 Done(1, action);
2400 return;
2403 void CMD_ExecUseShell(F_CMD_ARGS)
2405 char *arg=NULL;
2406 static char shell_set = 0;
2408 if (shell_set)
2410 free(exec_shell_name);
2412 shell_set = 1;
2413 action = GetNextToken(action,&arg);
2414 if (arg) /* specific shell was specified */
2416 exec_shell_name = arg;
2418 else /* no arg, so use $SHELL -- not working??? */
2420 if (getenv("SHELL"))
2422 exec_shell_name = safestrdup(getenv("SHELL"));
2424 else
2426 /* if $SHELL not set, use default */
2427 exec_shell_name = safestrdup("/bin/sh");
2432 void CMD_Exec(F_CMD_ARGS)
2434 char *cmd=NULL;
2436 /* if it doesn't already have an 'exec' as the first word, add that
2437 * to keep down number of procs started */
2438 /* need to parse string better to do this right though, so not doing
2439 * this for now... */
2440 #if 0
2441 if (strncasecmp(action,"exec",4)!=0)
2443 cmd = (char *)safemalloc(strlen(action)+6);
2444 strcpy(cmd,"exec ");
2445 strcat(cmd,action);
2447 else
2448 #endif
2450 cmd = safestrdup(action);
2452 if (!cmd)
2454 return;
2456 /* Use to grab the pointer here, but the fork guarantees that
2457 * we wont be held up waiting for the function to finish,
2458 * so the pointer-gram just caused needless delay and flashing
2459 * on the screen */
2460 /* Thought I'd try vfork and _exit() instead of regular fork().
2461 * The man page says that its better. */
2462 /* Not everyone has vfork! */
2463 /* According to the man page, vfork should never be used at all.
2466 if (!(fork())) /* child process */
2468 /* This is for fixing a problem with rox filer */
2469 int fd;
2471 fvmm_deinstall_signals();
2472 fd = open("/dev/null", O_RDONLY, 0);
2473 dup2(fd,STDIN_FILENO);
2475 if (fd != STDIN_FILENO)
2476 close(fd);
2478 if (fvwm_setpgrp() == -1)
2480 fvwm_msg(ERR, "exec_function", "setpgrp failed (%s)",
2481 strerror(errno));
2482 exit(100);
2484 if (execl(exec_shell_name, exec_shell_name, "-c", cmd, NULL) ==
2487 fvwm_msg(ERR, "exec_function", "execl failed (%s)",
2488 strerror(errno));
2489 exit(100);
2492 free(cmd);
2494 return;
2497 void CMD_Refresh(F_CMD_ARGS)
2499 refresh_window(Scr.Root, True);
2501 return;
2504 void CMD_RefreshWindow(F_CMD_ARGS)
2506 FvwmWindow * const fw = exc->w.fw;
2508 refresh_window(
2509 (exc->w.wcontext == C_ICON) ?
2510 FW_W_ICON_TITLE(fw) : FW_W_FRAME(fw), True);
2512 return;
2515 void CMD_Wait(F_CMD_ARGS)
2517 Bool done = False;
2518 Bool redefine_cursor = False;
2519 Bool is_ungrabbed;
2520 char *escape;
2521 Window nonewin = None;
2522 char *wait_string, *rest;
2523 FvwmWindow *t;
2525 /* try to get a single token */
2526 rest = GetNextToken(action, &wait_string);
2527 if (wait_string)
2529 while (*rest && isspace((unsigned char)*rest))
2531 rest++;
2533 if (*rest)
2535 int i;
2536 char *temp;
2538 /* nope, multiple tokens - try old syntax */
2540 /* strip leading and trailing whitespace */
2541 temp = action;
2542 while (*temp && isspace((unsigned char)*temp))
2544 temp++;
2546 wait_string = safestrdup(temp);
2547 for (i = strlen(wait_string) - 1; i >= 0 &&
2548 isspace(wait_string[i]); i--)
2550 wait_string[i] = 0;
2554 else
2556 wait_string = safestrdup("");
2559 is_ungrabbed = UngrabEm(GRAB_NORMAL);
2560 while (!done && !isTerminated)
2562 XEvent e;
2563 if (BUSY_WAIT & Scr.BusyCursor)
2565 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_WAIT]);
2566 redefine_cursor = True;
2568 if (My_XNextEvent(dpy, &e))
2570 dispatch_event(&e);
2571 if (XFindContext(
2572 dpy, e.xmap.window, FvwmContext,
2573 (caddr_t *)&t) == XCNOENT)
2575 t = NULL;
2578 if (e.type == MapNotify && e.xmap.event == Scr.Root)
2580 if (!*wait_string)
2582 done = True;
2584 if (t && matchWildcards(
2585 wait_string, t->name.name) == True)
2587 done = True;
2589 else if (t && t->class.res_class &&
2590 matchWildcards(
2591 wait_string,
2592 t->class.res_class) == True)
2594 done = True;
2596 else if (t && t->class.res_name &&
2597 matchWildcards(
2598 wait_string,
2599 t->class.res_name) == True)
2601 done = True;
2604 else if (e.type == KeyPress)
2606 /* should I be using <t> or <exc->w.fw>?
2607 * DV: t
2609 int context;
2610 XClassHint *class;
2611 char *name;
2613 context = GetContext(&t, t, &e, &nonewin);
2614 if (t != NULL)
2616 class = &(t->class);
2617 name = t->name.name;
2619 else
2621 class = NULL;
2622 name = NULL;
2624 escape = CheckBinding(
2625 Scr.AllBindings, STROKE_ARG(0)
2626 e.xkey.keycode, e.xkey.state,
2627 GetUnusedModifiers(), context,
2628 BIND_KEYPRESS, class, name);
2629 if (escape != NULL)
2631 if (!strcasecmp(escape,"escapefunc"))
2633 done = True;
2639 if (redefine_cursor)
2641 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
2643 if (is_ungrabbed)
2645 GrabEm(CRS_NONE, GRAB_NORMAL);
2647 free(wait_string);
2649 return;
2652 void CMD_Quit(F_CMD_ARGS)
2654 if (master_pid != getpid())
2656 kill(master_pid, SIGTERM);
2658 Done(0,NULL);
2660 return;
2663 void CMD_QuitScreen(F_CMD_ARGS)
2665 Done(0,NULL);
2667 return;
2670 void CMD_Echo(F_CMD_ARGS)
2672 int len;
2674 if (!action)
2676 action = "";
2678 len = strlen(action);
2679 if (len != 0)
2681 if (action[len-1]=='\n')
2683 action[len-1]='\0';
2686 fvwm_msg(ECHO,"Echo",action);
2688 return;
2691 void CMD_PrintInfo(F_CMD_ARGS)
2693 int verbose;
2694 char *rest, *subject = NULL;
2696 rest = GetNextToken(action, &subject);
2697 if (!rest || GetIntegerArguments(rest, NULL, &verbose, 1) != 1)
2699 verbose = 0;
2701 if (StrEquals(subject, "Colors"))
2703 PicturePrintColorInfo(verbose);
2705 else if (StrEquals(subject, "Locale"))
2707 FlocalePrintLocaleInfo(dpy, verbose);
2709 else if (StrEquals(subject, "NLS"))
2711 FGettextPrintLocalePath(verbose);
2713 else if (StrEquals(subject, "style"))
2715 print_styles(verbose);
2717 else if (StrEquals(subject, "ImageCache"))
2719 PicturePrintImageCache(verbose);
2721 else if (StrEquals(subject, "Bindings"))
2723 print_bindings();
2725 else
2727 fvwm_msg(ERR, "PrintInfo",
2728 "Unknown subject '%s'", action);
2730 if (subject)
2732 free(subject);
2734 return;
2737 void CMD_ColormapFocus(F_CMD_ARGS)
2739 if (MatchToken(action,"FollowsFocus"))
2741 Scr.ColormapFocus = COLORMAP_FOLLOWS_FOCUS;
2743 else if (MatchToken(action,"FollowsMouse"))
2745 Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
2747 else
2749 fvwm_msg(ERR, "SetColormapFocus",
2750 "ColormapFocus requires 1 arg: FollowsFocus or"
2751 " FollowsMouse");
2752 return;
2755 return;
2758 void CMD_ClickTime(F_CMD_ARGS)
2760 int val;
2762 if (GetIntegerArguments(action, NULL, &val, 1) != 1)
2764 Scr.ClickTime = DEFAULT_CLICKTIME;
2766 else
2768 Scr.ClickTime = (val < 0)? 0 : val;
2771 /* Use a negative value during startup and change sign afterwards. This
2772 * speeds things up quite a bit. */
2773 if (fFvwmInStartup)
2775 Scr.ClickTime = -Scr.ClickTime;
2778 return;
2782 void CMD_ImagePath(F_CMD_ARGS)
2784 PictureSetImagePath( action );
2786 return;
2789 void CMD_IconPath(F_CMD_ARGS)
2791 fvwm_msg(ERR, "iconPath_function",
2792 "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2793 obsolete_imagepaths( action );
2795 return;
2798 void CMD_PixmapPath(F_CMD_ARGS)
2800 fvwm_msg(ERR, "pixmapPath_function",
2801 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2802 " instead." );
2803 obsolete_imagepaths( action );
2805 return;
2808 void CMD_LocalePath(F_CMD_ARGS)
2810 FGettextSetLocalePath( action );
2812 return;
2815 void CMD_ModulePath(F_CMD_ARGS)
2817 static int need_to_free = 0;
2819 setPath( &ModulePath, action, need_to_free );
2820 need_to_free = 1;
2822 return;
2825 void CMD_ModuleTimeout(F_CMD_ARGS)
2827 int timeout;
2829 moduleTimeout = DEFAULT_MODULE_TIMEOUT;
2830 if (GetIntegerArguments(action, NULL, &timeout, 1) == 1 && timeout > 0)
2832 moduleTimeout = timeout;
2835 return;
2838 void CMD_HilightColor(F_CMD_ARGS)
2840 char *fore;
2841 char *back;
2842 #ifdef USEDECOR
2843 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2845 fvwm_msg(
2846 ERR, "SetHiColor",
2847 "Decors do not support the HilightColor command"
2848 " anymore. Please use"
2849 " 'Style <stylename> HilightFore <forecolor>' and"
2850 " 'Style <stylename> HilightBack <backcolor>' instead."
2851 " Sorry for the inconvenience.");
2852 return;
2854 #endif
2855 action = GetNextToken(action, &fore);
2856 GetNextToken(action, &back);
2857 if (fore && back)
2859 action = safemalloc(strlen(fore) + strlen(back) + 29);
2860 sprintf(action, "* HilightFore %s, HilightBack %s", fore, back);
2861 CMD_Style(F_PASS_ARGS);
2863 if (fore)
2865 free(fore);
2867 if (back)
2869 free(back);
2872 return;
2875 void CMD_HilightColorset(F_CMD_ARGS)
2877 char *newaction;
2879 #ifdef USEDECOR
2880 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2882 fvwm_msg(
2883 ERR, "SetHiColorset",
2884 "Decors do not support the HilightColorset command "
2885 "anymore. Please use "
2886 "'Style <stylename> HilightColorset <colorset>'"
2887 " instead. Sorry for the inconvenience.");
2888 return;
2890 #endif
2891 if (action)
2893 newaction = safemalloc(strlen(action) + 32);
2894 sprintf(newaction, "* HilightColorset %s", action);
2895 action = newaction;
2896 CMD_Style(F_PASS_ARGS);
2897 free(newaction);
2900 return;
2903 void CMD_TitleStyle(F_CMD_ARGS)
2905 do_title_style(F_PASS_ARGS, False);
2907 return;
2908 } /* SetTitleStyle */
2912 * Appends a titlestyle (veliaa@rpi.edu)
2915 void CMD_AddTitleStyle(F_CMD_ARGS)
2917 do_title_style(F_PASS_ARGS, True);
2919 return;
2922 void CMD_PropertyChange(F_CMD_ARGS)
2924 char string[256];
2925 char *token;
2926 char *rest;
2927 int ret;
2928 unsigned long argument;
2929 unsigned long data1;
2930 unsigned long data2;
2932 /* argument */
2933 token = PeekToken(action, &rest);
2934 if (token == NULL)
2936 return;
2938 ret = sscanf(token, "%lu", &argument);
2939 if (ret < 1)
2941 return;
2943 /* data1 */
2944 data1 = 0;
2945 token = PeekToken(rest, &rest);
2946 if (token != NULL)
2948 ret = sscanf(token, "%lu", &data1);
2949 if (ret < 1)
2951 rest = NULL;
2954 /* data2 */
2955 data2 = 0;
2956 token = PeekToken(rest, &rest);
2957 if (token != NULL)
2959 ret = sscanf(token, "%lu", &data2);
2960 if (ret < 1)
2962 rest = NULL;
2965 /* string */
2966 memset(string, 0, 256);
2967 if (rest != NULL)
2969 ret = sscanf(rest, "%255c", &(string[0]));
2971 BroadcastPropertyChange(argument, data1, data2, string);
2973 return;
2976 void CMD_DefaultIcon(F_CMD_ARGS)
2978 if (Scr.DefaultIcon)
2980 free(Scr.DefaultIcon);
2982 GetNextToken(action, &Scr.DefaultIcon);
2984 return;
2987 void CMD_DefaultColorset(F_CMD_ARGS)
2989 int cset;
2991 if (GetIntegerArguments(action, NULL, &cset, 1) != 1)
2993 return;
2995 Scr.DefaultColorset = cset;
2996 if (Scr.DefaultColorset < 0)
2998 Scr.DefaultColorset = -1;
3000 alloc_colorset(Scr.DefaultColorset);
3001 Scr.flags.do_need_window_update = 1;
3002 Scr.flags.has_default_color_changed = 1;
3004 return;
3007 void CMD_DefaultColors(F_CMD_ARGS)
3009 char *fore = NULL;
3010 char *back = NULL;
3012 action = GetNextToken(action, &fore);
3013 if (action)
3015 action = GetNextToken(action, &back);
3017 if (!back)
3019 back = safestrdup(DEFAULT_BACK_COLOR);
3021 if (!fore)
3023 fore = safestrdup(DEFAULT_FORE_COLOR);
3025 if (!StrEquals(fore, "-"))
3027 PictureFreeColors(dpy, Pcmap, &Scr.StdFore, 1, 0, True);
3028 Scr.StdFore = GetColor(fore);
3030 if (!StrEquals(back, "-"))
3032 PictureFreeColors(dpy, Pcmap, &Scr.StdBack, 3, 0, True);
3033 Scr.StdBack = GetColor(back);
3034 Scr.StdHilite = GetHilite(Scr.StdBack);
3035 Scr.StdShadow = GetShadow(Scr.StdBack);
3037 free(fore);
3038 free(back);
3040 Scr.DefaultColorset = -1;
3041 Scr.flags.do_need_window_update = 1;
3042 Scr.flags.has_default_color_changed = 1;
3044 return;
3047 void CMD_DefaultFont(F_CMD_ARGS)
3049 char *font;
3050 FlocaleFont *new_font;
3051 FvwmWindow *t;
3053 font = PeekToken(action, &action);
3054 if (!font)
3056 /* Try 'fixed', pass NULL font name */
3058 if (!(new_font = FlocaleLoadFont(dpy, font, "fvwm")))
3060 if (Scr.DefaultFont == NULL)
3062 exit(1);
3064 else
3066 return;
3069 FlocaleUnloadFont(dpy, Scr.DefaultFont);
3070 Scr.DefaultFont = new_font;
3071 /* we should do that here because a redraw can happen before
3072 flush_window_updates is called ... */
3073 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
3075 if (USING_DEFAULT_ICON_FONT(t))
3077 t->icon_font = Scr.DefaultFont;
3079 if (USING_DEFAULT_WINDOW_FONT(t))
3081 t->title_font = Scr.DefaultFont;
3084 /* set flags to indicate that the font has changed */
3085 Scr.flags.do_need_window_update = 1;
3086 Scr.flags.has_default_font_changed = 1;
3088 return;
3091 void CMD_IconFont(F_CMD_ARGS)
3093 char *newaction;
3095 #ifdef USEDECOR
3096 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3098 fvwm_msg(
3099 ERR, "LoadIconFont",
3100 "Decors do not support the IconFont command anymore."
3101 " Please use 'Style <stylename> IconFont <fontname>'"
3102 " instead. Sorry for the inconvenience.");
3103 return;
3105 #endif
3106 if (action)
3108 newaction = safemalloc(strlen(action) + 16);
3109 sprintf(newaction, "* IconFont %s", action);
3110 action = newaction;
3111 CMD_Style(F_PASS_ARGS);
3112 free(newaction);
3115 return;
3118 void CMD_WindowFont(F_CMD_ARGS)
3120 char *newaction;
3122 #ifdef USEDECOR
3123 if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3125 fvwm_msg(
3126 ERR, "LoadWindowFont",
3127 "Decors do not support the WindowFont command anymore."
3128 " Please use 'Style <stylename> Font <fontname>'"
3129 " instead. Sorry for the inconvenience.");
3130 return;
3132 #endif
3133 if (action)
3135 newaction = safemalloc(strlen(action) + 16);
3136 sprintf(newaction, "* Font %s", action);
3137 action = newaction;
3138 CMD_Style(F_PASS_ARGS);
3139 free(newaction);
3142 return;
3147 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3150 void CMD_ChangeDecor(F_CMD_ARGS)
3152 char *item;
3153 int old_height;
3154 FvwmDecor *decor = &Scr.DefaultDecor;
3155 FvwmDecor *found = NULL;
3156 FvwmWindow * const fw = exc->w.fw;
3158 item = PeekToken(action, &action);
3159 if (!action || !item)
3161 return;
3163 /* search for tag */
3164 for (; decor; decor = decor->next)
3166 if (decor->tag && StrEquals(item, decor->tag))
3168 found = decor;
3169 break;
3172 if (!found)
3174 XBell(dpy, 0);
3175 return;
3177 SET_DECOR_CHANGED(fw, 1);
3178 old_height = (fw->decor) ? fw->decor->title_height : 0;
3179 fw->decor = found;
3180 apply_decor_change(fw);
3182 return;
3187 * Destroys an FvwmDecor (veliaa@rpi.edu)
3190 void CMD_DestroyDecor(F_CMD_ARGS)
3192 char *item;
3193 FvwmDecor *decor = Scr.DefaultDecor.next;
3194 FvwmDecor *prev = &Scr.DefaultDecor, *found = NULL;
3195 Bool do_recreate = False;
3197 item = PeekToken(action, &action);
3198 if (!item)
3200 return;
3202 if (StrEquals(item, "recreate"))
3204 do_recreate = True;
3205 item = PeekToken(action, NULL);
3207 if (!item)
3209 return;
3212 /* search for tag */
3213 for (; decor; decor = decor->next)
3215 if (decor->tag && StrEquals(item, decor->tag))
3217 found = decor;
3218 break;
3220 prev = decor;
3223 if (found && (found != &Scr.DefaultDecor || do_recreate))
3225 if (!do_recreate)
3227 __remove_window_decors(F_PASS_ARGS, found);
3229 DestroyFvwmDecor(found);
3230 if (do_recreate)
3232 int i;
3234 InitFvwmDecor(found);
3235 found->tag = safestrdup(item);
3236 Scr.flags.do_need_window_update = 1;
3237 found->flags.has_changed = 1;
3238 found->flags.has_title_height_changed = 0;
3239 found->titlebar.flags.has_changed = 1;
3240 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
3242 TB_FLAGS(found->buttons[i]).has_changed = 1;
3245 else
3247 prev->next = found->next;
3248 free(found);
3252 return;
3257 * Initiates an AddToDecor (veliaa@rpi.edu)
3260 void CMD_AddToDecor(F_CMD_ARGS)
3262 FvwmDecor *decor;
3263 FvwmDecor *found = NULL;
3264 char *item = NULL;
3266 action = GetNextToken(action, &item);
3267 if (!item)
3269 return;
3271 if (!action)
3273 free(item);
3274 return;
3276 /* search for tag */
3277 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3279 if (decor->tag && StrEquals(item, decor->tag))
3281 found = decor;
3282 break;
3285 if (!found)
3287 /* then make a new one */
3288 found = (FvwmDecor *)safemalloc(sizeof( FvwmDecor ));
3289 InitFvwmDecor(found);
3290 found->tag = item; /* tag it */
3291 /* add it to list */
3292 for (decor = &Scr.DefaultDecor; decor->next;
3293 decor = decor->next)
3295 /* nop */
3297 decor->next = found;
3299 else
3301 free(item);
3304 if (found)
3306 AddToDecor(F_PASS_ARGS, found);
3307 /* Set + state to last decor */
3308 set_last_added_item(ADDED_DECOR, found);
3311 return;
3313 #endif /* USEDECOR */
3318 * Updates window decoration styles (veliaa@rpi.edu)
3321 void CMD_UpdateDecor(F_CMD_ARGS)
3323 FvwmWindow *fw2;
3324 #ifdef USEDECOR
3325 FvwmDecor *decor, *found = NULL;
3326 FvwmWindow *hilight = Scr.Hilite;
3327 char *item = NULL;
3329 action = GetNextToken(action, &item);
3330 if (item)
3332 /* search for tag */
3333 for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3335 if (decor->tag && StrEquals(item, decor->tag))
3337 found = decor;
3338 break;
3341 free(item);
3343 #endif
3345 for (fw2 = Scr.FvwmRoot.next; fw2; fw2 = fw2->next)
3347 #ifdef USEDECOR
3348 /* update specific decor, or all */
3349 if (found)
3351 if (fw2->decor == found)
3353 border_draw_decorations(
3354 fw2, PART_ALL, True, True, CLEAR_ALL,
3355 NULL, NULL);
3356 border_draw_decorations(
3357 fw2, PART_ALL, False, True, CLEAR_ALL,
3358 NULL, NULL);
3361 else
3362 #endif
3364 border_draw_decorations(
3365 fw2, PART_ALL, True, True, CLEAR_ALL, NULL,
3366 NULL);
3367 border_draw_decorations(
3368 fw2, PART_ALL, False, True, CLEAR_ALL, NULL,
3369 NULL);
3372 border_draw_decorations(
3373 hilight, PART_ALL, True, True, CLEAR_ALL, NULL, NULL);
3376 void CMD_ButtonStyle(F_CMD_ARGS)
3378 do_button_style(F_PASS_ARGS, False);
3380 return;
3385 * Appends a button decoration style (veliaa@rpi.edu)
3388 void CMD_AddButtonStyle(F_CMD_ARGS)
3390 do_button_style(F_PASS_ARGS, True);
3392 return;
3395 void CMD_SetEnv(F_CMD_ARGS)
3397 char *szVar = NULL;
3398 char *szValue = NULL;
3399 char *szPutenv = NULL;
3401 action = GetNextToken(action, &szVar);
3402 if (!szVar)
3404 return;
3406 action = GetNextToken(action, &szValue);
3407 if (!szValue)
3409 szValue = safestrdup("");
3411 szPutenv = safemalloc(strlen(szVar) + strlen(szValue) + 2);
3412 sprintf(szPutenv,"%s=%s", szVar, szValue);
3413 flib_putenv(szVar, szPutenv);
3414 free(szVar);
3415 free(szPutenv);
3416 free(szValue);
3418 return;
3421 void CMD_UnsetEnv(F_CMD_ARGS)
3423 char *szVar = NULL;
3425 szVar = PeekToken(action, &action);
3426 if (!szVar)
3428 return;
3430 flib_unsetenv(szVar);
3432 return;
3435 void CMD_GlobalOpts(F_CMD_ARGS)
3437 char *opt;
3438 char *replace;
3439 char buf[64];
3440 int i;
3441 Bool is_bugopt;
3442 char *optlist[] = {
3443 "WindowShadeShrinks",
3444 "WindowShadeScrolls",
3445 "SmartPlacementIsReallySmart",
3446 "SmartPlacementIsNormal",
3447 "ClickToFocusDoesntPassClick",
3448 "ClickToFocusPassesClick",
3449 "ClickToFocusDoesntRaise",
3450 "ClickToFocusRaises",
3451 "MouseFocusClickDoesntRaise",
3452 "MouseFocusClickRaises",
3453 "NoStipledTitles",
3454 "StipledTitles",
3455 "CaptureHonorsStartsOnPage",
3456 "CaptureIgnoresStartsOnPage",
3457 "RecaptureHonorsStartsOnPage",
3458 "RecaptureIgnoresStartsOnPage",
3459 "ActivePlacementHonorsStartsOnPage",
3460 "ActivePlacementIgnoresStartsOnPage",
3461 "RaiseOverNativeWindows",
3462 "IgnoreNativeWindows",
3463 NULL
3465 char *replacelist[] = {
3466 /* These options are mapped to the Style * command */
3467 NULL, /* NULL means to use "Style * <optionname>" */
3468 NULL,
3469 "* MinOverlapPlacement",
3470 "* TileCascadePlacement",
3471 "* ClickToFocusPassesClickOff",
3472 "* ClickToFocusPassesClick",
3473 "* ClickToFocusRaisesOff",
3474 "* ClickToFocusRaises",
3475 "* MouseFocusClickRaisesOff",
3476 "* MouseFocusClickRaises",
3477 "* StippledTitleOff",
3478 "* StippledTitle",
3479 NULL,
3480 NULL,
3481 NULL,
3482 NULL,
3483 "* ManualPlacementHonorsStartsOnPage",
3484 "* ManualPlacementIgnoresStartsOnPage",
3485 /* These options are mapped to the BugOpts command */
3486 "RaiseOverNativeWindows on",
3487 "RaiseOverNativeWindows off"
3490 fvwm_msg(ERR, "SetGlobalOptions",
3491 "The GlobalOpts command is obsolete.");
3492 for (action = GetNextSimpleOption(action, &opt); opt;
3493 action = GetNextSimpleOption(action, &opt))
3495 replace = NULL;
3496 is_bugopt = False;
3498 i = GetTokenIndex(opt, optlist, 0, NULL);
3499 if (i > -1)
3501 char *cmd;
3502 char *tmp;
3504 replace = replacelist[i];
3505 if (replace == NULL)
3507 replace = &(buf[0]);
3508 sprintf(buf, "* %s", opt);
3510 else if (*replace != '*')
3512 is_bugopt = True;
3514 tmp = action;
3515 action = replace;
3516 if (!is_bugopt)
3518 CMD_Style(F_PASS_ARGS);
3519 cmd = "Style";
3521 else
3523 CMD_BugOpts(F_PASS_ARGS);
3524 cmd = "BugOpts";
3526 action = tmp;
3527 fvwm_msg(
3528 ERR, "SetGlobalOptions",
3529 "Please replace 'GlobalOpts %s' with '%s %s'.",
3530 opt, cmd, replace);
3532 else
3534 fvwm_msg(ERR, "SetGlobalOptions",
3535 "Unknown Global Option '%s'", opt);
3537 /* should never be null, but checking anyways... */
3538 if (opt)
3540 free(opt);
3543 if (opt)
3545 free(opt);
3548 return;
3551 void CMD_BugOpts(F_CMD_ARGS)
3553 char *opt;
3554 int toggle;
3555 char *optstring;
3557 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3558 while (action && *action && *action != '\n')
3560 action = GetNextFullOption(action, &optstring);
3561 if (!optstring)
3563 /* no more options */
3564 return;
3566 toggle = ParseToggleArgument(
3567 SkipNTokens(optstring,1), NULL, 2, False);
3568 opt = PeekToken(optstring, NULL);
3569 free(optstring);
3571 if (!opt)
3573 return;
3575 /* toggle = ParseToggleArgument(rest, &rest, 2, False);*/
3577 if (StrEquals(opt, "FlickeringMoveWorkaround"))
3579 switch (toggle)
3581 case -1:
3582 Scr.bo.do_disable_configure_notify ^= 1;
3583 break;
3584 case 0:
3585 case 1:
3586 Scr.bo.do_disable_configure_notify = toggle;
3587 break;
3588 default:
3589 Scr.bo.do_disable_configure_notify = 0;
3590 break;
3593 else if (StrEquals(opt, "MixedVisualWorkaround"))
3595 switch (toggle)
3597 case -1:
3598 Scr.bo.do_install_root_cmap ^= 1;
3599 break;
3600 case 0:
3601 case 1:
3602 Scr.bo.do_install_root_cmap = toggle;
3603 break;
3604 default:
3605 Scr.bo.do_install_root_cmap = 0;
3606 break;
3609 else if (StrEquals(opt, "ModalityIsEvil"))
3611 switch (toggle)
3613 case -1:
3614 Scr.bo.is_modality_evil ^= 1;
3615 break;
3616 case 0:
3617 case 1:
3618 Scr.bo.is_modality_evil = toggle;
3619 break;
3620 default:
3621 Scr.bo.is_modality_evil = 0;
3622 break;
3624 if (Scr.bo.is_modality_evil)
3626 SetMWM_INFO(Scr.NoFocusWin);
3629 else if (StrEquals(opt, "RaiseOverNativeWindows"))
3631 switch (toggle)
3633 case -1:
3634 Scr.bo.is_raise_hack_needed ^= 1;
3635 break;
3636 case 0:
3637 case 1:
3638 Scr.bo.is_raise_hack_needed = toggle;
3639 break;
3640 default:
3641 Scr.bo.is_raise_hack_needed = 0;
3642 break;
3645 else if (StrEquals(opt, "RaiseOverUnmanaged"))
3647 switch (toggle)
3649 case -1:
3650 Scr.bo.do_raise_over_unmanaged ^= 1;
3651 break;
3652 case 0:
3653 case 1:
3654 Scr.bo.do_raise_over_unmanaged = toggle;
3655 break;
3656 default:
3657 Scr.bo.do_raise_over_unmanaged = 0;
3658 break;
3661 else if (StrEquals(opt, "FlickeringQtDialogsWorkaround"))
3663 switch (toggle)
3665 case -1:
3666 Scr.bo.do_enable_flickering_qt_dialogs_workaround ^= 1;
3667 break;
3668 case 0:
3669 case 1:
3670 Scr.bo.do_enable_flickering_qt_dialogs_workaround = toggle;
3671 break;
3672 default:
3673 Scr.bo.do_enable_flickering_qt_dialogs_workaround = 0;
3674 break;
3677 else if (StrEquals(opt, "QtDragnDropWorkaround") )
3679 switch (toggle)
3681 case -1:
3682 Scr.bo.do_enable_qt_drag_n_drop_workaround ^= 1;
3683 break;
3684 case 0:
3685 case 1:
3686 Scr.bo.do_enable_qt_drag_n_drop_workaround = toggle;
3687 break;
3688 default:
3689 Scr.bo.do_enable_qt_drag_n_drop_workaround = 0;
3690 break;
3693 else if (EWMH_BugOpts(opt, toggle))
3695 /* work is done in EWMH_BugOpts */
3697 else if (StrEquals(opt, "DisplayNewWindowNames"))
3699 switch (toggle)
3701 case -1:
3702 Scr.bo.do_display_new_window_names ^= 1;
3703 break;
3704 case 0:
3705 case 1:
3706 Scr.bo.do_display_new_window_names = toggle;
3707 break;
3708 default:
3709 Scr.bo.do_display_new_window_names = 0;
3710 break;
3713 else if (StrEquals(opt, "ExplainWindowPlacement"))
3715 switch (toggle)
3717 case -1:
3718 Scr.bo.do_explain_window_placement ^= 1;
3719 break;
3720 case 0:
3721 case 1:
3722 Scr.bo.do_explain_window_placement = toggle;
3723 break;
3724 default:
3725 Scr.bo.do_explain_window_placement = 0;
3726 break;
3729 else if (StrEquals(opt, "DebugCRMotionMethod"))
3731 switch (toggle)
3733 case -1:
3734 Scr.bo.do_debug_cr_motion_method ^= 1;
3735 break;
3736 case 0:
3737 case 1:
3738 Scr.bo.do_debug_cr_motion_method = toggle;
3739 break;
3740 default:
3741 Scr.bo.do_debug_cr_motion_method = 0;
3742 break;
3745 else if (StrEquals(opt, "TransliterateUtf8"))
3747 FiconvSetTransliterateUtf8(toggle);
3749 else
3751 fvwm_msg(ERR, "SetBugOptions",
3752 "Unknown Bug Option '%s'", opt);
3756 return;
3759 void CMD_Emulate(F_CMD_ARGS)
3761 char *style;
3763 style = PeekToken(action, NULL);
3764 if (!style || StrEquals(style, "fvwm"))
3766 Scr.gs.do_emulate_mwm = False;
3767 Scr.gs.do_emulate_win = False;
3769 else if (StrEquals(style, "mwm"))
3771 Scr.gs.do_emulate_mwm = True;
3772 Scr.gs.do_emulate_win = False;
3774 else if (StrEquals(style, "win"))
3776 Scr.gs.do_emulate_mwm = False;
3777 Scr.gs.do_emulate_win = True;
3779 else
3781 fvwm_msg(ERR, "Emulate", "Unknown style '%s'", style);
3782 return;
3784 Scr.flags.do_need_window_update = 1;
3785 Scr.flags.has_default_font_changed = 1;
3786 Scr.flags.has_default_color_changed = 1;
3788 return;
3791 void CMD_ColorLimit(F_CMD_ARGS)
3793 fvwm_msg(
3794 WARN, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3795 "fvwm -color-limit option");
3797 return;
3801 /* set animation parameters */
3802 void CMD_SetAnimation(F_CMD_ARGS)
3804 char *opt;
3805 int delay;
3806 float pct;
3807 int i = 0;
3809 opt = PeekToken(action, &action);
3810 if (!opt || sscanf(opt,"%d",&delay) != 1)
3812 fvwm_msg(ERR,"SetAnimation",
3813 "Improper milli-second delay as first argument");
3814 return;
3816 if (delay > 500)
3818 fvwm_msg(WARN,"SetAnimation",
3819 "Using longer than .5 seconds as between frame"
3820 " animation delay");
3822 cmsDelayDefault = delay;
3823 for (opt = PeekToken(action, &action); opt;
3824 opt = PeekToken(action, &action))
3826 if (sscanf(opt,"%f",&pct) != 1)
3828 fvwm_msg(ERR,"SetAnimation",
3829 "Use fractional values ending in 1.0 as args"
3830 " 2 and on");
3831 return;
3833 rgpctMovementDefault[i++] = pct;
3835 /* No pct entries means don't change them at all */
3836 if (i > 0 && rgpctMovementDefault[i-1] != 1.0)
3838 rgpctMovementDefault[i++] = 1.0;
3841 return;
3844 /* Determine which modifiers are required with a keycode to make <keysym>. */
3845 static Bool FKeysymToKeycode (Display *dpy, KeySym keysym,
3846 unsigned int *keycode, unsigned int *modifiers)
3848 int m;
3850 *keycode = XKeysymToKeycode(dpy, keysym);
3851 *modifiers = 0;
3853 for (m = 0; m <= 8; ++m)
3855 KeySym ks = XKeycodeToKeysym(dpy, *keycode, m);
3856 if (ks == keysym)
3858 switch (m)
3860 case 0: /* No modifiers */
3861 break;
3862 case 1: /* Shift modifier */
3863 *modifiers |= ShiftMask;
3864 break;
3865 default:
3866 fvwm_msg(ERR, "FKeysymToKeycode",
3867 "Unhandled modifier %d", m);
3868 break;
3870 return True;
3873 return False;
3876 static void __fake_event(F_CMD_ARGS, FakeEventType type)
3878 char *token;
3879 char *optlist[] = {
3880 "press", "p",
3881 "release", "r",
3882 "wait", "w",
3883 "modifiers", "m",
3884 "depth", "d",
3885 NULL
3887 unsigned int mask = 0;
3888 Window root = Scr.Root;
3889 int maxdepth = 0;
3890 static char args[128];
3891 strncpy(args, action, sizeof(args) - 1);
3893 /* get the mask of pressed/released buttons/keys */
3894 FQueryPointer(
3895 dpy, Scr.Root, &root, &JunkRoot, &JunkX, &JunkY, &JunkX,
3896 &JunkY, &mask);
3898 token = PeekToken(action, &action);
3899 while (token && action)
3901 int index = GetTokenIndex(token, optlist, 0, NULL);
3902 int val, depth;
3903 XEvent e;
3904 Window w;
3905 Window child_w;
3906 int x = 0;
3907 int y = 0;
3908 int rx = 0;
3909 int ry = 0;
3910 Bool do_unset;
3911 long add_mask = 0;
3912 KeySym keysym = NoSymbol;
3914 XFlush(dpy);
3915 do_unset = True;
3916 switch (index)
3918 case 0:
3919 case 1:
3920 do_unset = False;
3921 /* fall through */
3922 case 2:
3923 case 3:
3924 /* key/button press or release */
3925 if (type == FakeMouseEvent)
3927 if ((GetIntegerArguments(
3928 action, &action, &val, 1) != 1) ||
3929 val < 1 ||
3930 val > NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
3932 fvwm_msg(
3933 ERR, "__fake_event",
3934 "Invalid button specifier in"
3935 " \"%s\" for FakeClick.", args);
3936 return; /* error */
3939 else /* type == FakeKeyEvent */
3941 char *key = PeekToken(action, &action);
3942 if (key == NULL)
3944 fvwm_msg(
3945 ERR, "__fake_event",
3946 "No keysym specifier in \"%s\""
3947 " for FakeKeypress.", args);
3948 return;
3951 /* Do *NOT* use FvwmStringToKeysym() as it is
3952 * case insensitive. */
3953 keysym = XStringToKeysym(key);
3954 if (keysym == NoSymbol)
3956 fvwm_msg(
3957 ERR, "__fake_event",
3958 "Invalid keysym specifier (%s)"
3959 " in \"%s\" for FakeKeypress.",
3960 key, args);
3961 return;
3965 w = None;
3966 child_w = root;
3967 for (depth = 1;
3968 depth != maxdepth &&
3969 w != child_w && child_w != None;
3970 depth++)
3972 w = child_w;
3973 if (FQueryPointer(
3974 dpy, w, &root, &child_w,
3975 &rx, &ry, &x, &y,
3976 &JunkMask) == False)
3978 /* pointer is on a different
3979 * screen - that's okay here */
3983 if (type == FakeMouseEvent)
3985 e.type = (do_unset) ?
3986 ButtonRelease : ButtonPress;
3987 e.xbutton.display = dpy;
3988 e.xbutton.window = w;
3989 e.xbutton.subwindow = None;
3990 e.xbutton.root = root;
3991 e.xbutton.time = fev_get_evtime();
3992 e.xbutton.x = x;
3993 e.xbutton.y = y;
3994 e.xbutton.x_root = rx;
3995 e.xbutton.y_root = ry;
3996 e.xbutton.button = val;
3997 e.xbutton.state = mask;
3998 e.xbutton.same_screen = (Scr.Root == root);
3999 /* SS: I think this mask handling code is
4000 * buggy.
4001 * The value of <mask> is overridden during a
4002 * "wait" operation. Also why are we only using
4003 * Button1Mask? What if the user has requested
4004 * a FakeClick using some other button? */
4005 /* DV: Button1Mask is actually a bit. Shifting
4006 * it by (val -1) bits to the left gives
4007 * Button2Mask, Button3Mask etc. */
4008 if (do_unset)
4010 mask &= ~(Button1Mask << (val - 1));
4012 else
4014 mask |= (Button1Mask << (val - 1));
4016 add_mask = (do_unset) ?
4017 ButtonPressMask : ButtonReleaseMask;
4019 else
4021 /* type == FakeKeyEvent */
4022 e.type = (do_unset ? KeyRelease : KeyPress);
4023 e.xkey.display = dpy;
4024 e.xkey.subwindow = None;
4025 e.xkey.root = root;
4026 e.xkey.time = fev_get_evtime();
4027 e.xkey.x = x;
4028 e.xkey.y = y;
4029 e.xkey.x_root = rx;
4030 e.xkey.y_root = ry;
4031 e.xkey.same_screen = (Scr.Root == root);
4033 w = e.xkey.window = exc->w.w;
4035 if (FKeysymToKeycode(
4036 dpy, keysym, &(e.xkey.keycode),
4037 &(e.xkey.state)) != True)
4039 fvwm_msg(DBG, "__fake_event",
4040 "FKeysymToKeycode failed");
4041 return;
4043 e.xkey.state |= mask;
4044 add_mask = (do_unset) ?
4045 KeyReleaseMask : KeyPressMask;
4047 FSendEvent(dpy, w, True,
4048 SubstructureNotifyMask | add_mask, &e);
4049 XFlush(dpy);
4050 break;
4051 case 4:
4052 case 5:
4053 /* wait */
4054 if ((GetIntegerArguments(
4055 action, &action, &val, 1) != 1) ||
4056 val <= 0 || val > 1000000)
4058 fvwm_msg(ERR, "__fake_event",
4059 "Invalid wait value in \"%s\"", args);
4060 return;
4063 usleep(1000 * val);
4064 if (FQueryPointer(
4065 dpy, Scr.Root, &root, &JunkRoot,
4066 &JunkX, &JunkY, &JunkX, &JunkY,
4067 &mask) == False)
4069 /* pointer is on a different screen -
4070 * that's okay here */
4072 break;
4073 case 6:
4074 case 7:
4075 /* set modifier */
4076 if (GetIntegerArguments(action, &action, &val, 1) != 1)
4078 fvwm_msg(
4079 ERR, "__fake_event",
4080 "Invalid modifier value in \"%s\"",
4081 args);
4082 return;
4084 do_unset = False;
4085 if (val < 0)
4087 do_unset = True;
4088 val = -val;
4090 if (val == 6)
4092 val = ShiftMask;
4094 else if (val == 7)
4096 val = LockMask;
4098 else if (val == 8)
4100 val = ControlMask;
4102 else if (val >=1 && val <= 5)
4104 val = (Mod1Mask << (val - 1));
4106 else
4108 /* error */
4109 return;
4111 /* SS: Could be buggy if a "modifier" operation
4112 * preceeds a "wait" operation. */
4113 if (do_unset)
4115 mask &= ~val;
4117 else
4119 mask |= val;
4121 break;
4122 case 8:
4123 case 9:
4124 /* new max depth */
4125 if (GetIntegerArguments(action, &action, &val, 1) != 1)
4127 fvwm_msg(ERR, "__fake_event",
4128 "Invalid depth value in \"%s\"", args);
4129 return;
4131 maxdepth = val;
4132 break;
4133 default:
4134 fvwm_msg(ERR, "__fake_event",
4135 "Invalid command (%s) in \"%s\"", token, args);
4136 return;
4138 if (action)
4140 token = PeekToken(action, &action);
4144 return;
4147 void CMD_FakeClick(F_CMD_ARGS)
4149 __fake_event(F_PASS_ARGS, FakeMouseEvent);
4151 return;
4154 void CMD_FakeKeypress(F_CMD_ARGS)
4156 __fake_event(F_PASS_ARGS, FakeKeyEvent);
4158 return;
4161 /* A function to handle stroke (olicha Nov 11, 1999) */
4162 #ifdef HAVE_STROKE
4163 void CMD_StrokeFunc(F_CMD_ARGS)
4165 int finished = 0;
4166 int abort = 0;
4167 int modifiers = exc->x.etrigger->xbutton.state;
4168 int start_event_type = exc->x.etrigger->type;
4169 char sequence[STROKE_MAX_SEQUENCE + 1];
4170 char *stroke_action, *name;
4171 char *opt = NULL;
4172 Bool finish_on_release = True;
4173 KeySym keysym;
4174 Bool restore_repeat = False;
4175 Bool echo_sequence = False;
4176 Bool draw_motion = False;
4177 int i = 0;
4178 int *x = NULL;
4179 int *y = NULL;
4180 const int STROKE_CHUNK_SIZE = 0xff;
4181 int coords_size = STROKE_CHUNK_SIZE;
4182 Window JunkRoot, JunkChild;
4183 int JunkX, JunkY;
4184 int tmpx, tmpy;
4185 unsigned int JunkMask;
4186 Bool feed_back = False;
4187 int stroke_width = 1;
4188 XEvent e;
4189 XClassHint *class;
4193 if (!GrabEm(CRS_STROKE, GRAB_NORMAL))
4195 XBell(dpy, 0);
4196 return;
4198 x = (int*)safemalloc(coords_size * sizeof(int));
4199 y = (int*)safemalloc(coords_size * sizeof(int));
4200 e = *exc->x.etrigger;
4201 /* set the default option */
4202 if (e.type == KeyPress || e.type == ButtonPress)
4204 finish_on_release = True;
4206 else
4208 finish_on_release = False;
4211 /* parse the option */
4212 for (action = GetNextSimpleOption(action, &opt); opt;
4213 action = GetNextSimpleOption(action, &opt))
4215 if (StrEquals("NotStayPressed",opt))
4217 finish_on_release = False;
4219 else if (StrEquals("EchoSequence",opt))
4221 echo_sequence = True;
4223 else if (StrEquals("DrawMotion",opt))
4225 draw_motion = True;
4227 else if (StrEquals("FeedBack",opt))
4229 feed_back = True;
4231 else if (StrEquals("StrokeWidth",opt))
4233 /* stroke width takes a positive integer argument */
4234 if (opt)
4236 free(opt);
4238 action = GetNextToken(action, &opt);
4239 if (!opt)
4241 fvwm_msg(
4242 WARN, "StrokeWidth",
4243 "needs an integer argument");
4245 /* we allow stroke_width == 0 which means drawing a
4246 * `fast' line of width 1; the upper level of 100 is
4247 * arbitrary */
4248 else if (!sscanf(opt, "%d", &stroke_width) ||
4249 stroke_width < 0 || stroke_width > 100)
4251 fvwm_msg(
4252 WARN, "StrokeWidth",
4253 "Bad integer argument %d",
4254 stroke_width);
4255 stroke_width = 1;
4258 else
4260 fvwm_msg(WARN,"StrokeFunc","Unknown option %s", opt);
4262 if (opt)
4264 free(opt);
4267 if (opt)
4269 free(opt);
4272 /* Force auto repeat off and grab the Keyboard to get proper
4273 * KeyRelease events if we need it.
4274 * Some computers do not support KeyRelease events, can we
4275 * check this here ? No ? */
4276 if (start_event_type == KeyPress && finish_on_release)
4278 XKeyboardState kstate;
4280 XGetKeyboardControl(dpy, &kstate);
4281 if (kstate.global_auto_repeat == AutoRepeatModeOn)
4283 XAutoRepeatOff(dpy);
4284 restore_repeat = True;
4286 MyXGrabKeyboard(dpy);
4289 /* be ready to get a stroke sequence */
4290 stroke_init();
4292 if (draw_motion)
4294 MyXGrabServer(dpy);
4295 if (FQueryPointer(
4296 dpy, Scr.Root, &JunkRoot, &JunkChild, &x[0], &y[0],
4297 &JunkX, &JunkY, &JunkMask) == False)
4299 /* pointer is on a different screen */
4300 x[0] = 0;
4301 y[0] = 0;
4303 XSetLineAttributes(
4304 dpy,Scr.XorGC,stroke_width,LineSolid,CapButt,JoinMiter);
4307 while (!finished && !abort)
4309 /* block until there is an event */
4310 FMaskEvent(
4311 dpy, ButtonPressMask | ButtonReleaseMask |
4312 KeyPressMask | KeyReleaseMask | ButtonMotionMask |
4313 PointerMotionMask, &e);
4314 switch (e.type)
4316 case MotionNotify:
4317 if (e.xmotion.same_screen == False)
4319 continue;
4321 if (e.xany.window != Scr.Root)
4323 if (FQueryPointer(
4324 dpy, Scr.Root, &JunkRoot,
4325 &JunkChild, &tmpx, &tmpy, &JunkX,
4326 &JunkY, &JunkMask) == False)
4328 /* pointer is on a different screen */
4329 tmpx = 0;
4330 tmpy = 0;
4333 else
4335 tmpx = e.xmotion.x;
4336 tmpy = e.xmotion.y;
4338 stroke_record(tmpx,tmpy);
4339 if (draw_motion && (x[i] != tmpx || y[i] != tmpy))
4341 i++;
4342 if (i >= coords_size)
4344 coords_size += STROKE_CHUNK_SIZE;
4345 x = (int*)saferealloc(
4346 (void *)x, coords_size *
4347 sizeof(int));
4348 y = (int*)saferealloc(
4349 (void *)y, coords_size *
4350 sizeof(int));
4352 x[i] = tmpx;
4353 y[i] = tmpy;
4354 XDrawLine(
4355 dpy, Scr.Root, Scr.XorGC, x[i-1],
4356 y[i-1], x[i], y[i]);
4358 break;
4359 case ButtonRelease:
4360 if (finish_on_release && start_event_type ==
4361 ButtonPress)
4363 finished = 1;
4365 break;
4366 case KeyRelease:
4367 if (finish_on_release && start_event_type == KeyPress)
4369 finished = 1;
4371 break;
4372 case KeyPress:
4373 keysym = XLookupKeysym(&e.xkey, 0);
4374 /* abort if Escape or Delete is pressed (as in menus.c)
4376 if (keysym == XK_Escape || keysym == XK_Delete ||
4377 keysym == XK_KP_Separator)
4379 abort = 1;
4381 /* finish on enter or space (as in menus.c) */
4382 if (keysym == XK_Return || keysym == XK_KP_Enter ||
4383 keysym == XK_space)
4385 finished = 1;
4387 break;
4388 case ButtonPress:
4389 if (!finish_on_release)
4391 finished = 1;
4393 break;
4394 default:
4395 break;
4399 if (draw_motion)
4401 while (i > 0)
4403 XDrawLine(
4404 dpy, Scr.Root, Scr.XorGC, x[i-1], y[i-1], x[i],
4405 y[i]);
4406 i--;
4408 XSetLineAttributes(dpy,Scr.XorGC,0,LineSolid,CapButt,JoinMiter);
4409 MyXUngrabServer(dpy);
4411 if (x != NULL)
4413 free(x);
4414 free(y);
4416 if (start_event_type == KeyPress && finish_on_release)
4418 MyXUngrabKeyboard(dpy);
4420 UngrabEm(GRAB_NORMAL);
4421 if (restore_repeat)
4423 XAutoRepeatOn(dpy);
4426 /* get the stroke sequence */
4427 stroke_trans(sequence);
4429 if (echo_sequence)
4431 char num_seq[STROKE_MAX_SEQUENCE + 1];
4433 for (i = 0; sequence[i] != '\0';i++)
4435 /* Telephone to numeric pad */
4436 if ('7' <= sequence[i] && sequence[i] <= '9')
4438 num_seq[i] = sequence[i]-6;
4440 else if ('1' <= sequence[i] && sequence[i] <= '3')
4442 num_seq[i] = sequence[i]+6;
4444 else
4446 num_seq[i] = sequence[i];
4449 num_seq[i++] = '\0';
4450 fvwm_msg(INFO, "StrokeFunc", "stroke sequence: %s (N%s)",
4451 sequence, num_seq);
4453 if (abort)
4455 return;
4457 if (exc->w.fw == NULL)
4459 class = NULL;
4460 name = NULL;
4462 else
4464 class = &exc->w.fw->class;
4465 name = exc->w.fw->name.name;
4467 /* check for a binding */
4468 stroke_action = CheckBinding(
4469 Scr.AllBindings, sequence, 0, modifiers, GetUnusedModifiers(),
4470 exc->w.wcontext, BIND_STROKE, class, name);
4472 /* execute the action */
4473 if (stroke_action != NULL)
4475 const exec_context_t *exc2;
4476 exec_context_changes_t ecc;
4478 if (feed_back && atoi(sequence) != 0)
4480 GrabEm(CRS_WAIT, GRAB_BUSY);
4481 usleep(200000);
4482 UngrabEm(GRAB_BUSY);
4484 ecc.x.etrigger = &e;
4485 exc2 = exc_clone_context(exc, &ecc, ECC_ETRIGGER);
4486 execute_function(cond_rc, exc2, stroke_action, 0);
4487 exc_destroy_context(exc2);
4490 return;
4492 #endif /* HAVE_STROKE */
4494 void CMD_State(F_CMD_ARGS)
4496 unsigned int state;
4497 int toggle;
4498 int n;
4499 FvwmWindow * const fw = exc->w.fw;
4501 n = GetIntegerArguments(action, &action, (int *)&state, 1);
4502 if (n <= 0)
4504 return;
4506 if (state < 0 || state > 31)
4508 fvwm_msg(ERR, "CMD_State", "Illegal state %d\n", state);
4509 return;
4511 toggle = ParseToggleArgument(action, NULL, -1, 0);
4512 state = (1 << state);
4513 switch (toggle)
4515 case -1:
4516 TOGGLE_USER_STATES(fw, state);
4517 break;
4518 case 0:
4519 CLEAR_USER_STATES(fw, state);
4520 break;
4521 case 1:
4522 default:
4523 SET_USER_STATES(fw, state);
4524 break;
4527 return;