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
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 ---------------------- */
31 #include <sys/types.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"
60 #include "functions.h"
64 #include "module_interface.h"
70 #include "decorations.h"
71 #include "add_window.h"
74 #include "move_resize.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] =
110 "ToggledInactiveDown",
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 );
146 strcat( path
, PictureGetImagePath() );
148 PictureSetImagePath( path
);
155 * Reads a title button description (veliaa@rpi.edu)
158 static char *ReadTitleButton(
159 char *s
, TitleButton
*tb
, Boolean append
, int button
)
166 int bs_start
, bs_end
;
174 s
= SkipSpaces(s
, NULL
, 0);
175 t
= GetNextTokenIndex(s
, button_states
, 0, &bs
);
178 s
= SkipSpaces(t
, NULL
, 0);
186 else if (bs
== BS_Active
)
188 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
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
;
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
;
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
;
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
;
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
)
267 bs_end
= BS_MaxButtonState
- 1;
268 for (i
= bs_start
; (i
& use_mask
) != set_mask
&& i
<= bs_end
;
279 if (!(end
= strchr(++s
, ')')))
282 ERR
, "ReadTitleButton",
283 "missing parenthesis: %s", s
);
286 s
= SkipSpaces(s
, NULL
, 0);
288 spec
= safemalloc(len
);
289 strncpy(spec
, s
, len
- 1);
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 */
306 for (i
= bs_start
; i
<= bs_end
; ++i
)
308 if (multiple
&& (i
& use_mask
) != set_mask
)
312 ReadDecorFace(spec
, &TB_STATE(*tb
)[i
], button
, verbose
);
316 else if (ReadDecorFace(spec
, &tmpdf
, button
, True
))
320 DecorFace
*head
= &TB_STATE(*tb
)[bs_start
];
321 DecorFace
*tail
= head
;
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
) ==
334 /* override the default vector style */
336 &tail
->next
->style
, &head
->style
,
337 sizeof(DecorFaceStyle
));
338 DFS_FACE_TYPE(tail
->next
->style
) = VectorButton
;
341 FreeDecorFace(dpy
, head
);
342 memcpy(head
, next
, sizeof(DecorFace
));
345 for (i
= bs_start
+ 1; i
<= bs_end
; ++i
)
347 if (multiple
&& (i
& use_mask
) != set_mask
)
351 head
= &TB_STATE(*tb
)[i
];
357 tail
->next
= (DecorFace
*)safemalloc(
360 &DFS_FLAGS(tail
->next
->style
), 0,
361 sizeof(DFS_FLAGS(tail
->next
->style
)));
362 DFS_FACE_TYPE(tail
->next
->style
) =
364 tail
->next
->next
= NULL
;
365 ReadDecorFace(spec
, tail
->next
, button
, False
);
366 if (DFS_FACE_TYPE(tail
->next
->style
) ==
368 DFS_FACE_TYPE((&TB_STATE(*tb
)[i
])->style
) ==
371 /* override the default vector style */
375 sizeof(DecorFaceStyle
));
376 DFS_FACE_TYPE(tail
->next
->style
) =
380 FreeDecorFace(dpy
, head
);
381 memcpy(head
, next
, sizeof(DecorFace
));
388 FreeDecorFace(dpy
, &TB_STATE(*tb
)[bs_start
]);
390 &(TB_STATE(*tb
)[bs_start
]), &tmpdf
,
392 for (i
= bs_start
+ 1; i
<= bs_end
; ++i
)
394 if (multiple
&& (i
& use_mask
) != set_mask
)
399 spec
, &TB_STATE(*tb
)[i
], button
, False
);
407 end
= SkipSpaces(end
, NULL
, 0);
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
;
420 for (t
= Scr
.FvwmRoot
.next
; t
; t
= t
->next
)
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
;
429 ecc
.w
.wcontext
= C_WINDOW
;
430 exc2
= exc_clone_context(
431 exc
, &ecc
, ECC_FW
| ECC_WCONTEXT
);
433 cond_rc
, exc2
, "ChangeDecor Default", 0);
434 exc_destroy_context(exc2
);
441 static void do_title_style(F_CMD_ARGS
, Bool do_add
)
446 FvwmDecor
*decor
= Scr
.cur_decor
? Scr
.cur_decor
: &Scr
.DefaultDecor
;
448 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
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"))
475 sscanf(action
, "%d%n", &height
, &next
) <= 0 ||
476 height
< MIN_FONT_HEIGHT
||
477 height
> MAX_FONT_HEIGHT
)
481 fvwm_msg(ERR
, "do_title_style",
482 "bad height argument (height"
483 " must be from 5 to 256)");
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;
497 else if (!do_add
&& StrEquals(parm
,"MinHeight"))
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
)
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;
523 action
= ReadTitleButton(
524 prev
, &decor
->titlebar
, do_add
, -1);
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] =
558 Bool load_pixmap
= False
;
560 FvwmPictureAttributes fpa
;
562 df
->style
.face_type
= MultiPixmap
;
563 df
->u
.mp
.pixmaps
= pm
=
564 (FvwmPicture
**)safecalloc(
565 TBMP_NUM_PIXMAPS
, sizeof(FvwmPicture
*));
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
++)
573 acs
[i
].alpha_percent
= 100;
575 s
= GetNextTokenIndex(s
, pm_names
, 0, &pm_id
);
580 s
= DoPeekToken(s
, &token
, ",()", NULL
, NULL
);
581 if (StrEquals(token
, "stretched"))
584 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
586 else if (StrEquals(token
, "tiled"))
588 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
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",
604 df
->u
.mp
.stretch_flags
|= (1 << pm_id
);
606 if (strncasecmp (token
, "Colorset", 8) == 0)
611 tmp
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
612 if (!GetIntegerArguments(token
, NULL
, &val
, 1) ||
616 ERR
, "ReadMultiPixmapDecor",
617 "Colorset shoule take one or two "
618 "positive integers as argument");
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
));
634 else if (strncasecmp(token
, "TiledPixmap", 11) == 0)
636 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
639 else if (strncasecmp(token
, "AdjustedPixmap", 14) == 0)
641 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
643 df
->u
.mp
.stretch_flags
|= (1 << pm_id
);
645 else if (strncasecmp(token
, "Solid", 5) == 0)
647 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
650 df
->u
.mp
.pixels
[pm_id
] = GetColor(token
);
651 df
->u
.mp
.solid_flags
|= (1 << pm_id
);
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
);
665 fvwm_msg(ERR
, "ReadMultiPixmapDecor",
666 "Pixmap '%s' could not be loaded",
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;
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
];
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
++)
749 PDestroyFvwmPicture(dpy
, pm
[i
]);
751 else if (!!(df
->u
.mp
.solid_flags
& i
))
754 dpy
, Pcmap
, &df
->u
.mp
.pixels
[i
], 1, 0,
769 * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
770 * structure, but does not free the FvwmDecor itself
773 static void DestroyFvwmDecor(FvwmDecor
*decor
)
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
);
795 static void SetLayerButtonFlag(
796 int layer
, int multi
, int set
, FvwmDecor
*decor
, TitleButton
*tb
)
812 for (i
= start
; i
< NUMBER_OF_TITLE_BUTTONS
; i
+= add
)
816 TB_FLAGS(decor
->buttons
[i
]).has_layer
= 1;
817 TB_LAYER(decor
->buttons
[i
]) = layer
;
821 TB_FLAGS(decor
->buttons
[i
]).has_layer
= 0;
829 TB_FLAGS(*tb
).has_layer
= 1;
830 TB_LAYER(*tb
) = layer
;
834 TB_FLAGS(*tb
).has_layer
= 0;
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
)
863 for (i
= start
; i
< NUMBER_OF_TITLE_BUTTONS
; i
+= add
)
867 TB_MWM_DECOR_FLAGS(decor
->buttons
[i
]) |= flag
;
871 TB_MWM_DECOR_FLAGS(decor
->buttons
[i
]) &= ~flag
;
879 TB_MWM_DECOR_FLAGS(*tb
) |= flag
;
883 TB_MWM_DECOR_FLAGS(*tb
) &= ~flag
;
890 static void do_button_style(F_CMD_ARGS
, Bool do_add
)
899 TitleButton
*tb
= NULL
;
901 FvwmDecor
*decor
= Scr
.cur_decor
? Scr
.cur_decor
: &Scr
.DefaultDecor
;
903 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
906 parm
= PeekToken(action
, &text
);
907 if (parm
&& isdigit(*parm
))
910 button
= BUTTON_INDEX(button
);
913 if (parm
== NULL
|| button
>= NUMBER_OF_TITLE_BUTTONS
|| button
< 0)
916 ERR
, "ButtonStyle", "Bad button style (1) in line %s",
921 Scr
.flags
.do_need_window_update
= 1;
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 */
940 /* we're either resetting buttons or an invalid button
941 * set was specified */
942 if (StrEquals(parm
,"reset"))
944 ResetAllButtons(decor
);
950 "Bad button style (2) in line %s",
957 /* mark button style and decor as changed */
958 decor
->flags
.has_changed
= 1;
961 /* a single button was specified */
962 tb
= &decor
->buttons
[button
];
963 TB_FLAGS(*tb
).has_changed
= 1;
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;
980 for (prev
= text
; (parm
= PeekToken(text
, &text
)); prev
= text
)
982 if (!do_add
&& strcmp(parm
,"-") == 0)
985 text
= GetNextToken(text
, &tok
);
989 char *old_tok
= NULL
;
998 if (StrEquals(tok
,"Clear"))
1003 i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
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 ? */
1020 TB_JUSTIFICATION(*tb
) = (set
) ?
1023 memset(&TB_FLAGS(*tb
), (set
) ?
1025 sizeof(TB_FLAGS(*tb
)));
1026 /* ? not very useful if
1030 else if (StrEquals(tok
, "MWMDecorMenu"))
1033 MWM_DECOR_MENU
, multi
, set
,
1036 else if (StrEquals(tok
, "MWMDecorMin"))
1039 MWM_DECOR_MINIMIZE
, multi
, set
,
1042 else if (StrEquals(tok
, "MWMDecorMax"))
1045 MWM_DECOR_MAXIMIZE
, multi
, set
,
1048 else if (StrEquals(tok
, "MWMDecorShade"))
1051 MWM_DECOR_SHADE
, multi
, set
,
1054 else if (StrEquals(tok
, "MWMDecorStick"))
1057 MWM_DECOR_STICK
, multi
, set
,
1060 else if (StrEquals(tok
, "MwmDecorLayer"))
1062 int layer
, got_number
;
1064 text
= GetNextToken(text
, <ok
);
1076 if (!ltok
|| !got_number
)
1078 fvwm_msg(ERR
, "ButtonStyle",
1080 " integer value for"
1081 " layer -- line: %s",
1094 fvwm_msg(ERR
, "ButtonStyle",
1095 "unknown title button flag"
1096 " %s -- line: %s", tok
, text
);
1106 text
= GetNextToken(text
, &tok
);
1114 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
1116 if (((multi
& 1) && !(i
& 1)) ||
1117 ((multi
& 2) && (i
& 1)))
1119 text
= ReadTitleButton(
1126 else if (!(text
= ReadTitleButton(
1127 prev
, tb
, do_add
, button
)))
1138 int update_decorface_colorset(DecorFace
*df
, int cset
)
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;
1151 else if (DFS_FACE_TYPE(tdf
->style
) == MultiPixmap
)
1155 for (i
= 0; i
< TBMP_NUM_PIXMAPS
; i
++)
1157 if (tdf
->u
.mp
.acs
[i
].cs
== cset
)
1159 tdf
->flags
.has_changed
= 1;
1170 int update_titlebutton_colorset(TitleButton
*tb
, int cset
)
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
;
1185 void update_decors_colorset(int cset
)
1189 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
1192 for(decor
= &Scr
.DefaultDecor
; decor
!= NULL
; decor
= decor
->next
)
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
)
1220 *ret_action
= action
;
1221 n
= sscanf(action
, "%d%n", pcoord
, &offset
);
1227 /* check for offest */
1228 if (*action
== '+' || *action
== '-')
1230 n
= sscanf(action
, "%dp%n", poff
, &offset
);
1239 else if (*poff
> 127)
1249 *ret_action
= action
;
1254 static Bool
__parse_vector_line(
1255 char **ret_action
, int *px
, int *py
, int *pxoff
, int *pyoff
, int *pc
,
1258 Bool is_valid
= True
;
1262 *ret_action
= action
;
1263 if (__parse_vector_line_one_coord(&action
, px
, pxoff
, action
) == False
)
1272 if (__parse_vector_line_one_coord(&action
, py
, pyoff
, action
) == False
)
1281 /* read the line style */
1282 n
= sscanf(action
, "%d%n", pc
, &offset
);
1288 *ret_action
= action
;
1293 /* ---------------------------- interface functions ------------------------ */
1295 void refresh_window(Window w
, Bool window_update
)
1297 XSetWindowAttributes attributes
;
1298 unsigned long valuemask
;
1300 valuemask
= CWOverrideRedirect
| CWBackingStore
| CWSaveUnder
|
1302 attributes
.override_redirect
= True
;
1303 attributes
.save_under
= False
;
1304 attributes
.background_pixmap
= None
;
1305 attributes
.backing_store
= NotUseful
;
1307 dpy
, w
, 0, 0, Scr
.MyDisplayWidth
, Scr
.MyDisplayHeight
, 0,
1308 CopyFromParent
, CopyFromParent
, CopyFromParent
, valuemask
,
1311 if (Scr
.flags
.do_need_window_update
&& window_update
)
1313 flush_window_updates();
1315 XDestroyWindow(dpy
, w
);
1317 handle_all_expose();
1322 void ApplyDefaultFontAndColors(void)
1326 int cset
= Scr
.DefaultColorset
;
1329 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCBackground
;
1330 gcv
.function
= GXcopy
;
1331 if (Scr
.DefaultFont
->font
)
1334 gcv
.font
= Scr
.DefaultFont
->font
->fid
;
1339 gcv
.foreground
= Colorset
[cset
].fg
;
1340 gcv
.background
= Colorset
[cset
].bg
;
1344 gcv
.foreground
= Scr
.StdFore
;
1345 gcv
.background
= Scr
.StdBack
;
1349 XChangeGC(dpy
, Scr
.StdGC
, gcm
, &gcv
);
1353 Scr
.StdGC
= fvwmlib_XCreateGC(dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1356 gcm
= GCFunction
|GCLineWidth
|GCForeground
;
1359 gcv
.foreground
= Colorset
[cset
].hilite
;
1363 gcv
.foreground
= Scr
.StdHilite
;
1365 if (Scr
.StdReliefGC
)
1367 XChangeGC(dpy
, Scr
.StdReliefGC
, gcm
, &gcv
);
1371 Scr
.StdReliefGC
= fvwmlib_XCreateGC(
1372 dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1376 gcv
.foreground
= Colorset
[cset
].shadow
;
1380 gcv
.foreground
= Scr
.StdShadow
;
1382 if (Scr
.StdShadowGC
)
1384 XChangeGC(dpy
, Scr
.StdShadowGC
, gcm
, &gcv
);
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();
1401 void FreeDecorFace(Display
*dpy
, DecorFace
*df
)
1405 switch (DFS_FACE_TYPE(df
->style
))
1407 case GradientButton
:
1408 if (df
->u
.grad
.d_pixels
!= NULL
&& df
->u
.grad
.d_npixels
)
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
)
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
;
1428 dpy
, Pcmap
, p
, df
->u
.grad
.npixels
, 0, False
);
1431 if (df
->u
.grad
.xcs
!= NULL
)
1433 free(df
->u
.grad
.xcs
);
1438 case TiledPixmapButton
:
1439 case StretchedPixmapButton
:
1440 case AdjustedPixmapButton
:
1441 case ShrunkPixmapButton
:
1444 PDestroyFvwmPicture(dpy
, df
->u
.p
);
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
))
1461 dpy
, Pcmap
, &df
->u
.mp
.pixels
[i
],
1465 free(df
->u
.mp
.pixmaps
);
1471 if (df
->u
.mp
.pixels
)
1473 free(df
->u
.mp
.pixels
);
1477 case DefaultVectorButton
:
1480 free (df
->u
.vector
.x
);
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
);
1497 free (df
->u
.vector
.c
);
1504 /* delete any compound styles */
1507 FreeDecorFace(dpy
, df
->next
);
1511 memset(&df
->style
, 0, sizeof(df
->style
));
1512 memset(&df
->u
, 0, sizeof(df
->u
));
1513 DFS_FACE_TYPE(df
->style
) = SimpleButton
;
1520 * Reads a button face line into a structure (veliaa@rpi.edu)
1523 Bool
ReadDecorFace(char *s
, DecorFace
*df
, int button
, int verbose
)
1526 char style
[256], *file
;
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)
1535 fvwm_msg(ERR
, "ReadDecorFace", "error in face `%s'", s
);
1541 if (strncasecmp(style
, "--", 2) != 0)
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
);
1564 ERR
,"ReadDecorFace",
1565 "need default button"
1574 b
= BUTTON_INDEX(b
);
1577 if (b
>= 0 && b
< NUMBER_OF_TITLE_BUTTONS
)
1579 LoadDefaultButton(df
, b
);
1586 ERR
, "ReadDecorFace",
1587 "button number out of range:"
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
);
1608 num
= sscanf(style
,"%d",&num_coords
);
1611 if (num
< 1 || num_coords
<2 ||
1612 num_coords
> MAX_TITLE_BUTTON_VECTOR_LINES
)
1617 ERR
, "ReadDecorFace",
1618 "Bad button style (2) in line:"
1624 vc
->num
= num_coords
;
1626 vc
->x
= (signed char*)safemalloc(sizeof(char) *
1628 vc
->y
= (signed char*)safemalloc(sizeof(char) *
1630 vc
->xoff
= (signed char*)safemalloc(sizeof(char) *
1632 vc
->yoff
= (signed char*)safemalloc(sizeof(char) *
1634 vc
->c
= (signed char*)safemalloc(sizeof(char) *
1637 /* get the points */
1638 for (i
= 0; i
< vc
->num
; ++i
)
1646 if (__parse_vector_line(
1647 &s
, &x
, &y
, &xoff
, &yoff
, &c
, s
) ==
1677 if (c
== 2 || c
== 3)
1687 ERR
, "ReadDecorFace",
1688 "Bad button style (3) in line"
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
);
1711 memset(&df
->style
, 0, sizeof(df
->style
));
1712 DFS_FACE_TYPE(df
->style
) = SolidButton
;
1713 df
->u
.back
= GetColor(file
);
1721 ERR
, "ReadDecorFace",
1722 "no color given for Solid"
1723 " face type: %s", action
);
1728 else if (strncasecmp(style
+1, "Gradient", 8)==0)
1731 int npixels
, nsegs
, *perc
;
1733 Bool do_dither
= False
;
1735 if (!IsGradientTypeSupported(style
[0]))
1739 /* translate the gradient string into an array of
1741 npixels
= ParseGradient(
1742 s
, &s
, &s_colors
, &perc
, &nsegs
);
1743 while (*s
&& isspace(*s
))
1751 /* grab the colors */
1756 xcs
= AllocAllGradientColors(
1757 s_colors
, perc
, nsegs
, npixels
, do_dither
);
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
)
1787 ERR
, "ReadDecorFace",
1788 "couldn't load pixmap"
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
) =
1823 DFS_FACE_TYPE(df
->style
) = PixmapButton
;
1826 else if (strncasecmp(style
,"MultiPixmap",11)==0)
1833 ERR
, "ReadDecorFace",
1834 "MultiPixmap is only valid"
1839 s
= ReadMultiPixmapDecor(s
, df
);
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 */
1853 else if (strncasecmp (style
, "Colorset", 8) == 0)
1858 n
= GetIntegerArguments(s
, NULL
, val
, 2);
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;
1873 df
->u
.acs
.alpha_percent
=
1874 max(0, min(100,val
[1]));
1876 s
= SkipNTokens(s
, n
);
1883 ERR
, "ReadDecorFace",
1884 "unknown style %s: %s", style
, action
);
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))
1896 s
= GetNextToken(s
, &tok
);
1900 char *old_tok
= NULL
;
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"))
1918 DFS_H_JUSTIFICATION(df
->style
) =
1923 DFS_H_JUSTIFICATION(df
->style
) =
1927 else if (StrEquals(tok
,"Right"))
1931 DFS_H_JUSTIFICATION(df
->style
) =
1936 DFS_H_JUSTIFICATION(df
->style
) =
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"))
1949 DFS_V_JUSTIFICATION(df
->style
) =
1954 DFS_V_JUSTIFICATION(df
->style
) =
1958 else if (StrEquals(tok
,"Bottom"))
1962 DFS_V_JUSTIFICATION(df
->style
) =
1967 DFS_V_JUSTIFICATION(df
->style
) =
1971 else if (StrEquals(tok
,"Flat"))
1975 DFS_BUTTON_RELIEF(df
->style
) =
1978 else if (DFS_BUTTON_RELIEF(df
->style
) ==
1981 DFS_BUTTON_RELIEF(df
->style
) =
1985 else if (StrEquals(tok
,"Sunk"))
1989 DFS_BUTTON_RELIEF(df
->style
) =
1992 else if (DFS_BUTTON_RELIEF(df
->style
) ==
1995 DFS_BUTTON_RELIEF(df
->style
) =
1999 else if (StrEquals(tok
,"Raised"))
2003 DFS_BUTTON_RELIEF(df
->style
) =
2008 DFS_BUTTON_RELIEF(df
->style
) =
2012 else if (StrEquals(tok
,"UseTitleStyle"))
2016 DFS_USE_TITLE_STYLE(df
->style
) = 1;
2017 DFS_USE_BORDER_STYLE(df
->style
) = 0;
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"))
2034 DFS_USE_BORDER_STYLE(df
->style
) = 1;
2035 DFS_USE_TITLE_STYLE(df
->style
) = 0;
2039 DFS_USE_BORDER_STYLE(df
->style
) = 0;
2045 ERR
, "ReadDecorFace",
2046 "unknown button face flag '%s'"
2047 " -- line: %s", tok
, action
);
2057 s
= GetNextToken(s
, &tok
);
2071 * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
2074 void AddToDecor(F_CMD_ARGS
, FvwmDecor
*decor
)
2080 while (*action
&& isspace((unsigned char)*action
))
2088 Scr
.cur_decor
= decor
;
2089 execute_function(cond_rc
, exc
, action
, 0);
2090 Scr
.cur_decor
= NULL
;
2097 * InitFvwmDecor -- initializes an FvwmDecor structure to defaults
2100 void InitFvwmDecor(FvwmDecor
*decor
)
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
)
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
)
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
;
2135 void reset_decor_changes(void)
2138 Scr
.DefaultDecor
.flags
.has_changed
= 0;
2139 Scr
.DefaultDecor
.flags
.has_title_height_changed
= 0;
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 */
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
);
2167 /* ---------------------------- builtin commands --------------------------- */
2169 void CMD_Beep(F_CMD_ARGS
)
2172 parse_colorset(11, "RootTransparent");
2179 void CMD_Nop(F_CMD_ARGS
)
2184 void CMD_EscapeFunc(F_CMD_ARGS
)
2189 void CMD_CursorMove(F_CMD_ARGS
)
2192 int val1
, val2
, val1_unit
, val2_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");
2202 if (FQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
2203 &x
, &y
, &JunkX
, &JunkY
, &JunkMask
) == False
)
2205 /* pointer is on a different screen */
2209 x_unit
= val1
* val1_unit
/ 100;
2210 y_unit
= val2
* val2_unit
/ 100;
2219 x_pages
= x
/ Scr
.MyDisplayWidth
;
2223 x_pages
= ((x
+ 1) / Scr
.MyDisplayWidth
) - 1;
2225 virtual_x
+= x_pages
* Scr
.MyDisplayWidth
;
2226 x
-= x_pages
* Scr
.MyDisplayWidth
;
2232 else if (virtual_x
> Scr
.VxMax
)
2234 x
+= virtual_x
- Scr
.VxMax
;
2235 virtual_x
= Scr
.VxMax
;
2240 y_pages
= y
/ Scr
.MyDisplayHeight
;
2244 y_pages
= ((y
+ 1) / Scr
.MyDisplayHeight
) - 1;
2246 virtual_y
+= y_pages
* Scr
.MyDisplayHeight
;
2247 y
-= y_pages
* Scr
.MyDisplayHeight
;
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
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
))
2282 if (Scr
.EdgeScrollY
== 0 && (y
>= Scr
.MyDisplayHeight
||
2283 y
+ y_unit
>= Scr
.MyDisplayHeight
))
2286 FWarpPointerUpdateEvpos(
2287 exc
->x
.elast
, dpy
, None
, Scr
.Root
, 0, 0, Scr
.MyDisplayWidth
,
2288 Scr
.MyDisplayHeight
, x
, y
);
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
))
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. */
2310 dpy
, FW_W_PARENT(fw
), _XA_WM_DELETE_WINDOW
,
2315 if (WM_DELETES_WINDOW(fw
))
2318 dpy
, FW_W(fw
), _XA_WM_DELETE_WINDOW
, CurrentTime
);
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
);
2340 if (!is_function_allowed(F_DESTROY
, NULL
, fw
, True
, True
))
2347 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
2348 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2349 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
)
2352 XKillClient(dpy
, FW_W(fw
));
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
);
2369 if (!is_function_allowed(F_CLOSE
, NULL
, fw
, True
, True
))
2374 if (WM_DELETES_WINDOW(fw
))
2377 dpy
, FW_W(fw
), _XA_WM_DELETE_WINDOW
, CurrentTime
);
2382 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
2383 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2384 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
)
2387 XKillClient(dpy
, FW_W(fw
));
2396 void CMD_Restart(F_CMD_ARGS
)
2403 void CMD_ExecUseShell(F_CMD_ARGS
)
2406 static char shell_set
= 0;
2410 free(exec_shell_name
);
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"));
2426 /* if $SHELL not set, use default */
2427 exec_shell_name
= safestrdup("/bin/sh");
2432 void CMD_Exec(F_CMD_ARGS
)
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... */
2441 if (strncasecmp(action
,"exec",4)!=0)
2443 cmd
= (char *)safemalloc(strlen(action
)+6);
2444 strcpy(cmd
,"exec ");
2450 cmd
= safestrdup(action
);
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
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 */
2471 fvmm_deinstall_signals();
2472 fd
= open("/dev/null", O_RDONLY
, 0);
2473 dup2(fd
,STDIN_FILENO
);
2475 if (fd
!= STDIN_FILENO
)
2478 if (fvwm_setpgrp() == -1)
2480 fvwm_msg(ERR
, "exec_function", "setpgrp failed (%s)",
2484 if (execl(exec_shell_name
, exec_shell_name
, "-c", cmd
, NULL
) ==
2487 fvwm_msg(ERR
, "exec_function", "execl failed (%s)",
2497 void CMD_Refresh(F_CMD_ARGS
)
2499 refresh_window(Scr
.Root
, True
);
2504 void CMD_RefreshWindow(F_CMD_ARGS
)
2506 FvwmWindow
* const fw
= exc
->w
.fw
;
2509 (exc
->w
.wcontext
== C_ICON
) ?
2510 FW_W_ICON_TITLE(fw
) : FW_W_FRAME(fw
), True
);
2515 void CMD_Wait(F_CMD_ARGS
)
2518 Bool redefine_cursor
= False
;
2521 Window nonewin
= None
;
2522 char *wait_string
, *rest
;
2525 /* try to get a single token */
2526 rest
= GetNextToken(action
, &wait_string
);
2529 while (*rest
&& isspace((unsigned char)*rest
))
2538 /* nope, multiple tokens - try old syntax */
2540 /* strip leading and trailing whitespace */
2542 while (*temp
&& isspace((unsigned char)*temp
))
2546 wait_string
= safestrdup(temp
);
2547 for (i
= strlen(wait_string
) - 1; i
>= 0 &&
2548 isspace(wait_string
[i
]); i
--)
2556 wait_string
= safestrdup("");
2559 is_ungrabbed
= UngrabEm(GRAB_NORMAL
);
2560 while (!done
&& !isTerminated
)
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
))
2572 dpy
, e
.xmap
.window
, FvwmContext
,
2573 (caddr_t
*)&t
) == XCNOENT
)
2578 if (e
.type
== MapNotify
&& e
.xmap
.event
== Scr
.Root
)
2584 if (t
&& matchWildcards(
2585 wait_string
, t
->name
.name
) == True
)
2589 else if (t
&& t
->class.res_class
&&
2592 t
->class.res_class
) == True
)
2596 else if (t
&& t
->class.res_name
&&
2599 t
->class.res_name
) == True
)
2604 else if (e
.type
== KeyPress
)
2606 /* should I be using <t> or <exc->w.fw>?
2613 context
= GetContext(&t
, t
, &e
, &nonewin
);
2616 class = &(t
->class);
2617 name
= t
->name
.name
;
2624 escape
= CheckBinding(
2625 Scr
.AllBindings
, STROKE_ARG(0)
2626 e
.xkey
.keycode
, e
.xkey
.state
,
2627 GetUnusedModifiers(), context
,
2628 BIND_KEYPRESS
, class, name
);
2631 if (!strcasecmp(escape
,"escapefunc"))
2639 if (redefine_cursor
)
2641 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_ROOT
]);
2645 GrabEm(CRS_NONE
, GRAB_NORMAL
);
2652 void CMD_Quit(F_CMD_ARGS
)
2654 if (master_pid
!= getpid())
2656 kill(master_pid
, SIGTERM
);
2663 void CMD_QuitScreen(F_CMD_ARGS
)
2670 void CMD_Echo(F_CMD_ARGS
)
2678 len
= strlen(action
);
2681 if (action
[len
-1]=='\n')
2686 fvwm_msg(ECHO
,"Echo",action
);
2691 void CMD_PrintInfo(F_CMD_ARGS
)
2694 char *rest
, *subject
= NULL
;
2696 rest
= GetNextToken(action
, &subject
);
2697 if (!rest
|| GetIntegerArguments(rest
, NULL
, &verbose
, 1) != 1)
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"))
2727 fvwm_msg(ERR
, "PrintInfo",
2728 "Unknown subject '%s'", action
);
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
;
2749 fvwm_msg(ERR
, "SetColormapFocus",
2750 "ColormapFocus requires 1 arg: FollowsFocus or"
2758 void CMD_ClickTime(F_CMD_ARGS
)
2762 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
2764 Scr
.ClickTime
= DEFAULT_CLICKTIME
;
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. */
2775 Scr
.ClickTime
= -Scr
.ClickTime
;
2782 void CMD_ImagePath(F_CMD_ARGS
)
2784 PictureSetImagePath( action
);
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
);
2798 void CMD_PixmapPath(F_CMD_ARGS
)
2800 fvwm_msg(ERR
, "pixmapPath_function",
2801 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2803 obsolete_imagepaths( action
);
2808 void CMD_LocalePath(F_CMD_ARGS
)
2810 FGettextSetLocalePath( action
);
2815 void CMD_ModulePath(F_CMD_ARGS
)
2817 static int need_to_free
= 0;
2819 setPath( &ModulePath
, action
, need_to_free
);
2825 void CMD_ModuleTimeout(F_CMD_ARGS
)
2829 moduleTimeout
= DEFAULT_MODULE_TIMEOUT
;
2830 if (GetIntegerArguments(action
, NULL
, &timeout
, 1) == 1 && timeout
> 0)
2832 moduleTimeout
= timeout
;
2838 void CMD_HilightColor(F_CMD_ARGS
)
2843 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
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.");
2855 action
= GetNextToken(action
, &fore
);
2856 GetNextToken(action
, &back
);
2859 action
= safemalloc(strlen(fore
) + strlen(back
) + 29);
2860 sprintf(action
, "* HilightFore %s, HilightBack %s", fore
, back
);
2861 CMD_Style(F_PASS_ARGS
);
2875 void CMD_HilightColorset(F_CMD_ARGS
)
2880 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
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.");
2893 newaction
= safemalloc(strlen(action
) + 32);
2894 sprintf(newaction
, "* HilightColorset %s", action
);
2896 CMD_Style(F_PASS_ARGS
);
2903 void CMD_TitleStyle(F_CMD_ARGS
)
2905 do_title_style(F_PASS_ARGS
, False
);
2908 } /* SetTitleStyle */
2912 * Appends a titlestyle (veliaa@rpi.edu)
2915 void CMD_AddTitleStyle(F_CMD_ARGS
)
2917 do_title_style(F_PASS_ARGS
, True
);
2922 void CMD_PropertyChange(F_CMD_ARGS
)
2928 unsigned long argument
;
2929 unsigned long data1
;
2930 unsigned long data2
;
2933 token
= PeekToken(action
, &rest
);
2938 ret
= sscanf(token
, "%lu", &argument
);
2945 token
= PeekToken(rest
, &rest
);
2948 ret
= sscanf(token
, "%lu", &data1
);
2956 token
= PeekToken(rest
, &rest
);
2959 ret
= sscanf(token
, "%lu", &data2
);
2966 memset(string
, 0, 256);
2969 ret
= sscanf(rest
, "%255c", &(string
[0]));
2971 BroadcastPropertyChange(argument
, data1
, data2
, string
);
2976 void CMD_DefaultIcon(F_CMD_ARGS
)
2978 if (Scr
.DefaultIcon
)
2980 free(Scr
.DefaultIcon
);
2982 GetNextToken(action
, &Scr
.DefaultIcon
);
2987 void CMD_DefaultColorset(F_CMD_ARGS
)
2991 if (GetIntegerArguments(action
, NULL
, &cset
, 1) != 1)
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;
3007 void CMD_DefaultColors(F_CMD_ARGS
)
3012 action
= GetNextToken(action
, &fore
);
3015 action
= GetNextToken(action
, &back
);
3019 back
= safestrdup(DEFAULT_BACK_COLOR
);
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
);
3040 Scr
.DefaultColorset
= -1;
3041 Scr
.flags
.do_need_window_update
= 1;
3042 Scr
.flags
.has_default_color_changed
= 1;
3047 void CMD_DefaultFont(F_CMD_ARGS
)
3050 FlocaleFont
*new_font
;
3053 font
= PeekToken(action
, &action
);
3056 /* Try 'fixed', pass NULL font name */
3058 if (!(new_font
= FlocaleLoadFont(dpy
, font
, "fvwm")))
3060 if (Scr
.DefaultFont
== NULL
)
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;
3091 void CMD_IconFont(F_CMD_ARGS
)
3096 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
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.");
3108 newaction
= safemalloc(strlen(action
) + 16);
3109 sprintf(newaction
, "* IconFont %s", action
);
3111 CMD_Style(F_PASS_ARGS
);
3118 void CMD_WindowFont(F_CMD_ARGS
)
3123 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
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.");
3135 newaction
= safemalloc(strlen(action
) + 16);
3136 sprintf(newaction
, "* Font %s", action
);
3138 CMD_Style(F_PASS_ARGS
);
3147 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3150 void CMD_ChangeDecor(F_CMD_ARGS
)
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
)
3163 /* search for tag */
3164 for (; decor
; decor
= decor
->next
)
3166 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3177 SET_DECOR_CHANGED(fw
, 1);
3178 old_height
= (fw
->decor
) ? fw
->decor
->title_height
: 0;
3180 apply_decor_change(fw
);
3187 * Destroys an FvwmDecor (veliaa@rpi.edu)
3190 void CMD_DestroyDecor(F_CMD_ARGS
)
3193 FvwmDecor
*decor
= Scr
.DefaultDecor
.next
;
3194 FvwmDecor
*prev
= &Scr
.DefaultDecor
, *found
= NULL
;
3195 Bool do_recreate
= False
;
3197 item
= PeekToken(action
, &action
);
3202 if (StrEquals(item
, "recreate"))
3205 item
= PeekToken(action
, NULL
);
3212 /* search for tag */
3213 for (; decor
; decor
= decor
->next
)
3215 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3223 if (found
&& (found
!= &Scr
.DefaultDecor
|| do_recreate
))
3227 __remove_window_decors(F_PASS_ARGS
, found
);
3229 DestroyFvwmDecor(found
);
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;
3247 prev
->next
= found
->next
;
3257 * Initiates an AddToDecor (veliaa@rpi.edu)
3260 void CMD_AddToDecor(F_CMD_ARGS
)
3263 FvwmDecor
*found
= NULL
;
3266 action
= GetNextToken(action
, &item
);
3276 /* search for tag */
3277 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3279 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
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
)
3297 decor
->next
= found
;
3306 AddToDecor(F_PASS_ARGS
, found
);
3307 /* Set + state to last decor */
3308 set_last_added_item(ADDED_DECOR
, found
);
3313 #endif /* USEDECOR */
3318 * Updates window decoration styles (veliaa@rpi.edu)
3321 void CMD_UpdateDecor(F_CMD_ARGS
)
3325 FvwmDecor
*decor
, *found
= NULL
;
3326 FvwmWindow
*hilight
= Scr
.Hilite
;
3329 action
= GetNextToken(action
, &item
);
3332 /* search for tag */
3333 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3335 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3345 for (fw2
= Scr
.FvwmRoot
.next
; fw2
; fw2
= fw2
->next
)
3348 /* update specific decor, or all */
3351 if (fw2
->decor
== found
)
3353 border_draw_decorations(
3354 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
,
3356 border_draw_decorations(
3357 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
,
3364 border_draw_decorations(
3365 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
,
3367 border_draw_decorations(
3368 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
, 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
);
3385 * Appends a button decoration style (veliaa@rpi.edu)
3388 void CMD_AddButtonStyle(F_CMD_ARGS
)
3390 do_button_style(F_PASS_ARGS
, True
);
3395 void CMD_SetEnv(F_CMD_ARGS
)
3398 char *szValue
= NULL
;
3399 char *szPutenv
= NULL
;
3401 action
= GetNextToken(action
, &szVar
);
3406 action
= GetNextToken(action
, &szValue
);
3409 szValue
= safestrdup("");
3411 szPutenv
= safemalloc(strlen(szVar
) + strlen(szValue
) + 2);
3412 sprintf(szPutenv
,"%s=%s", szVar
, szValue
);
3413 flib_putenv(szVar
, szPutenv
);
3421 void CMD_UnsetEnv(F_CMD_ARGS
)
3425 szVar
= PeekToken(action
, &action
);
3430 flib_unsetenv(szVar
);
3435 void CMD_GlobalOpts(F_CMD_ARGS
)
3443 "WindowShadeShrinks",
3444 "WindowShadeScrolls",
3445 "SmartPlacementIsReallySmart",
3446 "SmartPlacementIsNormal",
3447 "ClickToFocusDoesntPassClick",
3448 "ClickToFocusPassesClick",
3449 "ClickToFocusDoesntRaise",
3450 "ClickToFocusRaises",
3451 "MouseFocusClickDoesntRaise",
3452 "MouseFocusClickRaises",
3455 "CaptureHonorsStartsOnPage",
3456 "CaptureIgnoresStartsOnPage",
3457 "RecaptureHonorsStartsOnPage",
3458 "RecaptureIgnoresStartsOnPage",
3459 "ActivePlacementHonorsStartsOnPage",
3460 "ActivePlacementIgnoresStartsOnPage",
3461 "RaiseOverNativeWindows",
3462 "IgnoreNativeWindows",
3465 char *replacelist
[] = {
3466 /* These options are mapped to the Style * command */
3467 NULL
, /* NULL means to use "Style * <optionname>" */
3469 "* MinOverlapPlacement",
3470 "* TileCascadePlacement",
3471 "* ClickToFocusPassesClickOff",
3472 "* ClickToFocusPassesClick",
3473 "* ClickToFocusRaisesOff",
3474 "* ClickToFocusRaises",
3475 "* MouseFocusClickRaisesOff",
3476 "* MouseFocusClickRaises",
3477 "* StippledTitleOff",
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
))
3498 i
= GetTokenIndex(opt
, optlist
, 0, NULL
);
3504 replace
= replacelist
[i
];
3505 if (replace
== NULL
)
3507 replace
= &(buf
[0]);
3508 sprintf(buf
, "* %s", opt
);
3510 else if (*replace
!= '*')
3518 CMD_Style(F_PASS_ARGS
);
3523 CMD_BugOpts(F_PASS_ARGS
);
3528 ERR
, "SetGlobalOptions",
3529 "Please replace 'GlobalOpts %s' with '%s %s'.",
3534 fvwm_msg(ERR
, "SetGlobalOptions",
3535 "Unknown Global Option '%s'", opt
);
3537 /* should never be null, but checking anyways... */
3551 void CMD_BugOpts(F_CMD_ARGS
)
3557 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3558 while (action
&& *action
&& *action
!= '\n')
3560 action
= GetNextFullOption(action
, &optstring
);
3563 /* no more options */
3566 toggle
= ParseToggleArgument(
3567 SkipNTokens(optstring
,1), NULL
, 2, False
);
3568 opt
= PeekToken(optstring
, NULL
);
3575 /* toggle = ParseToggleArgument(rest, &rest, 2, False);*/
3577 if (StrEquals(opt
, "FlickeringMoveWorkaround"))
3582 Scr
.bo
.do_disable_configure_notify
^= 1;
3586 Scr
.bo
.do_disable_configure_notify
= toggle
;
3589 Scr
.bo
.do_disable_configure_notify
= 0;
3593 else if (StrEquals(opt
, "MixedVisualWorkaround"))
3598 Scr
.bo
.do_install_root_cmap
^= 1;
3602 Scr
.bo
.do_install_root_cmap
= toggle
;
3605 Scr
.bo
.do_install_root_cmap
= 0;
3609 else if (StrEquals(opt
, "ModalityIsEvil"))
3614 Scr
.bo
.is_modality_evil
^= 1;
3618 Scr
.bo
.is_modality_evil
= toggle
;
3621 Scr
.bo
.is_modality_evil
= 0;
3624 if (Scr
.bo
.is_modality_evil
)
3626 SetMWM_INFO(Scr
.NoFocusWin
);
3629 else if (StrEquals(opt
, "RaiseOverNativeWindows"))
3634 Scr
.bo
.is_raise_hack_needed
^= 1;
3638 Scr
.bo
.is_raise_hack_needed
= toggle
;
3641 Scr
.bo
.is_raise_hack_needed
= 0;
3645 else if (StrEquals(opt
, "RaiseOverUnmanaged"))
3650 Scr
.bo
.do_raise_over_unmanaged
^= 1;
3654 Scr
.bo
.do_raise_over_unmanaged
= toggle
;
3657 Scr
.bo
.do_raise_over_unmanaged
= 0;
3661 else if (StrEquals(opt
, "FlickeringQtDialogsWorkaround"))
3666 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
^= 1;
3670 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= toggle
;
3673 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= 0;
3677 else if (StrEquals(opt
, "QtDragnDropWorkaround") )
3682 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
^= 1;
3686 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
= toggle
;
3689 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
= 0;
3693 else if (EWMH_BugOpts(opt
, toggle
))
3695 /* work is done in EWMH_BugOpts */
3697 else if (StrEquals(opt
, "DisplayNewWindowNames"))
3702 Scr
.bo
.do_display_new_window_names
^= 1;
3706 Scr
.bo
.do_display_new_window_names
= toggle
;
3709 Scr
.bo
.do_display_new_window_names
= 0;
3713 else if (StrEquals(opt
, "ExplainWindowPlacement"))
3718 Scr
.bo
.do_explain_window_placement
^= 1;
3722 Scr
.bo
.do_explain_window_placement
= toggle
;
3725 Scr
.bo
.do_explain_window_placement
= 0;
3729 else if (StrEquals(opt
, "DebugCRMotionMethod"))
3734 Scr
.bo
.do_debug_cr_motion_method
^= 1;
3738 Scr
.bo
.do_debug_cr_motion_method
= toggle
;
3741 Scr
.bo
.do_debug_cr_motion_method
= 0;
3745 else if (StrEquals(opt
, "TransliterateUtf8"))
3747 FiconvSetTransliterateUtf8(toggle
);
3751 fvwm_msg(ERR
, "SetBugOptions",
3752 "Unknown Bug Option '%s'", opt
);
3759 void CMD_Emulate(F_CMD_ARGS
)
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
;
3781 fvwm_msg(ERR
, "Emulate", "Unknown style '%s'", style
);
3784 Scr
.flags
.do_need_window_update
= 1;
3785 Scr
.flags
.has_default_font_changed
= 1;
3786 Scr
.flags
.has_default_color_changed
= 1;
3791 void CMD_ColorLimit(F_CMD_ARGS
)
3794 WARN
, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3795 "fvwm -color-limit option");
3801 /* set animation parameters */
3802 void CMD_SetAnimation(F_CMD_ARGS
)
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");
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"
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;
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
)
3850 *keycode
= XKeysymToKeycode(dpy
, keysym
);
3853 for (m
= 0; m
<= 8; ++m
)
3855 KeySym ks
= XKeycodeToKeysym(dpy
, *keycode
, m
);
3860 case 0: /* No modifiers */
3862 case 1: /* Shift modifier */
3863 *modifiers
|= ShiftMask
;
3866 fvwm_msg(ERR
, "FKeysymToKeycode",
3867 "Unhandled modifier %d", m
);
3876 static void __fake_event(F_CMD_ARGS
, FakeEventType type
)
3887 unsigned int mask
= 0;
3888 Window root
= Scr
.Root
;
3890 static char args
[128];
3891 strncpy(args
, action
, sizeof(args
) - 1);
3893 /* get the mask of pressed/released buttons/keys */
3895 dpy
, Scr
.Root
, &root
, &JunkRoot
, &JunkX
, &JunkY
, &JunkX
,
3898 token
= PeekToken(action
, &action
);
3899 while (token
&& action
)
3901 int index
= GetTokenIndex(token
, optlist
, 0, NULL
);
3912 KeySym keysym
= NoSymbol
;
3924 /* key/button press or release */
3925 if (type
== FakeMouseEvent
)
3927 if ((GetIntegerArguments(
3928 action
, &action
, &val
, 1) != 1) ||
3930 val
> NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
3933 ERR
, "__fake_event",
3934 "Invalid button specifier in"
3935 " \"%s\" for FakeClick.", args
);
3939 else /* type == FakeKeyEvent */
3941 char *key
= PeekToken(action
, &action
);
3945 ERR
, "__fake_event",
3946 "No keysym specifier in \"%s\""
3947 " for FakeKeypress.", args
);
3951 /* Do *NOT* use FvwmStringToKeysym() as it is
3952 * case insensitive. */
3953 keysym
= XStringToKeysym(key
);
3954 if (keysym
== NoSymbol
)
3957 ERR
, "__fake_event",
3958 "Invalid keysym specifier (%s)"
3959 " in \"%s\" for FakeKeypress.",
3968 depth
!= maxdepth
&&
3969 w
!= child_w
&& child_w
!= None
;
3974 dpy
, w
, &root
, &child_w
,
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();
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
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. */
4010 mask
&= ~(Button1Mask
<< (val
- 1));
4014 mask
|= (Button1Mask
<< (val
- 1));
4016 add_mask
= (do_unset
) ?
4017 ButtonPressMask
: ButtonReleaseMask
;
4021 /* type == FakeKeyEvent */
4022 e
.type
= (do_unset
? KeyRelease
: KeyPress
);
4023 e
.xkey
.display
= dpy
;
4024 e
.xkey
.subwindow
= None
;
4026 e
.xkey
.time
= fev_get_evtime();
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");
4043 e
.xkey
.state
|= mask
;
4044 add_mask
= (do_unset
) ?
4045 KeyReleaseMask
: KeyPressMask
;
4047 FSendEvent(dpy
, w
, True
,
4048 SubstructureNotifyMask
| add_mask
, &e
);
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
);
4065 dpy
, Scr
.Root
, &root
, &JunkRoot
,
4066 &JunkX
, &JunkY
, &JunkX
, &JunkY
,
4069 /* pointer is on a different screen -
4070 * that's okay here */
4076 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4079 ERR
, "__fake_event",
4080 "Invalid modifier value in \"%s\"",
4102 else if (val
>=1 && val
<= 5)
4104 val
= (Mod1Mask
<< (val
- 1));
4111 /* SS: Could be buggy if a "modifier" operation
4112 * preceeds a "wait" operation. */
4125 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4127 fvwm_msg(ERR
, "__fake_event",
4128 "Invalid depth value in \"%s\"", args
);
4134 fvwm_msg(ERR
, "__fake_event",
4135 "Invalid command (%s) in \"%s\"", token
, args
);
4140 token
= PeekToken(action
, &action
);
4147 void CMD_FakeClick(F_CMD_ARGS
)
4149 __fake_event(F_PASS_ARGS
, FakeMouseEvent
);
4154 void CMD_FakeKeypress(F_CMD_ARGS
)
4156 __fake_event(F_PASS_ARGS
, FakeKeyEvent
);
4161 /* A function to handle stroke (olicha Nov 11, 1999) */
4163 void CMD_StrokeFunc(F_CMD_ARGS
)
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
;
4172 Bool finish_on_release
= True
;
4174 Bool restore_repeat
= False
;
4175 Bool echo_sequence
= False
;
4176 Bool draw_motion
= False
;
4180 const int STROKE_CHUNK_SIZE
= 0xff;
4181 int coords_size
= STROKE_CHUNK_SIZE
;
4182 Window JunkRoot
, JunkChild
;
4185 unsigned int JunkMask
;
4186 Bool feed_back
= False
;
4187 int stroke_width
= 1;
4193 if (!GrabEm(CRS_STROKE
, GRAB_NORMAL
))
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
;
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
))
4227 else if (StrEquals("FeedBack",opt
))
4231 else if (StrEquals("StrokeWidth",opt
))
4233 /* stroke width takes a positive integer argument */
4238 action
= GetNextToken(action
, &opt
);
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
4248 else if (!sscanf(opt
, "%d", &stroke_width
) ||
4249 stroke_width
< 0 || stroke_width
> 100)
4252 WARN
, "StrokeWidth",
4253 "Bad integer argument %d",
4260 fvwm_msg(WARN
,"StrokeFunc","Unknown option %s", 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 */
4296 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
[0], &y
[0],
4297 &JunkX
, &JunkY
, &JunkMask
) == False
)
4299 /* pointer is on a different screen */
4304 dpy
,Scr
.XorGC
,stroke_width
,LineSolid
,CapButt
,JoinMiter
);
4307 while (!finished
&& !abort
)
4309 /* block until there is an event */
4311 dpy
, ButtonPressMask
| ButtonReleaseMask
|
4312 KeyPressMask
| KeyReleaseMask
| ButtonMotionMask
|
4313 PointerMotionMask
, &e
);
4317 if (e
.xmotion
.same_screen
== False
)
4321 if (e
.xany
.window
!= Scr
.Root
)
4324 dpy
, Scr
.Root
, &JunkRoot
,
4325 &JunkChild
, &tmpx
, &tmpy
, &JunkX
,
4326 &JunkY
, &JunkMask
) == False
)
4328 /* pointer is on a different screen */
4338 stroke_record(tmpx
,tmpy
);
4339 if (draw_motion
&& (x
[i
] != tmpx
|| y
[i
] != tmpy
))
4342 if (i
>= coords_size
)
4344 coords_size
+= STROKE_CHUNK_SIZE
;
4345 x
= (int*)saferealloc(
4346 (void *)x
, coords_size
*
4348 y
= (int*)saferealloc(
4349 (void *)y
, coords_size
*
4355 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1],
4356 y
[i
-1], x
[i
], y
[i
]);
4360 if (finish_on_release
&& start_event_type
==
4367 if (finish_on_release
&& start_event_type
== 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
)
4381 /* finish on enter or space (as in menus.c) */
4382 if (keysym
== XK_Return
|| keysym
== XK_KP_Enter
||
4389 if (!finish_on_release
)
4404 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1], y
[i
-1], x
[i
],
4408 XSetLineAttributes(dpy
,Scr
.XorGC
,0,LineSolid
,CapButt
,JoinMiter
);
4409 MyXUngrabServer(dpy
);
4416 if (start_event_type
== KeyPress
&& finish_on_release
)
4418 MyXUngrabKeyboard(dpy
);
4420 UngrabEm(GRAB_NORMAL
);
4426 /* get the stroke sequence */
4427 stroke_trans(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;
4446 num_seq
[i
] = sequence
[i
];
4449 num_seq
[i
++] = '\0';
4450 fvwm_msg(INFO
, "StrokeFunc", "stroke sequence: %s (N%s)",
4457 if (exc
->w
.fw
== NULL
)
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
);
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
);
4492 #endif /* HAVE_STROKE */
4494 void CMD_State(F_CMD_ARGS
)
4499 FvwmWindow
* const fw
= exc
->w
.fw
;
4501 n
= GetIntegerArguments(action
, &action
, (int *)&state
, 1);
4506 if (state
< 0 || state
> 31)
4508 fvwm_msg(ERR
, "CMD_State", "Illegal state %d\n", state
);
4511 toggle
= ParseToggleArgument(action
, NULL
, -1, 0);
4512 state
= (1 << state
);
4516 TOGGLE_USER_STATES(fw
, state
);
4519 CLEAR_USER_STATES(fw
, state
);
4523 SET_USER_STATES(fw
, state
);