summaryrefslogtreecommitdiff
path: root/app/fvwm/fvwm/builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/fvwm/fvwm/builtins.c')
-rw-r--r--app/fvwm/fvwm/builtins.c4871
1 files changed, 4871 insertions, 0 deletions
diff --git a/app/fvwm/fvwm/builtins.c b/app/fvwm/fvwm/builtins.c
new file mode 100644
index 000000000..65c3c8142
--- /dev/null
+++ b/app/fvwm/fvwm/builtins.c
@@ -0,0 +1,4871 @@
+/****************************************************************************
+ * This module is all original code
+ * by Rob Nation
+ * Copyright 1993, Robert Nation
+ * You may use this code for any purpose, as long as the original
+ * copyright remains in the source code and all documentation
+ ****************************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <X11/keysym.h>
+
+#include "fvwm.h"
+#include "menus.h"
+#include "misc.h"
+#include "parse.h"
+#include "screen.h"
+#include "module.h"
+
+static Boolean ReadMenuFace(char *s, MenuFace *mf, int verbose);
+static void FreeMenuFace(Display *dpy, MenuFace *mf);
+
+static char *exec_shell_name="/bin/sh";
+/* button state strings must match the enumerated states */
+static char *button_states[MaxButtonState]={
+ "ActiveUp",
+#ifdef ACTIVEDOWN_BTNS
+ "ActiveDown",
+#endif
+#ifdef INACTIVE_BTNS
+ "Inactive",
+#endif
+};
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DeferExecution - defer the execution of a function to the
+ * next button press if the context is C_ROOT
+ *
+ * Inputs:
+ * eventp - pointer to XEvent to patch up
+ * w - pointer to Window to patch up
+ * tmp_win - pointer to FvwmWindow Structure to patch up
+ * context - the context in which the mouse button was pressed
+ * func - the function to defer
+ * cursor - the cursor to display while waiting
+ * finishEvent - ButtonRelease or ButtonPress; tells what kind of event to
+ * terminate on.
+ *
+ ***********************************************************************/
+int DeferExecution(XEvent *eventp, Window *w,FvwmWindow **tmp_win,
+ unsigned long *context, int cursor, int FinishEvent)
+
+{
+ int done;
+ int finished = 0;
+ Window dummy;
+ Window original_w;
+
+ original_w = *w;
+
+ if((*context != C_ROOT)&&(*context != C_NO_CONTEXT)&&(tmp_win != NULL))
+ {
+ if((FinishEvent == ButtonPress)||((FinishEvent == ButtonRelease) &&
+ (eventp->type != ButtonPress)))
+ {
+ return FALSE;
+ }
+ }
+ if(!GrabEm(cursor))
+ {
+ XBell(dpy, 0);
+ return True;
+ }
+
+ while (!finished)
+ {
+ done = 0;
+ /* block until there is an event */
+ XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
+ ExposureMask |KeyPressMask | VisibilityChangeMask |
+ ButtonMotionMask| PointerMotionMask/* | EnterWindowMask |
+ LeaveWindowMask*/, eventp);
+ StashEventTime(eventp);
+
+ if(eventp->type == KeyPress)
+ Keyboard_shortcuts(eventp, NULL, FinishEvent);
+ if(eventp->type == FinishEvent)
+ finished = 1;
+ if(eventp->type == ButtonPress)
+ {
+ XAllowEvents(dpy,ReplayPointer,CurrentTime);
+ done = 1;
+ }
+ if(eventp->type == ButtonRelease)
+ done = 1;
+ if(eventp->type == KeyPress)
+ done = 1;
+
+ if(!done)
+ {
+ DispatchEvent();
+ }
+
+ }
+
+
+ *w = eventp->xany.window;
+ if(((*w == Scr.Root)||(*w == Scr.NoFocusWin))
+ && (eventp->xbutton.subwindow != (Window)0))
+ {
+ *w = eventp->xbutton.subwindow;
+ eventp->xany.window = *w;
+ }
+ if (*w == Scr.Root)
+ {
+ *context = C_ROOT;
+ XBell(dpy, 0);
+ UngrabEm();
+ return TRUE;
+ }
+ if (XFindContext (dpy, *w, FvwmContext, (caddr_t *)tmp_win) == XCNOENT)
+ {
+ *tmp_win = NULL;
+ XBell(dpy, 0);
+ UngrabEm();
+ return (TRUE);
+ }
+
+ if(*w == (*tmp_win)->Parent)
+ *w = (*tmp_win)->w;
+
+ if(original_w == (*tmp_win)->Parent)
+ original_w = (*tmp_win)->w;
+
+ /* this ugly mess attempts to ensure that the release and press
+ * are in the same window. */
+ if((*w != original_w)&&(original_w != Scr.Root)&&
+ (original_w != None)&&(original_w != Scr.NoFocusWin))
+ if(!((*w == (*tmp_win)->frame)&&
+ (original_w == (*tmp_win)->w)))
+ {
+ *context = C_ROOT;
+ XBell(dpy, 0);
+ UngrabEm();
+ return TRUE;
+ }
+
+ *context = GetContext(*tmp_win,eventp,&dummy);
+
+ UngrabEm();
+ return FALSE;
+}
+
+
+
+
+/**************************************************************************
+ *
+ * Moves focus to specified window
+ *
+ *************************************************************************/
+void FocusOn(FvwmWindow *t,Bool FocusByMouse)
+{
+#ifndef NON_VIRTUAL
+ int dx,dy;
+ int cx,cy;
+#endif
+ int x,y;
+
+ if(t == (FvwmWindow *)0)
+ return;
+
+ if(t->Desk != Scr.CurrentDesk)
+ {
+ changeDesks(t->Desk);
+ }
+
+#ifndef NON_VIRTUAL
+ if(t->flags & ICONIFIED)
+ {
+ cx = t->icon_xl_loc + t->icon_w_width/2;
+ cy = t->icon_y_loc + t->icon_p_height + ICON_HEIGHT/2;
+ }
+ else
+ {
+ cx = t->frame_x + t->frame_width/2;
+ cy = t->frame_y + t->frame_height/2;
+ }
+
+ dx = (cx + Scr.Vx)/Scr.MyDisplayWidth*Scr.MyDisplayWidth;
+ dy = (cy +Scr.Vy)/Scr.MyDisplayHeight*Scr.MyDisplayHeight;
+
+ MoveViewport(dx,dy,True);
+#endif
+
+ if(t->flags & ICONIFIED)
+ {
+ x = t->icon_xl_loc + t->icon_w_width/2;
+ y = t->icon_y_loc + t->icon_p_height + ICON_HEIGHT/2;
+ }
+ else
+ {
+ x = t->frame_x;
+ y = t->frame_y;
+ }
+#if 0 /* don't want to warp the pointer by default anymore */
+ if(!(t->flags & ClickToFocus))
+ XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, x+2,y+2);
+#endif /* 0 */
+#if 0 /* don't want to raise anymore either */
+ RaiseWindow(t);
+#endif /* 0 */
+ KeepOnTop();
+
+ /* If the window is still not visible, make it visible! */
+ if(((t->frame_x + t->frame_height)< 0)||(t->frame_y + t->frame_width < 0)||
+ (t->frame_x >Scr.MyDisplayWidth)||(t->frame_y>Scr.MyDisplayHeight))
+ {
+ SetupFrame(t,0,0,t->frame_width, t->frame_height,False);
+ if(!(t->flags & ClickToFocus))
+ XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, 2,2);
+ }
+ UngrabEm();
+ SetFocus(t->w,t,FocusByMouse);
+}
+
+
+
+/**************************************************************************
+ *
+ * Moves pointer to specified window
+ *
+ *************************************************************************/
+void WarpOn(FvwmWindow *t,int warp_x, int x_unit, int warp_y, int y_unit)
+{
+#ifndef NON_VIRTUAL
+ int dx,dy;
+ int cx,cy;
+#endif
+ int x,y;
+
+ if(t == (FvwmWindow *)0 || (t->flags & ICONIFIED && t->icon_w == None))
+ return;
+
+ if(t->Desk != Scr.CurrentDesk)
+ {
+ changeDesks(t->Desk);
+ }
+
+#ifndef NON_VIRTUAL
+ if(t->flags & ICONIFIED)
+ {
+ cx = t->icon_xl_loc + t->icon_w_width/2;
+ cy = t->icon_y_loc + t->icon_p_height + ICON_HEIGHT/2;
+ }
+ else
+ {
+ cx = t->frame_x + t->frame_width/2 + t->bw;
+ cy = t->frame_y + t->frame_height/2 + t->bw;
+ }
+
+ dx = (cx + Scr.Vx)/Scr.MyDisplayWidth*Scr.MyDisplayWidth;
+ dy = (cy +Scr.Vy)/Scr.MyDisplayHeight*Scr.MyDisplayHeight;
+
+ MoveViewport(dx,dy,True);
+#endif
+
+ if(t->flags & ICONIFIED)
+ {
+ x = t->icon_xl_loc + t->icon_w_width/2;
+ y = t->icon_y_loc + t->icon_p_height + ICON_HEIGHT/2;
+ }
+ else
+ {
+ if (x_unit != Scr.MyDisplayWidth)
+ x = t->frame_x + t->bw + warp_x;
+ else
+ x = t->frame_x + t->bw + (t->frame_width - 1) * warp_x / 100;
+ if (y_unit != Scr.MyDisplayHeight)
+ y = t->frame_y + t->bw + warp_y;
+ else
+ y = t->frame_y + t->bw + (t->frame_height - 1) * warp_y / 100;
+ }
+ if (warp_x >= 0 && warp_y >= 0) {
+ XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, x, y);
+ }
+ RaiseWindow(t);
+ KeepOnTop();
+
+ /* If the window is still not visible, make it visible! */
+ if(((t->frame_x + t->frame_height)< 0)||(t->frame_y + t->frame_width < 0)||
+ (t->frame_x >Scr.MyDisplayWidth)||(t->frame_y>Scr.MyDisplayHeight))
+ {
+ SetupFrame(t,0,0,t->frame_width, t->frame_height,False);
+ XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, 2,2);
+ }
+ UngrabEm();
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * (Un)Maximize a window.
+ *
+ ***********************************************************************/
+void Maximize(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ int new_width, new_height,new_x,new_y;
+ int val1, val2, val1_unit,val2_unit,n;
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
+ return;
+
+ if(tmp_win == NULL)
+ return;
+
+ if(check_allowed_function2(F_MAXIMIZE,tmp_win) == 0
+#ifdef WINDOWSHADE
+ || (tmp_win->buttons & WSHADE)
+#endif
+ )
+ {
+ XBell(dpy, 0);
+ return;
+ }
+ n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit);
+ if(n != 2)
+ {
+ val1 = 100;
+ val2 = 100;
+ val1_unit = Scr.MyDisplayWidth;
+ val2_unit = Scr.MyDisplayHeight;
+ }
+
+ if (tmp_win->flags & MAXIMIZED)
+ {
+ tmp_win->flags &= ~MAXIMIZED;
+ SetupFrame(tmp_win, tmp_win->orig_x, tmp_win->orig_y, tmp_win->orig_wd,
+ tmp_win->orig_ht,TRUE);
+ SetBorder(tmp_win,True,True,True,None);
+ }
+ else
+ {
+ new_width = tmp_win->frame_width;
+ new_height = tmp_win->frame_height;
+ new_x = tmp_win->frame_x;
+ new_y = tmp_win->frame_y;
+ if(val1 >0)
+ {
+ new_width = val1*val1_unit/100-2;
+ new_x = 0;
+ }
+ if(val2 >0)
+ {
+ new_height = val2*val2_unit/100-2;
+ new_y = 0;
+ }
+ if((val1==0)&&(val2==0))
+ {
+ new_x = 0;
+ new_y = 0;
+ new_height = Scr.MyDisplayHeight-2;
+ new_width = Scr.MyDisplayWidth-2;
+ }
+ tmp_win->flags |= MAXIMIZED;
+ ConstrainSize (tmp_win, &new_width, &new_height, False, 0, 0);
+ SetupFrame(tmp_win,new_x,new_y,new_width,new_height,TRUE);
+ SetBorder(tmp_win,Scr.Hilite == tmp_win,True,True,None);
+ }
+}
+
+#ifdef WINDOWSHADE
+/***********************************************************************
+ *
+ * WindowShade -- shades or unshades a window (veliaa@rpi.edu)
+ *
+ * Args: 1 -- force shade, 2 -- force unshade No Arg: toggle
+ *
+ ***********************************************************************/
+void WindowShade(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ int n = 0;
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
+ return;
+
+ if (!(tmp_win->flags & TITLE) || (tmp_win->flags & MAXIMIZED)) {
+ XBell(dpy, 0);
+ return;
+ }
+ while (isspace(*action))++action;
+ if (isdigit(*action))
+ sscanf(action,"%d",&n);
+
+ if (((tmp_win->buttons & WSHADE)||(n==2))&&(n!=1))
+ {
+ tmp_win->buttons &= ~WSHADE;
+ SetupFrame(tmp_win,
+ tmp_win->frame_x,
+ tmp_win->frame_y,
+ tmp_win->orig_wd,
+ tmp_win->orig_ht,
+ True);
+ BroadcastPacket(M_DEWINDOWSHADE, 3,
+ tmp_win->w, tmp_win->frame, (unsigned long)tmp_win);
+ }
+ else
+ {
+ tmp_win->buttons |= WSHADE;
+ SetupFrame(tmp_win,
+ tmp_win->frame_x,
+ tmp_win->frame_y,
+ tmp_win->frame_width,
+ tmp_win->title_height + tmp_win->boundary_width - tmp_win->bw,
+ False);
+ BroadcastPacket(M_WINDOWSHADE, 3,
+ tmp_win->w, tmp_win->frame, (unsigned long)tmp_win);
+ }
+}
+#endif /* WINDOWSHADE */
+
+/* For Ultrix 4.2 */
+#include <sys/types.h>
+#include <sys/time.h>
+
+
+MenuRoot *FindPopup(char *action)
+{
+ char *tmp;
+ MenuRoot *mr;
+
+ GetNextToken(action,&tmp);
+
+ if(tmp == NULL)
+ return NULL;
+
+ mr = Scr.menus.all;
+ while(mr != NULL)
+ {
+ if(mr->name != NULL)
+ if(strcasecmp(tmp,mr->name)== 0)
+ {
+ free(tmp);
+ return mr;
+ }
+ mr = mr->next;
+ }
+ free(tmp);
+ return NULL;
+
+}
+
+
+
+void Bell(XEvent *eventp,Window w,FvwmWindow *tmp_win,unsigned long context,
+ char *action, int *Module)
+{
+ XBell(dpy, 0);
+}
+
+
+#ifdef USEDECOR
+static FvwmDecor *last_decor = NULL, *cur_decor = NULL;
+#endif
+MenuRoot *last_menu=NULL;
+void add_item_to_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,
+ char *action, int *Module)
+{
+ MenuRoot *mr;
+ MenuRoot *mrPrior;
+ char *token, *rest,*item;
+
+#ifdef USEDECOR
+ last_decor = NULL;
+#endif
+
+ rest = GetNextToken(action,&token);
+ if (!token)
+ return;
+ mr = FollowMenuContinuations(FindPopup(token),&mrPrior);
+ if(mr == NULL)
+ mr = NewMenuRoot(token, False);
+ last_menu = mr;
+
+ rest = GetNextToken(rest,&item);
+ AddToMenu(mr, item,rest,TRUE /* pixmap scan */, TRUE);
+ if (item)
+ free(item);
+ /* These lines are correct! We must not release token if the string is empty.
+ * It cannot be NULL! GetNextToken never returns an empty string! */
+ if (*token)
+ free(token);
+
+ MakeMenu(mr);
+ return;
+}
+
+
+void add_another_item(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,
+ char *action, int *Module)
+{
+#ifdef USEDECOR
+ extern void AddToDecor(FvwmDecor *, char *);
+#endif
+ MenuRoot *mr;
+ MenuRoot *mrPrior;
+ char *rest,*item;
+
+ if (last_menu != NULL) {
+ mr = FollowMenuContinuations(last_menu,&mrPrior);
+ if(mr == NULL)
+ return;
+ rest = GetNextToken(action,&item);
+ AddToMenu(mr, item,rest,TRUE /* pixmap scan */, FALSE);
+ if (item)
+ free(item);
+ MakeMenu(mr);
+ }
+#ifdef USEDECOR
+ else if (last_decor != NULL) {
+ FvwmDecor *tmp = &Scr.DefaultDecor;
+ for (; tmp; tmp = tmp->next)
+ if (tmp == last_decor)
+ break;
+ if (!tmp)
+ return;
+ AddToDecor(tmp, action);
+ }
+#endif /* USEDECOR */
+}
+
+void destroy_menu(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,
+ char *action, int *Module)
+{
+ MenuRoot *mr;
+ MenuRoot *mrContinuation;
+
+ char *token, *rest;
+
+ rest = GetNextToken(action,&token);
+ if (!token)
+ return;
+ mr = FindPopup(token);
+ free(token);
+ while (mr)
+ {
+ mrContinuation = mr->continuation; /* save continuation before destroy */
+ DestroyMenu(mr);
+ mr = mrContinuation;
+ }
+ return;
+}
+
+void add_item_to_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,
+ char *action, int *Module)
+{
+ MenuRoot *mr;
+
+ char *token, *rest,*item;
+
+ rest = GetNextToken(action,&token);
+ if (!token)
+ return;
+ mr = FindPopup(token);
+ if(mr == NULL)
+ mr = NewMenuRoot(token, True);
+ last_menu = mr;
+ if (token)
+ free(token);
+ rest = GetNextToken(rest,&item);
+ AddToMenu(mr, item,rest,FALSE,FALSE);
+ if (item)
+ free(item);
+
+ return;
+}
+
+
+void Nop_func(XEvent *eventp, Window w, FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+
+}
+
+
+void movecursor(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ int x = 0, y = 0;
+ int val1, val2, val1_unit, val2_unit;
+#ifndef NON_VIRTUAL
+ int virtual_x, virtual_y;
+ int pan_x, pan_y;
+ int x_pages, y_pages;
+#endif
+
+ if (GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit) != 2)
+ {
+ fvwm_msg(ERR, "movecursor", "CursorMove needs 2 arguments");
+ return;
+ }
+
+ XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
+ &x, &y, &JunkX, &JunkY, &JunkMask);
+
+ x = x + val1 * val1_unit / 100;
+ y = y + val2 * val2_unit / 100;
+
+#ifndef NON_VIRTUAL
+ virtual_x = Scr.Vx;
+ virtual_y = Scr.Vy;
+ if (x >= 0)
+ x_pages = x / Scr.MyDisplayWidth;
+ else
+ x_pages = ((x + 1) / Scr.MyDisplayWidth) - 1;
+ virtual_x += x_pages * Scr.MyDisplayWidth;
+ x -= x_pages * Scr.MyDisplayWidth;
+ if (virtual_x < 0)
+ {
+ x += virtual_x;
+ virtual_x = 0;
+ }
+ else if (virtual_x > Scr.VxMax)
+ {
+ x += virtual_x - Scr.VxMax;
+ virtual_x = Scr.VxMax;
+ }
+
+ if (y >= 0)
+ y_pages = y / Scr.MyDisplayHeight;
+ else
+ y_pages = ((y + 1) / Scr.MyDisplayHeight) - 1;
+ virtual_y += y_pages * Scr.MyDisplayHeight;
+ y -= y_pages * Scr.MyDisplayHeight;
+ if (virtual_y < 0)
+ {
+ y += virtual_y;
+ virtual_y = 0;
+ }
+ else if (virtual_y > Scr.VyMax)
+ {
+ y += virtual_y - Scr.VyMax;
+ virtual_y = Scr.VyMax;
+ }
+ if (virtual_x != Scr.Vx || virtual_y != Scr.Vy)
+ MoveViewport(virtual_x, virtual_y, True);
+ pan_x = (Scr.EdgeScrollX != 0) ? 2 : 0;
+ pan_y = (Scr.EdgeScrollY != 0) ? 2 : 0;
+ /* prevent paging if EdgeScroll is active */
+ if (x >= Scr.MyDisplayWidth - pan_x)
+ x = Scr.MyDisplayWidth - pan_x -1;
+ else if (x < pan_x)
+ x = pan_x;
+ if (y >= Scr.MyDisplayHeight - pan_y)
+ y = Scr.MyDisplayHeight - pan_y - 1;
+ else if (y < pan_y)
+ y = pan_y;
+#endif
+
+ XWarpPointer(dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
+ Scr.MyDisplayHeight, x, y);
+ return;
+}
+
+
+void iconify_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+
+{
+ int val = 0;
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, ButtonRelease))
+ return;
+
+ GetIntegerArguments(action, NULL, &val, 1);
+
+ if (tmp_win->flags & ICONIFIED)
+ {
+ if(val <=0)
+ DeIconify(tmp_win);
+ }
+ else
+ {
+ if(check_allowed_function2(F_ICONIFY,tmp_win) == 0)
+ {
+ XBell(dpy, 0);
+ return;
+ }
+ if(val >=0)
+ Iconify(tmp_win,eventp->xbutton.x_root-5,eventp->xbutton.y_root-5);
+ }
+}
+
+void raise_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ name_list styles; /* place for merged styles */
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
+ return;
+
+ if(tmp_win)
+ RaiseWindow(tmp_win);
+
+ LookInList(tmp_win, &styles); /* get merged styles */
+ if (styles.on_flags & STAYSONTOP_FLAG) {
+ tmp_win->flags |= ONTOP;
+ }
+ KeepOnTop();
+}
+
+void lower_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, ButtonRelease))
+ return;
+
+ LowerWindow(tmp_win);
+
+ tmp_win->flags &= ~ONTOP;
+}
+
+void destroy_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY, ButtonRelease))
+ return;
+
+ if(check_allowed_function2(F_DESTROY,tmp_win) == 0)
+ {
+ XBell(dpy, 0);
+ return;
+ }
+
+ if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
+ Destroy(tmp_win);
+ else
+ XKillClient(dpy, tmp_win->w);
+ XSync(dpy,0);
+}
+
+void delete_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY,ButtonRelease))
+ return;
+
+ if(check_allowed_function2(F_DELETE,tmp_win) == 0)
+ {
+ XBell(dpy, 0);
+ return;
+ }
+
+ if (tmp_win->flags & DoesWmDeleteWindow)
+ {
+ send_clientmessage (dpy, tmp_win->w, _XA_WM_DELETE_WINDOW, CurrentTime);
+ return;
+ }
+ else
+ XBell (dpy, 0);
+ XSync(dpy,0);
+}
+
+void close_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY,ButtonRelease))
+ return;
+
+ if(check_allowed_function2(F_CLOSE,tmp_win) == 0)
+ {
+ XBell(dpy, 0);
+ return;
+ }
+
+ if (tmp_win->flags & DoesWmDeleteWindow)
+ {
+ send_clientmessage (dpy, tmp_win->w, _XA_WM_DELETE_WINDOW, CurrentTime);
+ return;
+ }
+ else if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
+ Destroy(tmp_win);
+ else
+ XKillClient(dpy, tmp_win->w);
+ XSync(dpy,0);
+}
+
+void restart_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ Done(1, action);
+}
+
+void exec_setup(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+{
+ char *arg=NULL;
+ static char shell_set = 0;
+
+ if (shell_set)
+ free(exec_shell_name);
+ shell_set = 1;
+ action = GetNextToken(action,&arg);
+ if (arg) /* specific shell was specified */
+ {
+ exec_shell_name = arg;
+ }
+ else /* no arg, so use $SHELL -- not working??? */
+ {
+ if (getenv("SHELL"))
+ exec_shell_name = strdup(getenv("SHELL"));
+ else
+ /* if $SHELL not set, use default */
+ exec_shell_name = strdup("/bin/sh");
+ }
+}
+
+void exec_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+{
+ char *cmd=NULL;
+
+ /* if it doesn't already have an 'exec' as the first word, add that
+ * to keep down number of procs started */
+ /* need to parse string better to do this right though, so not doing this
+ for now... */
+#if 0
+ if (strncasecmp(action,"exec",4)!=0)
+ {
+ cmd = (char *)safemalloc(strlen(action)+6);
+ strcpy(cmd,"exec ");
+ strcat(cmd,action);
+ }
+ else
+#endif
+ {
+ cmd = strdup(action);
+ }
+ if (!cmd)
+ return;
+ /* Use to grab the pointer here, but the fork guarantees that
+ * we wont be held up waiting for the function to finish,
+ * so the pointer-gram just caused needless delay and flashing
+ * on the screen */
+ /* Thought I'd try vfork and _exit() instead of regular fork().
+ * The man page says that its better. */
+ /* Not everyone has vfork! */
+ if (!(fork())) /* child process */
+ {
+ if (execl(exec_shell_name, exec_shell_name, "-c", cmd, (char *)NULL)==-1)
+ {
+ fvwm_msg(ERR,"exec_function","execl failed (%s)",strerror(errno));
+ exit(100);
+ }
+ }
+ free(cmd);
+ return;
+}
+
+void refresh_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ XSetWindowAttributes attributes;
+ unsigned long valuemask;
+
+#if 0
+ valuemask = (CWBackPixel);
+ attributes.background_pixel = 0;
+#else /* CKH - i'd like to try this a little differently (clear window)*/
+ valuemask = CWOverrideRedirect | CWBackingStore | CWSaveUnder | CWBackPixmap;
+ attributes.override_redirect = True;
+ attributes.save_under = False;
+ attributes.background_pixmap = None;
+#endif
+ attributes.backing_store = NotUseful;
+ w = XCreateWindow (dpy, Scr.Root, 0, 0,
+ (unsigned int) Scr.MyDisplayWidth,
+ (unsigned int) Scr.MyDisplayHeight,
+ (unsigned int) 0,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent, valuemask,
+ &attributes);
+ XMapWindow (dpy, w);
+ XDestroyWindow (dpy, w);
+ XFlush (dpy);
+}
+
+
+void refresh_win_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ XSetWindowAttributes attributes;
+ unsigned long valuemask;
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
+ return;
+
+ valuemask = CWOverrideRedirect | CWBackingStore | CWSaveUnder | CWBackPixmap;
+ attributes.override_redirect = True;
+ attributes.save_under = False;
+ attributes.background_pixmap = None;
+ attributes.backing_store = NotUseful;
+ w = XCreateWindow (dpy,
+ (context == C_ICON)?(tmp_win->icon_w):(tmp_win->frame),
+ 0, 0,
+ (unsigned int) Scr.MyDisplayWidth,
+ (unsigned int) Scr.MyDisplayHeight,
+ (unsigned int) 0,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent, valuemask,
+ &attributes);
+ XMapWindow (dpy, w);
+ XDestroyWindow (dpy, w);
+ XFlush (dpy);
+}
+
+
+void stick_function(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
+ return;
+
+ if(tmp_win->flags & STICKY)
+ {
+ tmp_win->flags &= ~STICKY;
+ }
+ else
+ {
+ tmp_win->flags |=STICKY;
+ move_window_doit(eventp, w, tmp_win, context, "", Module, FALSE, TRUE);
+ }
+ BroadcastConfig(M_CONFIGURE_WINDOW,tmp_win);
+ SetTitleBar(tmp_win,(Scr.Hilite==tmp_win),True);
+}
+
+void wait_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context,char *action, int *Module)
+{
+ Bool done = False;
+ extern FvwmWindow *Tmp_win;
+
+ while(!done)
+ {
+#if 0
+ GrabEm(WAIT);
+#endif
+ if(My_XNextEvent(dpy, &Event))
+ {
+ DispatchEvent ();
+ if(Event.type == MapNotify)
+ {
+ if((Tmp_win)&&(matchWildcards(action,Tmp_win->name)==True))
+ done = True;
+ if((Tmp_win)&&(Tmp_win->class.res_class)&&
+ (matchWildcards(action,Tmp_win->class.res_class)==True))
+ done = True;
+ if((Tmp_win)&&(Tmp_win->class.res_name)&&
+ (matchWildcards(action,Tmp_win->class.res_name)==True))
+ done = True;
+ }
+ else if (Event.type == KeyPress &&
+ XLookupKeysym(&(Event.xkey),0) == XK_Escape &&
+ Event.xbutton.state & ControlMask)
+ {
+ done = 1;
+ }
+ }
+ }
+#if 0
+ UngrabEm();
+#endif
+}
+
+void flip_focus_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
+ return;
+
+ /* Reorder the window list */
+ FocusOn(tmp_win,TRUE);
+}
+
+
+void focus_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
+ return;
+
+ FocusOn(tmp_win,FALSE);
+}
+
+
+void warp_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ int val1_unit, val2_unit, n;
+ int val1, val2;
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
+ return;
+
+ n = GetTwoArguments (action, &val1, &val2, &val1_unit, &val2_unit);
+
+ if (n == 2)
+ WarpOn (tmp_win, val1, val1_unit, val2, val2_unit);
+ else
+ WarpOn (tmp_win, 0, 0, 0, 0);
+}
+
+
+static void menu_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module,
+ Bool fStaysUp)
+{
+ extern int menuFromFrameOrWindowOrTitlebar;
+ MenuRoot *menu;
+ MenuItem *miExecuteAction = NULL;
+ MenuOptions mops;
+ char *menu_name = NULL;
+ XEvent *teventp;
+
+ mops.flags.allflags = 0;
+ action = GetNextToken(action,&menu_name);
+ action = GetMenuOptions(action,w,tmp_win,NULL,&mops);
+ while (action && *action && isspace(*action))
+ action++;
+ if (action && *action == 0)
+ action = NULL;
+ menu = FindPopup(menu_name);
+ if(menu == NULL)
+ {
+ if(menu_name != NULL)
+ {
+ fvwm_msg(ERR,"menu_func","No such menu %s",menu_name);
+ free(menu_name);
+ }
+ return;
+ }
+ if(menu_name != NULL)
+ free(menu_name);
+ menuFromFrameOrWindowOrTitlebar = FALSE;
+
+ if (!action && eventp && eventp->type == KeyPress)
+ teventp = (XEvent *)1;
+ else
+ teventp = eventp;
+ if ((do_menu(menu, NULL, &miExecuteAction, 0, fStaysUp, teventp, &mops) ==
+ MENU_DOUBLE_CLICKED) && action)
+ {
+ ExecuteFunction(action,tmp_win,eventp,context,*Module);
+ }
+}
+
+/* the function for the "Popup" command */
+void popup_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ menu_func(eventp, w, tmp_win, context, action, Module, False);
+}
+
+/* the function for the "Menu" command */
+void staysup_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ menu_func(eventp, w, tmp_win, context, action, Module, True);
+}
+
+
+void quit_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ if (master_pid != getpid())
+ kill(master_pid, SIGTERM);
+ Done(0,NULL);
+}
+
+void quit_screen_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ Done(0,NULL);
+}
+
+void echo_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ unsigned int len;
+
+ if (!action)
+ action = "";
+ len = strlen(action);
+ if (len != 0)
+ {
+ if (action[len-1]=='\n')
+ action[len-1]='\0';
+ }
+ fvwm_msg(INFO,"Echo",action);
+}
+
+void raiselower_func(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ name_list styles;
+
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
+ return;
+ if(tmp_win == NULL)
+ return;
+
+ if((tmp_win == Scr.LastWindowRaised)||
+ (tmp_win->flags & VISIBLE))
+ {
+ LowerWindow(tmp_win);
+ tmp_win->flags &= ~ONTOP;
+ }
+ else
+ {
+ RaiseWindow(tmp_win);
+ LookInList(tmp_win, &styles); /* get merged styles */
+ if (styles.on_flags & STAYSONTOP_FLAG) {
+ tmp_win->flags |= ONTOP;
+ }
+ KeepOnTop();
+ }
+}
+
+void SetEdgeScroll(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val1, val2, val1_unit,val2_unit,n;
+
+ n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit);
+ if(n != 2)
+ {
+ fvwm_msg(ERR,"SetEdgeScroll","EdgeScroll requires two arguments");
+ return;
+ }
+
+ /*
+ * if edgescroll >1000 and < 100000m
+ * wrap at edges of desktop (a "spherical" desktop)
+ */
+ if (val1 >= 1000)
+ {
+ val1 /= 1000;
+ Scr.flags |= EdgeWrapX;
+ }
+ else
+ {
+ Scr.flags &= ~EdgeWrapX;
+ }
+ if (val2 >= 1000)
+ {
+ val2 /= 1000;
+ Scr.flags |= EdgeWrapY;
+ }
+ else
+ {
+ Scr.flags &= ~EdgeWrapY;
+ }
+
+ Scr.EdgeScrollX = val1*val1_unit/100;
+ Scr.EdgeScrollY = val2*val2_unit/100;
+
+ checkPanFrames();
+}
+
+void SetEdgeResistance(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val[2];
+
+ if (GetIntegerArguments(action, NULL, val, 2) != 2)
+ {
+ fvwm_msg(ERR,"SetEdgeResistance","EdgeResistance requires two arguments");
+ return;
+ }
+
+ Scr.ScrollResistance = val[0];
+ Scr.MoveResistance = val[1];
+}
+
+void SetColormapFocus(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ if (MatchToken(action,"FollowsFocus"))
+ {
+ Scr.ColormapFocus = COLORMAP_FOLLOWS_FOCUS;
+ }
+ else if (MatchToken(action,"FollowsMouse"))
+ {
+ Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
+ }
+ else
+ {
+ fvwm_msg(ERR,"SetColormapFocus",
+ "ColormapFocus requires 1 arg: FollowsFocus or FollowsMouse");
+ return;
+ }
+}
+
+void SetClick(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val;
+
+ if(GetIntegerArguments(action, NULL, &val, 1) != 1)
+ {
+ Scr.ClickTime = DEFAULT_CLICKTIME;
+ }
+ else
+ {
+ Scr.ClickTime = (val < 0)? 0 : val;
+ }
+
+ /* Use a negative value during startup and change sign afterwards. This
+ * speeds things up quite a bit. */
+ if (fFvwmInStartup)
+ Scr.ClickTime = -Scr.ClickTime;
+}
+
+
+void SetSnapAttraction(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val;
+ char *token;
+
+ if(GetIntegerArguments(action, &action, &val, 1) != 1)
+ {
+ fvwm_msg(ERR,"SetSnapAttraction",
+ "SnapAttraction requires at least 1 argument");
+ return;
+ }
+ Scr.SnapAttraction = val;
+
+ action = GetNextToken(action, &token);
+ if(token == NULL)
+ {
+ return;
+ }
+
+ if(StrEquals(token,"All"))
+ { Scr.SnapMode = 0; }
+ if(StrEquals(token,"SameType"))
+ { Scr.SnapMode = 1; }
+ if(StrEquals(token,"Icons"))
+ { Scr.SnapMode = 2; }
+ if(StrEquals(token,"Windows"))
+ { Scr.SnapMode = 3; }
+
+ free(token);
+}
+
+void SetSnapGrid(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val[2];
+
+ if(GetIntegerArguments(action, NULL, &val[0], 2) != 2)
+ {
+ fvwm_msg(ERR,"SetSnapGrid","SetSnapGrid requires 2 arguments");
+ return;
+ }
+
+ Scr.SnapGridX = val[0];
+ if(Scr.SnapGridX < 1)
+ { Scr.SnapGridX = 1;}
+ Scr.SnapGridY = val[1];
+ if(Scr.SnapGridY < 1)
+ { Scr.SnapGridY = 1;}
+}
+
+
+void SetXOR(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val;
+ XGCValues gcv;
+ unsigned long gcm;
+
+ if(GetIntegerArguments(action, NULL, &val, 1) != 1)
+ {
+ fvwm_msg(ERR,"SetXOR","XORValue requires 1 argument");
+ return;
+ }
+
+ gcm = GCFunction|GCLineWidth|GCForeground|GCSubwindowMode;
+ gcv.function = GXxor;
+ gcv.line_width = 0;
+ /* use passed in value, or try to calculate appropriate value if 0 */
+ /* ctwm method: */
+ /*
+ gcv.foreground = (val1)?(val1):((((unsigned long) 1) << Scr.d_depth) - 1);
+ */
+ /* Xlib programming manual suggestion: */
+ gcv.foreground = (val)?
+ (val):(BlackPixel(dpy,Scr.screen) ^ WhitePixel(dpy,Scr.screen));
+ gcv.subwindow_mode = IncludeInferiors;
+ if (Scr.DrawGC)
+ XFreeGC(dpy, Scr.DrawGC);
+ Scr.DrawGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+}
+
+void SetOpaque(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val;
+
+ if(GetIntegerArguments(action, NULL, &val, 1) != 1)
+ {
+ fvwm_msg(ERR,"SetOpaque","OpaqueMoveSize requires 1 argument");
+ return;
+ }
+
+ Scr.OpaqueSize = val;
+}
+
+
+void SetDeskSize(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val[2];
+
+ if (GetIntegerArguments(action, NULL, val, 2) != 2 &&
+ GetRectangleArguments(action, &val[0], &val[1]) != 2)
+ {
+ fvwm_msg(ERR,"SetDeskSize","DesktopSize requires two arguments");
+ return;
+ }
+
+ Scr.VxMax = (val[0] <= 0)? 0: val[0]*Scr.MyDisplayWidth-Scr.MyDisplayWidth;
+ Scr.VyMax = (val[1] <= 0)? 0: val[1]*Scr.MyDisplayHeight-Scr.MyDisplayHeight;
+ BroadcastPacket(M_NEW_PAGE, 5,
+ Scr.Vx, Scr.Vy, Scr.CurrentDesk, Scr.VxMax, Scr.VyMax);
+
+ checkPanFrames();
+}
+
+#ifdef XPM
+char *PixmapPath = FVWM_ICONDIR;
+#else
+char *PixmapPath = "";
+#endif
+void setPixmapPath(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+#ifdef XPM
+ static char *ptemp = NULL;
+ char *tmp;
+
+ if(ptemp == NULL)
+ ptemp = PixmapPath;
+
+ if((PixmapPath != ptemp)&&(PixmapPath != NULL))
+ free(PixmapPath);
+ tmp = stripcpy(action);
+ PixmapPath = envDupExpand(tmp, 0);
+ free(tmp);
+#else
+ fvwm_msg(ERR, "setPixmapPath",
+ "XPM support has not been included in this version of Fvwm2.");
+#endif
+}
+
+char *IconPath = FVWM_ICONDIR;
+void setIconPath(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ static char *ptemp = NULL;
+ char *tmp;
+
+ if(ptemp == NULL)
+ ptemp = IconPath;
+
+ if((IconPath != ptemp)&&(IconPath != NULL))
+ free(IconPath);
+ tmp = stripcpy(action);
+ IconPath = envDupExpand(tmp, 0);
+ free(tmp);
+}
+
+char *ModulePath = FVWM_MODULEDIR;
+
+void setModulePath(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ static int need_to_free = 0;
+ char *tmp;
+
+ if ( need_to_free && ModulePath != NULL )
+ free(ModulePath);
+
+ tmp = stripcpy(action);
+ ModulePath = envDupExpand(tmp, 0);
+ need_to_free = 1;
+ free(tmp);
+}
+
+
+void SetHiColor(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ XGCValues gcv;
+ unsigned long gcm;
+ char *hifore=NULL, *hiback=NULL;
+ FvwmWindow *hilight;
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+
+ action = GetNextToken(action,&hifore);
+ GetNextToken(action,&hiback);
+ if(Scr.d_depth > 2)
+ {
+ if(hifore != NULL)
+ {
+ fl->HiColors.fore = GetColor(hifore);
+ }
+ if(hiback != NULL)
+ {
+ fl->HiColors.back = GetColor(hiback);
+ }
+ fl->HiRelief.back = GetShadow(fl->HiColors.back);
+ fl->HiRelief.fore = GetHilite(fl->HiColors.back);
+ }
+ else
+ {
+ fl->HiColors.back = GetColor("white");
+ fl->HiColors.fore = GetColor("black");
+ fl->HiRelief.back = GetColor("black");
+ fl->HiRelief.fore = GetColor("white");
+ }
+ if (hifore) free(hifore);
+ if (hiback) free(hiback);
+ gcm = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|GCForeground|
+ GCBackground;
+ gcv.foreground = fl->HiRelief.fore;
+ gcv.background = fl->HiRelief.back;
+ gcv.fill_style = FillSolid;
+ gcv.plane_mask = AllPlanes;
+ gcv.function = GXcopy;
+ gcv.graphics_exposures = False;
+ gcv.line_width = 0;
+ if(fl->HiReliefGC != NULL)
+ {
+ XFreeGC(dpy,fl->HiReliefGC);
+ }
+ fl->HiReliefGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = fl->HiRelief.back;
+ gcv.background = fl->HiRelief.fore;
+ if(fl->HiShadowGC != NULL)
+ {
+ XFreeGC(dpy,fl->HiShadowGC);
+ }
+ fl->HiShadowGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ if((Scr.flags & WindowsCaptured)&&(Scr.Hilite != NULL))
+ {
+ hilight = Scr.Hilite;
+ SetBorder(Scr.Hilite,False,True,True,None);
+ SetBorder(hilight,True,True,True,None);
+ }
+}
+
+
+void SafeDefineCursor(Window w, Cursor cursor)
+{
+ if (w) XDefineCursor(dpy,w,cursor);
+}
+
+void CursorStyle(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *cname=NULL, *newcursor=NULL;
+ int index,nc,i;
+ FvwmWindow *fw;
+ MenuRoot *mr;
+
+ action = GetNextToken(action,&cname);
+ action = GetNextToken(action,&newcursor);
+ if (!cname || !newcursor)
+ {
+ fvwm_msg(ERR,"CursorStyle","Bad cursor style");
+ if (cname)
+ free(cname);
+ if (newcursor)
+ free(newcursor);
+ return;
+ }
+ if (StrEquals("POSITION",cname)) index = POSITION;
+ else if (StrEquals("DEFAULT",cname)) index = DEFAULT;
+ else if (StrEquals("SYS",cname)) index = SYS;
+ else if (StrEquals("TITLE",cname)) index = TITLE_CURSOR;
+ else if (StrEquals("MOVE",cname)) index = MOVE;
+ else if (StrEquals("MENU",cname)) index = MENU;
+ else if (StrEquals("WAIT",cname)) index = WAIT;
+ else if (StrEquals("SELECT",cname)) index = SELECT;
+ else if (StrEquals("DESTROY",cname)) index = DESTROY;
+ else if (StrEquals("LEFT",cname)) index = LEFT;
+ else if (StrEquals("RIGHT",cname)) index = RIGHT;
+ else if (StrEquals("TOP",cname)) index = TOP;
+ else if (StrEquals("BOTTOM",cname)) index = BOTTOM;
+ else if (StrEquals("TOP_LEFT",cname)) index = TOP_LEFT;
+ else if (StrEquals("TOP_RIGHT",cname)) index = TOP_RIGHT;
+ else if (StrEquals("BOTTOM_LEFT",cname)) index = BOTTOM_LEFT;
+ else if (StrEquals("BOTTOM_RIGHT",cname)) index = BOTTOM_RIGHT;
+ else
+ {
+ fvwm_msg(ERR,"CursorStyle","Unknown cursor name %s",cname);
+ free(cname);
+ free(newcursor);
+ return;
+ }
+ nc = atoi(newcursor);
+ free(cname);
+ if ((nc < 0) || (nc >= XC_num_glyphs) || ((nc % 2) != 0))
+ {
+ fvwm_msg(ERR, "CursorStyle", "Bad cursor number %s", newcursor);
+ free(newcursor);
+ return;
+ }
+ free(newcursor);
+
+ /* replace the cursor defn */
+ if (Scr.FvwmCursors[index]) XFreeCursor(dpy,Scr.FvwmCursors[index]);
+ Scr.FvwmCursors[index] = XCreateFontCursor(dpy,nc);
+
+ /* redefine all the windows using cursors */
+ fw = Scr.FvwmRoot.next;
+ while(fw != NULL)
+ {
+ for (i=0;i<4;i++)
+ {
+ SafeDefineCursor(fw->corners[i],Scr.FvwmCursors[TOP_LEFT+i]);
+ SafeDefineCursor(fw->sides[i],Scr.FvwmCursors[TOP+i]);
+ }
+ for (i=0;i<Scr.nr_left_buttons;i++)
+ {
+ SafeDefineCursor(fw->left_w[i],Scr.FvwmCursors[SYS]);
+ }
+ for (i=0;i<Scr.nr_right_buttons;i++)
+ {
+ SafeDefineCursor(fw->right_w[i],Scr.FvwmCursors[SYS]);
+ }
+ SafeDefineCursor(fw->title_w, Scr.FvwmCursors[TITLE_CURSOR]);
+ fw = fw->next;
+ }
+
+ /* Do the menus for good measure */
+ mr = Scr.menus.all;
+ while(mr != NULL)
+ {
+ SafeDefineCursor(mr->w,Scr.FvwmCursors[MENU]);
+ mr = mr->next;
+ }
+}
+
+MenuStyle *FindMenuStyle(char *name)
+{
+ MenuStyle *ms = Scr.menus.DefaultStyle;
+
+ while(ms != NULL )
+ {
+ if(strcasecmp(ms->name,name)==0)
+ return ms;
+ ms = ms->next;
+ }
+ return NULL;
+}
+
+static void FreeMenuStyle(MenuStyle *ms)
+{
+ MenuRoot *mr;
+ MenuStyle *before = Scr.menus.DefaultStyle;
+
+ if (!ms)
+ return;
+ mr = Scr.menus.all;
+ while(mr != NULL)
+ {
+ if(mr->ms == ms)
+ mr->ms = Scr.menus.DefaultStyle;
+ mr = mr->next;
+ }
+ if(ms->look.MenuGC)
+ XFreeGC(dpy, ms->look.MenuGC);
+ if(ms->look.MenuActiveGC)
+ XFreeGC(dpy, ms->look.MenuActiveGC);
+ if(ms->look.MenuActiveBackGC)
+ XFreeGC(dpy, ms->look.MenuActiveBackGC);
+ if(ms->look.MenuReliefGC)
+ XFreeGC(dpy, ms->look.MenuReliefGC);
+ if(ms->look.MenuStippleGC)
+ XFreeGC(dpy, ms->look.MenuStippleGC);
+ if(ms->look.MenuShadowGC)
+ XFreeGC(dpy, ms->look.MenuShadowGC);
+ if (ms->look.sidePic)
+ DestroyPicture(dpy, ms->look.sidePic);
+ if (ms->look.f.hasSideColor == 1)
+ FreeColors(&ms->look.sideColor, 1);
+
+ while(before->next != ms)
+ /* Not too many checks, may segfaults in race conditions */
+ before = before->next;
+
+ before->next = ms->next;
+ free(ms->name);
+ free(ms);
+}
+
+void DestroyMenuStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ MenuStyle *ms = NULL;
+ char *name = NULL;
+ MenuRoot *mr;
+
+ action = GetNextToken(action,&name);
+ if (name == NULL)
+ {
+ fvwm_msg(ERR,"DestroyMenuStyle", "needs one parameter");
+ return;
+ }
+
+ ms = FindMenuStyle(name);
+ if(ms == NULL)
+ fvwm_msg(ERR,"DestroyMenuStyle", "cannot find style %s", name);
+ else if (ms == Scr.menus.DefaultStyle)
+ fvwm_msg(ERR,"DestroyMenuStyle", "cannot destroy Default Menu Face");
+ else
+ {
+ FreeMenuFace(dpy, &ms->look.face);
+ FreeMenuStyle(ms);
+ MakeMenus();
+ }
+ free(name);
+ for (mr = Scr.menus.all; mr != NULL; mr = mr->next)
+ {
+ if (mr->ms == ms)
+ mr->ms = Scr.menus.DefaultStyle;
+ }
+ MakeMenus();
+}
+
+static void UpdateMenuStyle(MenuStyle *ms)
+{
+ XGCValues gcv;
+ unsigned long gcm;
+
+ if (ms->look.pStdFont != NULL && ms->look.pStdFont != &Scr.StdFont)
+ {
+ ms->look.pStdFont->y = ms->look.pStdFont->font->ascent;
+ ms->look.pStdFont->height =
+ ms->look.pStdFont->font->ascent +
+ ms->look.pStdFont->font->descent;
+ }
+ ms->look.EntryHeight =
+ ms->look.pStdFont->height + HEIGHT_EXTRA;
+
+ /* calculate colors based on foreground */
+ if (!ms->look.f.hasActiveFore)
+ ms->look.MenuActiveColors.fore=ms->look.MenuColors.fore;
+
+ /* calculate colors based on background */
+ if (!ms->look.f.hasActiveBack)
+ ms->look.MenuActiveColors.back = ms->look.MenuColors.back;
+ if (!ms->look.f.hasStippleFore)
+ ms->look.MenuStippleColors.fore = ms->look.MenuColors.back;
+ if(Scr.d_depth > 2) { /* if not black and white */
+ ms->look.MenuRelief.back = GetShadow(ms->look.MenuColors.back);
+ ms->look.MenuRelief.fore = GetHilite(ms->look.MenuColors.back);
+ } else { /* black and white */
+ ms->look.MenuRelief.back = GetColor("black");
+ ms->look.MenuRelief.fore = GetColor("white");
+ }
+ ms->look.MenuStippleColors.back = ms->look.MenuColors.back;
+
+ /* make GC's */
+ gcm = GCFunction|GCPlaneMask|GCFont|GCGraphicsExposures|
+ GCLineWidth|GCForeground|GCBackground;
+ gcv.fill_style = FillSolid;
+ gcv.font = ms->look.pStdFont->font->fid;
+ gcv.plane_mask = AllPlanes;
+ gcv.function = GXcopy;
+ gcv.graphics_exposures = False;
+ gcv.line_width = 0;
+
+ gcv.foreground = ms->look.MenuRelief.fore;
+ gcv.background = ms->look.MenuRelief.back;
+ if(ms->look.MenuReliefGC != NULL)
+ XFreeGC(dpy,ms->look.MenuReliefGC);
+ ms->look.MenuReliefGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = ms->look.MenuRelief.back;
+ gcv.background = ms->look.MenuRelief.fore;
+ if(ms->look.MenuShadowGC != NULL)
+ XFreeGC(dpy,ms->look.MenuShadowGC);
+ ms->look.MenuShadowGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = (ms->look.f.hasActiveBack) ?
+ ms->look.MenuActiveColors.back : ms->look.MenuRelief.back;
+ gcv.background = (ms->look.f.hasActiveFore) ?
+ ms->look.MenuActiveColors.fore : ms->look.MenuRelief.fore;
+ if(ms->look.MenuActiveBackGC != NULL)
+ XFreeGC(dpy,ms->look.MenuActiveBackGC);
+ ms->look.MenuActiveBackGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = ms->look.MenuColors.fore;
+ gcv.background = ms->look.MenuColors.back;
+ if(ms->look.MenuGC != NULL)
+ XFreeGC(dpy,ms->look.MenuGC);
+ ms->look.MenuGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = ms->look.MenuActiveColors.fore;
+ gcv.background = ms->look.MenuActiveColors.back;
+ if(ms->look.MenuActiveGC != NULL)
+ XFreeGC(dpy,ms->look.MenuActiveGC);
+ ms->look.MenuActiveGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ if(ms->look.MenuStippleGC != NULL)
+ XFreeGC(dpy,ms->look.MenuStippleGC);
+ if(Scr.d_depth < 2)
+ {
+ gcv.fill_style = FillStippled;
+ gcv.stipple = Scr.gray_bitmap;
+ gcm=GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
+ GCForeground|GCBackground|GCFont|GCStipple|GCFillStyle;
+ ms->look.MenuStippleGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcm=GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth|
+ GCForeground|GCBackground|GCFont;
+ gcv.fill_style = FillSolid;
+ }
+ else
+ {
+ gcv.foreground = ms->look.MenuStippleColors.fore;
+ gcv.background = ms->look.MenuStippleColors.back;
+ ms->look.MenuStippleGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+ }
+}
+
+
+static int GetMenuStyleIndex(char *option)
+{
+ char *optlist[] = {
+ "fvwm", "mwm", "win",
+ "Foreground", "Background", "Greyed",
+ "HilightBack", "HilightBackOff",
+ "ActiveFore", "ActiveForeOff",
+ "Hilight3DThick", "Hilight3DThin", "Hilight3DOff",
+ "Animation", "AnimationOff",
+ "Font",
+ "MenuFace",
+ "PopupDelay", "PopupOffset",
+ "TitleWarp", "TitleWarpOff",
+ "TitleUnderlines0", "TitleUnderlines1", "TitleUnderlines2",
+ "SeparatorsLong", "SeparatorsShort",
+ "TrianglesSolid", "TrianglesRelief",
+ "PopupImmediately", "PopupDelayed",
+ "DoubleClickTime",
+ "SidePic", "SideColor",
+ NULL
+ };
+ return GetTokenIndex(option, optlist, 0, NULL);
+}
+
+static void NewMenuStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *name;
+ char *option = NULL;
+ char *optstring = NULL;
+ char *nextarg;
+ char *args;
+ char *arg1;
+ MenuStyle *ms;
+ MenuStyle *tmpms;
+ Bool is_initialised = True;
+ Bool gc_changed = False;
+ Bool is_default_style = False;
+ int val[2];
+ int n;
+ XFontStruct *xfs = NULL;
+ int i;
+
+ action = GetNextToken(action, &name);
+ if (!name)
+ {
+ fvwm_msg(ERR,"NewMenuStyle", "error in %s style specification",action);
+ return;
+ }
+
+ tmpms = (MenuStyle *)safemalloc(sizeof(MenuStyle));
+ memset(tmpms, 0, sizeof(MenuStyle));
+ ms = FindMenuStyle(name);
+ if (ms != NULL)
+ {
+ /* copy the structure over our temporary menu face. */
+ memcpy(tmpms, ms, sizeof(MenuStyle));
+ if (ms == Scr.menus.DefaultStyle)
+ is_default_style = True;
+ free(name);
+ }
+ else
+ {
+ tmpms->name = name;
+ is_initialised = False;
+ }
+
+ /* Parse the options. */
+ while (action && *action)
+ {
+ if (is_initialised == False)
+ {
+ /* some default configuration goes here for the new menu style */
+ tmpms->look.MenuColors.back = GetColor("white");
+ tmpms->look.MenuColors.fore = GetColor("black");
+ tmpms->look.pStdFont = &Scr.StdFont;
+ tmpms->look.face.type = SimpleMenu;
+ tmpms->look.f.hasActiveFore = 0;
+ tmpms->look.f.hasActiveBack = 0;
+ gc_changed = True;
+ option = "fvwm";
+ }
+ else
+ {
+ /* Read next option specification (delimited by a comma or \0). */
+ args = action;
+ action = GetQuotedString(action, &optstring, ",", NULL, NULL, NULL);
+ if (!optstring)
+ break;
+
+ args = GetNextToken(optstring, &option);
+ if (!option)
+ {
+ free(optstring);
+ break;
+ }
+ nextarg = GetNextToken(args, &arg1);
+ }
+
+ switch((i = GetMenuStyleIndex(option)))
+ {
+ case 0: /* fvwm */
+ case 1: /* mwm */
+ case 2: /* win */
+ if (i == 0) {
+ tmpms->feel.PopupOffsetPercent = 67;
+ tmpms->feel.PopupOffsetAdd = 0;
+ tmpms->feel.f.PopupImmediately = 0;
+ tmpms->feel.f.TitleWarp = 1;
+ tmpms->look.ReliefThickness = 1;
+ tmpms->look.TitleUnderlines = 1;
+ tmpms->look.f.LongSeparators = 0;
+ tmpms->look.f.TriangleRelief = 1;
+ tmpms->look.f.Hilight = 0;
+ } else if (i == 1) {
+ tmpms->feel.PopupOffsetPercent = 100;
+ tmpms->feel.PopupOffsetAdd = -3;
+ tmpms->feel.f.PopupImmediately = 1;
+ tmpms->feel.f.TitleWarp = 0;
+ tmpms->look.ReliefThickness = 2;
+ tmpms->look.TitleUnderlines = 2;
+ tmpms->look.f.LongSeparators = 1;
+ tmpms->look.f.TriangleRelief = 1;
+ tmpms->look.f.Hilight = 0;
+ } else /* i == 2 */ {
+ tmpms->feel.PopupOffsetPercent = 100;
+ tmpms->feel.PopupOffsetAdd = -5;
+ tmpms->feel.f.PopupImmediately = 1;
+ tmpms->feel.f.TitleWarp = 0;
+ tmpms->look.ReliefThickness = 0;
+ tmpms->look.TitleUnderlines = 1;
+ tmpms->look.f.LongSeparators = 0;
+ tmpms->look.f.TriangleRelief = 0;
+ tmpms->look.f.Hilight = 1;
+ }
+
+ /* common settings */
+ tmpms->feel.f.Animated = 0;
+ FreeMenuFace(dpy, &tmpms->look.face);
+ tmpms->look.face.type = SimpleMenu;
+ if (tmpms->look.pStdFont && tmpms->look.pStdFont != &Scr.StdFont)
+ {
+ XFreeFont(dpy, tmpms->look.pStdFont->font);
+ free(tmpms->look.pStdFont);
+ }
+ tmpms->look.pStdFont = &Scr.StdFont;
+ gc_changed = True;
+ if (tmpms->look.f.hasSideColor == 1)
+ {
+ FreeColors(&tmpms->look.sideColor, 1);
+ tmpms->look.f.hasSideColor = 0;
+ }
+ tmpms->look.f.hasSideColor = 0;
+ if (tmpms->look.sidePic)
+ {
+ DestroyPicture(dpy, tmpms->look.sidePic);
+ tmpms->look.sidePic = NULL;
+ }
+
+ if (is_initialised == False)
+ {
+ /* now begin the real work */
+ is_initialised = True;
+ continue;
+ }
+ break;
+
+ case 3: /* Foreground */
+ FreeColors(&tmpms->look.MenuColors.fore, 1);
+ if (arg1)
+ tmpms->look.MenuColors.fore = GetColor(arg1);
+ else
+ tmpms->look.MenuColors.fore = GetColor("black");
+ gc_changed = True;
+ break;
+
+ case 4: /* Background */
+ FreeColors(&tmpms->look.MenuColors.back, 1);
+ if (arg1)
+ tmpms->look.MenuColors.back = GetColor(arg1);
+ else
+ tmpms->look.MenuColors.back = GetColor("grey");
+ gc_changed = True;
+ break;
+
+ case 5: /* Greyed */
+ if (tmpms->look.f.hasStippleFore)
+ FreeColors(&tmpms->look.MenuStippleColors.fore, 1);
+ if (arg1 == NULL)
+ {
+ tmpms->look.f.hasStippleFore = 0;
+ }
+ else
+ {
+ tmpms->look.MenuStippleColors.fore = GetColor(arg1);
+ tmpms->look.f.hasStippleFore = 1;
+ }
+ gc_changed = True;
+ break;
+
+ case 6: /* HilightBack */
+ if (tmpms->look.f.hasActiveBack)
+ FreeColors(&tmpms->look.MenuActiveColors.back, 1);
+ if (arg1 == NULL)
+ {
+ tmpms->look.f.hasActiveBack = 0;
+ }
+ else
+ {
+ tmpms->look.MenuActiveColors.back = GetColor(arg1);
+ tmpms->look.f.hasActiveBack = 1;
+ }
+ tmpms->look.f.Hilight = 1;
+ gc_changed = True;
+ break;
+
+ case 7: /* HilightBackOff */
+ tmpms->look.f.Hilight = 0;
+ gc_changed = True;
+ break;
+
+ case 8: /* ActiveFore */
+ if (tmpms->look.f.hasActiveFore)
+ FreeColors(&tmpms->look.MenuActiveColors.fore, 1);
+ if (arg1 == NULL)
+ {
+ tmpms->look.f.hasActiveFore = 0;
+ }
+ else
+ {
+ tmpms->look.MenuActiveColors.fore = GetColor(arg1);
+ tmpms->look.f.hasActiveFore = 1;
+ }
+ gc_changed = True;
+ break;
+
+ case 9: /* ActiveForeOff */
+ tmpms->look.f.hasActiveFore = 0;
+ gc_changed = True;
+ break;
+
+ case 10: /* Hilight3DThick */
+ tmpms->look.ReliefThickness = 2;
+ break;
+
+ case 11: /* Hilight3DThin */
+ tmpms->look.ReliefThickness = 1;
+ break;
+
+ case 12: /* Hilight3DOff */
+ tmpms->look.ReliefThickness = 0;
+ break;
+
+ case 13: /* Animation */
+ tmpms->feel.f.Animated = 1;
+ break;
+
+ case 14: /* AnimationOff */
+ tmpms->feel.f.Animated = 0;
+ break;
+
+ case 15: /* Font */
+ if (arg1 != NULL && (xfs = GetFontOrFixed(dpy, arg1)) == NULL)
+ {
+ fvwm_msg(ERR,"NewMenuStyle",
+ "Couldn't load font '%s' or 'fixed'\n", arg1);
+ break;
+ }
+ if (tmpms->look.pStdFont && tmpms->look.pStdFont != &Scr.StdFont)
+ {
+ if (tmpms->look.pStdFont->font != NULL)
+ XFreeFont(dpy, tmpms->look.pStdFont->font);
+ free(tmpms->look.pStdFont);
+ }
+ if (arg1 == NULL)
+ {
+ /* reset to screen font */
+ tmpms->look.pStdFont = &Scr.StdFont;
+ }
+ else
+ {
+ tmpms->look.pStdFont = (MyFont *)safemalloc(sizeof(MyFont));
+ tmpms->look.pStdFont->font = xfs;
+ }
+ gc_changed = True;
+ break;
+
+ case 16: /* MenuFace */
+ while (args && *args != '\0' && isspace(*args))
+ args++;
+ ReadMenuFace(args, &tmpms->look.face, True);
+ break;
+
+ case 17: /* PopupDelay */
+ if (GetIntegerArguments(args, NULL, val, 1) == 0 || *val < 0)
+ Scr.menus.PopupDelay10ms = DEFAULT_POPUP_DELAY;
+ else
+ Scr.menus.PopupDelay10ms = (*val+9)/10;
+ if (!is_default_style)
+ {
+ fvwm_msg(WARN, "NewMenuStyle",
+ "PopupDelay applied to style '%s' will affect all menus",
+ tmpms->name);
+ }
+ break;
+
+ case 18: /* PopupOffset */
+ if ((n = GetIntegerArguments(args, NULL, val, 2)) == 0)
+ {
+ fvwm_msg(ERR,"NewMenuStyle",
+ "PopupOffset requires one or two arguments");
+ }
+ else
+ {
+ tmpms->feel.PopupOffsetAdd = val[0];
+ if (n == 2 && val[1] <= 100 && val[1] >= 0)
+ tmpms->feel.PopupOffsetPercent = val[1];
+ else
+ tmpms->feel.PopupOffsetPercent = 100;
+ }
+ break;
+
+ case 19: /* TitleWarp */
+ tmpms->feel.f.TitleWarp = 1;
+ break;
+
+ case 20: /* TitleWarpOff */
+ tmpms->feel.f.TitleWarp = 0;
+ break;
+
+ case 21: /* TitleUnderlines0 */
+ tmpms->look.TitleUnderlines = 0;
+ break;
+
+ case 22: /* TitleUnderlines1 */
+ tmpms->look.TitleUnderlines = 1;
+ break;
+
+ case 23: /* TitleUnderlines2 */
+ tmpms->look.TitleUnderlines = 2;
+ break;
+
+ case 24: /* SeparatorsLong */
+ tmpms->look.f.LongSeparators = 1;
+ break;
+
+ case 25: /* SeparatorsShort */
+ tmpms->look.f.LongSeparators = 0;
+ break;
+
+ case 26: /* TrianglesSolid */
+ tmpms->look.f.TriangleRelief = 0;
+ break;
+
+ case 27: /* TrianglesRelief */
+ tmpms->look.f.TriangleRelief = 1;
+ break;
+
+ case 28: /* PopupImmediately */
+ tmpms->feel.f.PopupImmediately = 1;
+ break;
+
+ case 29: /* PopupDelayed */
+ tmpms->feel.f.PopupImmediately = 0;
+ break;
+
+ case 30: /* DoubleClickTime */
+ if (GetIntegerArguments(args, NULL, val, 1) == 0 || *val < 0)
+ Scr.menus.DoubleClickTime = DEFAULT_MENU_CLICKTIME;
+ else
+ Scr.menus.DoubleClickTime = *val;
+ if (!is_default_style)
+ {
+ fvwm_msg(WARN, "NewMenuStyle",
+ "DoubleClickTime for style '%s' will affect all menus",
+ tmpms->name);
+ }
+ break;
+
+ case 31: /* SidePic */
+ if (tmpms->look.sidePic)
+ {
+ DestroyPicture(dpy, tmpms->look.sidePic);
+ tmpms->look.sidePic = NULL;
+ }
+ if (arg1 != NULL)
+ {
+ tmpms->look.sidePic = CachePicture(dpy, Scr.Root, IconPath,
+ PixmapPath, arg1, Scr.ColorLimit);
+ if (!tmpms->look.sidePic)
+ fvwm_msg(WARN, "NewMenuStyle", "Couldn't find pixmap %s", arg1);
+ }
+ break;
+
+ case 32: /* SideColor */
+ if (tmpms->look.f.hasSideColor == 1)
+ {
+ FreeColors(&tmpms->look.sideColor, 1);
+ tmpms->look.f.hasSideColor = 0;
+ }
+ if (arg1 != NULL)
+ {
+ tmpms->look.sideColor = GetColor(arg1);
+ tmpms->look.f.hasSideColor = 1;
+ }
+ break;
+
+#if 0
+ case 33: /* PositionHints */
+ break;
+#endif
+
+ default:
+ fvwm_msg(ERR,"NewMenuStyle", "unknown option '%s'", option);
+ break;
+ } /* switch */
+
+ if (option)
+ {
+ free(option);
+ option = NULL;
+ }
+ free(optstring);
+ optstring = NULL;
+ if (arg1)
+ {
+ free(arg1);
+ arg1 = NULL;
+ }
+ } /* while */
+
+ if (gc_changed)
+ {
+ UpdateMenuStyle(tmpms);
+ } /* if (gc_changed) */
+
+ if(Scr.menus.DefaultStyle == NULL)
+ {
+ /* First MenuStyle MUST be the default style */
+ Scr.menus.DefaultStyle = tmpms;
+ tmpms->next = NULL;
+ }
+ else if (ms != NULL)
+ {
+ /* copy our new menu face over the old one */
+ memcpy(ms, tmpms, sizeof(MenuStyle));
+ free(tmpms);
+ }
+ else
+ {
+ MenuStyle *before = Scr.menus.DefaultStyle;
+
+ /* add a new menu face to list */
+ tmpms->next = NULL;
+ while(before->next != NULL)
+ before = before->next;
+ before->next = tmpms;
+ }
+
+ MakeMenus();
+
+ return;
+}
+
+static void OldMenuStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *buffer, *rest;
+ char *fore, *back, *stipple, *font, *style, *animated;
+ size_t len;
+
+ rest = GetNextToken(action,&fore);
+ rest = GetNextToken(rest,&back);
+ rest = GetNextToken(rest,&stipple);
+ rest = GetNextToken(rest,&font);
+ rest = GetNextToken(rest,&style);
+ rest = GetNextToken(rest,&animated);
+
+ if(!fore || !back || !stipple || !font || !style)
+ {
+ fvwm_msg(ERR,"OldMenuStyle", "error in %s style specification", action);
+ }
+ else
+ {
+ len = strlen(action) + 100;
+ buffer = (char *)safemalloc(len);
+ snprintf(buffer, len,
+ "* %s, Foreground %s, Background %s, Greyed %s, Font %s, %s",
+ style, fore, back, stipple, font,
+ (animated != NULL && StrEquals(animated, "anim")) ?
+ "Animation" : "AnimationOff");
+ NewMenuStyle(eventp, w, tmp_win, context, buffer, Module);
+ free(buffer);
+ }
+
+ if(fore != NULL)
+ free(fore);
+ if(back != NULL)
+ free(back);
+ if(stipple != NULL)
+ free(stipple);
+ if(font != NULL)
+ free(font);
+ if(style != NULL)
+ free(style);
+ if(animated != NULL)
+ free(animated);
+}
+
+
+void SetMenuStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *option;
+
+ GetNextOption(SkipNTokens(action, 1), &option);
+ if (option == NULL || GetMenuStyleIndex(option) != -1)
+ NewMenuStyle(eventp, w, tmp_win, context, action, Module);
+ else
+ OldMenuStyle(eventp, w, tmp_win, context, action, Module);
+ if (option)
+ free(option);
+ return;
+}
+
+
+void ChangeMenuStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *name = NULL, *menuname = NULL;
+ MenuStyle *ms = NULL;
+ MenuRoot *mr = NULL;
+
+
+ action = GetNextToken(action,&name);
+ if (name == NULL)
+ {
+ fvwm_msg(ERR,"ChangeMenuStyle", "needs at least two parameters");
+ return;
+ }
+
+ ms = FindMenuStyle(name);
+ if(ms == NULL)
+ {
+ fvwm_msg(ERR,"ChangeMenuStyle", "cannot find style %s", name);
+ free(name);
+ return;
+ }
+ free(name);
+
+ action = GetNextToken(action,&menuname);
+ while(menuname != NULL && *menuname)
+ {
+ mr = FindPopup(menuname);
+ if(mr == NULL)
+ {
+ fvwm_msg(ERR,"ChangeMenuStyle", "cannot find menu %s", menuname);
+ free(menuname);
+ break;
+ }
+ mr->ms = ms;
+ MakeMenu(mr);
+ free(menuname);
+ action = GetNextToken(action,&menuname);
+ }
+}
+
+
+Boolean ReadButtonFace(char *s, ButtonFace *bf, int button, int verbose);
+void FreeButtonFace(Display *dpy, ButtonFace *bf);
+
+#ifdef BORDERSTYLE
+/****************************************************************************
+ *
+ * Sets the border style (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void SetBorderStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *parm = NULL, *prev = action;
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+
+ action = GetNextToken(action, &parm);
+ while (parm)
+ {
+ if (StrEquals(parm,"active") || StrEquals(parm,"inactive"))
+ {
+ int len;
+ char *end, *tmp;
+ ButtonFace tmpbf, *bf;
+ tmpbf.style = SimpleButton;
+#ifdef MULTISTYLE
+ tmpbf.next = NULL;
+#endif
+#ifdef MINI_ICONS
+ tmpbf.u.p = NULL;
+#endif
+ if (StrEquals(parm,"active"))
+ bf = &fl->BorderStyle.active;
+ else
+ bf = &fl->BorderStyle.inactive;
+ while (isspace(*action)) ++action;
+ if ('(' != *action) {
+ if (!*action) {
+ fvwm_msg(ERR,"SetBorderStyle",
+ "error in %s border specification", parm);
+ free(parm);
+ return;
+ }
+ free(parm);
+ if (ReadButtonFace(action, &tmpbf,-1,True)) {
+ FreeButtonFace(dpy, bf);
+ *bf = tmpbf;
+ }
+ break;
+ }
+ end = strchr(++action, ')');
+ if (!end) {
+ fvwm_msg(ERR,"SetBorderStyle",
+ "error in %s border specification", parm);
+ free(parm);
+ return;
+ }
+ len = end - action + 1;
+ tmp = safemalloc(len);
+ strncpy(tmp, action, len - 1);
+ tmp[len - 1] = 0;
+ ReadButtonFace(tmp, bf,-1,True);
+ free(tmp);
+ action = end + 1;
+ }
+ else if (strcmp(parm,"--")==0) {
+ if (ReadButtonFace(prev, &fl->BorderStyle.active,-1,True))
+ ReadButtonFace(prev, &fl->BorderStyle.inactive,-1,False);
+ free(parm);
+ break;
+ } else {
+ ButtonFace tmpbf;
+ tmpbf.style = SimpleButton;
+#ifdef MULTISTYLE
+ tmpbf.next = NULL;
+#endif
+#ifdef MINI_ICONS
+ tmpbf.u.p = NULL;
+#endif
+ if (ReadButtonFace(prev, &tmpbf,-1,True)) {
+ FreeButtonFace(dpy,&fl->BorderStyle.active);
+ fl->BorderStyle.active = tmpbf;
+ ReadButtonFace(prev, &fl->BorderStyle.inactive,-1,False);
+ }
+ free(parm);
+ break;
+ }
+ free(parm);
+ prev = action;
+ action = GetNextToken(action,&parm);
+ }
+}
+#endif
+
+char *ReadTitleButton(char *s, TitleButton *tb, Boolean append, int button);
+
+#if defined(MULTISTYLE) && defined(EXTENDED_TITLESTYLE)
+/*****************************************************************************
+ *
+ * Appends a titlestyle (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void AddTitleStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+ char *parm=NULL;
+
+ /* See if there's a next token. We actually don't care what it is, so
+ GetNextToken allocating memory is overkill, but... */
+ GetNextToken(action,&parm);
+ while (parm)
+ {
+ free(parm);
+ if ((action = ReadTitleButton(action, &fl->titlebar, True, -1)) == NULL)
+ break;
+ GetNextToken(action, &parm);
+ }
+}
+#endif /* MULTISTYLE && EXTENDED_TITLESTYLE */
+
+void SetTitleStyle(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *parm=NULL, *prev = action;
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+
+ action = GetNextToken(action,&parm);
+ while(parm)
+ {
+ if (StrEquals(parm,"centered"))
+ {
+ fl->titlebar.flags &= ~HOffCenter;
+ }
+ else if (StrEquals(parm,"leftjustified"))
+ {
+ fl->titlebar.flags |= HOffCenter;
+ fl->titlebar.flags &= ~HRight;
+ }
+ else if (StrEquals(parm,"rightjustified"))
+ {
+ fl->titlebar.flags |= HOffCenter | HRight;
+ }
+#ifdef EXTENDED_TITLESTYLE
+ else if (StrEquals(parm,"height"))
+ {
+ int height, next;
+ if ( sscanf(action, "%d%n", &height, &next) > 0
+ && height > 4
+ && height <= 256)
+ {
+ int x,y,w,h,extra_height;
+ FvwmWindow *tmp = Scr.FvwmRoot.next, *hi = Scr.Hilite;
+
+ extra_height = fl->TitleHeight;
+ fl->TitleHeight = height;
+ extra_height -= fl->TitleHeight;
+
+ fl->WindowFont.y = fl->WindowFont.font->ascent
+ + (height - (fl->WindowFont.font->ascent
+ + fl->WindowFont.font->descent + 3)) / 2;
+ if (fl->WindowFont.y < fl->WindowFont.font->ascent)
+ fl->WindowFont.y = fl->WindowFont.font->ascent;
+
+ tmp = Scr.FvwmRoot.next;
+ hi = Scr.Hilite;
+ while(tmp != NULL)
+ {
+ if (!(tmp->flags & TITLE)
+#ifdef USEDECOR
+ || (tmp->fl != fl)
+#endif
+ ) {
+ tmp = tmp->next;
+ continue;
+ }
+ x = tmp->frame_x;
+ y = tmp->frame_y;
+ w = tmp->frame_width;
+ h = tmp->frame_height-extra_height;
+ tmp->frame_x = 0;
+ tmp->frame_y = 0;
+ tmp->frame_height = 0;
+ tmp->frame_width = 0;
+ SetupFrame(tmp,x,y,w,h,True);
+ SetTitleBar(tmp,True,True);
+ SetTitleBar(tmp,False,True);
+ tmp = tmp->next;
+ }
+ SetTitleBar(hi,True,True);
+ }
+ else
+ fvwm_msg(ERR,"SetTitleStyle",
+ "bad height argument (height must be from 5 to 256)");
+ action += next;
+ }
+ else
+ {
+ if (!(action = ReadTitleButton(prev, &fl->titlebar, False, -1))) {
+ free(parm);
+ break;
+ }
+ }
+#else /* ! EXTENDED_TITLESTYLE */
+ else if (strcmp(parm,"--")==0) {
+ if (!(action = ReadTitleButton(prev, &fl->titlebar, False, -1))) {
+ free(parm);
+ break;
+ }
+ }
+#endif /* EXTENDED_TITLESTYLE */
+ free(parm);
+ prev = action;
+ action = GetNextToken(action,&parm);
+ }
+} /* SetTitleStyle */
+
+static void ApplyDefaultFontAndColors(void)
+{
+ XGCValues gcv;
+ unsigned long gcm;
+ MenuStyle *ms;
+ int wid;
+ int hei;
+
+ Scr.StdFont.y = Scr.StdFont.font->ascent;
+ Scr.StdFont.height = Scr.StdFont.font->ascent + Scr.StdFont.font->descent;
+
+ /* make GC's */
+ gcm = GCFunction|GCPlaneMask|GCFont|GCGraphicsExposures|
+ GCLineWidth|GCForeground|GCBackground;
+ gcv.fill_style = FillSolid;
+ gcv.font = Scr.StdFont.font->fid;
+ gcv.plane_mask = AllPlanes;
+ gcv.function = GXcopy;
+ gcv.graphics_exposures = False;
+ gcv.line_width = 0;
+
+ gcv.foreground = Scr.StdColors.fore;
+ gcv.background = Scr.StdColors.back;
+ if(Scr.StdGC != NULL)
+ XFreeGC(dpy, Scr.StdGC);
+ Scr.StdGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = Scr.StdRelief.fore;
+ gcv.background = Scr.StdRelief.back;
+ if(Scr.StdReliefGC != NULL)
+ XFreeGC(dpy, Scr.StdReliefGC);
+ Scr.StdReliefGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ gcv.foreground = Scr.StdRelief.back;
+ gcv.background = Scr.StdRelief.fore;
+ if(Scr.StdShadowGC != NULL)
+ XFreeGC(dpy, Scr.StdShadowGC);
+ Scr.StdShadowGC = XCreateGC(dpy, Scr.Root, gcm, &gcv);
+
+ /* update the geometry window for move/resize */
+ if(Scr.SizeWindow != None)
+ {
+ XSetWindowBackground(dpy, Scr.SizeWindow, Scr.StdColors.back);
+ Scr.SizeStringWidth = XTextWidth(Scr.StdFont.font, " +8888 x +8888 ", 15);
+ wid = Scr.SizeStringWidth + 2 * SIZE_HINDENT;
+ hei = Scr.StdFont.height + 2 * SIZE_VINDENT;
+ if(Scr.gs.EmulateMWM)
+ {
+ XMoveResizeWindow(dpy,Scr.SizeWindow,
+ (Scr.MyDisplayWidth - wid)/2,
+ (Scr.MyDisplayHeight - hei)/2, wid, hei);
+ }
+ else
+ {
+ XMoveResizeWindow(dpy,Scr.SizeWindow,0, 0, wid,hei);
+ }
+ }
+
+ if (Scr.hasIconFont == False)
+ {
+ Scr.IconFont.font = Scr.StdFont.font;
+ ApplyIconFont();
+ }
+
+ if (Scr.hasWindowFont == False)
+ {
+ Scr.DefaultDecor.WindowFont.font = Scr.StdFont.font;
+ ApplyWindowFont(&Scr.DefaultDecor);
+ }
+
+ for (ms = Scr.menus.DefaultStyle; ms != NULL; ms = ms->next)
+ {
+ if (ms->look.pStdFont == &Scr.StdFont)
+ ms->look.EntryHeight = Scr.StdFont.height + HEIGHT_EXTRA;
+ UpdateMenuStyle(ms);
+ }
+ MakeMenus();
+}
+
+void SetDefaultColors(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *fore = NULL;
+ char *back = NULL;
+
+ action = GetNextToken(action, &fore);
+ action = GetNextToken(action, &back);
+
+ if (!back)
+ back = strdup("grey");
+ if (!fore)
+ back = strdup("black");
+
+ if (!StrEquals(fore, "-"))
+ {
+ FreeColors(&Scr.StdColors.fore, 1);
+ Scr.StdColors.fore = GetColor(fore);
+ }
+ if (!StrEquals(back, "-"))
+ {
+ FreeColors(&Scr.StdColors.back, 1);
+ FreeColors(&Scr.StdRelief.back, 1);
+ FreeColors(&Scr.StdRelief.fore, 1);
+ Scr.StdColors.back = GetColor(back);
+ Scr.StdRelief.fore = GetHilite(Scr.StdColors.back);
+ Scr.StdRelief.back = GetShadow(Scr.StdColors.back);
+ }
+ free(fore);
+ free(back);
+
+ ApplyDefaultFontAndColors();
+}
+
+void LoadDefaultFont(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *font;
+ XFontStruct *xfs = NULL;
+
+ action = GetNextToken(action,&font);
+ if (!font)
+ {
+ /* Try 'fixed' */
+ font = strdup("");
+ }
+
+ if ((xfs = GetFontOrFixed(dpy, font)) == NULL)
+ {
+ fvwm_msg(ERR,"SetDefaultFont","Couldn't load font '%s' or 'fixed'\n",
+ font);
+ free(font);
+ if (Scr.StdFont.font == NULL)
+ exit(1);
+ else
+ return;
+ }
+ free(font);
+ if (Scr.StdFont.font != NULL)
+ XFreeFont(dpy, Scr.StdFont.font);
+ Scr.StdFont.font = xfs;
+
+ ApplyDefaultFontAndColors();
+}
+
+void ApplyIconFont(void)
+{
+ FvwmWindow *tmp;
+
+ Scr.IconFont.height = Scr.IconFont.font->ascent+Scr.IconFont.font->descent;
+ Scr.IconFont.y = Scr.IconFont.font->ascent;
+
+ tmp = Scr.FvwmRoot.next;
+ while(tmp != NULL)
+ {
+ RedoIconName(tmp);
+
+ if(tmp->flags& ICONIFIED)
+ {
+ DrawIconWindow(tmp);
+ }
+ tmp = tmp->next;
+ }
+}
+
+void LoadIconFont(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *font;
+ XFontStruct *newfont;
+
+ action = GetNextToken(action,&font);
+ if (!font)
+ {
+ if (Scr.hasIconFont == True)
+ {
+ /* reset to default font */
+ XFreeFont(dpy, Scr.IconFont.font);
+ Scr.hasIconFont = False;
+ }
+ Scr.IconFont.font = Scr.StdFont.font;
+ ApplyIconFont();
+ return;
+ }
+
+ if ((newfont = GetFontOrFixed(dpy, font))!=NULL)
+ {
+ if (Scr.IconFont.font != NULL && Scr.hasIconFont == True)
+ XFreeFont(dpy, Scr.IconFont.font);
+ Scr.hasIconFont = True;
+ Scr.IconFont.font = newfont;
+ ApplyIconFont();
+ }
+ else
+ {
+ fvwm_msg(ERR,"LoadIconFont","Couldn't load font '%s' or 'fixed'\n", font);
+ }
+ free(font);
+}
+
+void ApplyWindowFont(FvwmDecor *fl)
+{
+ FvwmWindow *tmp,*hi;
+ int x,y,w,h,extra_height;
+
+ fl->WindowFont.height =
+ fl->WindowFont.font->ascent+fl->WindowFont.font->descent;
+ fl->WindowFont.y = fl->WindowFont.font->ascent;
+ extra_height = fl->TitleHeight;
+ fl->TitleHeight=fl->WindowFont.font->ascent+fl->WindowFont.font->descent+3;
+ extra_height -= fl->TitleHeight;
+
+ tmp = Scr.FvwmRoot.next;
+ hi = Scr.Hilite;
+ while(tmp != NULL)
+ {
+ if (!(tmp->flags & TITLE)
+#ifdef USEDECOR
+ || (tmp->fl != fl)
+#endif
+ )
+ {
+ tmp = tmp->next;
+ continue;
+ }
+ x = tmp->frame_x;
+ y = tmp->frame_y;
+ w = tmp->frame_width;
+ h = tmp->frame_height-extra_height;
+ tmp->frame_x = 0;
+ tmp->frame_y = 0;
+ tmp->frame_height = 0;
+ tmp->frame_width = 0;
+ SetupFrame(tmp,x,y,w,h,True);
+ SetTitleBar(tmp,True,True);
+ SetTitleBar(tmp,False,True);
+ tmp = tmp->next;
+ }
+ SetTitleBar(hi,True,True);
+}
+
+void LoadWindowFont(XEvent *eventp,Window win,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *font;
+ XFontStruct *newfont;
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+
+ action = GetNextToken(action,&font);
+ if (!font)
+ {
+ /* reset to default font */
+ if (Scr.hasWindowFont)
+ {
+ XFreeFont(dpy, Scr.DefaultDecor.WindowFont.font);
+ Scr.hasWindowFont = False;
+ fl->WindowFont.font = Scr.StdFont.font;
+ ApplyWindowFont(&Scr.DefaultDecor);
+ }
+ return;
+ }
+
+ if ((newfont = GetFontOrFixed(dpy, font))!=NULL)
+ {
+ if (fl->WindowFont.font != NULL &&
+ (fl != &Scr.DefaultDecor || Scr.hasWindowFont == True))
+ XFreeFont(dpy, fl->WindowFont.font);
+ if (fl == &Scr.DefaultDecor)
+ Scr.hasWindowFont = True;
+ fl->WindowFont.font = newfont;
+ ApplyWindowFont(fl);
+ }
+ else
+ {
+ fvwm_msg(ERR,"LoadWindowFont","Couldn't load font '%s' or 'fixed'\n",font);
+ }
+
+ free(font);
+}
+
+void FreeButtonFace(Display *dpy, ButtonFace *bf)
+{
+ switch (bf->style)
+ {
+#ifdef GRADIENT_BUTTONS
+ case HGradButton:
+ case VGradButton:
+ /* - should we check visual is not TrueColor before doing this?
+
+ XFreeColors(dpy, Scr.FvwmRoot.attr.colormap,
+ bf->u.grad.pixels, bf->u.grad.npixels,
+ AllPlanes); */
+ free(bf->u.grad.pixels);
+ bf->u.grad.pixels = NULL;
+ break;
+#endif
+
+#ifdef PIXMAP_BUTTONS
+ case PixmapButton:
+ case TiledPixmapButton:
+ if (bf->u.p)
+ DestroyPicture(dpy, bf->u.p);
+ bf->u.p = NULL;
+ break;
+#endif
+ default:
+ break;
+ }
+#ifdef MULTISTYLE
+ /* delete any compound styles */
+ if (bf->next) {
+ FreeButtonFace(dpy, bf->next);
+ free(bf->next);
+ }
+ bf->next = NULL;
+#endif
+ bf->style = SimpleButton;
+}
+
+/*****************************************************************************
+ *
+ * Reads a button face line into a structure (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+Boolean ReadButtonFace(char *s, ButtonFace *bf, int button, int verbose)
+{
+ int offset;
+ char style[256], *file;
+ char *action = s;
+
+ if (sscanf(s, "%s%n", style, &offset) < 1) {
+ if (verbose)
+ fvwm_msg(ERR, "ReadButtonFace", "error in face `%s'", s);
+ return False;
+ }
+
+ if (strncasecmp(style, "--", 2) != 0) {
+ s += offset;
+
+ FreeButtonFace(dpy, bf);
+
+ /* determine button style */
+ if (strncasecmp(style,"Simple",6)==0)
+ {
+ bf->style = SimpleButton;
+ }
+ else if (strncasecmp(style,"Default",7)==0) {
+ int b = -1, n = sscanf(s, "%d%n", &b, &offset);
+
+ if (n < 1) {
+ if (button == -1) {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "need default button number to load");
+ return False;
+ }
+ b = button;
+ }
+ s += offset;
+ if ((b > 0) && (b <= 10))
+ LoadDefaultButton(bf, b);
+ else {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "button number out of range: %d", b);
+ return False;
+ }
+ }
+#ifdef VECTOR_BUTTONS
+ else if (strncasecmp(style,"Vector",6)==0 ||
+ (strlen(style)<=2 && isdigit(*style)))
+ {
+ /* normal coordinate list button style */
+ int i, num_coords, num;
+ struct vector_coords *vc = &bf->vector;
+
+ /* get number of points */
+ if (strncasecmp(style,"Vector",6)==0) {
+ num = sscanf(s,"%d%n",&num_coords,&offset);
+ s += offset;
+ } else
+ num = sscanf(style,"%d",&num_coords);
+
+ if((num != 1)||(num_coords>20)||(num_coords<2))
+ {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "Bad button style (2) in line: %s",action);
+ return False;
+ }
+
+ vc->num = num_coords;
+
+ /* get the points */
+ for(i = 0; i < vc->num; ++i)
+ {
+ /* X x Y @ line_style */
+ num = sscanf(s,"%dx%d@%d%n",&vc->x[i],&vc->y[i],
+ &vc->line_style[i], &offset);
+ if(num != 3)
+ {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "Bad button style (3) in line %s",
+ action);
+ return False;
+ }
+ s += offset;
+ }
+ bf->style = VectorButton;
+ }
+#endif
+ else if (strncasecmp(style,"Solid",5)==0)
+ {
+ s = GetNextToken(s, &file);
+ if (file) {
+ bf->style = SolidButton;
+ bf->u.back = GetColor(file);
+ free(file);
+ } else {
+ if(verbose)
+ fvwm_msg(ERR,"ReadButtonFace",
+ "no color given for Solid face type: %s", action);
+ return False;
+ }
+ }
+#ifdef GRADIENT_BUTTONS
+ else if (strncasecmp(style,"HGradient",9)==0
+ || strncasecmp(style,"VGradient",9)==0)
+ {
+ char *item, **s_colors;
+ int npixels, nsegs, i, sum, *perc;
+ Pixel *pixels;
+
+ if (!(s = GetNextToken(s, &item)) || (item == NULL)) {
+ if(verbose)
+ fvwm_msg(ERR,"ReadButtonFace",
+ "expected number of colors to allocate in gradient");
+ if (item)
+ free(item);
+ return False;
+ }
+ npixels = atoi(item);
+ free(item);
+
+ if (!(s = GetNextToken(s, &item)) || (item == NULL)) {
+ if(verbose)
+ fvwm_msg(ERR,"ReadButtonFace", "incomplete gradient style");
+ if (item)
+ free(item);
+ return False;
+ }
+
+ if (!(isdigit(*item))) {
+ s_colors = (char **)safemalloc(sizeof(char *) * 2);
+ perc = (int *)safemalloc(sizeof(int));
+ nsegs = 1;
+ s_colors[0] = item;
+ s = GetNextToken(s, &s_colors[1]);
+ perc[0] = 100;
+ } else {
+ nsegs = atoi(item);
+ free(item);
+ if (nsegs < 1) nsegs = 1;
+ if (nsegs > 128) nsegs = 128;
+ s_colors = (char **)safemalloc(sizeof(char *) * (nsegs + 1));
+ perc = (int *)safemalloc(sizeof(int) * nsegs);
+ for (i = 0; i <= nsegs; ++i) {
+ s =GetNextToken(s, &s_colors[i]);
+ if (i < nsegs) {
+ s = GetNextToken(s, &item);
+ if (item)
+ {
+ perc[i] = atoi(item);
+ free(item);
+ }
+ else
+ perc[i] = 0;
+ }
+ }
+ }
+
+ for (i = 0, sum = 0; i < nsegs; ++i)
+ sum += perc[i];
+
+ if (sum != 100) {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "multi gradient lengths must sum to 100");
+ for (i = 0; i <= nsegs; ++i)
+ if (s_colors[i])
+ free(s_colors[i]);
+ free(s_colors);
+ free(perc);
+ return False;
+ }
+
+ if (npixels < 2) npixels = 2;
+ if (npixels > 128) npixels = 128;
+
+ pixels = AllocNonlinearGradient(s_colors, perc, nsegs, npixels);
+ for (i = 0; i <= nsegs; ++i)
+ if (s_colors[i])
+ free(s_colors[i]);
+ free(s_colors);
+ free(perc);
+
+ if (!pixels) {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "couldn't create gradient");
+ return False;
+ }
+
+ bf->u.grad.pixels = pixels;
+ bf->u.grad.npixels = npixels;
+
+ if (strncasecmp(style,"H",1)==0)
+ bf->style = HGradButton;
+ else
+ bf->style = VGradButton;
+ }
+#endif /* GRADIENT_BUTTONS */
+#ifdef PIXMAP_BUTTONS
+ else if (strncasecmp(style,"Pixmap",6)==0
+ || strncasecmp(style,"TiledPixmap",11)==0)
+ {
+ s = GetNextToken(s, &file);
+ bf->u.p = CachePicture(dpy, Scr.Root,
+ IconPath,
+ PixmapPath,
+ file,Scr.ColorLimit);
+ if (bf->u.p == NULL)
+ {
+ if (file)
+ {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "couldn't load pixmap %s", file);
+ free(file);
+ }
+ return False;
+ }
+ if (file)
+ {
+ free(file);
+ file = NULL;
+ }
+
+ if (strncasecmp(style,"Tiled",5)==0)
+ bf->style = TiledPixmapButton;
+ else
+ bf->style = PixmapButton;
+ }
+#ifdef MINI_ICONS
+ else if (strncasecmp (style, "MiniIcon", 8) == 0) {
+ bf->style = MiniIconButton;
+#if 0
+/* Have to remove this again. This is all so badly written there is no chance
+ * to prevent a coredump and a memory leak the same time without a rewrite of
+ * large parts of the code. */
+ if (bf->u.p)
+ DestroyPicture(dpy, bf->u.p);
+#endif
+ bf->u.p = NULL; /* pixmap read in when the window is created */
+ }
+#endif
+#endif /* PIXMAP_BUTTONS */
+ else {
+ if(verbose)fvwm_msg(ERR,"ReadButtonFace",
+ "unknown style %s: %s", style, action);
+ return False;
+ }
+ }
+
+ /* Process button flags ("--" signals start of flags,
+ it is also checked for above) */
+ s = GetNextToken(s, &file);
+ if (file && (strcmp(file,"--")==0)) {
+ char *tok;
+ s = GetNextToken(s, &tok);
+ while (tok&&*tok)
+ {
+ int set = 1;
+
+ if (*tok == '!') { /* flag negate */
+ set = 0;
+ ++tok;
+ }
+ if (StrEquals(tok,"Clear")) {
+ if (set)
+ bf->style &= ButtonFaceTypeMask;
+ else
+ bf->style |= ~ButtonFaceTypeMask; /* ? */
+ }
+ else if (StrEquals(tok,"Left"))
+ {
+ if (set) {
+ bf->style |= HOffCenter;
+ bf->style &= ~HRight;
+ } else
+ bf->style |= HOffCenter | HRight;
+ }
+ else if (StrEquals(tok,"Right"))
+ {
+ if (set)
+ bf->style |= HOffCenter | HRight;
+ else {
+ bf->style |= HOffCenter;
+ bf->style &= ~HRight;
+ }
+ }
+ else if (StrEquals(tok,"Centered")) {
+ bf->style &= ~HOffCenter;
+ bf->style &= ~VOffCenter;
+ }
+ else if (StrEquals(tok,"Top"))
+ {
+ if (set) {
+ bf->style |= VOffCenter;
+ bf->style &= ~VBottom;
+ } else
+ bf->style |= VOffCenter | VBottom;
+
+ }
+ else if (StrEquals(tok,"Bottom"))
+ {
+ if (set)
+ bf->style |= VOffCenter | VBottom;
+ else {
+ bf->style |= VOffCenter;
+ bf->style &= ~VBottom;
+ }
+ }
+ else if (StrEquals(tok,"Flat"))
+ {
+ if (set) {
+ bf->style &= ~SunkButton;
+ bf->style |= FlatButton;
+ } else
+ bf->style &= ~FlatButton;
+ }
+ else if (StrEquals(tok,"Sunk"))
+ {
+ if (set) {
+ bf->style &= ~FlatButton;
+ bf->style |= SunkButton;
+ } else
+ bf->style &= ~SunkButton;
+ }
+ else if (StrEquals(tok,"Raised"))
+ {
+ if (set) {
+ bf->style &= ~FlatButton;
+ bf->style &= ~SunkButton;
+ } else {
+ bf->style |= SunkButton;
+ bf->style &= ~FlatButton;
+ }
+ }
+#ifdef EXTENDED_TITLESTYLE
+ else if (StrEquals(tok,"UseTitleStyle"))
+ {
+ if (set) {
+ bf->style |= UseTitleStyle;
+#ifdef BORDERSTYLE
+ bf->style &= ~UseBorderStyle;
+#endif
+ } else
+ bf->style &= ~UseTitleStyle;
+ }
+#endif
+#ifdef BORDERSTYLE
+ else if (StrEquals(tok,"HiddenHandles"))
+ {
+ if (set)
+ bf->style |= HiddenHandles;
+ else
+ bf->style &= ~HiddenHandles;
+ }
+ else if (StrEquals(tok,"NoInset"))
+ {
+ if (set)
+ bf->style |= NoInset;
+ else
+ bf->style &= ~NoInset;
+ }
+ else if (StrEquals(tok,"UseBorderStyle"))
+ {
+ if (set) {
+ bf->style |= UseBorderStyle;
+#ifdef EXTENDED_TITLESTYLE
+ bf->style &= ~UseTitleStyle;
+#endif
+ } else
+ bf->style &= ~UseBorderStyle;
+ }
+#endif
+ else
+ if(verbose)
+ fvwm_msg(ERR,"ReadButtonFace",
+ "unknown button face flag %s -- line: %s",
+ tok, action);
+ if (set)
+ free(tok);
+ else
+ free(tok - 1);
+ s = GetNextToken(s, &tok);
+ }
+ }
+ if (file)
+ free(file);
+ return True;
+}
+
+
+/*****************************************************************************
+ *
+ * Reads a title button description (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+char *ReadTitleButton(char *s, TitleButton *tb, Boolean append, int button)
+{
+ char *end = NULL, *spec;
+ ButtonFace tmpbf;
+ enum ButtonState bs = MaxButtonState;
+ int i = 0, all = 0, pstyle = 0;
+
+ while(isspace(*s))++s;
+ for (; i < MaxButtonState; ++i)
+ if (strncasecmp(button_states[i],s,
+ strlen(button_states[i]))==0) {
+ bs = i;
+ break;
+ }
+ if (bs != MaxButtonState)
+ s += strlen(button_states[bs]);
+ else
+ all = 1;
+ while(isspace(*s))++s;
+ if ('(' == *s) {
+ int len;
+ pstyle = 1;
+ if (!(end = strchr(++s, ')'))) {
+ fvwm_msg(ERR,"ReadTitleButton",
+ "missing parenthesis: %s", s);
+ return NULL;
+ }
+ len = end - s + 1;
+ spec = safemalloc(len);
+ strncpy(spec, s, len - 1);
+ spec[len - 1] = 0;
+ } else
+ spec = s;
+
+ while(isspace(*spec))++spec;
+ /* setup temporary in case button read fails */
+ tmpbf.style = SimpleButton;
+#ifdef MULTISTYLE
+ tmpbf.next = NULL;
+#endif
+#ifdef MINI_ICONS
+ tmpbf.u.p = NULL;
+#endif
+
+ if (strncmp(spec, "--",2)==0) {
+ /* only change flags */
+ if (ReadButtonFace(spec, &tb->state[all ? 0 : bs],button,True) && all) {
+ for (i = 0; i < MaxButtonState; ++i)
+ ReadButtonFace(spec, &tb->state[i],-1,False);
+ }
+ }
+ else if (ReadButtonFace(spec, &tmpbf,button,True)) {
+ int b = all ? 0 : bs;
+#ifdef MULTISTYLE
+ if (append) {
+ ButtonFace *tail = &tb->state[b];
+ while (tail->next) tail = tail->next;
+ tail->next = (ButtonFace *)safemalloc(sizeof(ButtonFace));
+ *tail->next = tmpbf;
+ if (all)
+ for (i = 1; i < MaxButtonState; ++i) {
+ tail = &tb->state[i];
+ while (tail->next) tail = tail->next;
+ tail->next = (ButtonFace *)safemalloc(sizeof(ButtonFace));
+ tail->next->style = SimpleButton;
+ tail->next->next = NULL;
+ ReadButtonFace(spec, tail->next, button, False);
+ }
+ }
+ else {
+#endif
+ FreeButtonFace(dpy, &tb->state[b]);
+ tb->state[b] = tmpbf;
+ if (all)
+ for (i = 1; i < MaxButtonState; ++i)
+ ReadButtonFace(spec, &tb->state[i],button,False);
+#ifdef MULTISTYLE
+ }
+#endif
+
+ }
+ if (pstyle) {
+ free(spec);
+ ++end;
+ while(isspace(*end))++end;
+ }
+ return end;
+}
+
+static void FreeMenuFace(Display *dpy, MenuFace *mf)
+{
+ switch (mf->type)
+ {
+#ifdef GRADIENT_BUTTONS
+ case HGradMenu:
+ case VGradMenu:
+ case DGradMenu:
+ /* - should we check visual is not TrueColor before doing this?
+ *
+ * XFreeColors(dpy, Scr.FvwmRoot.attr.colormap,
+ * ms->u.grad.pixels, ms->u.grad.npixels,
+ * AllPlanes); */
+ free(mf->u.grad.pixels);
+ mf->u.grad.pixels = NULL;
+ break;
+#endif
+
+#ifdef PIXMAP_BUTTONS
+ case PixmapMenu:
+ case TiledPixmapMenu:
+ if (mf->u.p)
+ DestroyPicture(dpy, mf->u.p);
+ mf->u.p = NULL;
+ break;
+#endif
+ case SolidMenu:
+ FreeColors(&mf->u.back, 1);
+ default:
+ break;
+ }
+ mf->type = SimpleMenu;
+}
+
+/*****************************************************************************
+ *
+ * Reads a menu face line into a structure (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+static Boolean ReadMenuFace(char *s, MenuFace *mf, int verbose)
+{
+ char *style;
+ char *token;
+ char *action = s;
+
+ s = GetNextToken(s, &style);
+ if (style && strncasecmp(style, "--", 2) == 0)
+ {
+ free(style);
+ return True;
+ }
+
+ FreeMenuFace(dpy, mf);
+ mf->type = SimpleMenu;
+
+ /* determine menu style */
+ if (!style)
+ return True;
+ else if (StrEquals(style,"Solid"))
+ {
+ s = GetNextToken(s, &token);
+ if (token)
+ {
+ mf->type = SolidMenu;
+ mf->u.back = GetColor(token);
+ free(token);
+ }
+ else
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "no color given for Solid face type: %s",
+ action);
+ free(style);
+ return False;
+ }
+ }
+
+#ifdef GRADIENT_BUTTONS
+ else if (StrEquals(style,"HGradient") || StrEquals(style, "VGradient") ||
+ StrEquals(style,"DGradient") || StrEquals(style, "BGradient"))
+ {
+ char *item, **s_colors;
+ int npixels, nsegs, i, sum, perc[128];
+ Pixel *pixels;
+ char gtype = style[0];
+
+ s = GetNextToken(s, &item);
+ if (!item)
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace",
+ "expected number of colors to allocate in gradient");
+ free(style);
+ return False;
+ }
+ npixels = atoi(item);
+ free(item);
+
+ s = GetNextToken(s, &item);
+ if (!item)
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "incomplete gradient style");
+ free(style);
+ return False;
+ }
+
+ if (!(isdigit(*item)))
+ {
+ s_colors = (char **)safemalloc(sizeof(char *) * 2);
+ nsegs = 1;
+ s_colors[0] = item;
+ s = GetNextToken(s, &s_colors[1]);
+ if (!s_colors[1])
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "incomplete gradient style");
+ free(s_colors);
+ free(item);
+ free(style);
+ return False;
+ }
+ perc[0] = 100;
+ }
+ else
+ {
+ nsegs = atoi(item);
+ free(item);
+ if (nsegs < 1)
+ nsegs = 1;
+ if (nsegs > 128)
+ nsegs = 128;
+ s_colors = (char **)safemalloc(sizeof(char *) * (nsegs + 1));
+ for (i = 0; i <= nsegs; ++i)
+ {
+ s = GetNextToken(s, &s_colors[i]);
+ if (i < nsegs)
+ {
+ s = GetNextToken(s, &item);
+ perc[i] = (item) ? atoi(item) : 0;
+ if (item)
+ free(item);
+ }
+ }
+ }
+
+ for (i = 0, sum = 0; i < nsegs; ++i)
+ sum += perc[i];
+
+ if (sum != 100)
+ {
+ if(verbose)
+ fvwm_msg(ERR,"ReadMenuFace", "multi gradient lenghts must sum to 100");
+ for (i = 0; i <= nsegs; ++i)
+ if (s_colors[i])
+ free(s_colors[i]);
+ free(style);
+ free(s_colors);
+ return False;
+ }
+
+ if (npixels < 2)
+ npixels = 2;
+ if (npixels > 128)
+ npixels = 128;
+
+ pixels = AllocNonlinearGradient(s_colors, perc, nsegs, npixels);
+ for (i = 0; i <= nsegs; ++i)
+ if (s_colors[i])
+ free(s_colors[i]);
+ free(s_colors);
+
+ if (!pixels)
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "couldn't create gradient");
+ free(style);
+ return False;
+ }
+
+ mf->u.grad.pixels = pixels;
+ mf->u.grad.npixels = npixels;
+
+ switch (gtype)
+ {
+ case 'h':
+ case 'H':
+ mf->type = HGradMenu;
+ break;
+ case 'v':
+ case 'V':
+ mf->type = VGradMenu;
+ break;
+ case 'd':
+ case 'D':
+ mf->type = DGradMenu;
+ break;
+ default:
+ mf->type = BGradMenu;
+ break;
+ }
+ }
+#endif /* GRADIENT_BUTTONS */
+
+#ifdef PIXMAP_BUTTONS
+ else if (StrEquals(style,"Pixmap") || StrEquals(style,"TiledPixmap"))
+ {
+ s = GetNextToken(s, &token);
+ if (token)
+ {
+ mf->u.p = CachePicture(dpy, Scr.Root, IconPath,
+ PixmapPath,
+ token, Scr.ColorLimit);
+ if (mf->u.p == NULL)
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "couldn't load pixmap %s", token);
+ free(token);
+ free(style);
+ return False;
+ }
+ free(token);
+ mf->type = (StrEquals(style,"TiledPixmap")) ?
+ TiledPixmapMenu : PixmapMenu;
+ }
+ else
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "missing pixmap name for style %s",
+ style);
+ free(style);
+ return False;
+ }
+ }
+#endif /* PIXMAP_BUTTONS */
+
+ else
+ {
+ if(verbose)
+ fvwm_msg(ERR, "ReadMenuFace", "unknown style %s: %s", style, action);
+ free(style);
+ return False;
+ }
+
+ free(style);
+ return True;
+}
+
+#ifdef USEDECOR
+/*****************************************************************************
+ *
+ * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void AddToDecor(FvwmDecor *fl, char *s)
+{
+ if (!s) return;
+ while (*s&&isspace(*s))++s;
+ if (!*s) return;
+ cur_decor = fl;
+ ExecuteFunction(s,NULL,&Event,C_ROOT,-1);
+ cur_decor = NULL;
+}
+
+/*****************************************************************************
+ *
+ * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void ChangeDecor(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int *Module)
+{
+ char *item;
+ int x,y,width,height,old_height,extra_height;
+ FvwmDecor *fl = &Scr.DefaultDecor, *found = NULL;
+ if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
+ return;
+ action = GetNextToken(action, &item);
+ if (!action || !item)
+ {
+ if (item)
+ free(item);
+ return;
+ }
+ /* search for tag */
+ for (; fl; fl = fl->next)
+ if (fl->tag)
+ if (StrEquals(item, fl->tag)) {
+ found = fl;
+ break;
+ }
+ free(item);
+ if (!found) {
+ XBell(dpy, 0);
+ return;
+ }
+ old_height = tmp_win->fl->TitleHeight;
+ tmp_win->fl = found;
+ extra_height = (tmp_win->flags & TITLE) ?
+ (old_height - tmp_win->fl->TitleHeight) : 0;
+ x = tmp_win->frame_x;
+ y = tmp_win->frame_y;
+ width = tmp_win->frame_width;
+ height = tmp_win->frame_height - extra_height;
+ tmp_win->frame_x = 0;
+ tmp_win->frame_y = 0;
+ tmp_win->frame_height = 0;
+ tmp_win->frame_width = 0;
+ SetupFrame(tmp_win,x,y,width,height,True);
+ SetBorder(tmp_win,Scr.Hilite == tmp_win,True,True,None);
+}
+
+/*****************************************************************************
+ *
+ * Destroys an FvwmDecor (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void DestroyDecor(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *item;
+ FvwmDecor *fl = Scr.DefaultDecor.next;
+ FvwmDecor *prev = &Scr.DefaultDecor, *found = NULL;
+
+ action = GetNextToken(action, &item);
+ if (!action || !item)
+ {
+ if (item)
+ free(item);
+ return;
+ }
+
+ /* search for tag */
+ for (; fl; fl = fl->next) {
+ if (fl->tag)
+ if (StrEquals(item, fl->tag)) {
+ found = fl;
+ break;
+ }
+ prev = fl;
+ }
+ free(item);
+
+ if (found && (found != &Scr.DefaultDecor)) {
+ FvwmWindow *fw = Scr.FvwmRoot.next;
+ while(fw != NULL)
+ {
+ if (fw->fl == found)
+ ExecuteFunction("ChangeDecor Default",fw,eventp,
+ C_WINDOW,*Module);
+ fw = fw->next;
+ }
+ prev->next = found->next;
+ DestroyFvwmDecor(found);
+ free(found);
+ }
+}
+
+/*****************************************************************************
+ *
+ * Initiates an AddToDecor (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void add_item_to_decor(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmDecor *fl, *found = NULL;
+ char *item = NULL, *s = action;
+
+ last_menu = NULL;
+
+ s = GetNextToken(s, &item);
+
+ if (!item)
+ return;
+ if (!s)
+ {
+ free(item);
+ return;
+ }
+ /* search for tag */
+ for (fl = &Scr.DefaultDecor; fl; fl = fl->next)
+ if (fl->tag)
+ if (StrEquals(item, fl->tag)) {
+ found = fl;
+ break;
+ }
+ if (!found) { /* then make a new one */
+ found = (FvwmDecor *)safemalloc(sizeof( FvwmDecor ));
+ InitFvwmDecor(found);
+ found->tag = item; /* tag it */
+ /* add it to list */
+ for (fl = &Scr.DefaultDecor; fl->next; fl = fl->next);
+ fl->next = found;
+ } else
+ free(item);
+ if (found) {
+ AddToDecor(found, s);
+ last_decor = found;
+ }
+}
+#endif /* USEDECOR */
+
+
+/*****************************************************************************
+ *
+ * Updates window decoration styles (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void UpdateDecor(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmWindow *fw = Scr.FvwmRoot.next;
+#ifdef USEDECOR
+ FvwmDecor *fl = &Scr.DefaultDecor, *found = NULL;
+ char *item = NULL;
+ action = GetNextToken(action, &item);
+ if (item) {
+ /* search for tag */
+ for (; fl; fl = fl->next)
+ if (fl->tag)
+ if (strcasecmp(item, fl->tag)==0) {
+ found = fl;
+ break;
+ }
+ free(item);
+ }
+#endif
+
+ for (; fw != NULL; fw = fw->next)
+ {
+#ifdef USEDECOR
+ /* update specific decor, or all */
+ if (found) {
+ if (fw->fl == found) {
+ SetBorder(fw,True,True,True,None);
+ SetBorder(fw,False,True,True,None);
+ }
+ }
+ else
+#endif
+ {
+ SetBorder(fw,True,True,True,None);
+ SetBorder(fw,False,True,True,None);
+ }
+ }
+ SetBorder(Scr.Hilite,True,True,True,None);
+}
+
+
+/*****************************************************************************
+ *
+ * Changes a button decoration style (changes by veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+#define SetButtonFlag(a) \
+ do { \
+ int i; \
+ if (multi) { \
+ if (multi&1) \
+ for (i=0;i<5;++i) \
+ if (set) \
+ fl->left_buttons[i].flags |= (a); \
+ else \
+ fl->left_buttons[i].flags &= ~(a); \
+ if (multi&2) \
+ for (i=0;i<5;++i) \
+ if (set) \
+ fl->right_buttons[i].flags |= (a); \
+ else \
+ fl->right_buttons[i].flags &= ~(a); \
+ } else \
+ if (set) \
+ tb->flags |= (a); \
+ else \
+ tb->flags &= ~(a); } while (0)
+
+void ButtonStyle(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int button = 0,n;
+ int multi = 0;
+ char *text = action, *prev;
+ char *parm = NULL;
+ TitleButton *tb = NULL;
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+
+ text = GetNextToken(text, &parm);
+ if (parm && isdigit(*parm))
+ button = atoi(parm);
+
+ if ((parm == NULL) || (button > 10) || (button < 0)) {
+ fvwm_msg(ERR,"ButtonStyle","Bad button style (1) in line %s",action);
+ if (parm)
+ free(parm);
+ return;
+ }
+
+ if (!isdigit(*parm)) {
+ if (StrEquals(parm,"left"))
+ multi = 1; /* affect all left buttons */
+ else if (StrEquals(parm,"right"))
+ multi = 2; /* affect all right buttons */
+ else if (StrEquals(parm,"all"))
+ multi = 3; /* affect all buttons */
+ else {
+ /* we're either resetting buttons or
+ an invalid button set was specified */
+ if (StrEquals(parm,"reset"))
+ ResetAllButtons(fl);
+ else
+ fvwm_msg(ERR,"ButtonStyle","Bad button style (2) in line %s",
+ action);
+ free(parm);
+ return;
+ }
+ }
+ free(parm);
+ if (multi == 0) {
+ /* a single button was specified */
+ if (button==10) button=0;
+ /* which arrays to use? */
+ n=button/2;
+ if((n*2) == button)
+ {
+ /* right */
+ n = n - 1;
+ if(n<0)n=4;
+ tb = &fl->right_buttons[n];
+ }
+ else {
+ /* left */
+ tb = &fl->left_buttons[n];
+ }
+ }
+
+ prev = text;
+ text = GetNextToken(text,&parm);
+ while(parm)
+ {
+ if (strcmp(parm,"-")==0) {
+ char *tok;
+ text = GetNextToken(text, &tok);
+ while (tok)
+ {
+ int set = 1;
+
+ if (*tok == '!') { /* flag negate */
+ set = 0;
+ ++tok;
+ }
+ if (StrEquals(tok,"Clear")) {
+ int i;
+ if (multi) {
+ if (multi&1) {
+ for (i=0;i<5;++i)
+ if (set)
+ fl->left_buttons[i].flags = 0;
+ else
+ fl->left_buttons[i].flags = ~0;
+ }
+ if (multi&2) {
+ for (i=0;i<5;++i) {
+ if (set)
+ fl->right_buttons[i].flags = 0;
+ else
+ fl->right_buttons[i].flags = ~0;
+ }
+ }
+ } else {
+ if (set)
+ tb->flags = 0;
+ else
+ tb->flags = ~0;
+ }
+ }
+ else if (strncasecmp(tok,"MWMDecorMenu",12)==0) {
+ SetButtonFlag(MWMDecorMenu);
+ } else if (strncasecmp(tok,"MWMDecorMin",11)==0) {
+ SetButtonFlag(MWMDecorMinimize);
+ } else if (strncasecmp(tok,"MWMDecorMax",11)==0) {
+ SetButtonFlag(MWMDecorMaximize);
+ } else {
+ fvwm_msg(ERR, "ButtonStyle",
+ "unknown title button flag %s -- line: %s",
+ tok, text);
+ }
+ if (set)
+ free(tok);
+ else
+ free(tok - 1);
+ text = GetNextToken(text, &tok);
+ }
+ free(parm);
+ break;
+ } else {
+ if (multi) {
+ int i;
+ if (multi&1)
+ for (i=0;i<5;++i)
+ text = ReadTitleButton(prev, &fl->left_buttons[i],
+ False, i*2+1);
+ if (multi&2)
+ for (i=0;i<5;++i)
+ text = ReadTitleButton(prev, &fl->right_buttons[i],
+ False, i*2);
+ }
+ else if (!(text = ReadTitleButton(prev, tb, False, button))) {
+ free(parm);
+ break;
+ }
+ }
+ free(parm);
+ prev = text;
+ text = GetNextToken(text,&parm);
+ }
+}
+
+#ifdef MULTISTYLE
+/*****************************************************************************
+ *
+ * Appends a button decoration style (veliaa@rpi.edu)
+ *
+ ****************************************************************************/
+void AddButtonStyle(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int button = 0,n;
+ int multi = 0;
+ char *text = action, *prev;
+ char *parm = NULL;
+ TitleButton *tb = NULL;
+#ifdef USEDECOR
+ FvwmDecor *fl = cur_decor ? cur_decor : &Scr.DefaultDecor;
+#else
+ FvwmDecor *fl = &Scr.DefaultDecor;
+#endif
+
+ text = GetNextToken(text, &parm);
+ if (parm && isdigit(*parm))
+ button = atoi(parm);
+
+ if ((parm == NULL) || (button > 10) || (button < 0)) {
+ fvwm_msg(ERR,"ButtonStyle","Bad button style (1) in line %s",action);
+ if (parm)
+ free(parm);
+ return;
+ }
+
+ if (!isdigit(*parm)) {
+ if (StrEquals(parm,"left"))
+ multi = 1; /* affect all left buttons */
+ else if (StrEquals(parm,"right"))
+ multi = 2; /* affect all right buttons */
+ else if (StrEquals(parm,"all"))
+ multi = 3; /* affect all buttons */
+ else {
+ /* we're either resetting buttons or
+ an invalid button set was specified */
+ if (StrEquals(parm,"reset"))
+ ResetAllButtons(fl);
+ else
+ fvwm_msg(ERR,"ButtonStyle","Bad button style (2) in line %s",
+ action);
+ free(parm);
+ return;
+ }
+ }
+ free(parm);
+ if (multi == 0) {
+ /* a single button was specified */
+ if (button==10) button=0;
+ /* which arrays to use? */
+ n=button/2;
+ if((n*2) == button)
+ {
+ /* right */
+ n = n - 1;
+ if(n<0)n=4;
+ tb = &fl->right_buttons[n];
+ }
+ else {
+ /* left */
+ tb = &fl->left_buttons[n];
+ }
+ }
+
+ prev = text;
+ text = GetNextToken(text,&parm);
+ while(parm)
+ {
+ if (multi) {
+ int i;
+ if (multi&1)
+ for (i=0;i<5;++i)
+ text = ReadTitleButton(prev, &fl->left_buttons[i], True, i*2+1);
+ if (multi&2)
+ for (i=0;i<5;++i)
+ text = ReadTitleButton(prev, &fl->right_buttons[i], True, i*2);
+ }
+ else if (!(text = ReadTitleButton(prev, tb, True, button))) {
+ free(parm);
+ break;
+ }
+ free(parm);
+ prev = text;
+ text = GetNextToken(text,&parm);
+ }
+}
+#endif /* MULTISTYLE */
+
+
+void SetEnv(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *szVar = NULL;
+ char *szValue = NULL;
+ char *szPutenv = NULL;
+ size_t len;
+
+ action = GetNextToken(action,&szVar);
+ if (!szVar)
+ return;
+ action = GetNextToken(action,&szValue);
+ if (!szValue)
+ {
+ free(szVar);
+ return;
+ }
+
+ len = strlen(szVar)+strlen(szValue)+2;
+ szPutenv = safemalloc(len);
+ snprintf(szPutenv,len,"%s=%s",szVar,szValue);
+ putenv(szPutenv);
+ free(szVar);
+ free(szValue);
+}
+
+/**********************************************************************
+ * Parses the flag string and returns the text between [ ] or ( )
+ * characters. The start of the rest of the line is put in restptr.
+ * Note that the returned string is allocated here and it must be
+ * freed when it is not needed anymore.
+ **********************************************************************/
+char *CreateFlagString(char *string, char **restptr)
+{
+ char *retval;
+ char *c;
+ char *start;
+ char closeopt;
+ int length;
+
+ c = string;
+ while (isspace(*c) && (*c != 0))
+ c++;
+
+ if (*c == '[' || *c == '(')
+ {
+ /* Get the text between [ ] or ( ) */
+ if (*c == '[')
+ closeopt = ']';
+ else
+ closeopt = ')';
+ c++;
+ start = c;
+ length = 0;
+ while (*c != closeopt) {
+ if (*c == 0) {
+ fvwm_msg(ERR, "CreateConditionMask",
+ "Conditionals require closing parenthesis");
+ *restptr = NULL;
+ return NULL;
+ }
+ c++;
+ length++;
+ }
+
+ /* We must allocate a new string because we null terminate the string
+ * between the [ ] or ( ) characters.
+ */
+ retval = safemalloc(length + 1);
+ strncpy(retval, start, length);
+ retval[length] = 0;
+
+ *restptr = c + 1;
+ }
+ else {
+ retval = NULL;
+ *restptr = c;
+ }
+
+ return retval;
+}
+
+/**********************************************************************
+ * The name field of the mask is allocated in CreateConditionMask.
+ * It must be freed.
+ **********************************************************************/
+void FreeConditionMask(WindowConditionMask *mask)
+{
+ if (mask->needsName)
+ free(mask->name);
+ else if (mask->needsNotName)
+ free(mask->name - 1);
+}
+
+/* Assign the default values for the window mask */
+void DefaultConditionMask(WindowConditionMask *mask)
+{
+ mask->name = NULL;
+ mask->needsCurrentDesk = 0;
+ mask->needsCurrentPage = 0;
+ mask->needsName = 0;
+ mask->needsNotName = 0;
+ mask->useCirculateHit = 0;
+ mask->useCirculateHitIcon = 0;
+ mask->onFlags = 0;
+ mask->offFlags = 0;
+}
+
+/**********************************************************************
+ * Note that this function allocates the name field of the mask struct.
+ * FreeConditionMask must be called for the mask when the mask is discarded.
+ **********************************************************************/
+void CreateConditionMask(char *flags, WindowConditionMask *mask)
+{
+ char *condition;
+ char *prev_condition = NULL;
+ char *tmp;
+
+ if (flags == NULL)
+ return;
+
+ /* Next parse the flags in the string. */
+ tmp = flags;
+ tmp = GetNextToken(tmp, &condition);
+
+ while (condition)
+ {
+ if (StrEquals(condition,"Iconic"))
+ mask->onFlags |= ICONIFIED;
+ else if(StrEquals(condition,"!Iconic"))
+ mask->offFlags |= ICONIFIED;
+ else if(StrEquals(condition,"Visible"))
+ mask->onFlags |= VISIBLE;
+ else if(StrEquals(condition,"!Visible"))
+ mask->offFlags |= VISIBLE;
+ else if(StrEquals(condition,"Sticky"))
+ mask->onFlags |= STICKY;
+ else if(StrEquals(condition,"!Sticky"))
+ mask->offFlags |= STICKY;
+ else if(StrEquals(condition,"Maximized"))
+ mask->onFlags |= MAXIMIZED;
+ else if(StrEquals(condition,"!Maximized"))
+ mask->offFlags |= MAXIMIZED;
+ else if(StrEquals(condition,"Transient"))
+ mask->onFlags |= TRANSIENT;
+ else if(StrEquals(condition,"!Transient"))
+ mask->offFlags |= TRANSIENT;
+ else if(StrEquals(condition,"Raised"))
+ mask->onFlags |= RAISED;
+ else if(StrEquals(condition,"!Raised"))
+ mask->offFlags |= RAISED;
+ else if(StrEquals(condition,"CurrentDesk"))
+ mask->needsCurrentDesk = 1;
+ else if(StrEquals(condition,"CurrentPage"))
+ {
+ mask->needsCurrentDesk = 1;
+ mask->needsCurrentPage = 1;
+ }
+ else if(StrEquals(condition,"CurrentPageAnyDesk") ||
+ StrEquals(condition,"CurrentScreen"))
+ mask->needsCurrentPage = 1;
+ else if(StrEquals(condition,"CirculateHit"))
+ mask->useCirculateHit = 1;
+ else if(StrEquals(condition,"CirculateHitIcon"))
+ mask->useCirculateHitIcon = 1;
+ else if(!mask->needsName && !mask->needsNotName)
+ {
+ /* only 1st name to avoid mem leak */
+ mask->name = condition;
+ condition = NULL;
+ if (mask->name[0] == '!')
+ {
+ mask->needsNotName = 1;
+ mask->name++;
+ }
+ else
+ mask->needsName = 1;
+ }
+
+ if (prev_condition)
+ free(prev_condition);
+
+ prev_condition = condition;
+ tmp = GetNextToken(tmp, &condition);
+ }
+
+ if(prev_condition != NULL)
+ free(prev_condition);
+}
+
+/**********************************************************************
+ * Checks whether the given window matches the mask created with
+ * CreateConditionMask.
+ **********************************************************************/
+Bool MatchesConditionMask(FvwmWindow *fw, WindowConditionMask *mask)
+{
+ Bool fMatchesName;
+ Bool fMatchesIconName;
+ Bool fMatchesClass;
+ Bool fMatchesResource;
+ Bool fMatches;
+
+ if ((mask->onFlags & fw->flags) != mask->onFlags)
+ return 0;
+
+ if ((mask->offFlags & fw->flags) != 0)
+ return 0;
+
+ if (!mask->useCirculateHit && (fw->flags & CirculateSkip))
+ return 0;
+
+ /* This logic looks terribly wrong to me, but it was this way before so I
+ * did not change it (domivogt (24-Dec-1998)) */
+ if (!mask->useCirculateHitIcon && fw->flags & ICONIFIED &&
+ fw->flags & CirculateSkipIcon)
+ return 0;
+
+ if (fw->flags & ICONIFIED && fw->flags & TRANSIENT &&
+ fw->tmpflags.IconifiedByParent)
+ return 0;
+
+ if (mask->needsCurrentDesk && fw->Desk != Scr.CurrentDesk)
+ return 0;
+
+ if (mask->needsCurrentPage && !(fw->frame_x < Scr.MyDisplayWidth &&
+ fw->frame_y < Scr.MyDisplayHeight &&
+ fw->frame_x + fw->frame_width > 0 &&
+ fw->frame_y + fw->frame_height > 0))
+ return 0;
+
+ /* Yes, I know this could be shorter, but it's hard to understand then */
+ fMatchesName = matchWildcards(mask->name, fw->name);
+ fMatchesIconName = matchWildcards(mask->name, fw->icon_name);
+ fMatchesClass = (fw->class.res_class &&
+ matchWildcards(mask->name,fw->class.res_class));
+ fMatchesResource = (fw->class.res_name &&
+ matchWildcards(mask->name, fw->class.res_name));
+ fMatches = (fMatchesName || fMatchesIconName || fMatchesClass ||
+ fMatchesResource);
+
+ if (mask->needsName && !fMatches)
+ return 0;
+
+ if (mask->needsNotName && fMatches)
+ return 0;
+
+ return 1;
+}
+
+/**************************************************************************
+ *
+ * Direction = 1 ==> "Next" operation
+ * Direction = -1 ==> "Previous" operation
+ * Direction = 0 ==> operation on current window (returns pass or fail)
+ *
+ **************************************************************************/
+FvwmWindow *Circulate(char *action, int Direction, char **restofline)
+{
+ int pass = 0;
+ FvwmWindow *fw, *found = NULL;
+ WindowConditionMask mask;
+ char *flags;
+
+ /* Create window mask */
+ flags = CreateFlagString(action, restofline);
+ DefaultConditionMask(&mask);
+ if (Direction == 0) { /* override for Current [] */
+ mask.useCirculateHit = 1;
+ mask.useCirculateHitIcon = 1;
+ }
+ CreateConditionMask(flags, &mask);
+ if (flags)
+ free(flags);
+
+ if(Scr.Focus != NULL)
+ {
+ if(Direction == 1)
+ fw = Scr.Focus->prev;
+ else if(Direction == -1)
+ fw = Scr.Focus->next;
+ else
+ fw = Scr.Focus;
+ }
+ else
+ fw = NULL;
+
+ while((pass < 3)&&(found == NULL))
+ {
+ while((fw != NULL)&&(found==NULL)&&(fw != &Scr.FvwmRoot))
+ {
+#ifdef FVWM_DEBUG_MSGS
+ fvwm_msg(DBG,"Circulate","Trying %s",fw->name);
+#endif /* FVWM_DEBUG_MSGS */
+ /* Make CirculateUp and CirculateDown take args. by Y.NOMURA */
+ if (MatchesConditionMask(fw, &mask))
+ found = fw;
+ else
+ {
+ if(Direction == 1)
+ fw = fw->prev;
+ else
+ fw = fw->next;
+ }
+ if (Direction == 0)
+ {
+ FreeConditionMask(&mask);
+ return found;
+ }
+ }
+ if((fw == NULL)||(fw == &Scr.FvwmRoot))
+ {
+ if(Direction == 1)
+ {
+ /* Go to end of list */
+ fw = &Scr.FvwmRoot;
+ while((fw) && (fw->next != NULL))
+ {
+ fw = fw->next;
+ }
+ }
+ else
+ {
+ /* GO to top of list */
+ fw = Scr.FvwmRoot.next;
+ }
+ }
+ pass++;
+ }
+ FreeConditionMask(&mask);
+ return found;
+}
+
+void PrevFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmWindow *found;
+ char *restofline;
+
+ found = Circulate(action, -1, &restofline);
+ if(found != NULL && restofline != NULL)
+ {
+ ExecuteFunction(restofline,found,eventp,C_WINDOW,*Module);
+ }
+
+}
+
+void NextFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmWindow *found;
+ char *restofline;
+
+ found = Circulate(action, 1, &restofline);
+ if(found != NULL && restofline != NULL)
+ {
+ ExecuteFunction(restofline,found,eventp,C_WINDOW,*Module);
+ }
+
+}
+
+void NoneFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmWindow *found;
+ char *restofline;
+
+ found = Circulate(action, 1, &restofline);
+ if(found == NULL && restofline != NULL)
+ {
+ ExecuteFunction(restofline,NULL,eventp,C_ROOT,*Module);
+ }
+}
+
+void CurrentFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmWindow *found;
+ char *restofline;
+
+ found = Circulate(action, 0, &restofline);
+ if(found != NULL && restofline != NULL)
+ {
+ ExecuteFunction(restofline,found,eventp,C_WINDOW,*Module);
+ }
+}
+
+static void GetDirectionReference(FvwmWindow *w, int *x, int *y)
+{
+ if ((w->flags & ICONIFIED) != 0)
+ {
+ *x = w->icon_x_loc + w->icon_w_width / 2;
+ *y = w->icon_y_loc + w->icon_w_height / 2;
+ }
+ else
+ {
+ *x = w->frame_x + w->frame_width / 2;
+ *y = w->frame_y + w->frame_height / 2;
+ }
+}
+
+/**********************************************************************
+ * Execute a function to the closest window in the given
+ * direction.
+ **********************************************************************/
+void DirectionFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action, int *Module)
+{
+ char *directions[] = { "North", "East", "South", "West", "NorthEast",
+ "SouthEast", "SouthWest", "NorthWest", NULL };
+ int my_x;
+ int my_y;
+ int his_x;
+ int his_y;
+ int score;
+ int offset;
+ int distance;
+ int best_score;
+ FvwmWindow *window;
+ FvwmWindow *best_window;
+ int dir;
+ char *flags;
+ char *restofline;
+ char *tmp;
+ WindowConditionMask mask;
+
+ /* Parse the direction. */
+ action = GetNextToken(action, &tmp);
+ dir = GetTokenIndex(tmp, directions, 0, NULL);
+ if (dir == -1)
+ {
+ fvwm_msg(ERR, "Direction","Invalid direction %s", (tmp)? tmp : "");
+ if (tmp)
+ free(tmp);
+ return;
+ }
+ if (tmp)
+ free(tmp);
+
+ /* Create the mask for flags */
+ flags = CreateFlagString(action, &restofline);
+ if (!restofline)
+ {
+ if (flags)
+ free(flags);
+ return;
+ }
+ DefaultConditionMask(&mask);
+ CreateConditionMask(flags, &mask);
+ if (flags)
+ free(flags);
+
+ /* If there is a focused window, use that as a starting point.
+ * Otherwise we use the pointer as a starting point. */
+ if (tmp_win != NULL)
+ {
+ GetDirectionReference(tmp_win, &my_x, &my_y);
+ }
+ else
+ XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
+ &my_x, &my_y, &JunkX, &JunkY, &JunkMask);
+
+ /* Next we iterate through all windows and choose the closest one in
+ * the wanted direction.
+ */
+ best_window = NULL;
+ best_score = -1;
+ for (window = Scr.FvwmRoot.next; window != NULL; window = window->next) {
+ /* Skip every window that does not match conditionals.
+ * Skip also currently focused window. That would be too close. :)
+ */
+ if (window == tmp_win || !MatchesConditionMask(window, &mask))
+ continue;
+
+ /* Calculate relative location of the window. */
+ GetDirectionReference(window, &his_x, &his_y);
+ his_x -= my_x;
+ his_y -= my_y;
+
+ if (dir > 3)
+ {
+ int tx;
+ /* Rotate the diagonals 45 degrees counterclockwise. To do this,
+ * multiply the matrix /+h +h\ with the vector (x y).
+ * \-h +h/
+ * h = sqrt(0.5). We can set h := 1 since absolute distance doesn't
+ * matter here. */
+ tx = his_x + his_y;
+ his_y = -his_x + his_y;
+ his_x = tx;
+ }
+ /* Arrange so that distance and offset are positive in desired direction.
+ */
+ switch (dir)
+ {
+ case 0: /* N */
+ case 2: /* S */
+ case 4: /* NE */
+ case 6: /* SW */
+ offset = (his_x < 0) ? -his_x : his_x;
+ distance = (dir == 0 || dir == 4) ? -his_y : his_y;
+ break;
+ case 1: /* E */
+ case 3: /* W */
+ case 5: /* SE */
+ case 7: /* NW */
+ offset = (his_y < 0) ? -his_y : his_y;
+ distance = (dir == 3 || dir == 7) ? -his_x : his_x;
+ break;
+ }
+
+ /* Target must be in given direction. */
+ if (distance <= 0) continue;
+
+ /* Calculate score for this window. The smaller the better. */
+ score = 1024 * offset / distance + 2 * distance + 2 * offset;
+ if (best_score == -1 || score < best_score) {
+ best_window = window;
+ best_score = score;
+ }
+ } /* for */
+
+ if (best_window != NULL)
+ ExecuteFunction(restofline, best_window, eventp, C_WINDOW, *Module);
+
+ FreeConditionMask(&mask);
+}
+
+void WindowIdFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ FvwmWindow *found=NULL,*t;
+ char *num;
+ unsigned long win;
+
+ action = GetNextToken(action, &num);
+
+ if (num)
+ {
+ win = (unsigned long)strtol(num,NULL,0); /* SunOS doesn't have strtoul */
+ free(num);
+ }
+ else
+ win = 0;
+ for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
+ {
+ if (t->w == win)
+ {
+ found = t;
+ break;
+ }
+ }
+ if(found)
+ {
+ ExecuteFunction(action,found,eventp,C_WINDOW,*Module);
+ }
+}
+
+
+void module_zapper(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *condition;
+
+ GetNextToken(action,&condition);
+ if (!condition)
+ return;
+ KillModuleByName(condition);
+ free(condition);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Reborder - Removes fvwm border windows
+ *
+ ************************************************************************/
+void Recapture(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ XEvent event;
+
+ /* Wow, this grabbing speeds up recapture tremendously! I think that is the
+ * solution for this weird -blackout option. */
+ MyXGrabServer(dpy);
+ GrabEm(WAIT);
+ BlackoutScreen(); /* if they want to hide the recapture */
+ CaptureAllWindows();
+ UnBlackoutScreen();
+ /* Throw away queued up events. We don't want user input during a
+ * recapture. The window the user clicks in might disapper at the very same
+ * moment and the click goes through to the root window. Not goot */
+ while (XCheckMaskEvent(dpy, ButtonPressMask|ButtonReleaseMask|
+ ButtonMotionMask|PointerMotionMask|EnterWindowMask|
+ LeaveWindowMask, &event) != False)
+ ;
+ UngrabEm();
+ MyXUngrabServer(dpy);
+ XSync(dpy, 0);
+}
+
+void SetGlobalOptions(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *opt;
+
+ /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
+ for (action = GetNextOption(action, &opt); opt;
+ action = GetNextOption(action, &opt))
+ {
+ /* fvwm_msg(DBG,"SetGlobalOptions"," opt == '%s'\n",opt); */
+ /* fvwm_msg(DBG,"SetGlobalOptions"," remaining == '%s'\n",
+ action?action:"(NULL)"); */
+ if (StrEquals(opt,"SMARTPLACEMENTISREALLYSMART"))
+ {
+ Scr.SmartPlacementIsClever = True;
+ }
+ else if (StrEquals(opt,"SMARTPLACEMENTISNORMAL"))
+ {
+ Scr.SmartPlacementIsClever = False;
+ }
+ else if (StrEquals(opt,"CLICKTOFOCUSDOESNTPASSCLICK"))
+ {
+ Scr.ClickToFocusPassesClick = False;
+ }
+ else if (StrEquals(opt,"CLICKTOFOCUSPASSESCLICK"))
+ {
+ Scr.ClickToFocusPassesClick = True;
+ }
+ else if (StrEquals(opt,"CLICKTOFOCUSDOESNTRAISE"))
+ {
+ Scr.ClickToFocusRaises = False;
+ }
+ else if (StrEquals(opt,"CLICKTOFOCUSRAISES"))
+ {
+ Scr.ClickToFocusRaises = True;
+ }
+ else if (StrEquals(opt,"MOUSEFOCUSCLICKDOESNTRAISE"))
+ {
+ Scr.MouseFocusClickRaises = False;
+ }
+ else if (StrEquals(opt,"MOUSEFOCUSCLICKRAISES"))
+ {
+ Scr.MouseFocusClickRaises = True;
+ }
+ else if (StrEquals(opt,"NOSTIPLEDTITLES"))
+ {
+ Scr.StipledTitles = False;
+ }
+ else if (StrEquals(opt,"STIPLEDTITLES"))
+ {
+ Scr.StipledTitles = True;
+ }
+ /* RBW - 11/14/1998 - I'll eventually remove these. */
+/*
+ else if (StrEquals(opt,"STARTSONPAGEMODIFIESUSPOSITION"))
+ {
+ Scr.go.ModifyUSP = True;
+ }
+ else if (StrEquals(opt,"STARTSONPAGEHONORSUSPOSITION"))
+ {
+ Scr.go.ModifyUSP = False;
+ }
+*/
+ else if (StrEquals(opt,"CAPTUREHONORSSTARTSONPAGE"))
+ {
+ Scr.go.CaptureHonorsStartsOnPage = True;
+ }
+ else if (StrEquals(opt,"CAPTUREIGNORESSTARTSONPAGE"))
+ {
+ Scr.go.CaptureHonorsStartsOnPage = False;
+ }
+ else if (StrEquals(opt,"RECAPTUREHONORSSTARTSONPAGE"))
+ {
+ Scr.go.RecaptureHonorsStartsOnPage = True;
+ }
+ else if (StrEquals(opt,"RECAPTUREIGNORESSTARTSONPAGE"))
+ {
+ Scr.go.RecaptureHonorsStartsOnPage = False;
+ }
+ else if (StrEquals(opt,"ACTIVEPLACEMENTHONORSSTARTSONPAGE"))
+ {
+ Scr.go.ActivePlacementHonorsStartsOnPage = True;
+ }
+ else if (StrEquals(opt,"ACTIVEPLACEMENTIGNORESSTARTSONPAGE"))
+ {
+ Scr.go.ActivePlacementHonorsStartsOnPage = False;
+ }
+ else
+ fvwm_msg(ERR,"SetGlobalOptions","Unknown Global Option '%s'",opt);
+ if (opt) /* should never be null, but checking anyways... */
+ free(opt);
+ }
+ if (opt)
+ free(opt);
+}
+
+void Emulate(XEvent *eventp, Window junk, FvwmWindow *tmp_win,
+ unsigned long context, char *action, int* Module)
+{
+ char *style;
+
+ GetNextToken(action, &style);
+ if (!style || StrEquals(style, "fvwm"))
+ {
+ Scr.gs.EmulateMWM = False;
+ Scr.gs.EmulateWIN = False;
+ }
+ else if (StrEquals(style, "mwm"))
+ {
+ Scr.gs.EmulateMWM = True;
+ Scr.gs.EmulateWIN = False;
+ }
+ else if (StrEquals(style, "win"))
+ {
+ Scr.gs.EmulateMWM = False;
+ Scr.gs.EmulateWIN = True;
+ }
+ else
+ {
+ fvwm_msg(ERR, "Emulate", "Unknown style '%s'", style);
+ }
+ free(style);
+ ApplyDefaultFontAndColors();
+ return;
+}
+
+void SetColorLimit(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ int val;
+
+ if (GetIntegerArguments(action, NULL, &val, 1) != 1)
+ {
+ fvwm_msg(ERR,"SetColorLimit","ColorLimit requires one argument");
+ return;
+ }
+
+ Scr.ColorLimit = (long)val;
+}
+
+
+extern float rgpctMovementDefault[32];
+extern int cpctMovementDefault;
+extern int cmsDelayDefault;
+
+
+/* set animation parameters */
+void set_animation(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+ unsigned long context, char *action,int* Module)
+{
+ char *opt;
+ int delay;
+ float pct;
+ int i = 0;
+
+ action = GetNextToken(action, &opt);
+ if (!opt || sscanf(opt,"%d",&delay) != 1) {
+ fvwm_msg(ERR,"SetAnimation",
+ "Improper milli-second delay as first argument");
+ if (opt)
+ free(opt);
+ return;
+ }
+ free(opt);
+ if (delay > 500) {
+ fvwm_msg(WARN,"SetAnimation",
+ "Using longer than .5 seconds as between frame animation delay");
+ }
+ cmsDelayDefault = delay;
+ action = GetNextToken(action, &opt);
+ while (opt) {
+ if (sscanf(opt,"%f",&pct) != 1) {
+ fvwm_msg(ERR,"SetAnimation",
+ "Use fractional values ending in 1.0 as args 2 and on");
+ free(opt);
+ return;
+ }
+ rgpctMovementDefault[i++] = pct;
+ free(opt);
+ action = GetNextToken(action, &opt);
+ }
+ /* No pct entries means don't change them at all */
+ if (i>0 && rgpctMovementDefault[i-1] != 1.0) {
+ rgpctMovementDefault[i++] = 1.0;
+ }
+}