/****************************************************************************
* This module is all new
* by Rob Nation
* Copyright 1993 Robert Nation. No restrictions are placed on this code,
* as long as the copyright notice is preserved
****************************************************************************/
#include <FVWMconfig.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"
/*****************************************************************************
*
* 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;
Time t0;
extern Time lastTimestamp;
xcurrent = x;
ycurrent = y;
t0 = lastTimestamp;
while((total < Scr.ClickTime)&&
(x - xcurrent < 3)&&(x - xcurrent > -3)&&
(y - ycurrent < 3)&&(y - ycurrent > -3)&&
((lastTimestamp - t0) < Scr.ClickTime))
{
sleep_a_little(20000);
total+=20;
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(XEvent *eventp,Window w,FvwmWindow *tmp_win,
unsigned long context, char *action, int *Module)
{
char type = MOTION;
char c;
MenuItem *mi;
Bool Persist = False;
Bool HaveDoubleClick = False;
Bool NeedsTarget = False;
char *arguments[10], *junk, *taction;
int x, y ,i;
XEvent d, *ev;
MenuRoot *mr;
extern Bool desperate;
mr = FindPopup(action);
if(mr == NULL)
{
if(!desperate)
fvwm_msg(ERR,"ComplexFunction","No such function %s",action);
return;
}
desperate = 0;
/* Get the argument list */
/* First entry in action is the function-name, ignore it */
action = GetNextToken(action,&junk);
if(junk != NULL)
free(junk);
for(i=0;i<10;i++)
action = GetNextToken(action,&arguments[i]);
/* 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
*/
ev = eventp;
/* In case we want to perform an action on a button press, we
* need to fool other routines */
if(eventp->type == ButtonPress)
eventp->type = ButtonRelease;
mi = mr->first;
while(mi != NULL)
{
/* make lower case */
c = *(mi->item);
if((mi->func_type >= 100)&&(mi->func_type < 1000))
NeedsTarget = True;
if(isupper(c))
c=tolower(c);
if(c==DOUBLE_CLICK)
{
HaveDoubleClick = True;
Persist = True;
}
else if(c == IMMEDIATE)
{
if(tmp_win)
w = tmp_win->frame;
else
w = None;
taction = expand(mi->action,arguments,tmp_win);
ExecuteFunction(taction,tmp_win,eventp,context,-2);
free(taction);
}
else
Persist = True;
mi = mi->next;
}
if(!Persist)
{
for(i=0;i<10;i++)
if(arguments[i] != NULL)free(arguments[i]);
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();
for(i=0;i<10;i++)
if(arguments[i] != NULL)free(arguments[i]);
return;
}
}
if(!GrabEm(SELECT))
{
XBell(dpy,Scr.screen);
for(i=0;i<10;i++)
if(arguments[i] != NULL)free(arguments[i]);
return;
}
XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
&x,&y,&JunkX, &JunkY, &JunkMask);
/* Wait and see if we have a click, or a move */
/* wait 100 msec, see if the user releases the button */
if(IsClick(x,y,ButtonReleaseMask,&d))
{
ev = &d;
type = CLICK;
}
/* 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(ev->type == ButtonPress)
ev->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;
taction = expand(mi->action,arguments,tmp_win);
ExecuteFunction(taction,tmp_win,ev,context,-2);
free(taction);
}
mi = mi->next;
}
WaitForButtonsUp();
UngrabEm();
for(i=0;i<10;i++)
if(arguments[i] != NULL)free(arguments[i]);
}
char *expand(char *input, char *arguments[],FvwmWindow *tmp_win)
{
int l,i,l2,n,k,j;
char *out;
l = strlen(input);
l2 = strlen(input);
i=0;
while(i<l)
{
if(input[i] == '$')
{
n = input[i+1] - '0';
if((n >= 0)&&(n <= 9)&&(arguments[n] != NULL))
{
l2 += strlen(arguments[n])-2;
i++;
}
else if(input[i+1]=='w')
{
l2 += 16;
i++;
}
}
i++;
}
out = safemalloc(l2+1);
i=0;
j=0;
while(i<l)
{
if(input[i] == '$')
{
n = input[i+1] - '0';
if((n >= 0)&&(n <= 9)&&(arguments[n] != NULL))
{
for(k=0;k<strlen(arguments[n]);k++)
out[j++] = arguments[n][k];
i++;
}
else if(input[i+1] == 'w')
{
if(tmp_win)
sprintf(&out[j],"0x%x",tmp_win->w);
else
sprintf(&out[j],"$w");
j = strlen(out);
i++;
}
else if(input[i+1] == '$')
{
out[j++] = '$';
i++;
}
else
out[j++] = input[i];
}
else
out[j++] = input[i];
i++;
}
out[j] = 0;
return out;
}
syntax highlighted by Code2HTML, v. 0.9.1