/**************************************************************************** * * Initiates a menu pop-up * * Style = 1 = sticky menu, stays up on initial button release. * Style = 0 = transient menu, drops on initial release. ***************************************************************************/ int do_menu(MenuRoot * menu, int style) { int prevStashedX = 0, prevStashedY = 0; MenuRoot *PrevActiveMenu = 0; MenuItem *PrevActiveItem = 0; int retval = MENU_NOP; int x, y; Time t0; extern Time lastTimestamp; int PrevMenuX = PrevActiveMenuX; /* this condition could get ugly */ if (menu->in_use) return MENU_ERROR; /* In case we wind up with a move from a menu which is * from a window border, we'll return to here to start * the move */ XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, &x, &y, &JunkX, &JunkY, &JunkMask); if (menu_on) { prevStashedX = Stashed_X; prevStashedY = Stashed_Y; PrevActiveMenu = ActiveMenu; PrevActiveItem = ActiveItem; if (ActiveMenu) x = Stashed_X + ActiveMenu->width - 3; if (ActiveItem) y = ActiveItem->y_offset + MenuY; } else { mouse_moved = 0; t0 = lastTimestamp; if (!GrabEm(MENU)) { XBell(dpy, Scr.screen); return MENU_DONE; } x += 2; } if (PopUpMenu(menu, x, y)) { retval = UpdateMenu(style); } else XBell(dpy, Scr.screen); ActiveMenu = PrevActiveMenu; ActiveItem = PrevActiveItem; if ((ActiveItem) && (menu_on)) ActiveItem->state = 1; Stashed_X = prevStashedX; Stashed_Y = prevStashedY; if (!menu_on) { UngrabEm(); WaitForButtonsUp(); } if (((lastTimestamp - t0) < 3 * Scr.ClickTime) && (mouse_moved == 0)) menu_aborted = 1; else menu_aborted = 0; PrevActiveMenuX = PrevMenuX; return retval; }
/***************************************************************************** * * 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]); }
/*********************************************************************** * * Procedure: * ExecuteFunction - execute a fvwm built in function * * Inputs: * Action - the menu action to execute * tmp_win - the fvwm window structure * eventp - pointer to the event that caused the function * context - the context in which the button was pressed * ***********************************************************************/ void ExecuteFunction(char *Action, FvwmWindow *tmp_win, XEvent *eventp, unsigned long context, int Module) { Window w; int matched,j; char *function; char *action, *taction; char *arguments[10]; struct functions *bif; if (!Action || Action[0] == 0 || Action[1] == 0) { /* impossibly short command */ return; /* done */ } if (Action[0] == '#') { /* a comment */ return; /* done */ } /* Note: the module config command, "*" can not be handled by the regular command table because there is no required white space after the asterisk. */ if (Action[0] == '*') { /* a module config command */ ModuleConfig(NULL,0,0,0,Action,0); /* process the command */ return; /* done */ } for(j=0;j<10;j++) arguments[j] = NULL; if(tmp_win == NULL) w = Scr.Root; else w = tmp_win->w; if((tmp_win) &&(eventp)) w = eventp->xany.window; if((tmp_win)&&(eventp->xbutton.subwindow != None)&& (eventp->xany.window != tmp_win->w)) w = eventp->xbutton.subwindow; taction = expand(Action,arguments,tmp_win); action = GetNextToken(taction,&function); if (!function) return; j=0; matched = FALSE; bif = FindBuiltinFunction(function); if (bif) { matched = TRUE; bif->action(eventp,w,tmp_win,context,action,&Module); } if(!matched) { desperate = 1; ComplexFunction(eventp,w,tmp_win,context,taction, &Module); if(desperate) executeModule(eventp,w,tmp_win,context,taction, &Module); desperate = 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(); if (function) free(function); if(taction != NULL) free(taction); return; }