fvwm1/fvwm/functions.c
2019-08-26 23:33:33 +01:00

1712 lines
42 KiB
C

/****************************************************************************
* This module is based on Twm, but has been siginificantly modified
* by Rob Nation
****************************************************************************/
/*****************************************************************************/
/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
/** Salt Lake City, Utah **/
/** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
/** Cambridge, Massachusetts **/
/** **/
/** All Rights Reserved **/
/** **/
/** Permission to use, copy, modify, and distribute this software and **/
/** its documentation for any purpose and without fee is hereby **/
/** granted, provided that the above copyright notice appear in all **/
/** copies and that both that copyright notice and this permis- **/
/** sion notice appear in supporting documentation, and that the **/
/** names of Evans & Sutherland and M.I.T. not be used in advertising **/
/** in publicity pertaining to distribution of the software without **/
/** specific, written prior permission. **/
/** **/
/** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
/** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
/** OR PERFORMANCE OF THIS SOFTWARE. **/
/*****************************************************************************/
/***********************************************************************
*
* fvwm menu code
*
***********************************************************************/
#include "../configure.h"
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "fvwm.h"
#include "menus.h"
#include "misc.h"
#include "parse.h"
#include "screen.h"
#include "module.h"
extern XEvent Event;
extern FvwmWindow *Tmp_win;
extern int menuFromFrameOrWindowOrTitlebar;
extern DoHandlePageing;
extern char **g_argv;
/***********************************************************************
*
* Procedure:
* ExecuteFunction - execute a fvwm built in function
*
* Inputs:
* func - the function to execute
* action - the menu action to execute
* w - the window to execute this function on
* tmp_win - the fvwm window structure
* event - the event that caused the function
* context - the context in which the button was pressed
* val1,val2 - the distances to move in a scroll operation
*
***********************************************************************/
void ExecuteFunction(int func,char *action, Window in_w, FvwmWindow *tmp_win,
XEvent *eventp, unsigned long context,long val1,long val2,
int val1_unit, int val2_unit, MenuRoot *menu, int Module)
{
FvwmWindow *t,*temp;
char *junk, *junkC;
unsigned long junkN;
int junkD;
int x,y;
Window w;
#ifndef NON_VIRTUAL
int delta_x,delta_y;
#endif
int warp_x=0,warp_y=0;
#ifndef NO_PAGER
Pixel TextColor,BackColor;
Pixmap BackPixmap;
#endif
/* Defer Execution may wish to alter this value */
w = in_w;
switch (func)
{
case F_NOP:
case F_TITLE:
break;
case F_BEEP:
XBell(dpy, Scr.screen);
break;
case F_RESIZE:
if (DeferExecution(eventp,&w,&tmp_win,&context, MOVE, ButtonPress))
break;
if(tmp_win == NULL)
break;
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
tmp_win->flags &= ~MAXIMIZED;
resize_window(w,tmp_win,val1,val2,val1_unit,val2_unit);
break;
case F_MOVE:
if (DeferExecution(eventp,&w,&tmp_win,&context, MOVE,ButtonPress))
break;
if(tmp_win == NULL)
break;
move_window(eventp,w,tmp_win,context,val1,val2,val1_unit,val2_unit);
break;
#ifndef NON_VIRTUAL
case F_SCROLL:
if((val1 > -100000)&&(val1 < 100000))
x=Scr.Vx + val1*val1_unit/100;
else
x = Scr.Vx + (val1/1000)*val1_unit/100;
if((val2 > -100000)&&(val2 < 100000))
y=Scr.Vy + val2*val2_unit/100;
else
y = Scr.Vy + (val2/1000)*val2_unit/100;
if(((val1 <= -100000)||(val1 >= 100000))&&(x>Scr.VxMax))
{
x = 0;
y += Scr.MyDisplayHeight;
if(y > Scr.VyMax)
y=0;
}
if(((val1 <= -100000)||(val1 >= 100000))&&(x<0))
{
x = Scr.VxMax;
y -= Scr.MyDisplayHeight;
if(y < 0)
y=Scr.VyMax;
}
if(((val2 <= -100000)||(val2>= 100000))&&(y>Scr.VyMax))
{
y = 0;
x += Scr.MyDisplayWidth;
if(x > Scr.VxMax)
x=0;
}
if(((val2 <= -100000)||(val2>= 100000))&&(y<0))
{
y = Scr.VyMax;
x -= Scr.MyDisplayWidth;
if(x < 0)
x=Scr.VxMax;
}
MoveViewport(x,y,True);
break;
#endif
case F_MOVECURSOR:
XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
&x,&y,&JunkX, &JunkY, &JunkMask);
#ifndef NON_VIRTUAL
delta_x = 0;
delta_y = 0;
warp_x = 0;
warp_y = 0;
if(x >= Scr.MyDisplayWidth -2)
{
delta_x = Scr.EdgeScrollX;
warp_x = Scr.EdgeScrollX - 4;
}
if(y>= Scr.MyDisplayHeight -2)
{
delta_y = Scr.EdgeScrollY;
warp_y = Scr.EdgeScrollY - 4;
}
if(x < 2)
{
delta_x = -Scr.EdgeScrollX;
warp_x = -Scr.EdgeScrollX + 4;
}
if(y < 2)
{
delta_y = -Scr.EdgeScrollY;
warp_y = -Scr.EdgeScrollY + 4;
}
if(Scr.Vx + delta_x < 0)
delta_x = -Scr.Vx;
if(Scr.Vy + delta_y < 0)
delta_y = -Scr.Vy;
if(Scr.Vx + delta_x > Scr.VxMax)
delta_x = Scr.VxMax - Scr.Vx;
if(Scr.Vy + delta_y > Scr.VyMax)
delta_y = Scr.VyMax - Scr.Vy;
if((delta_x!=0)||(delta_y!=0))
{
MoveViewport(Scr.Vx + delta_x,Scr.Vy+delta_y,True);
XWarpPointer(dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
Scr.MyDisplayHeight,
x - warp_x,
y - warp_y);
}
#endif
XWarpPointer(dpy, Scr.Root, Scr.Root, 0, 0, Scr.MyDisplayWidth,
Scr.MyDisplayHeight, x + val1*val1_unit/100-warp_x,
y+val2*val2_unit/100 - warp_y);
break;
case F_ICONIFY:
if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, ButtonRelease))
break;
if(tmp_win == NULL)
break;
if (tmp_win->flags & ICONIFIED)
{
if(val1 <=0)
DeIconify(tmp_win);
}
else
{
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
if(val1 >=0)
{
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
Iconify(tmp_win,eventp->xbutton.x_root-5,eventp->xbutton.y_root-5);
}
}
break;
case F_RAISE:
if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
break;
if(tmp_win)
RaiseWindow(tmp_win);
if (LookInList(Scr.TheList,tmp_win->name, &tmp_win->class, &junk, &junkD,
&junkD, &junkD, &junkC, &junkC, &junkN)& STAYSONTOP_FLAG)
tmp_win->flags |= ONTOP;
KeepOnTop();
break;
case F_LOWER:
if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, ButtonRelease))
break;
if(tmp_win == NULL)
break;
LowerWindow(tmp_win);
tmp_win->flags &= ~ONTOP;
break;
case F_DESTROY:
if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY, ButtonRelease))
break;
if(tmp_win == NULL)
break;
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
#ifndef NO_PAGER
/* Dont delete the pager - it crashes the program! */
if((tmp_win->w == Scr.Pager_w)||(tmp_win == Scr.FvwmPager))
break;
#endif
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);
break;
case F_DELETE:
if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY,ButtonRelease))
break;
if(tmp_win == NULL)
break;
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
#ifndef NO_PAGER
/* Dont delete the pager - it crashes the program! */
if((tmp_win->w == Scr.Pager_w)||(tmp_win == Scr.FvwmPager))
break;
#endif
if (tmp_win->flags & DoesWmDeleteWindow)
{
send_clientmessage (tmp_win->w, _XA_WM_DELETE_WINDOW, CurrentTime);
break;
}
else
XBell (dpy, Scr.screen);
XSync(dpy,0);
break;
case F_CLOSE:
if (DeferExecution(eventp,&w,&tmp_win,&context, DESTROY,ButtonRelease))
break;
if(tmp_win == NULL)
break;
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
#ifndef NO_PAGER
/* Dont delete the pager - it crashes the program! */
if((tmp_win->w == Scr.Pager_w)||(tmp_win == Scr.FvwmPager))
break;
#endif
if (tmp_win->flags & DoesWmDeleteWindow)
{
send_clientmessage (tmp_win->w, _XA_WM_DELETE_WINDOW, CurrentTime);
break;
}
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);
break;
case F_RESTART:
Done(1, action);
break;
case F_EXEC:
XGrabPointer(dpy, Scr.Root, True,
ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
Scr.Root, Scr.FvwmCursors[WAIT], CurrentTime);
XSync (dpy,0);
if (!(fork())) /* child process */
if (execl("/bin/sh", "/bin/sh", "-c", action, (char *)0)==-1)
exit(100);
XUngrabPointer(dpy,CurrentTime);
XSync (dpy,0);
break;
case F_REFRESH:
{
XSetWindowAttributes attributes;
unsigned long valuemask;
valuemask = (CWBackPixel);
attributes.background_pixel = Scr.StdColors.fore;
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);
}
break;
case F_STICK:
/* stick/unstick a window */
if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
break;
if(tmp_win == NULL)
break;
if(tmp_win->flags & STICKY)
{
tmp_win->flags &= ~STICKY;
if(tmp_win->BackPixel == Scr.StickyColors.back)
{
tmp_win->ReliefPixel = Scr.StdRelief.fore;
tmp_win->ShadowPixel = Scr.StdRelief.back;
tmp_win->BackPixel = Scr.StdColors.back;
}
if(tmp_win->TextPixel == Scr.StickyColors.fore)
tmp_win->TextPixel = Scr.StdColors.fore;
}
else
{
tmp_win->flags |=STICKY;
if(tmp_win->BackPixel == Scr.StdColors.back)
{
tmp_win->BackPixel = Scr.StickyColors.back;
tmp_win->ShadowPixel = Scr.StickyRelief.back;
tmp_win->ReliefPixel = Scr.StickyRelief.fore;
}
if(tmp_win->TextPixel == Scr.StdColors.fore)
tmp_win->TextPixel = Scr.StickyColors.fore;
}
if(Scr.Hilite != tmp_win)
{
/* Need to make SetBorder change the window back color */
temp=Scr.Hilite;
SetBorder(tmp_win,True,True,True,None);
SetBorder(tmp_win,False,True,True,None);
SetBorder(temp,True,True,True,None);
}
BroadcastConfig(M_CONFIGURE_WINDOW,tmp_win);
#ifndef NO_PAGER
MoveResizePagerView(tmp_win);
/* Need to re-draw pager_view in case the window
* is unsticking */
if(Scr.Hilite == tmp_win)
{
TextColor = Scr.HiColors.fore;
BackPixmap= Scr.gray_pixmap;
BackColor = Scr.HiColors.back;
}
else
{
TextColor = Scr.StdColors.fore;
BackPixmap = Scr.light_gray_pixmap;
BackColor = Scr.StdColors.back;
}
if(Scr.d_depth < 2)
XSetWindowBackgroundPixmap(dpy,tmp_win->pager_view,BackPixmap);
else
XSetWindowBackground(dpy,tmp_win->pager_view,BackColor);
XClearWindow(dpy,tmp_win->pager_view);
if((tmp_win->icon_name != NULL)&&(Scr.PagerFont.height > 0))
{
NewFontAndColor(Scr.PagerFont.font->fid,TextColor,BackColor);
XDrawString (dpy, tmp_win->pager_view,Scr.FontGC,2,Scr.PagerFont.y+2,
tmp_win->icon_name, strlen(tmp_win->icon_name));
}
#endif
break;
#ifndef NON_VIRTUAL
case F_GOTO_PAGE:
/* back up 1 virtual desktop page */
x=val1*Scr.MyDisplayWidth;
y=val2*Scr.MyDisplayHeight;
MoveViewport(x,y,True);
break;
#endif
#ifndef NON_VIRTUAL
case F_TOGGLE_PAGE:
if (DoHandlePageing)
{
DoHandlePageing = 0;
Broadcast(M_TOGGLE_PAGING,1,0,0,0,0,0,0,0);
}
else
{
DoHandlePageing = 1;
Broadcast(M_TOGGLE_PAGING,1,1,0,0,0,0,0,0);
}
checkPanFrames();
break;
#endif
case F_CIRCULATE_UP:
t=Circulate(tmp_win,action,UP);
if(t)FocusOn(t,0);
break;
case F_CIRCULATE_DOWN:
t=Circulate(tmp_win,action,DOWN);
if(t)FocusOn(t,0);
break;
case F_WARP:
t=Circulate(tmp_win,action,DOWN);
if((t)&&(t->flags & ICONIFIED))
{
FocusOn(t,0);
DeIconify(t);
}
if(t)FocusOn(t,0);
break;
case F_WAIT:
{
Bool done = False;
if(val1 == 0)
val1 = 1;
while(!done)
{
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;
}
}
}
}
XSync(dpy,0);
break;
case F_RAISE_IT:
if(val1 != 0)
{
FocusOn((FvwmWindow *)val1,0);
if (((FvwmWindow *)(val1))->flags & ICONIFIED)
{
DeIconify((FvwmWindow *)val1);
FocusOn((FvwmWindow *)val1,0);
}
}
break;
case F_FOCUS:
if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
break;
FocusOn(tmp_win,0);
break;
case F_CHANGE_WINDOWS_DESK:
if (DeferExecution(eventp,&w,&tmp_win,&context,SELECT,ButtonRelease))
break;
if(tmp_win == NULL)
break;
changeWindowsDesk(tmp_win,val1);
break;
case F_DESK:
changeDesks(val1,val2);
break;
case F_MODULE:
if(eventp->type != KeyPress)
UngrabEm();
if(tmp_win)
executeModule(action, (FILE *)NULL,(char **)tmp_win->w,(int *)context);
else
executeModule(action, (FILE *)NULL,(char **)0, (int *)context);
/* If we execute a module, don't wait for buttons to come up,
* that way, a pop-up menu could be implemented */
Module = 0;
break;
case F_RAISELOWER:
if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
break;
if(tmp_win == NULL)
break;
if((tmp_win == Scr.LastWindowRaised)||
(tmp_win->flags & VISIBLE))
{
LowerWindow(tmp_win);
tmp_win->flags &= ~ONTOP;
}
else
{
RaiseWindow(tmp_win);
if (LookInList(Scr.TheList,tmp_win->name, &tmp_win->class,&junk,
&junkD,&junkD, &junkD, &junkC,&junkC,&junkN)&STAYSONTOP_FLAG)
tmp_win->flags |= ONTOP;
KeepOnTop();
}
break;
case F_POPUP:
ActiveItem = NULL;
ActiveMenu = NULL;
menuFromFrameOrWindowOrTitlebar = FALSE;
do_menu(menu);
break;
case F_MAXIMIZE:
if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonRelease))
break;
if(tmp_win == NULL)
break;
if(check_allowed_function2(func,tmp_win) == 0)
{
XBell(dpy, Scr.screen);
break;
}
Maximize(tmp_win,val1,val2,val1_unit,val2_unit);
break;
case F_QUIT:
Done(0, NULL);
break;
case F_WINDOWLIST:
do_windowList(val1,val2);
break;
case F_FUNCTION:
ComplexFunction(w, tmp_win, eventp, context,menu);
break;
case F_QUICKIE:
QuickRestart();
break;
case F_SEND_WINDOW_LIST:
if(Module >= 0)
{
SendPacket(Module,M_TOGGLE_PAGING,1,DoHandlePageing,0,0,0,0,0,0);
SendPacket(Module,M_NEW_DESK,1,Scr.CurrentDesk,0,0,0,0,0,0);
SendPacket(Module,M_NEW_PAGE,3,Scr.Vx,Scr.Vy,Scr.CurrentDesk,
0,0,0,0);
if(Scr.Hilite != NULL)
SendPacket(Module,M_FOCUS_CHANGE,3,Scr.Hilite->w,Scr.Hilite->frame,
(unsigned long)Scr.Hilite,0,0,0,0);
else
SendPacket(Module,M_FOCUS_CHANGE,3,0,0,0,0,0,0,0);
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
SendConfig(Module,M_CONFIGURE_WINDOW,t);
SendName(Module,M_WINDOW_NAME,t->w,t->frame,
(unsigned long)t,t->name);
SendName(Module,M_ICON_NAME,t->w,t->frame,
(unsigned long)t,t->icon_name);
SendName(Module,M_RES_CLASS,t->w,t->frame,
(unsigned long)t,t->class.res_class);
SendName(Module,M_RES_NAME,t->w,t->frame,
(unsigned long)t,t->class.res_name);
if((t->flags & ICONIFIED)&&(!(t->flags & ICON_UNMAPPED)))
SendPacket(Module,M_ICONIFY,7,t->w,t->frame,
(unsigned long)t,
t->icon_x_loc,t->icon_y_loc,
t->icon_w_width,
t->icon_w_height+t->icon_p_height);
if((t->flags & ICONIFIED) && (t->flags & ICON_UNMAPPED))
SendPacket(Module,M_ICONIFY,7,t->w,t->frame,
(unsigned long)t,0,0,0,0);
}
if(Scr.Hilite == NULL)
{
Broadcast(M_FOCUS_CHANGE,3,0,0,0,0,0,0,0);
}
else
{
Broadcast(M_FOCUS_CHANGE,3,Scr.Hilite->w,
Scr.Hilite->frame,(unsigned long)Scr.Hilite,0,0,0,0);
}
SendPacket(Module,M_END_WINDOWLIST,0,0,0,0,0,0,0,0);
}
}
/* Only wait for an all-buttons-up condition after calls from
* regular built-ins, not from complex-functions or modules. */
if(Module == -1)
WaitForButtonsUp();
return;
}
FvwmWindow *Circulate(FvwmWindow *tmp_win, char *action,Bool Direction)
{
FvwmWindow *t,*selected;
Bool found;
int count,pass=1;
int base, best;
while(pass< 3)
{
if(tmp_win)
base = tmp_win->focus_sequence;
else
base = -1;
if(Direction == DOWN)
best = -1;
else
best = 10000;
selected = tmp_win;
/* move focus to the next window */
found = FALSE;
t = tmp_win;
count = 0;
while(count < 3)
{
if(Direction == DOWN)
{
if((t == (FvwmWindow *)0)||(t->next == NULL))
{
t = Scr.FvwmRoot.next;
count++;
}
else
t =t->next;
}
else /* Direction Up */
{
if ((t == (FvwmWindow *)0)||(t == &Scr.FvwmRoot)||
(t->prev == &Scr.FvwmRoot)||(t->prev == (FvwmWindow *)NULL))
{
for(t=Scr.FvwmRoot.next;t->next != (FvwmWindow *)NULL;t=t->next);
count++;
}
else
t=t->prev;
}
found = TRUE;
if(t->Desk != Scr.CurrentDesk)
found = False;
if((!(Scr.flags & Lenience))&&
(t)&&(t->wmhints)&&(t->wmhints->flags&InputHint)&&
(t->wmhints->input == False)&&
!(t->flags & DoesWmTakeFocus))
found = False;
if (t->flags & CIRCULATESKIP)
found = FALSE;
/* optional skip over icons */
if((t->flags & ICONIFIED)&&(Scr.flags & CirculateSkipIcons))
found = FALSE;
/* Make CirculateUp and CirculateDown take args. by Y.NOMURA */
if (action && (strlen(action) > 0)&&
!(matchWildcards(action, t->name)) &&
!(matchWildcards(action, t->icon_name))&&
t->class.res_name &&
!(matchWildcards(action, t->class.res_name)))
found = FALSE;
if((found)&&(Direction == DOWN)&&(t->focus_sequence > best))
{
best = t->focus_sequence;
selected = t;
}
if((found)&&(Direction != DOWN)&&(t->focus_sequence < best)
&&(t->focus_sequence > base))
{
best = t->focus_sequence;
selected = t;
}
}
if((selected)&&(selected == tmp_win)&&(base > 0))
{
if(Direction == DOWN)
{
ClearCirculatedFlag();
tmp_win->focus_sequence = 0;
}
else
{
FvwmWindow *temp;
temp = Scr.FvwmRoot.next;
while(temp != NULL)
{
temp->focus_sequence++;
if(temp == tmp_win)temp->focus_sequence = 0;
temp = temp->next;
}
}
pass++;
}
else
pass = 3;
}
return selected;
}
/***********************************************************************
*
* 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))
{
if((FinishEvent == ButtonPress)||((FinishEvent == ButtonRelease) &&
(eventp->type != ButtonPress)))
{
return FALSE;
}
}
if(!GrabEm(cursor))
{
XBell(dpy,Scr.screen);
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,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,Scr.screen);
UngrabEm();
return TRUE;
}
if (XFindContext (dpy, *w, FvwmContext, (caddr_t *)tmp_win) == XCNOENT)
{
*tmp_win = NULL;
XBell(dpy,Scr.screen);
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,Scr.screen);
UngrabEm();
return TRUE;
}
*context = GetContext(*tmp_win,eventp,&dummy);
UngrabEm();
return FALSE;
}
/****************************************************************************
*
* This is used to tell applications which windows on the screen are
* top level appication windows, and which windows are the icon windows
* that go with them.
*
****************************************************************************/
void SetMapStateProp(FvwmWindow *tmp_win, int state)
{
unsigned long data[2]; /* "suggested" by ICCCM version 1 */
data[0] = (unsigned long) state;
data[1] = (unsigned long) tmp_win->icon_w;
/* data[2] = (unsigned long) tmp_win->icon_pixmap_w;*/
XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
PropModeReplace, (unsigned char *) data, 2);
return;
}
/****************************************************************************
*
* Keeps the "StaysOnTop" windows on the top of the pile.
* This is achieved by clearing a flag for OnTop windows here, and waiting
* for a visibility notify on the windows. Eception: OnTop windows which are
* obscured by other OnTop windows, which need to be raised here.
*
****************************************************************************/
void KeepOnTop()
{
FvwmWindow *t;
/* flag that on-top windows should be re-raised */
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
if((t->flags & ONTOP)&&!(t->flags & VISIBLE))
{
RaiseWindow(t);
t->flags &= ~RAISED;
}
else
t->flags |= RAISED;
}
}
/***************************************************************************
*
* Moves the viewport within thwe virtual desktop
*
***************************************************************************/
#ifndef NON_VIRTUAL
void MoveViewport(int newx, int newy, Bool grab)
{
FvwmWindow *t;
int deltax,deltay;
if(grab)
XGrabServer(dpy);
if(newx > Scr.VxMax)
newx = Scr.VxMax;
if(newy > Scr.VyMax)
newy = Scr.VyMax;
if(newx <0)
newx = 0;
if(newy <0)
newy = 0;
deltay = Scr.Vy - newy;
deltax = Scr.Vx - newx;
Scr.Vx = newx;
Scr.Vy = newy;
Broadcast(M_NEW_PAGE,3,Scr.Vx,Scr.Vy,Scr.CurrentDesk,0,0,0,0);
if((deltax!=0)||(deltay!=0))
{
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
/* If the window is iconified, and sticky Icons is set,
* then the window should essentially be sticky */
if(!((t->flags & ICONIFIED)&&(Scr.flags & StickyIcons)) &&
(!(t->flags & STICKY)))
{
if(!(Scr.flags & StickyIcons))
{
t->icon_x_loc += deltax;
t->icon_xl_loc += deltax;
t->icon_y_loc += deltay;
if(t->icon_pixmap_w != None)
XMoveWindow(dpy,t->icon_pixmap_w,t->icon_x_loc,
t->icon_y_loc);
if(t->icon_w != None)
XMoveWindow(dpy,t->icon_w,t->icon_x_loc,
t->icon_y_loc+t->icon_p_height);
if(!(t->flags &ICON_UNMAPPED))
Broadcast(M_ICON_LOCATION,7,t->w,t->frame,
(unsigned long)t,
t->icon_x_loc,t->icon_y_loc,
t->icon_w_width,
t->icon_w_height+t->icon_p_height);
}
}
if(!(t->flags & STICKY))
SetupFrame (t, t->frame_x+ deltax, t->frame_y + deltay,
t->frame_width, t->frame_height,FALSE);
}
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
/* If its an icon, and its sticking, autoplace it so
* that it doesn't wind up on top a a stationary
* icon */
if(((t->flags & STICKY)||(Scr.flags & StickyIcons))&&
(t->flags & ICONIFIED)&&(!(t->flags & ICON_MOVED))&&
(!(t->flags & ICON_UNMAPPED)))
AutoPlace(t);
}
}
/* fix up the viewport indicator */
MoveResizeViewPortIndicator();
#ifndef NON_VIRTUAL
checkPanFrames();
/* do this with PanFrames too ??? HEDU */
while(XCheckTypedEvent(dpy,MotionNotify,&Event))
StashEventTime(&Event);
#endif
if(grab)
XUngrabServer(dpy);
}
#endif
/**************************************************************************
*
* Moves focus to specified window
*
*************************************************************************/
void FocusOn(FvwmWindow *t,int DeIconifyOnly)
{
#ifndef NON_VIRTUAL
int dx,dy;
int cx,cy;
#endif
int x,y;
if(t == (FvwmWindow *)0)
return;
if(t->Desk != Scr.CurrentDesk)
{
changeDesks(0,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;
}
/* Put center of window on the visible screen */
if((!DeIconifyOnly)&&(Scr.flags & CenterOnCirculate))
{
dx = cx - Scr.MyDisplayWidth/2 + Scr.Vx;
dy = cy - Scr.MyDisplayHeight/2 + Scr.Vy;
}
else
{
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(!(Scr.flags & ClickToFocus))
XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, x+2,y+2);
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);
if(!(Scr.flags & ClickToFocus))
XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, 2,2);
}
UngrabEm();
SetFocus(t->w,t);
}
/***********************************************************************
*
* Procedure:
* (Un)Maximize a window.
*
***********************************************************************/
void Maximize(FvwmWindow *tmp_win,int val1,int val2,
int val1_unit,int val2_unit)
{
int new_width, new_height,new_x,new_y;
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);
SetupFrame(tmp_win,new_x,new_y,new_width,new_height,TRUE);
SetBorder(tmp_win,Scr.Hilite == tmp_win,True,True,tmp_win->right_w[0]);
}
#ifndef NO_PAGER
RedrawPager();
#endif
}
/*****************************************************************************
*
* Grab the pointer and keyboard
*
****************************************************************************/
Bool GrabEm(int cursor)
{
int i=0,val=0;
unsigned int mask;
XSync(dpy,0);
/* move the keyboard focus prior to grabbing the pointer to
* eliminate the enterNotify and exitNotify events that go
* to the windows */
if(Scr.PreviousFocus == NULL)
Scr.PreviousFocus = Scr.Focus;
SetFocus(Scr.NoFocusWin,NULL);
mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask
| EnterWindowMask | LeaveWindowMask;
while((i<1000)&&(val=XGrabPointer(dpy, Scr.Root, True, mask,
GrabModeAsync, GrabModeAsync, Scr.Root,
Scr.FvwmCursors[cursor], CurrentTime)!=
GrabSuccess))
{
i++;
/* If you go too fast, other windows may not get a change to release
* any grab that they have. */
sleep_a_little(1000);
}
/* If we fall out of the loop without grabbing the pointer, its
time to give up */
XSync(dpy,0);
if(val!=GrabSuccess)
{
return False;
}
return True;
}
/*****************************************************************************
*
* UnGrab the pointer and keyboard
*
****************************************************************************/
void UngrabEm()
{
Window w;
XSync(dpy,0);
XUngrabPointer(dpy,CurrentTime);
if(Scr.PreviousFocus != NULL)
{
w = Scr.PreviousFocus->w;
/* if the window still exists, focus on it */
if (w)
{
SetFocus(w,Scr.PreviousFocus);
}
Scr.PreviousFocus = NULL;
}
XSync(dpy,0);
}
/*****************************************************************************
*
* Waits Scr.ClickTime, or until it is evident that the user is not
* clicking, but is moving the cursor
*
****************************************************************************/
Bool IsClick(int x,int y,unsigned EndMask, XEvent *d)
{
int xcurrent,ycurrent,total = 0;
xcurrent = x;
ycurrent = y;
while((total < Scr.ClickTime)&&
(x - xcurrent < 5)&&(x - xcurrent > -5)&&
(y - ycurrent < 5)&&(y - ycurrent > -5))
{
sleep_a_little(10000);
total+=10;
if(XCheckMaskEvent (dpy,EndMask, d))
{
StashEventTime(d);
return True;
}
if(XCheckMaskEvent (dpy,ButtonMotionMask|PointerMotionMask, d))
{
xcurrent = d->xmotion.x_root;
ycurrent = d->xmotion.y_root;
StashEventTime(d);
}
}
return False;
}
/*****************************************************************************
*
* Builtin which determines if the button press was a click or double click...
*
****************************************************************************/
void ComplexFunction(Window w, FvwmWindow *tmp_win, XEvent *eventp,
unsigned long context, MenuRoot *mr)
{
char type = MOTION;
char c;
XEvent *ev;
MenuItem *mi;
XEvent d;
Bool Persist = False;
Bool HaveDoubleClick = False;
Bool NeedsTarget = False;
int x, y ;
if(mr == NULL)
return;
/* These built-ins require a selected window
* The function code is >= 100 and < 1000
* F_RESIZE
* F_MOVE
* F_ICONIFY
* F_RAISE
* F_LOWER
* F_DESTROY
* F_DELETE
* F_STICK
* F_RAISELOWER
* F_MAXIMIZE
* F_FOCUS
*
* These do not:
* The function code is < 100
* F_NOP
* F_TITLE
* F_BEEP
* F_SCROLL
* F_MOVECURSOR
* F_RESTART
* F_EXEC
* F_REFRESH
* F_GOTO_PAGE
* F_TOGGLE_PAGE
* F_CIRCULATE_UP
* F_CIRCULATE_DOWN
* F_WARP
* F_DESK
* F_MODULE
* F_POPUP
* F_QUIT
* F_WINDOWLIST
* F_FUNCTION
* F_SEND_WINDOW_LIST
*/
mi = mr->first;
while(mi != NULL)
{
/* make lower case */
c = *(mi->item);
if((mi->func >= 100)&&(mi->func < 1000))
NeedsTarget = True;
if(isupper(c))
c=tolower(c);
if(c==DOUBLE_CLICK)
HaveDoubleClick = True;
else if(c == IMMEDIATE)
{
if(tmp_win)
w = tmp_win->frame;
else
w = None;
ExecuteFunction(mi->func, mi->action,w,
tmp_win, eventp, context,mi->val1,mi->val2,
mi->val1_unit,mi->val2_unit,
mi->menu,-1);
}
else
Persist = True;
mi = mi->next;
}
if(!Persist)
return;
/* Only defer execution if there is a possibility of needing
* a window to operate on */
if(NeedsTarget)
{
if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT,ButtonPress))
{
WaitForButtonsUp();
return;
}
}
if(!GrabEm(SELECT))
{
XBell(dpy,Scr.screen);
return;
}
XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
&x,&y,&JunkX, &JunkY, &JunkMask);
/* A window has already been selected */
ev = eventp;
/* Wait and see if we have a click, or a move */
/* wait 100 msec, see if the used releases the button */
if(IsClick(x,y,ButtonReleaseMask,&d))
{
type = CLICK;
ev = &d;
}
/* If it was a click, wait to see if its a double click */
if((HaveDoubleClick) && (type == CLICK) &&
(IsClick(x,y,ButtonPressMask, &d)))
{
type = ONE_AND_A_HALF_CLICKS;
ev = &d;
}
if((HaveDoubleClick) && (type == ONE_AND_A_HALF_CLICKS) &&
(IsClick(x,y,ButtonReleaseMask, &d)))
{
type = DOUBLE_CLICK;
ev = &d;
}
/* some functions operate on button release instead of
* presses. These gets really weird for complex functions ... */
if(eventp->type == ButtonPress)
eventp->type = ButtonRelease;
mi = mr->first;
while(mi != NULL)
{
/* make lower case */
c = *(mi->item);
if(isupper(c))
c=tolower(c);
if(c == type)
{
if(tmp_win)
w = tmp_win->frame;
else
w = None;
ExecuteFunction(mi->func, mi->action,w,
tmp_win, eventp, context,
mi->val1,mi->val2,
mi->val1_unit,mi->val2_unit,mi->menu,-2);
}
mi = mi->next;
}
WaitForButtonsUp();
UngrabEm();
}
/* For Ultrix 4.2 */
#include <sys/types.h>
#include <sys/time.h>
/**************************************************************************
*
* Move to a new desktop
*
*************************************************************************/
void changeDesks(int val1,int val2)
{
int oldDesk;
FvwmWindow *t;
FvwmWindow *FocusWin = 0;
static FvwmWindow *StickyWin = 0;
oldDesk = Scr.CurrentDesk;
if(val1 != 0)
{
Scr.CurrentDesk = Scr.CurrentDesk + val1;
}
else
{
Scr.CurrentDesk = val2;
if(Scr.CurrentDesk == oldDesk)
return;
}
Broadcast(M_NEW_DESK,1,Scr.CurrentDesk,0,0,0,0,0,0);
/* Scan the window list, mapping windows on the new Desk,
* unmapping windows on the old Desk */
XGrabServer(dpy);
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
/* Only change mapping for non-sticky windows */
if(!((t->flags & ICONIFIED)&&(Scr.flags & StickyIcons)) &&
(!(t->flags & STICKY))&&(!(t->flags & ICON_UNMAPPED)))
{
if(t->Desk == oldDesk) {
if (Scr.Focus == t)
t->FocusDesk = oldDesk;
else
t->FocusDesk = -1;
UnmapIt(t);
} else if(t->Desk == Scr.CurrentDesk) {
MapIt(t);
if (t->FocusDesk == Scr.CurrentDesk) {
FocusWin = t;
}
}
}
else
{
/* Window is sticky */
t->Desk = Scr.CurrentDesk;
if (Scr.Focus == t) {
t->FocusDesk = oldDesk;
StickyWin = t;
}
}
}
XUngrabServer(dpy);
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
/* If its an icon, and its sticking, autoplace it so
* that it doesn't wind up on top a a stationary
* icon */
if(((t->flags & STICKY)||(Scr.flags & StickyIcons))&&
(t->flags & ICONIFIED)&&(!(t->flags & ICON_MOVED))&&
(!(t->flags & ICON_UNMAPPED)))
AutoPlace(t);
}
/* Better re-draw the pager now */
RedrawPager();
if(Scr.flags & ClickToFocus) {
#ifndef NO_REMEMBER_FOCUS
if (FocusWin)
SetFocus(FocusWin->w, FocusWin);
else if (StickyWin && (StickyWin->flags && STICKY))
SetFocus(StickyWin->w, StickyWin);
else
#endif
SetFocus(Scr.NoFocusWin,NULL);
}
}
/**************************************************************************
*
* Move to a new desktop
*
*************************************************************************/
void changeWindowsDesk(FvwmWindow *t,int val1)
{
if(val1 == t->Desk)
return;
/* Scan the window list, mapping windows on the new Desk,
* unmapping windows on the old Desk */
/* Only change mapping for non-sticky windows */
if(!((t->flags & ICONIFIED)&&(Scr.flags & StickyIcons)) &&
(!(t->flags & STICKY))&&(!(t->flags & ICON_UNMAPPED)))
{
if(t->Desk == Scr.CurrentDesk)
{
t->Desk = val1;
UnmapIt(t);
}
else if(val1 == Scr.CurrentDesk)
{
t->Desk = val1;
/* If its an icon, auto-place it */
if(t->flags & ICONIFIED)
AutoPlace(t);
MapIt(t);
}
else
t->Desk = val1;
}
/* Better re-draw the pager now */
BroadcastConfig(M_CONFIGURE_WINDOW,t);
RedrawPager();
}
/**************************************************************************
*
* Unmaps a window on transition to a new desktop
*
*************************************************************************/
void UnmapIt(FvwmWindow *t)
{
XWindowAttributes winattrs;
unsigned long eventMask;
/*
* Prevent the receipt of an UnmapNotify, since that would
* cause a transition to the Withdrawn state.
*/
XGetWindowAttributes(dpy, t->w, &winattrs);
eventMask = winattrs.your_event_mask;
XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
if(t->flags & ICONIFIED)
{
if(t->icon_pixmap_w != None)
XUnmapWindow(dpy,t->icon_pixmap_w);
if(t->icon_w != None)
XUnmapWindow(dpy,t->icon_w);
}
else if(t->flags & (MAPPED|MAP_PENDING))
{
XUnmapWindow(dpy,t->frame);
}
XSelectInput(dpy, t->w, eventMask);
MoveResizePagerView(t);
}
/**************************************************************************
*
* Maps a window on transition to a new desktop
*
*************************************************************************/
void MapIt(FvwmWindow *t)
{
if(t->flags & ICONIFIED)
{
if(t->icon_pixmap_w != None)
XMapWindow(dpy,t->icon_pixmap_w);
if(t->icon_w != None)
XMapWindow(dpy,t->icon_w);
}
else if(t->flags & MAPPED)
{
XMapWindow(dpy,t->frame);
t->flags |= MAP_PENDING;
XMapWindow(dpy, t->Parent);
}
MoveResizePagerView(t);
}
void QuickRestart(void)
{
extern char *m4_options;
extern char *display_name;
int i;
FvwmWindow *tmp,*next;
extern unsigned PopupCount;
extern int have_the_colors;
MenuRoot *PopupTable[MAXPOPUPS];
extern MenuRoot *ActiveMenu;
extern MenuItem *ActiveItem;
extern int menu_on;
XEvent event;
PopDownMenu();
PopDownMenu();
UngrabEm();
InstallWindowColormaps (&Scr.FvwmRoot); /* force reinstall */
Reborder();
tmp = Scr.FvwmRoot.next;
while (tmp != NULL)
{
next = tmp->next;
Destroy(tmp);
tmp = next;
}
XSync(dpy,0);
for(i=0;i<PopupCount;i++)
{
/* free(PopupTable[i]);*/
PopupTable[i] = NULL;
}
PopupCount = 0;
ActiveMenu = NULL;
ActiveItem = NULL;
menu_on = 0;
have_the_colors = 0;
InitVariables();
#ifdef M4
MakeMenus(display_name, m4_options);
#else
MakeMenus(display_name, NULL);
#endif
#ifndef NON_VIRTUAL
XUnmapWindow(dpy,Scr.PanFrameLeft.win);
XUnmapWindow (dpy,Scr.PanFrameRight.win);
XUnmapWindow (dpy,Scr.PanFrameBottom.win);
XUnmapWindow(dpy,Scr.PanFrameTop.win);
Scr.PanFrameBottom.isMapped=
Scr.PanFrameTop.isMapped=
Scr.PanFrameLeft.isMapped=
Scr.PanFrameRight.isMapped=
False;
#endif
while(XPending(dpy))
XNextEvent(dpy,&event);
CaptureAllWindows();
#ifndef NON_VIRTUAL
checkPanFrames();
#endif
HandleEvents();
}