2015-10-15 21:39:42 +02:00

5598 lines
148 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*****************************************************************************/
/** 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. **/
/*****************************************************************************/
/*
* [ ctwm ]
*
* Copyright 1992 Claude Lecommandeur.
*
* Permission to use, copy, modify and distribute this software [ctwm] and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting documen-
* tation, and that the name of Claude Lecommandeur not be used in adverti-
* sing or publicity pertaining to distribution of the software without
* specific, written prior permission. Claude Lecommandeur make no represen-
* tations about the suitability of this software for any purpose. It is
* provided "as is" without express or implied warranty.
*
* Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES 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.
*
* Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
*/
/***********************************************************************
*
* $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
*
* twm menu code
*
* 17-Nov-87 Thomas E. LaStrange File created
*
* Do the necessary modification to be integrated in ctwm.
* Can no longer be used for the standard twm.
*
* 22-April-92 Claude Lecommandeur.
*
*
***********************************************************************/
#if defined(USE_SIGNALS) && defined(__sgi)
# define _BSD_SIGNALS
#endif
#include <stdio.h>
#include <signal.h>
#ifdef VMS
#include <stdlib.h>
#include <string.h>
#include <unixio.h>
#include <file.h>
#include <decw$include/Xos.h>
#include <decw$include/Xatom.h>
#else
#include <X11/Xos.h>
#include <X11/Xatom.h>
#endif
#include "twm.h"
#include "ctwm.h"
#include "gc.h"
#include "menus.h"
#include "resize.h"
#include "events.h"
#include "list.h"
#include "util.h"
#include "parse.h"
#include "screen.h"
#include "icons.h"
#include "add_window.h"
#include "windowbox.h"
#include "workmgr.h"
#include "cursor.h"
#include "gnomewindefs.h"
#ifdef SOUNDS
# include "sound.h"
#endif
#ifdef VMS
# include <X11Xmu/CharSet.h>
# include <decw$bitmaps/menu12.xbm>
# include <X11SM/SMlib.h>
# include "vms_cmd_services.h"
# include <lib$routines.h>
#else
# include <X11/Xmu/CharSet.h>
# include <X11/SM/SMlib.h>
#endif
#include "version.h"
#if defined(MACH) || defined(__MACH__) || defined(sony_news) || defined(NeXT)
#define lrand48 random
#endif
#if defined(VMS) || defined(__DARWIN__)
#define lrand48 rand
#endif
#ifndef VMS
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif
#define ABS(x) ((x)<0?-(x):(x))
int RootFunction = 0;
MenuRoot *ActiveMenu = NULL; /* the active menu */
MenuItem *ActiveItem = NULL; /* the active menu item */
int MoveFunction; /* either F_MOVE or F_FORCEMOVE */
int WindowMoved = FALSE;
int menuFromFrameOrWindowOrTitlebar = FALSE;
char *CurrentSelectedWorkspace;
int AlternateKeymap;
Bool AlternateContext;
extern char *captivename;
int ConstMove = FALSE; /* constrained move variables */
int ConstMoveDir;
int ConstMoveX;
int ConstMoveY;
int ConstMoveXL;
int ConstMoveXR;
int ConstMoveYT;
int ConstMoveYB;
/* Globals used to keep track of whether the mouse has moved during
a resize function. */
int ResizeOrigX;
int ResizeOrigY;
int MenuDepth = 0; /* number of menus up */
static struct {
int x;
int y;
} MenuOrigins[MAXMENUDEPTH];
static Cursor LastCursor;
static Bool addingdefaults = False;
void jump (TwmWindow *tmp_win, int direction, char *action);
void waitamoment (float timeout);
extern char *Action;
extern int Context;
extern TwmWindow *ButtonWindow, *Tmp_win;
extern XEvent ButtonEvent;
extern char *InitFile;
extern int ConstrainedMoveTime;
static void Identify (TwmWindow *t);
#define SHADOWWIDTH 5 /* in pixels */
#ifdef GNOME
extern Atom _XA_WIN_STATE;
#endif /* GNOME */
/***********************************************************************
*
* Procedure:
* InitMenus - initialize menu roots
*
***********************************************************************
*/
void InitMenus(void)
{
Scr->DefaultFunction.func = 0;
Scr->WindowFunction.func = 0;
Scr->ChangeWorkspaceFunction.func = 0;
Scr->DeIconifyFunction.func = 0;
Scr->IconifyFunction.func = 0;
Scr->FuncKeyRoot.next = NULL;
Scr->FuncButtonRoot.next = NULL;
}
/***********************************************************************
*
* Procedure:
* AddFuncKey - add a function key to the list
*
* Inputs:
* name - the name of the key
* cont - the context to look for the key press in
* mods - modifier keys that need to be pressed
* func - the function to perform
* win_name- the window name (if any)
* action - the action string associated with the function (if any)
*
***********************************************************************
*/
Bool AddFuncKey (char *name, int cont, int mods, int func,
MenuRoot *menu, char *win_name, char *action)
{
FuncKey *tmp;
KeySym keysym;
KeyCode keycode;
/*
* Don't let a 0 keycode go through, since that means AnyKey to the
* XGrabKey call in GrabKeys().
*/
if ((keysym = XStringToKeysym(name)) == NoSymbol ||
(keycode = XKeysymToKeycode(dpy, keysym)) == 0)
{
return False;
}
/* see if there already is a key defined for this context */
for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
{
if (tmp->keysym == keysym &&
tmp->cont == cont &&
tmp->mods == mods)
break;
}
if (tmp && addingdefaults) return (True);
if (tmp == NULL)
{
tmp = (FuncKey *) malloc(sizeof(FuncKey));
tmp->next = Scr->FuncKeyRoot.next;
Scr->FuncKeyRoot.next = tmp;
}
tmp->name = name;
tmp->keysym = keysym;
tmp->keycode = keycode;
tmp->cont = cont;
tmp->mods = mods;
tmp->func = func;
tmp->menu = menu;
tmp->win_name = win_name;
tmp->action = action;
return True;
}
/***********************************************************************
*
* Procedure:
* AddFuncButton - add a function button to the list
*
* Inputs:
* num - the num of the button
* cont - the context to look for the key press in
* mods - modifier keys that need to be pressed
* func - the function to perform
* menu - the menu (if any)
* item - the menu item (if any)
*
***********************************************************************
*/
Bool AddFuncButton (int num, int cont, int mods, int func,
MenuRoot *menu, MenuItem *item)
{
FuncButton *tmp;
/* see if there already is a key defined for this context */
for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
if ((tmp->num == num) && (tmp->cont == cont) && (tmp->mods == mods))
break;
}
if (tmp && addingdefaults) return (True);
if (tmp == NULL) {
tmp = (FuncButton*) malloc (sizeof (FuncButton));
tmp->next = Scr->FuncButtonRoot.next;
Scr->FuncButtonRoot.next = tmp;
}
tmp->num = num;
tmp->cont = cont;
tmp->mods = mods;
tmp->func = func;
tmp->menu = menu;
tmp->item = item;
return True;
}
static TitleButton *cur_tb = NULL;
void ModifyCurrentTB(int button, int mods, int func, char *action,
MenuRoot *menuroot)
{
TitleButtonFunc *tbf;
if (!cur_tb) {
fprintf (stderr, "%s: can't find titlebutton\n", ProgramName);
return;
}
for (tbf = cur_tb->funs; tbf; tbf = tbf->next) {
if (tbf->num == button && tbf->mods == mods)
break;
}
if (!tbf) {
tbf = (TitleButtonFunc *)malloc(sizeof(TitleButtonFunc));
if (!tbf) {
fprintf (stderr, "%s: out of memory\n", ProgramName);
return;
}
tbf->next = cur_tb->funs;
cur_tb->funs = tbf;
}
tbf->num = button;
tbf->mods = mods;
tbf->func = func;
tbf->action = action;
tbf->menuroot = menuroot;
}
int CreateTitleButton (char *name, int func, char *action, MenuRoot *menuroot,
Bool rightside, Bool append)
{
int button;
cur_tb = (TitleButton *) malloc (sizeof(TitleButton));
if (!cur_tb) {
fprintf (stderr,
"%s: unable to allocate %lu bytes for title button\n",
ProgramName, (unsigned long) sizeof(TitleButton));
return 0;
}
cur_tb->next = NULL;
cur_tb->name = name; /* note that we are not copying */
cur_tb->image = None; /* WARNING, values not set yet */
cur_tb->width = 0; /* see InitTitlebarButtons */
cur_tb->height = 0; /* ditto */
cur_tb->rightside = rightside;
cur_tb->funs = NULL;
if (rightside) {
Scr->TBInfo.nright++;
} else {
Scr->TBInfo.nleft++;
}
for(button = 0; button < MAX_BUTTONS; button++){
ModifyCurrentTB(button + 1, 0, func, action, menuroot);
}
/*
* Cases for list:
*
* 1. empty list, prepend left put at head of list
* 2. append left, prepend right put in between left and right
* 3. append right put at tail of list
*
* Do not refer to widths and heights yet since buttons not created
* (since fonts not loaded and heights not known).
*/
if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */
cur_tb->next = Scr->TBInfo.head;
Scr->TBInfo.head = cur_tb;
} else if (append && rightside) { /* 3 */
register TitleButton *t;
for /* SUPPRESS 530 */
(t = Scr->TBInfo.head; t->next; t = t->next);
t->next = cur_tb;
cur_tb->next = NULL;
} else { /* 2 */
register TitleButton *t, *prev = NULL;
for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
prev = t;
}
if (prev) {
cur_tb->next = prev->next;
prev->next = cur_tb;
} else {
cur_tb->next = Scr->TBInfo.head;
Scr->TBInfo.head = cur_tb;
}
}
return 1;
}
/*
* InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
* button. If we can't find the button, then put in a question; if we can't
* find the question mark, something is wrong and we are probably going to be
* in trouble later on.
*/
void InitTitlebarButtons (void)
{
TitleButton *tb;
int h;
/*
* initialize dimensions
*/
Scr->TBInfo.width = (Scr->TitleHeight -
2 * (Scr->FramePadding + Scr->ButtonIndent));
if (Scr->use3Dtitles)
Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
? ((Scr->TitlePadding + 1) / 2) : 0);
else
Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
? ((Scr->TitlePadding + 1) / 2) : 1);
h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
/*
* add in some useful buttons and bindings so that novices can still
* use the system.
*/
if (!Scr->NoDefaults) {
/* insert extra buttons */
if (Scr->use3Dtitles) {
if (!CreateTitleButton (TBPM_3DDOT, F_ICONIFY, "", (MenuRoot *) NULL,
False, False)) {
fprintf (stderr, "%s: unable to add iconify button\n", ProgramName);
}
if (!CreateTitleButton (TBPM_3DRESIZE, F_RESIZE, "", (MenuRoot *) NULL,
True, True)) {
fprintf (stderr, "%s: unable to add resize button\n", ProgramName);
}
}
else {
if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
False, False)) {
fprintf (stderr, "%s: unable to add iconify button\n", ProgramName);
}
if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
True, True)) {
fprintf (stderr, "%s: unable to add resize button\n", ProgramName);
}
}
addingdefaults = True;
AddDefaultBindings ();
addingdefaults = False;
}
ComputeCommonTitleOffsets ();
/*
* load in images and do appropriate centering
*/
for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
tb->image = GetImage (tb->name, Scr->TitleC);
if (!tb->image) {
tb->image = GetImage (TBPM_QUESTION, Scr->TitleC);
if (!tb->image) { /* cannot happen (see util.c) */
fprintf (stderr, "%s: unable to add titlebar button \"%s\"\n",
ProgramName, tb->name);
continue;
}
}
tb->width = tb->image->width;
tb->height = tb->image->height;
tb->dstx = (h - tb->width + 1) / 2;
if (tb->dstx < 0) { /* clip to minimize copying */
tb->srcx = -(tb->dstx);
tb->width = h;
tb->dstx = 0;
} else {
tb->srcx = 0;
}
tb->dsty = (h - tb->height + 1) / 2;
if (tb->dsty < 0) {
tb->srcy = -(tb->dsty);
tb->height = h;
tb->dsty = 0;
} else {
tb->srcy = 0;
}
}
}
void PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
{
if (Scr->use3Dmenus)
Paint3DEntry (mr, mi, exposure);
else
PaintNormalEntry (mr, mi, exposure);
if (mi->state) mr->lastactive = mi;
}
void Paint3DEntry(MenuRoot *mr, MenuItem *mi, int exposure)
{
int y_offset;
int text_y;
GC gc;
y_offset = mi->item_num * Scr->EntryHeight + Scr->MenuShadowDepth;
text_y = y_offset + Scr->MenuFont.y + 2;
if (mi->func != F_TITLE) {
int x, y;
gc = Scr->NormalGC;
if (mi->state) {
Draw3DBorder (mr->w, Scr->MenuShadowDepth, y_offset,
mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
mi->highlight, off, True, False);
FB(mi->highlight.fore, mi->highlight.back);
XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, gc,
mi->x + Scr->MenuShadowDepth, text_y, mi->item, mi->strlen);
}
else {
if (mi->user_colors || !exposure) {
XSetForeground (dpy, gc, mi->normal.back);
XFillRectangle (dpy, mr->w, gc,
Scr->MenuShadowDepth, y_offset,
mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight);
FB (mi->normal.fore, mi->normal.back);
}
else {
gc = Scr->MenuGC;
}
XmbDrawImageString (dpy, mr->w, Scr->MenuFont.font_set, gc,
mi->x + Scr->MenuShadowDepth, text_y,
mi->item, mi->strlen);
if (mi->separated) {
FB (Scr->MenuC.shadd, Scr->MenuC.shadc);
XDrawLine (dpy, mr->w, Scr->NormalGC,
Scr->MenuShadowDepth,
y_offset + Scr->EntryHeight - 2,
mr->width - Scr->MenuShadowDepth,
y_offset + Scr->EntryHeight - 2);
FB (Scr->MenuC.shadc, Scr->MenuC.shadd);
XDrawLine (dpy, mr->w, Scr->NormalGC,
Scr->MenuShadowDepth,
y_offset + Scr->EntryHeight - 1,
mr->width - Scr->MenuShadowDepth,
y_offset + Scr->EntryHeight - 1);
}
}
if (mi->func == F_MENU) {
/* create the pull right pixmap if needed */
if (Scr->pullPm == None)
{
Scr->pullPm = Create3DMenuIcon (Scr->MenuFont.height, &Scr->pullW,
&Scr->pullH, Scr->MenuC);
}
x = mr->width - Scr->pullW - Scr->MenuShadowDepth - 2;
y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2) + 2;
XCopyArea (dpy, Scr->pullPm, mr->w, gc, 0, 0, Scr->pullW, Scr->pullH, x, y);
}
}
else
{
Draw3DBorder (mr->w, Scr->MenuShadowDepth, y_offset,
mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
mi->normal, off, True, False);
FB (mi->normal.fore, mi->normal.back);
XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC,
mi->x + 2, text_y, mi->item, mi->strlen);
}
}
void PaintNormalEntry(MenuRoot *mr, MenuItem *mi, int exposure)
{
int y_offset;
int text_y;
GC gc;
y_offset = mi->item_num * Scr->EntryHeight;
text_y = y_offset + Scr->MenuFont.y;
if (mi->func != F_TITLE)
{
int x, y;
if (mi->state)
{
XSetForeground(dpy, Scr->NormalGC, mi->highlight.back);
XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
mr->width, Scr->EntryHeight);
FB(mi->highlight.fore, mi->highlight.back);
XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC,
mi->x, text_y, mi->item, mi->strlen);
gc = Scr->NormalGC;
}
else
{
if (mi->user_colors || !exposure)
{
XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
mr->width, Scr->EntryHeight);
FB(mi->normal.fore, mi->normal.back);
gc = Scr->NormalGC;
}
else {
gc = Scr->MenuGC;
}
XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, gc, mi->x,
text_y, mi->item, mi->strlen);
if (mi->separated)
XDrawLine (dpy, mr->w, gc, 0, y_offset + Scr->EntryHeight - 1,
mr->width, y_offset + Scr->EntryHeight - 1);
}
if (mi->func == F_MENU)
{
/* create the pull right pixmap if needed */
if (Scr->pullPm == None)
{
Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
&Scr->pullW, &Scr->pullH);
}
x = mr->width - Scr->pullW - 5;
y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
Scr->pullW, Scr->pullH, x, y, 1);
}
}
else
{
int y;
XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
/* fill the rectangle with the title background color */
XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
mr->width, Scr->EntryHeight);
{
XSetForeground(dpy, Scr->NormalGC, mi->normal.fore);
/* now draw the dividing lines */
if (y_offset)
XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
mr->width, y_offset);
y = ((mi->item_num+1) * Scr->EntryHeight)-1;
XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
}
FB(mi->normal.fore, mi->normal.back);
/* finally render the title */
XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC, mi->x,
text_y, mi->item, mi->strlen);
}
}
void PaintMenu(MenuRoot *mr, XEvent *e)
{
MenuItem *mi;
if (Scr->use3Dmenus) {
Draw3DBorder (mr->w, 0, 0, mr->width, mr->height,
Scr->MenuShadowDepth, Scr->MenuC, off, False, False);
}
for (mi = mr->first; mi != NULL; mi = mi->next)
{
int y_offset = mi->item_num * Scr->EntryHeight;
/* be smart about handling the expose, redraw only the entries
* that we need to
*/
if (e->xexpose.y <= (y_offset + Scr->EntryHeight) &&
(e->xexpose.y + e->xexpose.height) >= y_offset)
{
PaintEntry(mr, mi, True);
}
}
XSync(dpy, 0);
}
void MakeWorkspacesMenu (void)
{
static char **actions = NULL;
WorkSpace *wlist;
char **act;
if (! Scr->Workspaces) return;
AddToMenu (Scr->Workspaces, "TWM Workspaces", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
if (! actions) {
int count = 0;
for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
count++;
}
count++;
actions = (char**) malloc (count * sizeof (char*));
act = actions;
for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
*act = (char*) malloc (strlen ("WGOTO : ") + strlen (wlist->name) + 1);
sprintf (*act, "WGOTO : %s", wlist->name);
act++;
}
*act = NULL;
}
act = actions;
for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
AddToMenu (Scr->Workspaces, wlist->name, *act, Scr->Windows, F_MENU, NULL, NULL);
act++;
}
Scr->Workspaces->pinned = False;
MakeMenu (Scr->Workspaces);
}
static Bool fromMenu;
int UpdateMenu(void)
{
MenuItem *mi;
int i, x, y, x_root, y_root, entry;
int done;
MenuItem *badItem = NULL;
fromMenu = TRUE;
while (TRUE)
{
/* block until there is an event */
if (!menuFromFrameOrWindowOrTitlebar) {
XMaskEvent(dpy,
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask |
EnterWindowMask | ExposureMask |
VisibilityChangeMask | LeaveWindowMask |
ButtonMotionMask, &Event);
}
if (Event.type == MotionNotify) {
/* discard any extra motion events before a release */
while(XCheckMaskEvent(dpy,
ButtonMotionMask | ButtonReleaseMask, &Event))
if (Event.type == ButtonRelease)
break;
}
if (!DispatchEvent ())
continue;
if ((! ActiveMenu) || Cancel) {
menuFromFrameOrWindowOrTitlebar = FALSE;
fromMenu = FALSE;
return (0);
}
if (Event.type != MotionNotify)
continue;
done = FALSE;
XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
&x_root, &y_root, &x, &y, &JunkMask);
/* if we haven't recieved the enter notify yet, wait */
if (ActiveMenu && !ActiveMenu->entered)
continue;
if (XFindContext(dpy, ActiveMenu->w, ScreenContext, (XPointer *)&Scr)
!= XCSUCCESS)
continue;
if (x < 0 || y < 0 ||
x >= ActiveMenu->width || y >= ActiveMenu->height)
{
if (ActiveItem && ActiveItem->func != F_TITLE)
{
ActiveItem->state = 0;
PaintEntry(ActiveMenu, ActiveItem, False);
}
ActiveItem = NULL;
continue;
}
/* look for the entry that the mouse is in */
entry = y / Scr->EntryHeight;
for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
{
if (i == entry)
break;
}
/* if there is an active item, we might have to turn it off */
if (ActiveItem)
{
/* is the active item the one we are on ? */
if (ActiveItem->item_num == entry && ActiveItem->state)
done = TRUE;
/* if we weren't on the active entry, let's turn the old
* active one off
*/
if (!done && ActiveItem->func != F_TITLE)
{
ActiveItem->state = 0;
PaintEntry(ActiveMenu, ActiveItem, False);
}
}
/* if we weren't on the active item, change the active item and turn
* it on
*/
if (!done)
{
ActiveItem = mi;
if (ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state)
{
ActiveItem->state = 1;
PaintEntry(ActiveMenu, ActiveItem, False);
}
}
/* now check to see if we were over the arrow of a pull right entry */
if (ActiveItem && ActiveItem->func == F_MENU &&
((ActiveMenu->width - x) < (ActiveMenu->width / 3)))
{
MenuRoot *save = ActiveMenu;
int savex = MenuOrigins[MenuDepth - 1].x;
int savey = MenuOrigins[MenuDepth - 1].y;
if (MenuDepth < MAXMENUDEPTH) {
if (ActiveMenu == Scr->Workspaces)
CurrentSelectedWorkspace = ActiveItem->item;
PopUpMenu (ActiveItem->sub,
(savex + (((2 * ActiveMenu->width) / 3) - 1)),
(savey + ActiveItem->item_num * Scr->EntryHeight)
/*(savey + ActiveItem->item_num * Scr->EntryHeight +
(Scr->EntryHeight >> 1))*/, False);
CurrentSelectedWorkspace = NULL;
} else if (!badItem) {
XBell (dpy, 0);
badItem = ActiveItem;
}
/* if the menu did get popped up, unhighlight the active item */
if (save != ActiveMenu && ActiveItem->state)
{
ActiveItem->state = 0;
PaintEntry(save, ActiveItem, False);
ActiveItem = NULL;
}
}
if (badItem != ActiveItem) badItem = NULL;
XFlush(dpy);
}
}
/***********************************************************************
*
* Procedure:
* NewMenuRoot - create a new menu root
*
* Returned Value:
* (MenuRoot *)
*
* Inputs:
* name - the name of the menu root
*
***********************************************************************
*/
MenuRoot *NewMenuRoot(char *name)
{
MenuRoot *tmp;
#define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */
tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
tmp->highlight.fore = UNUSED_PIXEL;
tmp->highlight.back = UNUSED_PIXEL;
tmp->name = name;
tmp->prev = NULL;
tmp->first = NULL;
tmp->last = NULL;
tmp->defaultitem = NULL;
tmp->items = 0;
tmp->width = 0;
tmp->mapped = NEVER_MAPPED;
tmp->pull = FALSE;
tmp->w = None;
tmp->shadow = None;
tmp->real_menu = FALSE;
if (Scr->MenuList == NULL)
{
Scr->MenuList = tmp;
Scr->MenuList->next = NULL;
}
if (Scr->LastMenu == NULL)
{
Scr->LastMenu = tmp;
Scr->LastMenu->next = NULL;
}
else
{
Scr->LastMenu->next = tmp;
Scr->LastMenu = tmp;
Scr->LastMenu->next = NULL;
}
if (strcmp(name, TWM_WINDOWS) == 0)
Scr->Windows = tmp;
if (strcmp(name, TWM_ICONS) == 0)
Scr->Icons = tmp;
if (strcmp(name, TWM_WORKSPACES) == 0) {
Scr->Workspaces = tmp;
if (!Scr->Windows) NewMenuRoot (TWM_WINDOWS);
}
if (strcmp(name, TWM_ALLWINDOWS) == 0)
Scr->AllWindows = tmp;
/* Added by dl 2004 */
if (strcmp(name, TWM_ALLICONS) == 0)
Scr->AllIcons = tmp;
/* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */
if (strcmp(name, TWM_KEYS) == 0)
Scr->Keys = tmp;
if (strcmp(name, TWM_VISIBLE) == 0)
Scr->Visible = tmp;
/* End addition */
return (tmp);
}
/***********************************************************************
*
* Procedure:
* AddToMenu - add an item to a root menu
*
* Returned Value:
* (MenuItem *)
*
* Inputs:
* menu - pointer to the root menu to add the item
* item - the text to appear in the menu
* action - the string to possibly execute
* sub - the menu root if it is a pull-right entry
* func - the numeric function
* fore - foreground color string
* back - background color string
*
***********************************************************************
*/
MenuItem *AddToMenu(MenuRoot *menu, char *item, char *action,
MenuRoot *sub, int func, char *fore, char *back)
{
MenuItem *tmp;
int width;
char *itemname;
XRectangle ink_rect;
XRectangle logical_rect;
#ifdef DEBUG_MENUS
fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
item, action, sub, func);
#endif
tmp = (MenuItem *) malloc(sizeof(MenuItem));
tmp->root = menu;
if (menu->first == NULL)
{
menu->first = tmp;
tmp->prev = NULL;
}
else
{
menu->last->next = tmp;
tmp->prev = menu->last;
}
menu->last = tmp;
if ((menu == Scr->Workspaces) ||
(menu == Scr->Windows) ||
(menu == Scr->Icons) ||
(menu == Scr->AllWindows) ||
/* Added by dl 2004 */
(menu == Scr->AllIcons) ||
/* Added by Dan Lillehorn (dl@dl.nu) 2000-02-29 */
(menu == Scr->Keys) ||
(menu == Scr->Visible)) {
itemname = item;
} else
if (*item == '*') {
itemname = item + 1;
menu->defaultitem = tmp;
}
else {
itemname = item;
}
tmp->item = itemname;
tmp->strlen = strlen(itemname);
tmp->action = action;
tmp->next = NULL;
tmp->sub = NULL;
tmp->state = 0;
tmp->func = func;
tmp->separated = 0;
if (!Scr->HaveFonts) CreateFonts();
XmbTextExtents(Scr->MenuFont.font_set,
itemname, tmp->strlen,
&ink_rect, &logical_rect);
width = logical_rect.width;
if (width <= 0)
width = 1;
if (width > menu->width)
menu->width = width;
tmp->user_colors = FALSE;
if (Scr->Monochrome == COLOR && fore != NULL)
{
int save;
save = Scr->FirstTime;
Scr->FirstTime = TRUE;
GetColor(COLOR, &tmp->normal.fore, fore);
GetColor(COLOR, &tmp->normal.back, back);
if (Scr->use3Dmenus && !Scr->BeNiceToColormap) GetShadeColors (&tmp->normal);
Scr->FirstTime = save;
tmp->user_colors = TRUE;
}
if (sub != NULL)
{
tmp->sub = sub;
menu->pull = TRUE;
}
tmp->item_num = menu->items++;
return (tmp);
}
void MakeMenus(void)
{
MenuRoot *mr;
for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
{
if (mr->real_menu == FALSE)
continue;
mr->pinned = False;
MakeMenu(mr);
}
}
int MakeMenu(MenuRoot *mr)
{
MenuItem *start, *end, *cur, *tmp;
XColor f1, f2, f3;
XColor b1, b2, b3;
XColor save_fore, save_back;
int num, i;
int fred, fgreen, fblue;
int bred, bgreen, bblue;
int width, borderwidth;
unsigned long valuemask;
XSetWindowAttributes attributes;
Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
XRectangle ink_rect;
XRectangle logical_rect;
Scr->EntryHeight = Scr->MenuFont.height + 4;
/* lets first size the window accordingly */
if (mr->mapped == NEVER_MAPPED)
{
if (mr->pull == TRUE) {
mr->width += 16 + 10;
}
width = mr->width + 10;
for (cur = mr->first; cur != NULL; cur = cur->next) {
if (cur->func != F_TITLE)
cur->x = 5;
else {
XmbTextExtents(Scr->MenuFont.font_set, cur->item, cur->strlen,
&ink_rect, &logical_rect);
cur->x = width - logical_rect.width;
cur->x /= 2;
}
}
mr->height = mr->items * Scr->EntryHeight;
mr->width += 10;
if (Scr->use3Dmenus) {
mr->width += 2 * Scr->MenuShadowDepth;
mr->height += 2 * Scr->MenuShadowDepth;
}
if (Scr->Shadow && ! mr->pinned)
{
/*
* Make sure that you don't draw into the shadow window or else
* the background bits there will get saved
*/
valuemask = (CWBackPixel | CWBorderPixel);
attributes.background_pixel = Scr->MenuShadowColor;
attributes.border_pixel = Scr->MenuShadowColor;
if (Scr->SaveUnder) {
valuemask |= CWSaveUnder;
attributes.save_under = True;
}
mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
(unsigned int) mr->width,
(unsigned int) mr->height,
(unsigned int)0,
CopyFromParent,
(unsigned int) CopyFromParent,
(Visual *) CopyFromParent,
valuemask, &attributes);
}
valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
attributes.background_pixel = Scr->MenuC.back;
attributes.border_pixel = Scr->MenuC.fore;
if (mr->pinned) {
attributes.event_mask = (ExposureMask | EnterWindowMask
| LeaveWindowMask | ButtonPressMask
| ButtonReleaseMask | PointerMotionMask
| ButtonMotionMask
);
attributes.cursor = Scr->MenuCursor;
valuemask |= CWCursor;
}
else
attributes.event_mask = (ExposureMask | EnterWindowMask);
if (Scr->SaveUnder && ! mr->pinned) {
valuemask |= CWSaveUnder;
attributes.save_under = True;
}
if (Scr->BackingStore) {
valuemask |= CWBackingStore;
attributes.backing_store = Always;
}
borderwidth = Scr->use3Dmenus ? 0 : 1;
mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
(unsigned int) mr->height, (unsigned int) borderwidth,
CopyFromParent, (unsigned int) CopyFromParent,
(Visual *) CopyFromParent,
valuemask, &attributes);
XSaveContext(dpy, mr->w, MenuContext, (XPointer)mr);
XSaveContext(dpy, mr->w, ScreenContext, (XPointer)Scr);
mr->mapped = UNMAPPED;
}
if (Scr->use3Dmenus && (Scr->Monochrome == COLOR) && (mr->highlight.back == UNUSED_PIXEL)) {
XColor xcol;
char colname [32];
short save;
xcol.pixel = Scr->MenuC.back;
XQueryColor (dpy, cmap, &xcol);
sprintf (colname, "#%04x%04x%04x",
5 * ((int)xcol.red / 6),
5 * ((int)xcol.green / 6),
5 * ((int)xcol.blue / 6));
save = Scr->FirstTime;
Scr->FirstTime = True;
GetColor (Scr->Monochrome, &mr->highlight.back, colname);
Scr->FirstTime = save;
}
if (Scr->use3Dmenus && (Scr->Monochrome == COLOR) && (mr->highlight.fore == UNUSED_PIXEL)) {
XColor xcol;
char colname [32];
short save;
xcol.pixel = Scr->MenuC.fore;
XQueryColor (dpy, cmap, &xcol);
sprintf (colname, "#%04x%04x%04x",
5 * ((int)xcol.red / 6),
5 * ((int)xcol.green / 6),
5 * ((int)xcol.blue / 6));
save = Scr->FirstTime;
Scr->FirstTime = True;
GetColor (Scr->Monochrome, &mr->highlight.fore, colname);
Scr->FirstTime = save;
}
if (Scr->use3Dmenus && !Scr->BeNiceToColormap) GetShadeColors (&mr->highlight);
/* get the default colors into the menus */
for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
{
if (!tmp->user_colors) {
if (tmp->func != F_TITLE) {
tmp->normal.fore = Scr->MenuC.fore;
tmp->normal.back = Scr->MenuC.back;
} else {
tmp->normal.fore = Scr->MenuTitleC.fore;
tmp->normal.back = Scr->MenuTitleC.back;
}
}
if (mr->highlight.fore != UNUSED_PIXEL)
{
tmp->highlight.fore = mr->highlight.fore;
tmp->highlight.back = mr->highlight.back;
}
else
{
tmp->highlight.fore = tmp->normal.back;
tmp->highlight.back = tmp->normal.fore;
}
if (Scr->use3Dmenus && !Scr->BeNiceToColormap) {
if (tmp->func != F_TITLE)
GetShadeColors (&tmp->highlight);
else
GetShadeColors (&tmp->normal);
}
}
mr->pmenu = NULL;
if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
return 0;
start = mr->first;
while (TRUE)
{
for (; start != NULL; start = start->next)
{
if (start->user_colors)
break;
}
if (start == NULL)
break;
for (end = start->next; end != NULL; end = end->next)
{
if (end->user_colors)
break;
}
if (end == NULL)
break;
/* we have a start and end to interpolate between */
num = end->item_num - start->item_num;
f1.pixel = start->normal.fore;
XQueryColor(dpy, cmap, &f1);
f2.pixel = end->normal.fore;
XQueryColor(dpy, cmap, &f2);
b1.pixel = start->normal.back;
XQueryColor(dpy, cmap, &b1);
b2.pixel = end->normal.back;
XQueryColor(dpy, cmap, &b2);
fred = ((int)f2.red - (int)f1.red) / num;
fgreen = ((int)f2.green - (int)f1.green) / num;
fblue = ((int)f2.blue - (int)f1.blue) / num;
bred = ((int)b2.red - (int)b1.red) / num;
bgreen = ((int)b2.green - (int)b1.green) / num;
bblue = ((int)b2.blue - (int)b1.blue) / num;
f3 = f1;
f3.flags = DoRed | DoGreen | DoBlue;
b3 = b1;
b3.flags = DoRed | DoGreen | DoBlue;
start->highlight.back = start->normal.fore;
start->highlight.fore = start->normal.back;
num -= 1;
for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
{
f3.red += fred;
f3.green += fgreen;
f3.blue += fblue;
save_fore = f3;
b3.red += bred;
b3.green += bgreen;
b3.blue += bblue;
save_back = b3;
XAllocColor(dpy, cmap, &f3);
XAllocColor(dpy, cmap, &b3);
cur->highlight.back = cur->normal.fore = f3.pixel;
cur->highlight.fore = cur->normal.back = b3.pixel;
cur->user_colors = True;
f3 = save_fore;
b3 = save_back;
}
start = end;
start->highlight.back = start->normal.fore;
start->highlight.fore = start->normal.back;
}
return 1;
}
/***********************************************************************
*
* Procedure:
* PopUpMenu - pop up a pull down menu
*
* Inputs:
* menu - the root pointer of the menu to pop up
* x, y - location of upper left of menu
* center - whether or not to center horizontally over position
*
***********************************************************************
*/
Bool PopUpMenu (MenuRoot *menu, int x, int y, Bool center)
{
int WindowNameCount;
TwmWindow **WindowNames;
TwmWindow *tmp_win2,*tmp_win3;
int i;
int xl, yt;
Bool clipped;
#ifdef CLAUDE
char tmpname3 [256], tmpname4 [256];
int hasmoz = 0;
#endif
if (!menu) return False;
InstallRootColormap();
if ((menu == Scr->Windows) ||
(menu == Scr->Icons) ||
(menu == Scr->AllWindows) ||
/* Added by Dan 'dl' Lilliehorn 040607 */
(menu == Scr->AllIcons) ||
/* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */
(menu == Scr->Visible))
{
TwmWindow *tmp_win;
WorkSpace *ws;
Boolean all, icons, visible_, allicons; /* visible, allicons:
Added by dl */
int func;
/* this is the twm windows menu, let's go ahead and build it */
all = (menu == Scr->AllWindows);
icons = (menu == Scr->Icons);
visible_ = (menu == Scr->Visible); /* Added by dl */
allicons = (menu == Scr->AllIcons);
DestroyMenu (menu);
menu->first = NULL;
menu->last = NULL;
menu->items = 0;
menu->width = 0;
menu->mapped = NEVER_MAPPED;
menu->highlight.fore = UNUSED_PIXEL;
menu->highlight.back = UNUSED_PIXEL;
if (menu == Scr->Windows)
AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
else
if (menu == Scr->Icons)
AddToMenu(menu, "TWM Icons", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
else
if (menu == Scr->Visible) /* Added by dl 2000 */
AddToMenu(menu, "TWM Visible", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
else
if (menu == Scr->AllIcons) /* Added by dl 2004 */
AddToMenu(menu, "TWM All Icons", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
else
AddToMenu(menu, "TWM All Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
ws = NULL;
if (! (all || allicons)
&& CurrentSelectedWorkspace && Scr->workSpaceManagerActive) {
for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
if (strcmp (ws->name, CurrentSelectedWorkspace) == 0) break;
}
}
if (!Scr->currentvs) return False;
if (!ws) ws = Scr->currentvs->wsw->currentwspc;
for (tmp_win = Scr->FirstWindow, WindowNameCount = 0;
tmp_win != NULL;
tmp_win = tmp_win->next) {
if (tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) continue;
if (Scr->ShortAllWindowsMenus && (tmp_win->wspmgr || tmp_win->iconmgr)) continue;
if (!(all || allicons) && !OCCUPY (tmp_win, ws)) continue;
if (allicons && !tmp_win->isicon) continue;
if (icons && !tmp_win->isicon) continue;
if (visible_ && tmp_win->isicon) continue; /* added by dl */
WindowNameCount++;
}
WindowNames = (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
WindowNameCount = 0;
for (tmp_win = Scr->FirstWindow;
tmp_win != NULL;
tmp_win = tmp_win->next)
{
if (LookInList (Scr->IconMenuDontShow, tmp_win->full_name, &tmp_win->class)) continue;
if (tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) continue;
if (Scr->ShortAllWindowsMenus &&
tmp_win == Scr->currentvs->wsw->twm_win) continue;
if (Scr->ShortAllWindowsMenus && tmp_win->iconmgr) continue;
if (!(all || allicons)&& ! OCCUPY (tmp_win, ws)) continue;
if (allicons && !tmp_win->isicon) continue;
if (icons && !tmp_win->isicon) continue;
if (visible_ && tmp_win->isicon) continue; /* added by dl */
tmp_win2 = tmp_win;
for (i = 0; i < WindowNameCount; i++) {
int compresult;
char *tmpname1, *tmpname2;
tmpname1 = tmp_win2->name;
tmpname2 = WindowNames[i]->name;
#ifdef CLAUDE
if (strlen (tmpname1) == 1) tmpname1 = " No title";
if (strlen (tmpname2) == 1) tmpname2 = " No title";
if (!strncasecmp (tmp_win2->class.res_class, "navigator", 9) ||
!strncasecmp (tmp_win2->class.res_class, "mozilla", 7)) {
tmpname3 [0] = ' '; tmpname3 [1] = '\0';
strcat (tmpname3, tmpname1);
} else {
strcpy (tmpname3, tmpname1);
}
if (!strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) ||
!strncasecmp (WindowNames[i]->class.res_class, "mozilla", 7)) {
tmpname4 [0] = ' '; tmpname4 [1] = '\0';
strcat (tmpname4, tmpname2);
} else {
strcpy (tmpname4, tmpname2);
}
tmpname1 = tmpname3;
tmpname2 = tmpname4;
#endif
if (Scr->CaseSensitive)
compresult = strcmp(tmpname1,tmpname2);
else
compresult = XmuCompareISOLatin1(tmpname1,tmpname2);
if (compresult < 0) {
tmp_win3 = tmp_win2;
tmp_win2 = WindowNames[i];
WindowNames[i] = tmp_win3;
}
}
WindowNames[WindowNameCount] = tmp_win2;
WindowNameCount++;
}
func = (all || allicons || CurrentSelectedWorkspace) ? F_WINWARP :
F_POPUP;
for (i = 0; i < WindowNameCount; i++)
{
char *tmpname;
tmpname = WindowNames[i]->name;
#ifdef CLAUDE
if (!strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) ||
!strncasecmp (WindowNames[i]->class.res_class, "mozilla", 7) ||
!strncasecmp (WindowNames[i]->class.res_class, "netscape", 8) ||
!strncasecmp (WindowNames[i]->class.res_class, "konqueror", 9)) {
hasmoz = 1;
}
if (hasmoz && strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) &&
strncasecmp (WindowNames[i]->class.res_class, "mozilla", 7) &&
strncasecmp (WindowNames[i]->class.res_class, "netscape", 8) &&
strncasecmp (WindowNames[i]->class.res_class, "konqueror", 9)) {
menu->last->separated = 1;
hasmoz = 0;
}
#endif
AddToMenu(menu, tmpname, (char *)WindowNames[i],
NULL, func,NULL,NULL);
}
free(WindowNames);
menu->pinned = False;
MakeMenu(menu);
}
/* Keys added by dl */
if (menu == Scr->Keys) {
FuncKey *tmpKey;
char *tmpStr, *tmpStr2;
char modStr[5];
char *oldact = 0;
int oldmod = 0;
int tmpLen;
DestroyMenu (menu);
menu->first = NULL;
menu->last = NULL;
menu->items = 0;
menu->width = 0;
menu->mapped = NEVER_MAPPED;
menu->highlight.fore = UNUSED_PIXEL;
menu->highlight.back = UNUSED_PIXEL;
AddToMenu(menu, "Twm Keys", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
for (tmpKey = Scr->FuncKeyRoot.next; tmpKey != NULL; tmpKey = tmpKey->next) {
if (tmpKey->func != F_EXEC) continue;
if ((tmpKey->action == oldact) && (tmpKey->mods == oldmod)) continue;
strcpy (modStr, "");
switch (tmpKey->mods) {
case 1: strcpy (modStr, "S"); break;
case 4: strcpy (modStr, "C"); break;
case 5: strcpy (modStr, "S + C"); break;
case 8: strcpy (modStr, "M"); break;
case 9: strcpy (modStr, "S + M"); break;
case 12: strcpy (modStr, "C + M"); break;
default: break;
}
tmpLen = (strlen (tmpKey->name) + strlen (modStr) + 5);
tmpStr = malloc (sizeof(char) * tmpLen);
sprintf (tmpStr,"[%s + %s]", tmpKey->name, modStr);
tmpStr2 = malloc (sizeof(char) * (strlen (tmpKey->action) + tmpLen + 2));
sprintf (tmpStr2, "%s %s", tmpStr, tmpKey->action);
AddToMenu (menu, tmpStr2, tmpKey->action, NULL, tmpKey->func, NULLSTR, NULLSTR);
oldact = tmpKey->action;
oldmod = tmpKey->mods;
}
menu->pinned = False;
MakeMenu(menu);
}
if (menu->w == None || menu->items == 0) return False;
/* Prevent recursively bringing up menus. */
if ((!menu->pinned) && (menu->mapped == MAPPED)) return False;
/*
* Dynamically set the parent; this allows pull-ups to also be main
* menus, or to be brought up from more than one place.
*/
menu->prev = ActiveMenu;
if (menu->pinned) {
ActiveMenu = menu;
menu->mapped = MAPPED;
menu->entered = TRUE;
MenuOrigins [MenuDepth].x = menu->x;
MenuOrigins [MenuDepth].y = menu->y;
MenuDepth++;
XRaiseWindow (dpy, menu->w);
return (True);
}
XGrabPointer(dpy, Scr->Root, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
ButtonMotionMask | PointerMotionHintMask,
GrabModeAsync, GrabModeAsync,
Scr->Root,
Scr->MenuCursor, CurrentTime);
XGrabKeyboard (dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
ActiveMenu = menu;
menu->mapped = MAPPED;
menu->entered = FALSE;
if (center) {
x -= (menu->width / 2);
y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
}
/*
* clip to screen
*/
clipped = FALSE;
if (x + menu->width > Scr->rootw) {
x = Scr->rootw - menu->width;
clipped = TRUE;
}
if (x < 0) {
x = 0;
clipped = TRUE;
}
if (y + menu->height > Scr->rooth) {
y = Scr->rooth - menu->height;
clipped = TRUE;
}
if (y < 0) {
y = 0;
clipped = TRUE;
}
MenuOrigins[MenuDepth].x = x;
MenuOrigins[MenuDepth].y = y;
MenuDepth++;
if (Scr->Root != Scr->CaptiveRoot) {
XReparentWindow (dpy, menu->shadow, Scr->Root, x, y);
XReparentWindow (dpy, menu->w, Scr->Root, x, y);
} else
XMoveWindow (dpy, menu->w, x, y);
if (Scr->Shadow) {
XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
XRaiseWindow (dpy, menu->shadow);
}
XMapRaised(dpy, menu->w);
if (!Scr->NoWarpToMenuTitle && clipped && center) {
xl = x + (menu->width / 2);
yt = y + (Scr->EntryHeight / 2);
XWarpPointer (dpy, Scr->Root, Scr->Root, x, y, menu->width, menu->height, xl, yt);
}
if (Scr->Shadow) XMapWindow (dpy, menu->shadow);
XSync(dpy, 0);
return True;
}
/***********************************************************************
*
* Procedure:
* PopDownMenu - unhighlight the current menu selection and
* take down the menus
*
***********************************************************************
*/
int PopDownMenu(void)
{
MenuRoot *tmp;
if (ActiveMenu == NULL)
return (1);
if (ActiveItem)
{
ActiveItem->state = 0;
PaintEntry(ActiveMenu, ActiveItem, False);
}
for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
{
if (! tmp->pinned) HideMenu (tmp);
UninstallRootColormap();
}
XFlush(dpy);
ActiveMenu = NULL;
ActiveItem = NULL;
MenuDepth = 0;
XUngrabKeyboard (dpy, CurrentTime);
if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE || Context == C_ICON)
menuFromFrameOrWindowOrTitlebar = TRUE;
return 1;
}
Bool HideMenu (MenuRoot *menu)
{
if (!menu) return False;
if (Scr->Shadow) {
XUnmapWindow (dpy, menu->shadow);
}
XUnmapWindow (dpy, menu->w);
menu->mapped = UNMAPPED;
return True;
}
/***********************************************************************
*
* Procedure:
* FindMenuRoot - look for a menu root
*
* Returned Value:
* (MenuRoot *) - a pointer to the menu root structure
*
* Inputs:
* name - the name of the menu root
*
***********************************************************************
*/
MenuRoot *FindMenuRoot(char *name)
{
MenuRoot *tmp;
for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
{
if (strcmp(name, tmp->name) == 0)
return (tmp);
}
return NULL;
}
static Bool belongs_to_twm_window (register TwmWindow *t, register Window w)
{
if (!t) return False;
if (w == t->frame || w == t->title_w || w == t->hilite_wl || w == t->hilite_wr ||
(t->icon && (w == t->icon->w || w == t->icon->bm_w))) return True;
if (t && t->titlebuttons) {
register TBWindow *tbw;
register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
if (tbw->window == w) return True;
}
}
return False;
}
/***********************************************************************
*
* Procedure:
* resizeFromCenter -
*
***********************************************************************
*/
void resizeFromCenter(Window w, TwmWindow *tmp_win)
{
int lastx, lasty, bw2;
int namelen;
XRectangle inc_rect;
XRectangle logical_rect;
namelen = strlen (tmp_win->name);
bw2 = tmp_win->frame_bw * 2;
AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D;
AddingH = tmp_win->attr.height + tmp_win->title_height + bw2 + 2 * tmp_win->frame_bw3D;
XmbTextExtents(Scr->SizeFont.font_set, tmp_win->name, namelen,
&inc_rect, &logical_rect);
XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
&DragWidth, &DragHeight,
&JunkBW, &JunkDepth);
XWarpPointer(dpy, None, w,
0, 0, 0, 0, DragWidth/2, DragHeight/2);
XQueryPointer (dpy, Scr->Root, &JunkRoot,
&JunkChild, &JunkX, &JunkY,
&AddingX, &AddingY, &JunkMask);
lastx = -10000;
lasty = -10000;
MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
while (TRUE)
{
XMaskEvent(dpy,
ButtonPressMask | PointerMotionMask | ExposureMask, &Event);
if (Event.type == MotionNotify) {
/* discard any extra motion events before a release */
while(XCheckMaskEvent(dpy,
ButtonMotionMask | ButtonPressMask, &Event))
if (Event.type == ButtonPress)
break;
}
if (Event.type == ButtonPress)
{
MenuEndResize(tmp_win);
XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
break;
}
if (Event.type != MotionNotify) {
(void)DispatchEvent2 ();
continue;
}
/*
* XXX - if we are going to do a loop, we ought to consider
* using multiple GXxor lines so that we don't need to
* grab the server.
*/
XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
&JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
if (lastx != AddingX || lasty != AddingY)
{
MenuDoResize(AddingX, AddingY, tmp_win);
lastx = AddingX;
lasty = AddingY;
}
}
}
/***********************************************************************
*
* Procedure:
* ExecuteFunction - execute a twm root function
*
* Inputs:
* func - the function to execute
* action - the menu action to execute
* w - the window to execute this function on
* tmp_win - the twm window structure
* event - the event that caused the function
* context - the context in which the button was pressed
* pulldown- flag indicating execution from pull down menu
*
* Returns:
* TRUE if should continue with remaining actions else FALSE to abort
*
***********************************************************************
*/
int ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win,
XEvent *eventp, int context, int pulldown)
{
static Time last_time = 0;
char tmp[200];
char *ptr;
char buff[MAX_FILE_SIZE];
int count, fd;
Window rootw;
int origX, origY;
int do_next_action = TRUE;
int moving_icon = FALSE;
Bool fromtitlebar = False;
Bool from3dborder = False;
TwmWindow *t;
RootFunction = 0;
if (Cancel)
return TRUE; /* XXX should this be FALSE? */
switch (func)
{
case F_UPICONMGR:
case F_LEFTICONMGR:
case F_RIGHTICONMGR:
case F_DOWNICONMGR:
case F_FORWICONMGR:
case F_BACKICONMGR:
case F_NEXTICONMGR:
case F_PREVICONMGR:
case F_NOP:
case F_TITLE:
case F_DELTASTOP:
case F_RAISELOWER:
case F_WARPTOSCREEN:
case F_WARPTO:
case F_WARPRING:
case F_WARPTOICONMGR:
case F_COLORMAP:
case F_ALTKEYMAP:
case F_ALTCONTEXT:
break;
default:
XGrabPointer(dpy, Scr->Root, True,
ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
Scr->Root, Scr->WaitCursor, CurrentTime);
break;
}
switch (func)
{
#ifdef SOUNDS
case F_TOGGLESOUND:
toggle_sound();
break;
case F_REREADSOUNDS:
reread_sounds();
break;
#endif
case F_NOP:
case F_TITLE:
break;
case F_DELTASTOP:
if (WindowMoved) do_next_action = FALSE;
break;
case F_RESTART: {
DoRestart(eventp->xbutton.time);
break;
}
case F_UPICONMGR:
case F_DOWNICONMGR:
case F_LEFTICONMGR:
case F_RIGHTICONMGR:
case F_FORWICONMGR:
case F_BACKICONMGR:
MoveIconManager(func);
break;
case F_FORWMAPICONMGR:
case F_BACKMAPICONMGR:
MoveMappedIconManager(func);
break;
case F_NEXTICONMGR:
case F_PREVICONMGR:
JumpIconManager(func);
break;
case F_SHOWLIST:
if (Scr->NoIconManagers) break;
ShowIconManager ();
break;
case F_STARTANIMATION :
StartAnimation ();
break;
case F_STOPANIMATION :
StopAnimation ();
break;
case F_SPEEDUPANIMATION :
ModifyAnimationSpeed (1);
break;
case F_SLOWDOWNANIMATION :
ModifyAnimationSpeed (-1);
break;
case F_HIDELIST:
if (Scr->NoIconManagers) break;
HideIconManager ();
break;
case F_SHOWWORKMGR:
if (! Scr->workSpaceManagerActive) break;
DeIconify (Scr->currentvs->wsw->twm_win);
RaiseWindow(Scr->currentvs->wsw->twm_win);
break;
case F_HIDEWORKMGR:
if (! Scr->workSpaceManagerActive) break;
Iconify (Scr->currentvs->wsw->twm_win, eventp->xbutton.x_root - 5,
eventp->xbutton.y_root - 5);
break;
case F_TOGGLEWORKMGR:
if (! Scr->workSpaceManagerActive) break;
if (Scr->currentvs->wsw->twm_win->mapped)
Iconify (Scr->currentvs->wsw->twm_win, eventp->xbutton.x_root - 5,
eventp->xbutton.y_root - 5);
else {
DeIconify (Scr->currentvs->wsw->twm_win);
RaiseWindow(Scr->currentvs->wsw->twm_win);
}
break;
case F_TOGGLESTATE :
WMapToggleState (Scr->currentvs);
break;
case F_SETBUTTONSTATE :
WMapSetButtonsState (Scr->currentvs);
break;
case F_SETMAPSTATE :
WMapSetMapState (Scr->currentvs);
break;
case F_PIN :
if (! ActiveMenu) break;
if (ActiveMenu->pinned) {
XUnmapWindow (dpy, ActiveMenu->w);
ActiveMenu->mapped = UNMAPPED;
}
else {
XWindowAttributes attr;
MenuRoot *menu;
if (ActiveMenu->pmenu == NULL) {
menu = (MenuRoot*) malloc (sizeof (struct MenuRoot));
*menu = *ActiveMenu;
menu->pinned = True;
menu->mapped = NEVER_MAPPED;
menu->width -= 10;
if (menu->pull) menu->width -= 16 + 10;
MakeMenu (menu);
ActiveMenu->pmenu = menu;
}
else menu = ActiveMenu->pmenu;
if (menu->mapped == MAPPED) break;
XGetWindowAttributes (dpy, ActiveMenu->w, &attr);
menu->x = attr.x;
menu->y = attr.y;
XMoveWindow (dpy, menu->w, menu->x, menu->y);
XMapRaised (dpy, menu->w);
menu->mapped = MAPPED;
}
PopDownMenu();
break;
case F_MOVEMENU:
break;
case F_FITTOCONTENT :
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
if (!tmp_win->iswinbox) {
XBell (dpy, 0);
break;
}
fittocontent (tmp_win);
break;
case F_VANISH:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
WMgrRemoveFromCurrentWorkSpace (Scr->currentvs, tmp_win);
break;
case F_WARPHERE:
WMgrAddToCurrentWorkSpaceAndWarp (Scr->currentvs, action);
break;
case F_ADDTOWORKSPACE:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
AddToWorkSpace (action, tmp_win);
break;
case F_REMOVEFROMWORKSPACE:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
RemoveFromWorkSpace (action, tmp_win);
break;
case F_TOGGLEOCCUPATION:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
ToggleOccupation (action, tmp_win);
break;
case F_MOVETONEXTWORKSPACE:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
MoveToNextWorkSpace(Scr->currentvs,tmp_win);
break;
case F_MOVETOPREVWORKSPACE:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
MoveToPrevWorkSpace(Scr->currentvs,tmp_win);
break;
case F_MOVETONEXTWORKSPACEANDFOLLOW:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
MoveToNextWorkSpaceAndFollow(Scr->currentvs,tmp_win);
break;
case F_MOVETOPREVWORKSPACEANDFOLLOW:
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
MoveToPrevWorkSpaceAndFollow(Scr->currentvs,tmp_win);
break;
case F_SORTICONMGR:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
{
int save_sort;
save_sort = Scr->SortIconMgr;
Scr->SortIconMgr = TRUE;
if (context == C_ICONMGR)
SortIconManager((IconMgr *) NULL);
else if (tmp_win->iconmgr)
SortIconManager(tmp_win->iconmgrp);
else
XBell(dpy, 0);
Scr->SortIconMgr = save_sort;
}
break;
case F_ALTKEYMAP: {
int alt, stat_;
if (! action) return TRUE;
stat_ = sscanf (action, "%d", &alt);
if (stat_ != 1) return TRUE;
if ((alt < 1) || (alt > 5)) return TRUE;
AlternateKeymap = Alt1Mask << (alt - 1);
XGrabPointer (dpy, Scr->Root, True, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
Scr->Root, Scr->AlterCursor, CurrentTime);
XGrabKeyboard (dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
return TRUE;
}
case F_ALTCONTEXT: {
AlternateContext = True;
XGrabPointer (dpy, Scr->Root, False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
Scr->Root, Scr->AlterCursor, CurrentTime);
XGrabKeyboard (dpy, Scr->Root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
return TRUE;
}
case F_IDENTIFY:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
Identify(tmp_win);
break;
case F_INITSIZE: {
int grav, x, y;
unsigned int width, height, swidth, sheight;
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
grav = ((tmp_win->hints.flags & PWinGravity)
? tmp_win->hints.win_gravity : NorthWestGravity);
if (!(tmp_win->hints.flags & USSize) && !(tmp_win->hints.flags & PSize)) break;
width = tmp_win->hints.width + 2 * tmp_win->frame_bw3D;
height = tmp_win->hints.height + 2 * tmp_win->frame_bw3D + tmp_win->title_height;
ConstrainSize (tmp_win, &width, &height);
x = tmp_win->frame_x;
y = tmp_win->frame_y;
swidth = tmp_win->frame_width;
sheight = tmp_win->frame_height;
switch (grav) {
case ForgetGravity :
case StaticGravity :
case NorthWestGravity :
case NorthGravity :
case WestGravity :
case CenterGravity :
break;
case NorthEastGravity :
case EastGravity :
x += swidth - width;
break;
case SouthWestGravity :
case SouthGravity :
y += sheight - height;
break;
case SouthEastGravity :
x += swidth - width;
y += sheight - height;
break;
}
SetupWindow (tmp_win, x, y, width, height, -1);
break;
}
case F_MOVERESIZE: {
int x, y, mask;
unsigned int width, height;
int px = 20, py = 30;
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
mask = XParseGeometry (action, &x, &y, &width, &height);
if (!(mask & WidthValue)) width = tmp_win->frame_width;
else width += 2 * tmp_win->frame_bw3D;
if (!(mask & HeightValue)) height = tmp_win->frame_height;
else height += 2 * tmp_win->frame_bw3D + tmp_win->title_height;
ConstrainSize (tmp_win, &width, &height);
if (mask & XValue) {
if (mask & XNegative) x += Scr->rootw - width;
} else x = tmp_win->frame_x;
if (mask & YValue) {
if (mask & YNegative) y += Scr->rooth - height;
} else y = tmp_win->frame_y;
{
int junkX, junkY;
unsigned int junkK;
Window junkW;
XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
}
px -= tmp_win->frame_x; if (px > width) px = width / 2;
py -= tmp_win->frame_y; if (py > height) px = height / 2;
SetupWindow (tmp_win, x, y, width, height, -1);
XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, x + px, y + py);
break;
}
case F_VERSION:
Identify ((TwmWindow *) NULL);
break;
case F_AUTORAISE:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
tmp_win->auto_raise = !tmp_win->auto_raise;
if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
else --(Scr->NumAutoRaises);
break;
case F_AUTOLOWER:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
tmp_win->auto_lower = !tmp_win->auto_lower;
if (tmp_win->auto_lower) ++(Scr->NumAutoLowers);
else --(Scr->NumAutoLowers);
break;
case F_BEEP:
XBell(dpy, 0);
break;
case F_POPUP:
tmp_win = (TwmWindow *)action;
if (! tmp_win) break;
if (Scr->WindowFunction.func != 0)
{
ExecuteFunction(Scr->WindowFunction.func,
Scr->WindowFunction.item->action,
w, tmp_win, eventp, C_FRAME, FALSE);
}
else
{
DeIconify(tmp_win);
RaiseWindow (tmp_win);
}
break;
case F_WINWARP:
tmp_win = (TwmWindow *)action;
if (! tmp_win) break;
if (Scr->WarpUnmapped || tmp_win->mapped) {
if (!tmp_win->mapped) DeIconify (tmp_win);
WarpToWindow (tmp_win, Scr->RaiseOnWarp);
}
break;
case F_RESIZE:
EventHandler[EnterNotify] = HandleUnknown;
EventHandler[LeaveNotify] = HandleUnknown;
if (DeferExecution(context, func, Scr->MoveCursor))
return TRUE;
PopDownMenu();
if (tmp_win->squeezed) {
XBell (dpy, 0);
break;
}
if (tmp_win->OpaqueResize) {
/*
* OpaqueResize defaults to a thousand. Assume that any number
* >= 1000 is "infinity" and don't bother calculating.
*/
if (Scr->OpaqueResizeThreshold >= 1000)
Scr->OpaqueResize = TRUE;
else {
/*
* scrsz will hold the number of pixels in your resolution,
* which can get big. [signed] int may not cut it.
*/
unsigned long winsz, scrsz;
winsz = tmp_win->frame_width * tmp_win->frame_height;
scrsz = Scr->rootw * Scr->rooth;
if (winsz > (scrsz * (Scr->OpaqueResizeThreshold / 100.0)))
Scr->OpaqueResize = FALSE;
else
Scr->OpaqueResize = TRUE;
}
}
else
Scr->OpaqueResize = FALSE;
if (pulldown)
XWarpPointer(dpy, None, Scr->Root,
0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
if (!tmp_win->icon || (w != tmp_win->icon->w)) { /* can't resize icons */
/* fromMenu = False; ????? */
if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
&& fromMenu)
resizeFromCenter(w, tmp_win);
else {
/*
* see if this is being done from the titlebar
*/
from3dborder = (eventp->xbutton.window == tmp_win->frame);
fromtitlebar = !from3dborder &&
belongs_to_twm_window (tmp_win, eventp->xbutton.window);
/* Save pointer position so we can tell if it was moved or
not during the resize. */
ResizeOrigX = eventp->xbutton.x_root;
ResizeOrigY = eventp->xbutton.y_root;
StartResize (eventp, tmp_win, fromtitlebar, from3dborder);
do {
XMaskEvent(dpy,
ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask |
ButtonMotionMask | VisibilityChangeMask | ExposureMask, &Event);
if (fromtitlebar && Event.type == ButtonPress) {
fromtitlebar = False;
continue;
}
if (Event.type == MotionNotify) {
/* discard any extra motion events before a release */
while
(XCheckMaskEvent
(dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
if (Event.type == ButtonRelease)
break;
}
if (!DispatchEvent2 ()) continue;
} while (!(Event.type == ButtonRelease || Cancel));
return TRUE;
}
}
break;
case F_ZOOM:
case F_HORIZOOM:
case F_FULLZOOM:
case F_LEFTZOOM:
case F_RIGHTZOOM:
case F_TOPZOOM:
case F_BOTTOMZOOM:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
if (tmp_win->squeezed) {
XBell(dpy, 0);
break;
}
fullzoom(tmp_win, func);
break;
case F_PACK:
if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
if (tmp_win->squeezed) { XBell(dpy, 0); break; }
packwindow (tmp_win, action);
break;
case F_FILL:
if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
if (tmp_win->squeezed) { XBell(dpy, 0); break; }
fillwindow (tmp_win, action);
break;
case F_JUMPLEFT:
if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
if (tmp_win->squeezed) { XBell(dpy, 0); break; }
jump (tmp_win, J_LEFT, action);
break;
case F_JUMPRIGHT:
if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
if (tmp_win->squeezed) { XBell(dpy, 0); break; }
jump (tmp_win, J_RIGHT, action);
break;
case F_JUMPDOWN:
if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
if (tmp_win->squeezed) { XBell(dpy, 0); break; }
jump (tmp_win, J_BOTTOM, action);
break;
case F_JUMPUP:
if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
if (tmp_win->squeezed) { XBell(dpy, 0); break; }
jump (tmp_win, J_TOP, action);
break;
case F_SAVEGEOMETRY:
if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
savegeometry (tmp_win);
break;
case F_RESTOREGEOMETRY:
if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
restoregeometry (tmp_win);
break;
case F_HYPERMOVE: {
Bool cont = True;
Window root = RootWindow (dpy, Scr->screen);
Cursor cursor;
CaptiveCTWM cctwm0, cctwm;
if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
if (tmp_win->iswinbox || tmp_win->wspmgr) {
XBell (dpy, 0);
break;
}
cctwm0 = GetCaptiveCTWMUnderPointer ();
cursor = MakeStringCursor (cctwm0.name);
free (cctwm0.name);
if (DeferExecution (context, func, Scr->MoveCursor)) return TRUE;
XGrabPointer (dpy, root, True,
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, root, cursor, CurrentTime);
while (cont) {
XMaskEvent (dpy, ButtonPressMask | ButtonMotionMask |
ButtonReleaseMask, &Event);
switch (Event.xany.type) {
case ButtonPress :
cont = False;
break;
case ButtonRelease :
cont = False;
cctwm = GetCaptiveCTWMUnderPointer ();
free (cctwm.name);
if (cctwm.root == Scr->Root) break;
SetNoRedirect (tmp_win->w);
XUngrabButton (dpy, AnyButton, AnyModifier, tmp_win->w);
XReparentWindow (dpy, tmp_win->w, cctwm.root, 0, 0);
XMapWindow (dpy, tmp_win->w);
break;
case MotionNotify :
cctwm = GetCaptiveCTWMUnderPointer ();
if (cctwm.root != cctwm0.root) {
XFreeCursor (dpy, cursor);
cursor = MakeStringCursor (cctwm.name);
cctwm0 = cctwm;
XChangeActivePointerGrab (dpy,
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
cursor, CurrentTime);
}
free (cctwm.name);
break;
}
}
ButtonPressed = -1;
XUngrabPointer (dpy, CurrentTime);
XFreeCursor (dpy, cursor);
break;
}
case F_MOVE:
case F_FORCEMOVE:
case F_MOVEPACK:
case F_MOVEPUSH: {
Window grabwin, dragroot;
if (DeferExecution(context, func, Scr->MoveCursor))
return TRUE;
PopDownMenu();
if (tmp_win->OpaqueMove) {
int sw, ss;
float sf;
sw = tmp_win->frame_width * tmp_win->frame_height;
ss = Scr->rootw * Scr->rooth;
sf = Scr->OpaqueMoveThreshold / 100.0;
if (sw > (ss * sf))
Scr->OpaqueMove = FALSE;
else
Scr->OpaqueMove = TRUE;
}
else
Scr->OpaqueMove = FALSE;
dragroot = Scr->XineramaRoot;
if (tmp_win->winbox) {
XTranslateCoordinates (dpy, dragroot, tmp_win->winbox->window,
eventp->xbutton.x_root, eventp->xbutton.y_root,
&(eventp->xbutton.x_root), &(eventp->xbutton.y_root), &JunkChild);
}
rootw = eventp->xbutton.root;
MoveFunction = func;
if (pulldown)
XWarpPointer(dpy, None, Scr->Root,
0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
EventHandler[EnterNotify] = HandleUnknown;
EventHandler[LeaveNotify] = HandleUnknown;
if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
XGrabServer(dpy);
}
Scr->SizeStringOffset = SIZE_HINDENT;
XResizeWindow (dpy, Scr->SizeWindow,
Scr->SizeStringWidth + SIZE_HINDENT * 2,
Scr->SizeFont.height + SIZE_VINDENT * 2);
XMapRaised (dpy, Scr->SizeWindow);
grabwin = Scr->XineramaRoot;
if (tmp_win->winbox) grabwin = tmp_win->winbox->window;
XGrabPointer(dpy, grabwin, True,
ButtonPressMask | ButtonReleaseMask |
ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime);
if (context == C_ICON && tmp_win->icon && tmp_win->icon->w)
{
w = tmp_win->icon->w;
DragX = eventp->xbutton.x;
DragY = eventp->xbutton.y;
moving_icon = TRUE;
if (tmp_win->OpaqueMove) Scr->OpaqueMove = TRUE;
}
else if (! tmp_win->icon || w != tmp_win->icon->w)
{
XTranslateCoordinates(dpy, w, tmp_win->frame,
eventp->xbutton.x,
eventp->xbutton.y,
&DragX, &DragY, &JunkChild);
w = tmp_win->frame;
}
DragWindow = None;
/* Get x/y relative to parent window, i.e. the virtual screen, Root.
* XMoveWindow() moves are relative to this.
* MoveOutline()s however are drawn from the XineramaRoot since they
* may cross virtual screens.
*/
XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
&DragWidth, &DragHeight, &DragBW,
&JunkDepth);
JunkBW = DragBW;
origX = eventp->xbutton.x_root;
origY = eventp->xbutton.y_root;
CurrentDragX = origDragX;
CurrentDragY = origDragY;
/*
* only do the constrained move if timer is set; need to check it
* in case of stupid or wicked fast servers
*/
if (ConstrainedMoveTime &&
(eventp->xbutton.time - last_time) < ConstrainedMoveTime)
{
int width, height;
ConstMove = TRUE;
ConstMoveDir = MOVE_NONE;
ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
width = DragWidth + 2 * JunkBW;
height = DragHeight + 2 * JunkBW;
ConstMoveXL = ConstMoveX + width/3;
ConstMoveXR = ConstMoveX + 2*(width/3);
ConstMoveYT = ConstMoveY + height/3;
ConstMoveYB = ConstMoveY + 2*(height/3);
XWarpPointer(dpy, None, w,
0, 0, 0, 0, DragWidth/2, DragHeight/2);
XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
&JunkX, &JunkY, &DragX, &DragY, &JunkMask);
}
last_time = eventp->xbutton.time;
if (!Scr->OpaqueMove)
{
InstallRootColormap();
if (!Scr->MoveDelta)
{
/*
* Draw initial outline. This was previously done the
* first time though the outer loop by dropping out of
* the XCheckMaskEvent inner loop down to one of the
* MoveOutline's below.
*/
MoveOutline(dragroot,
origDragX - JunkBW + Scr->currentvs->x,
origDragY - JunkBW + Scr->currentvs->y,
DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
tmp_win->frame_bw,
moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
/*
* This next line causes HandleReleaseNotify to call
* XRaiseWindow(). This is solely to preserve the
* previous behaviour that raises a window being moved
* on button release even if you never actually moved
* any distance (unless you move less than MoveDelta or
* NoRaiseMove is set or OpaqueMove is set).
*/
DragWindow = w;
}
}
/*
* see if this is being done from the titlebar
*/
fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
if (menuFromFrameOrWindowOrTitlebar) {
/* warp the pointer to the middle of the window */
XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
origDragX + DragWidth / 2,
origDragY + DragHeight / 2);
XFlush(dpy);
}
DisplayPosition (tmp_win, CurrentDragX, CurrentDragY);
while (TRUE)
{
long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
ButtonPress : ButtonRelease;
long movementMask = menuFromFrameOrWindowOrTitlebar ?
PointerMotionMask : ButtonMotionMask;
/* block until there is an interesting event */
XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask |
ExposureMask | movementMask |
VisibilityChangeMask, &Event);
/* throw away enter and leave events until release */
if (Event.xany.type == EnterNotify ||
Event.xany.type == LeaveNotify) continue;
if (Event.type == MotionNotify) {
/* discard any extra motion events before a logical release */
while(XCheckMaskEvent(dpy,
movementMask | releaseEvent, &Event))
if (Event.type == releaseEvent) {
break;
}
}
/* test to see if we have a second button press to abort move */
if (!menuFromFrameOrWindowOrTitlebar)
if (Event.type == ButtonPress && DragWindow != None) {
Cursor cur;
if (Scr->OpaqueMove) {
XMoveWindow (dpy, DragWindow, origDragX, origDragY);
} else {
MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
}
DragWindow = None;
XUnmapWindow (dpy, Scr->SizeWindow);
cur = LeftButt;
if (Event.xbutton.button == Button2)
cur = MiddleButt;
else if (Event.xbutton.button >= Button3)
cur = RightButt;
XGrabPointer (dpy, Scr->Root, True,
ButtonReleaseMask | ButtonPressMask,
GrabModeAsync, GrabModeAsync,
Scr->Root, cur, CurrentTime);
return TRUE;
}
if (fromtitlebar && Event.type == ButtonPress) {
fromtitlebar = False;
CurrentDragX = origX = Event.xbutton.x_root;
CurrentDragY = origY = Event.xbutton.y_root;
XTranslateCoordinates (dpy, rootw, tmp_win->frame,
origX, origY,
&DragX, &DragY, &JunkChild);
continue;
}
if (!DispatchEvent2 ()) continue;
if (Cancel)
{
WindowMoved = FALSE;
if (!Scr->OpaqueMove)
UninstallRootColormap();
return TRUE; /* XXX should this be FALSE? */
}
if (Event.type == releaseEvent)
{
MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
if (moving_icon &&
((CurrentDragX != origDragX ||
CurrentDragY != origDragY)))
tmp_win->icon_moved = TRUE;
if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) {
int xl = Event.xbutton.x_root - (DragWidth / 2),
yt = Event.xbutton.y_root - (DragHeight / 2);
if (!moving_icon &&
(MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH))
TryToPack (tmp_win, &xl, &yt);
XMoveWindow(dpy, DragWindow, xl, yt);
}
if (menuFromFrameOrWindowOrTitlebar) DragWindow = None;
break;
}
/* something left to do only if the pointer moved */
if (Event.type != MotionNotify)
continue;
XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
&(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
&JunkX, &JunkY, &JunkMask);
FixRootEvent (eventp);
if (tmp_win->winbox) {
XTranslateCoordinates (dpy, dragroot, tmp_win->winbox->window,
eventp->xmotion.x_root, eventp->xmotion.y_root,
&(eventp->xmotion.x_root), &(eventp->xmotion.y_root), &JunkChild);
}
if (DragWindow == None &&
abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
continue;
DragWindow = w;
if (!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved)
RaiseFrame(DragWindow);
WindowMoved = TRUE;
if (ConstMove)
{
switch (ConstMoveDir)
{
case MOVE_NONE:
if (eventp->xmotion.x_root < ConstMoveXL ||
eventp->xmotion.x_root > ConstMoveXR)
ConstMoveDir = MOVE_HORIZ;
if (eventp->xmotion.y_root < ConstMoveYT ||
eventp->xmotion.y_root > ConstMoveYB)
ConstMoveDir = MOVE_VERT;
XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
&JunkX, &JunkY, &DragX, &DragY, &JunkMask);
break;
case MOVE_VERT:
ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
break;
case MOVE_HORIZ:
ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
break;
}
if (ConstMoveDir != MOVE_NONE)
{
int xl, yt, width, height;
xl = ConstMoveX;
yt = ConstMoveY;
width = DragWidth + 2 * JunkBW;
height = DragHeight + 2 * JunkBW;
if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
TryToGrid (tmp_win, &xl, &yt);
if (!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove)
TryToPush (tmp_win, xl, yt, 0);
if (!moving_icon &&
(MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH))
TryToPack (tmp_win, &xl, &yt);
if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
{
ConstrainByBorders (tmp_win, &xl, width, &yt, height);
}
CurrentDragX = xl;
CurrentDragY = yt;
if (Scr->OpaqueMove) {
if (MoveFunction == F_MOVEPUSH && !moving_icon) {
SetupWindow (tmp_win, xl, yt,
tmp_win->frame_width, tmp_win->frame_height, -1);
} else {
XMoveWindow(dpy, DragWindow, xl, yt);
}
WMapSetupWindow (tmp_win, xl, yt, -1, -1);
}
else {
MoveOutline(dragroot, xl + Scr->currentvs->x,
yt + Scr->currentvs->y, width, height,
tmp_win->frame_bw,
moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
}
}
}
else if (DragWindow != None)
{
int xroot, yroot;
int xl, yt, width, height;
/*
* this is split out for virtual screens. In that case, it's
* possible to drag windows from one workspace to another, and
* as such, these need to be adjusted to the root, rather
* than this virtual screen...
*/
xroot = eventp->xmotion.x_root;
yroot = eventp->xmotion.y_root;
if (!menuFromFrameOrWindowOrTitlebar) {
xl = xroot - DragX - JunkBW;
yt = yroot - DragY - JunkBW;
}
else {
xl = xroot - (DragWidth / 2);
yt = yroot - (DragHeight / 2);
}
width = DragWidth + 2 * JunkBW;
height = DragHeight + 2 * JunkBW;
if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
TryToGrid (tmp_win, &xl, &yt);
if (!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove)
TryToPush (tmp_win, xl, yt, 0);
if (!moving_icon &&
(MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH))
TryToPack (tmp_win, &xl, &yt);
if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
{
ConstrainByBorders (tmp_win, &xl, width, &yt, height);
}
CurrentDragX = xl;
CurrentDragY = yt;
if (Scr->OpaqueMove) {
if (MoveFunction == F_MOVEPUSH && !moving_icon) {
SetupWindow (tmp_win, xl, yt,
tmp_win->frame_width, tmp_win->frame_height, -1);
} else {
XMoveWindow(dpy, DragWindow, xl, yt);
}
if (! moving_icon) WMapSetupWindow (tmp_win, xl, yt, -1, -1);
}
else {
MoveOutline(dragroot, xl + Scr->currentvs->x,
yt + Scr->currentvs->y, width, height,
tmp_win->frame_bw,
moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
}
}
DisplayPosition (tmp_win, CurrentDragX, CurrentDragY);
}
XUnmapWindow (dpy, Scr->SizeWindow);
if (!Scr->OpaqueMove && DragWindow == None)
UninstallRootColormap();
break;
}
case F_MOVETITLEBAR:
{
Window grabwin;
int deltax = 0, newx = 0;
int origNum;
SqueezeInfo *si;
if (DeferExecution(context, func, Scr->MoveCursor))
return TRUE;
PopDownMenu();
if (tmp_win->squeezed ||
!tmp_win->squeeze_info ||
!tmp_win->title_w ||
context == C_ICON ) {
XBell (dpy, 0);
break;
}
/* If the SqueezeInfo isn't copied yet, do it now */
if (!tmp_win->squeeze_info_copied) {
SqueezeInfo *s = malloc(sizeof(SqueezeInfo));
if (!s)
break;
*s = *tmp_win->squeeze_info;
tmp_win->squeeze_info = s;
tmp_win->squeeze_info_copied = 1;
}
si = tmp_win->squeeze_info;
if (si->denom != 0) {
int target_denom = tmp_win->frame_width;
/*
* If not pixel based, scale the denominator to equal the
* window width, so the numerator equals pixels.
* That way we can just modify it by pixel units, just
* like the other case.
*/
if (si->denom != target_denom) {
float scale = (float)target_denom / si->denom;
si->num *= scale;
si->denom = target_denom; /* s->denom *= scale; */
}
}
/* now move the mouse */
if (tmp_win->winbox) {
XTranslateCoordinates (dpy, Scr->Root, tmp_win->winbox->window,
eventp->xbutton.x_root, eventp->xbutton.y_root,
&eventp->xbutton.x_root, &eventp->xbutton.y_root, &JunkChild);
}
/*
* the event is always a button event, since key events
* are "weeded out" - although incompletely only
* F_MOVE and F_RESIZE - in HandleKeyPress().
*/
rootw = eventp->xbutton.root;
EventHandler[EnterNotify] = HandleUnknown;
EventHandler[LeaveNotify] = HandleUnknown;
if (!Scr->NoGrabServer) {
XGrabServer(dpy);
}
grabwin = Scr->Root;
if (tmp_win->winbox) grabwin = tmp_win->winbox->window;
XGrabPointer(dpy, grabwin, True,
ButtonPressMask | ButtonReleaseMask |
ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime);
#if 0 /* what's this for ? */
if (! tmp_win->icon || w != tmp_win->icon->w)
{
XTranslateCoordinates(dpy, w, tmp_win->frame,
eventp->xbutton.x,
eventp->xbutton.y,
&DragX, &DragY, &JunkChild);
w = tmp_win->frame;
}
#endif
DragWindow = None;
XGetGeometry(dpy, tmp_win->title_w, &JunkRoot, &origDragX, &origDragY,
&DragWidth, &DragHeight, &DragBW,
&JunkDepth);
origX = eventp->xbutton.x_root;
origNum = si->num;
if (menuFromFrameOrWindowOrTitlebar) {
/* warp the pointer to the middle of the window */
XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
origDragX + DragWidth / 2,
origDragY + DragHeight / 2);
XFlush(dpy);
}
while (TRUE)
{
long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
ButtonPress : ButtonRelease;
long movementMask = menuFromFrameOrWindowOrTitlebar ?
PointerMotionMask : ButtonMotionMask;
/* block until there is an interesting event */
XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask |
ExposureMask | movementMask |
VisibilityChangeMask, &Event);
/* throw away enter and leave events until release */
if (Event.xany.type == EnterNotify ||
Event.xany.type == LeaveNotify) continue;
if (Event.type == MotionNotify) {
/* discard any extra motion events before a logical release */
while (XCheckMaskEvent(dpy,
movementMask | releaseEvent, &Event)) {
if (Event.type == releaseEvent) {
break;
}
}
}
if (!DispatchEvent2())
continue;
if (Event.type == releaseEvent)
break;
/* something left to do only if the pointer moved */
if (Event.type != MotionNotify)
continue;
/* get current pointer pos, useful when there is lag */
XQueryPointer(dpy, rootw, &eventp->xmotion.root, &JunkChild,
&eventp->xmotion.x_root, &eventp->xmotion.y_root,
&JunkX, &JunkY, &JunkMask);
FixRootEvent(eventp);
if (tmp_win->winbox) {
XTranslateCoordinates(dpy, Scr->Root, tmp_win->winbox->window,
eventp->xmotion.x_root, eventp->xmotion.y_root,
&eventp->xmotion.x_root, &eventp->xmotion.y_root, &JunkChild);
}
if (!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved)
RaiseFrame(w);
deltax = eventp->xmotion.x_root - origX;
newx = origNum + deltax;
/*
* Clamp to left and right.
* If we're in pixel size, keep within [ 0, frame_width >.
* If we're proportional, don't cross the 0.
* Also don't let the nominator get bigger than the denominator.
* Keep within [ -denom, -1] or [ 0, denom >.
*/
{
int wtmp = tmp_win->frame_width; /* or si->denom; if it were != 0 */
if (origNum < 0) {
if (newx >= 0)
newx = -1;
else if (newx < -wtmp)
newx = -wtmp;
} else if (origNum >= 0) {
if (newx < 0)
newx = 0;
else if (newx >= wtmp)
newx = wtmp - 1;
}
}
si->num = newx;
/* This, finally, actually moves the title bar */
/* XXX pressing a second button should cancel and undo this */
SetFrameShape(tmp_win);
}
break;
}
case F_FUNCTION:
{
MenuRoot *mroot;
MenuItem *mitem;
if ((mroot = FindMenuRoot(action)) == NULL)
{
if (!action) action = "undef";
fprintf (stderr, "%s: couldn't find function \"%s\"\n",
ProgramName, (char *)action);
return TRUE;
}
if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
else
{
for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
{
if (!ExecuteFunction (mitem->func, mitem->action, w,
tmp_win, eventp, context, pulldown))
/* pebl FIXME: the focus should be updated here,
or the function would operate on the same window */
break;
}
}
}
break;
case F_DEICONIFY:
case F_ICONIFY:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
if (tmp_win->isicon)
{
DeIconify(tmp_win);
}
else if (func == F_ICONIFY)
{
Iconify (tmp_win, eventp->xbutton.x_root - 5,
eventp->xbutton.y_root - 5);
}
break;
case F_SQUEEZE:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
Squeeze (tmp_win);
break;
case F_SHOWBGRD:
ShowBackground (Scr->currentvs);
break;
case F_RAISELOWER:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
if (!WindowMoved) {
if (tmp_win->icon && w == tmp_win->icon->w) {
RaiseLowerFrame(w, ONTOP_DEFAULT);
} else {
RaiseLower(tmp_win);
WMapRaiseLower (tmp_win);
}
}
break;
case F_RAISE:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
/* check to make sure raise is not from the WindowFunction */
if (tmp_win->icon && (w == tmp_win->icon->w) && Context != C_ROOT)
XRaiseWindow(dpy, tmp_win->icon->w);
else {
RaiseWindow (tmp_win);
WMapRaise (tmp_win);
}
break;
case F_LOWER:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
if (tmp_win->icon && (w == tmp_win->icon->w))
XLowerWindow(dpy, tmp_win->icon->w);
else {
LowerWindow(tmp_win);
WMapLower (tmp_win);
}
break;
case F_RAISEICONS:
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t->icon && t->icon->w) {
XRaiseWindow (dpy, t->icon->w);
}
}
break;
case F_FOCUS:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
if (tmp_win->isicon == FALSE)
{
if (!Scr->FocusRoot && Scr->Focus == tmp_win)
{
FocusOnRoot();
}
else
{
InstallWindowColormaps (0, tmp_win);
SetFocus (tmp_win, eventp->xbutton.time);
Scr->FocusRoot = FALSE;
}
}
break;
case F_DESTROY:
if (DeferExecution(context, func, Scr->DestroyCursor))
return TRUE;
if (tmp_win->iconmgr || tmp_win->iswinbox || tmp_win->wspmgr
|| (Scr->workSpaceMgr.occupyWindow
&& tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
XBell(dpy, 0);
break;
}
XKillClient(dpy, tmp_win->w);
if (ButtonPressed != -1) {
XEvent kev;
XMaskEvent (dpy, ButtonReleaseMask, &kev);
if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root;
XPutBackEvent (dpy, &kev);
}
break;
case F_DELETE:
if (DeferExecution(context, func, Scr->DestroyCursor))
return TRUE;
if (tmp_win->iconmgr) { /* don't send ourself a message */
HideIconManager ();
break;
}
if (tmp_win->iswinbox || tmp_win->wspmgr
|| (Scr->workSpaceMgr.occupyWindow
&& tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
XBell (dpy, 0);
break;
}
if (tmp_win->protocols & DoesWmDeleteWindow) {
SendDeleteWindowMessage (tmp_win, LastTimestamp());
if (ButtonPressed != -1) {
XEvent kev;
XMaskEvent (dpy, ButtonReleaseMask, &kev);
if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root;
XPutBackEvent (dpy, &kev);
}
break;
}
XBell (dpy, 0);
break;
case F_DELETEORDESTROY:
if (DeferExecution(context, func, Scr->DestroyCursor)) return TRUE;
if (tmp_win->iconmgr) {
HideIconManager ();
break;
}
if (tmp_win->iswinbox || tmp_win->wspmgr
|| (Scr->workSpaceMgr.occupyWindow
&& tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
XBell (dpy, 0);
break;
}
if (tmp_win->protocols & DoesWmDeleteWindow) {
SendDeleteWindowMessage (tmp_win, LastTimestamp());
} else {
XKillClient(dpy, tmp_win->w);
}
if (ButtonPressed != -1) {
XEvent kev;
XMaskEvent (dpy, ButtonReleaseMask, &kev);
if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root;
XPutBackEvent (dpy, &kev);
}
break;
case F_SAVEYOURSELF:
if (DeferExecution (context, func, Scr->SelectCursor))
return TRUE;
if (tmp_win->protocols & DoesWmSaveYourself)
SendSaveYourselfMessage (tmp_win, LastTimestamp());
else
XBell (dpy, 0);
break;
case F_CIRCLEUP:
XCirculateSubwindowsUp(dpy, Scr->Root);
break;
case F_CIRCLEDOWN:
XCirculateSubwindowsDown(dpy, Scr->Root);
break;
case F_EXEC:
PopDownMenu();
if (!Scr->NoGrabServer) {
XUngrabServer (dpy);
XSync (dpy, 0);
}
XUngrabPointer (dpy, CurrentTime);
XSync (dpy, 0);
Execute(action);
break;
case F_UNFOCUS:
FocusOnRoot();
break;
case F_CUT:
strcpy(tmp, action);
strcat(tmp, "\n");
XStoreBytes(dpy, tmp, strlen(tmp));
break;
case F_CUTFILE:
ptr = XFetchBytes(dpy, &count);
if (ptr) {
if (sscanf (ptr, "%s", tmp) == 1) {
XFree (ptr);
ptr = ExpandFilename(tmp);
if (ptr) {
#ifdef VMS
fd = open (ptr, O_RDONLY, 0);
#else
fd = open (ptr, 0);
#endif
if (fd >= 0) {
count = read (fd, buff, MAX_FILE_SIZE - 1);
if (count > 0) XStoreBytes (dpy, buff, count);
close(fd);
} else {
fprintf (stderr,
"%s: unable to open cut file \"%s\"\n",
ProgramName, tmp);
}
if (ptr != tmp) free (ptr);
}
} else {
XFree(ptr);
}
} else {
fprintf(stderr, "%s: cut buffer is empty\n", ProgramName);
}
break;
case F_WARPTOSCREEN:
{
if (strcmp (action, WARPSCREEN_NEXT) == 0) {
WarpToScreen (Scr->screen + 1, 1);
} else if (strcmp (action, WARPSCREEN_PREV) == 0) {
WarpToScreen (Scr->screen - 1, -1);
} else if (strcmp (action, WARPSCREEN_BACK) == 0) {
WarpToScreen (PreviousScreen, 0);
} else {
WarpToScreen (atoi (action), 0);
}
}
break;
case F_COLORMAP:
{
if (strcmp (action, COLORMAP_NEXT) == 0) {
BumpWindowColormap (tmp_win, 1);
} else if (strcmp (action, COLORMAP_PREV) == 0) {
BumpWindowColormap (tmp_win, -1);
} else {
BumpWindowColormap (tmp_win, 0);
}
}
break;
case F_WARPTO:
{
register TwmWindow *tw;
int len;
len = strlen(action);
#ifdef WARPTO_FROM_ICONMGR
if (len == 0 && tmp_win && tmp_win->iconmgr)
{
printf ("curren iconmgr entry: %s", tmp_win->iconmgr->Current);
}
#endif /* #ifdef WARPTO_FROM_ICONMGR */
for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
if (!strncmp(action, tw->full_name, len)) break;
if (match (action, tw->full_name)) break;
}
if (!tw) {
for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
if (!strncmp(action, tw->class.res_name, len)) break;
if (match (action, tw->class.res_name)) break;
}
if (!tw) {
for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
if (!strncmp(action, tw->class.res_class, len)) break;
if (match (action, tw->class.res_class)) break;
}
}
}
if (tw) {
if (Scr->WarpUnmapped || tw->mapped) {
if (!tw->mapped) DeIconify (tw);
WarpToWindow (tw, Scr->RaiseOnWarp);
}
} else {
XBell (dpy, 0);
}
}
break;
case F_WARPTOICONMGR:
{
TwmWindow *tw;
int len;
Window raisewin = None, iconwin = None;
len = strlen(action);
if (len == 0) {
if (tmp_win && tmp_win->iconmanagerlist) {
raisewin = tmp_win->iconmanagerlist->iconmgr->twm_win->frame;
iconwin = tmp_win->iconmanagerlist->icon;
} else if (Scr->iconmgr->active) {
raisewin = Scr->iconmgr->twm_win->frame;
iconwin = Scr->iconmgr->active->w;
}
} else {
for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
if (strncmp (action, tw->icon_name, len) == 0) {
if (tw->iconmanagerlist &&
tw->iconmanagerlist->iconmgr->twm_win->mapped) {
raisewin = tw->iconmanagerlist->iconmgr->twm_win->frame;
break;
}
}
}
}
if (raisewin) {
RaiseFrame(raisewin);
XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
} else {
XBell (dpy, 0);
}
}
break;
case F_RING: /* Taken from vtwm version 5.3 */
if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
if ( tmp_win->ring.next || tmp_win->ring.prev ) {
/* It's in the ring, let's take it out. */
TwmWindow *prev = tmp_win->ring.prev, *next = tmp_win->ring.next;
/*
* 1. Unlink window
* 2. If window was only thing in ring, null out ring
* 3. If window was ring leader, set to next (or null)
*/
if (prev) prev->ring.next = next;
if (next) next->ring.prev = prev;
if (Scr->Ring == tmp_win)
Scr->Ring = (next != tmp_win ? next : (TwmWindow *) NULL);
if (!Scr->Ring || Scr->RingLeader == tmp_win)
Scr->RingLeader = Scr->Ring;
tmp_win->ring.next = tmp_win->ring.prev = NULL;
} else {
/* Not in the ring, so put it in. */
if (Scr->Ring) {
tmp_win->ring.next = Scr->Ring->ring.next;
if (Scr->Ring->ring.next->ring.prev)
Scr->Ring->ring.next->ring.prev = tmp_win;
Scr->Ring->ring.next = tmp_win;
tmp_win->ring.prev = Scr->Ring;
} else {
tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
}
}
/*tmp_win->ring.cursor_valid = False;*/
break;
case F_WARPRING:
switch (((char *)action)[0]) {
case 'n':
WarpAlongRing (&eventp->xbutton, True);
break;
case 'p':
WarpAlongRing (&eventp->xbutton, False);
break;
default:
XBell (dpy, 0);
break;
}
break;
case F_FILE:
action = ExpandFilename(action);
#ifdef VMS
fd = open (action, O_RDONLY, 0);
#else
fd = open(action, 0);
#endif
if (fd >= 0)
{
count = read(fd, buff, MAX_FILE_SIZE - 1);
if (count > 0)
XStoreBytes(dpy, buff, count);
close(fd);
}
else
{
fprintf (stderr, "%s: unable to open file \"%s\"\n",
ProgramName, (char *)action);
}
free(action);
break;
case F_REFRESH:
{
XSetWindowAttributes attributes;
unsigned long valuemask;
valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
attributes.background_pixel = Scr->Black;
attributes.backing_store = NotUseful;
attributes.save_under = False;
w = XCreateWindow (dpy, Scr->Root, 0, 0,
(unsigned int) Scr->rootw,
(unsigned int) Scr->rooth,
(unsigned int) 0,
CopyFromParent, (unsigned int) CopyFromParent,
(Visual *) CopyFromParent, valuemask,
&attributes);
XMapWindow (dpy, w);
XDestroyWindow (dpy, w);
XFlush (dpy);
}
break;
case F_OCCUPY:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
Occupy (tmp_win);
break;
case F_OCCUPYALL:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
OccupyAll (tmp_win);
break;
case F_GOTOWORKSPACE:
GotoWorkSpaceByName (Scr->currentvs, action);
break;
case F_PREVWORKSPACE:
GotoPrevWorkSpace (Scr->currentvs);
break;
case F_NEXTWORKSPACE:
GotoNextWorkSpace (Scr->currentvs);
break;
case F_RIGHTWORKSPACE:
GotoRightWorkSpace (Scr->currentvs);
break;
case F_LEFTWORKSPACE:
GotoLeftWorkSpace (Scr->currentvs);
break;
case F_UPWORKSPACE:
GotoUpWorkSpace (Scr->currentvs);
break;
case F_DOWNWORKSPACE:
GotoDownWorkSpace (Scr->currentvs);
break;
case F_MENU:
if (action && ! strncmp (action, "WGOTO : ", 8)) {
GotoWorkSpaceByName (/* XXXXX */ Scr->currentvs,
((char *)action) + 8);
}
else {
MenuItem *item;
item = ActiveItem;
while (item && item->sub) {
if (!item->sub->defaultitem) break;
if (item->sub->defaultitem->func != F_MENU) break;
item = item->sub->defaultitem;
}
if (item && item->sub && item->sub->defaultitem) {
ExecuteFunction (item->sub->defaultitem->func,
item->sub->defaultitem->action,
w, tmp_win, eventp, context, pulldown);
}
}
break;
case F_WINREFRESH:
if (DeferExecution(context, func, Scr->SelectCursor))
return TRUE;
if (context == C_ICON && tmp_win->icon && tmp_win->icon->w)
w = XCreateSimpleWindow(dpy, tmp_win->icon->w,
0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
else
w = XCreateSimpleWindow(dpy, tmp_win->frame,
0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
XMapWindow(dpy, w);
XDestroyWindow(dpy, w);
XFlush(dpy);
break;
case F_ADOPTWINDOW:
adoptWindow ();
break;
case F_TRACE:
DebugTrace (action);
break;
case F_CHANGESIZE:
ChangeSize (action, tmp_win);
break;
case F_QUIT:
Done(0);
break;
}
if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
return do_next_action;
}
/***********************************************************************
*
* Procedure:
* DeferExecution - defer the execution of a function to the
* next button press if the context is C_ROOT
*
* Inputs:
* context - the context in which the mouse button was pressed
* func - the function to defer
* cursor - the cursor to display while waiting
*
***********************************************************************
*/
int DeferExecution(int context, int func, Cursor cursor)
{
if ((context == C_ROOT) || (context == C_ALTERNATE))
{
LastCursor = cursor;
if (func == F_ADOPTWINDOW) {
XGrabPointer(dpy, Scr->Root, True,
ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
None, cursor, CurrentTime);
} else {
XGrabPointer(dpy, Scr->Root, True,
ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
Scr->Root, cursor, CurrentTime);
}
RootFunction = func;
return (TRUE);
}
return (FALSE);
}
/***********************************************************************
*
* Procedure:
* ReGrab - regrab the pointer with the LastCursor;
*
***********************************************************************
*/
void ReGrab(void)
{
XGrabPointer(dpy, Scr->Root, True,
ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync,
Scr->Root, LastCursor, CurrentTime);
}
/***********************************************************************
*
* Procedure:
* NeedToDefer - checks each function in the list to see if it
* is one that needs to be defered.
*
* Inputs:
* root - the menu root to check
*
***********************************************************************
*/
int NeedToDefer(MenuRoot *root)
{
MenuItem *mitem;
for (mitem = root->first; mitem != NULL; mitem = mitem->next)
{
switch (mitem->func)
{
case F_IDENTIFY:
case F_RESIZE:
case F_MOVE:
case F_FORCEMOVE:
case F_DEICONIFY:
case F_ICONIFY:
case F_RAISELOWER:
case F_RAISE:
case F_LOWER:
case F_FOCUS:
case F_DESTROY:
case F_WINREFRESH:
case F_ZOOM:
case F_FULLZOOM:
case F_HORIZOOM:
case F_RIGHTZOOM:
case F_LEFTZOOM:
case F_TOPZOOM:
case F_BOTTOMZOOM:
case F_SQUEEZE:
case F_AUTORAISE:
case F_AUTOLOWER:
return TRUE;
}
}
return FALSE;
}
/***********************************************************************
*
* Procedure:
* Execute - execute the string by /bin/sh
*
* Inputs:
* s - the string containing the command
*
***********************************************************************
*/
void Execute(char *s)
{
#ifdef VMS
createProcess(s);
#else
static char buf[256];
char *ds = DisplayString (dpy);
char *colon, *dot1;
char oldDisplay[256];
char *doisplay;
int restorevar = 0;
Bool replace;
char *subs, *name, *news;
int len;
oldDisplay[0] = '\0';
doisplay=getenv("DISPLAY");
if (doisplay)
strcpy (oldDisplay, doisplay);
/*
* Build a display string using the current screen number, so that
* X programs which get fired up from a menu come up on the screen
* that they were invoked from, unless specifically overridden on
* their command line.
*/
colon = strrchr (ds, ':');
if (colon) { /* if host[:]:dpy */
strcpy (buf, "DISPLAY=");
strcat (buf, ds);
colon = buf + 8 + (colon - ds); /* use version in buf */
dot1 = strchr (colon, '.'); /* first period after colon */
if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */
(void) sprintf (dot1, ".%d", Scr->screen);
putenv (buf);
restorevar = 1;
}
replace = False;
subs = strstr (s, "$currentworkspace");
name = GetCurrentWorkSpaceName (Scr->currentvs);
if (subs && name) {
len = strlen (s) - strlen ("$currentworkspace") + strlen (name);
news = (char*) malloc (len + 1);
*subs = '\0';
strcpy (news, s);
*subs = '$';
strcat (news, name);
subs += strlen ("$currentworkspace");
strcat (news, subs);
s = news;
replace = True;
}
subs = strstr (s, "$redirect");
if (subs) {
if (captive) {
name = (char*) malloc (21 + strlen (captivename) + 1);
sprintf (name, "-xrm 'ctwm.redirect:%s'", captivename);
} else {
name = (char*) malloc (1);
*name = '\0';
}
len = strlen (s) - strlen ("$redirect") + strlen (name);
news = (char*) malloc (len + 1);
*subs = '\0';
strcpy (news, s);
*subs = '$';
strcat (news, name);
subs += strlen ("$redirect");
strcat (news, subs);
s = news;
free (name);
replace = True;
}
#ifdef USE_SIGNALS
{
SigProc sig;
sig = signal (SIGALRM, SIG_IGN);
(void) system (s);
signal (SIGALRM, sig);
}
#else /* USE_SIGNALS */
(void) system (s);
#endif /* USE_SIGNALS */
if (restorevar) { /* why bother? */
(void) sprintf (buf, "DISPLAY=%s", oldDisplay);
putenv (buf);
}
if (replace) free (s);
#endif
}
Window lowerontop = -1;
void PlaceTransients (TwmWindow *tmp_win, int where)
{
int sp, sc;
TwmWindow *t;
XWindowChanges xwc;
xwc.stack_mode = where;
sp = tmp_win->frame_width * tmp_win->frame_height;
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t != tmp_win &&
((t->transient && t->transientfor == tmp_win->w) ||
t->group == tmp_win->w)) {
if (t->frame) {
sc = t->frame_width * t->frame_height;
if (sc < ((sp * Scr->TransientOnTop) / 100)) {
xwc.sibling = tmp_win->frame;
XConfigureWindow(dpy, t->frame, CWSibling | CWStackMode, &xwc);
if (lowerontop == t->frame) {
lowerontop = (Window)-1;
}
}
}
}
}
}
#include <assert.h>
void PlaceOntop (int ontop, int where)
{
TwmWindow *t;
XWindowChanges xwc;
xwc.stack_mode = where;
lowerontop = (Window)-1;
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t->ontoppriority > ontop) {
XConfigureWindow(dpy, t->frame, CWStackMode, &xwc);
PlaceTransients(t, Above);
if (lowerontop == (Window)-1) {
lowerontop = t->frame;
}
}
}
}
void MapRaised (TwmWindow *tmp_win)
{
XMapWindow(dpy, tmp_win->frame);
RaiseWindow(tmp_win);
}
void RaiseWindow (TwmWindow *tmp_win)
{
XWindowChanges xwc;
int xwcm;
if (tmp_win->ontoppriority == ONTOP_MAX) {
XRaiseWindow(dpy, tmp_win->frame);
if (lowerontop == (Window)-1) {
lowerontop = tmp_win->frame;
} else if (lowerontop == tmp_win->frame) {
lowerontop = (Window)-1;
}
} else {
if (lowerontop == (Window)-1) {
PlaceOntop(tmp_win->ontoppriority, Above);
}
xwcm = CWStackMode;
if (lowerontop != (Window)-1) {
xwc.stack_mode = Below;
xwc.sibling = lowerontop;
xwcm |= CWSibling;
} else {
xwc.stack_mode = Above;
}
XConfigureWindow(dpy, tmp_win->frame, xwcm, &xwc);
}
PlaceTransients(tmp_win, Above);
}
void RaiseLower (TwmWindow *tmp_win)
{
XWindowChanges xwc;
PlaceOntop(tmp_win->ontoppriority, Below);
PlaceTransients(tmp_win, Below);
lowerontop = (Window)-1;
xwc.stack_mode = Opposite;
XConfigureWindow(dpy, tmp_win->frame, CWStackMode, &xwc);
PlaceOntop(tmp_win->ontoppriority, Above);
PlaceTransients(tmp_win, Above);
}
void RaiseLowerFrame (Window frame, int ontop)
{
XWindowChanges xwc;
PlaceOntop(ontop, Below);
lowerontop = (Window)-1;
xwc.stack_mode = Opposite;
XConfigureWindow(dpy, frame, CWStackMode, &xwc);
PlaceOntop(ontop, Above);
}
void LowerWindow (TwmWindow *tmp_win)
{
XLowerWindow(dpy, tmp_win->frame);
if (tmp_win->frame == lowerontop) {
lowerontop = (Window)-1;
}
PlaceTransients(tmp_win, Above);
}
void RaiseFrame (Window frame)
{
TwmWindow *tmp_win;
tmp_win = GetTwmWindow(frame);
if (tmp_win != NULL) {
RaiseWindow(tmp_win);
} else {
XRaiseWindow(dpy, frame);
}
}
/***********************************************************************
*
* Procedure:
* FocusOnRoot - put input focus on the root window
*
***********************************************************************
*/
void FocusOnRoot(void)
{
SetFocus ((TwmWindow *) NULL, LastTimestamp());
InstallColormaps(0, &Scr->RootColormaps);
if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE;
}
static void ReMapOne(TwmWindow *t, TwmWindow *leader)
{
if (t->icon_on)
Zoom(t->icon->w, t->frame);
else if (leader->icon)
Zoom(leader->icon->w, t->frame);
if (!t->squeezed)
XMapWindow(dpy, t->w);
t->mapped = TRUE;
if (Scr->Root != Scr->CaptiveRoot) /* XXX dubious test */
XReparentWindow (dpy, t->frame, Scr->Root, t->frame_x, t->frame_y);
if (Scr->NoRaiseDeicon)
XMapWindow(dpy, t->frame);
else
MapRaised(t);
SetMapStateProp(t, NormalState);
if (t->icon && t->icon->w) {
XUnmapWindow(dpy, t->icon->w);
IconDown(t);
if (Scr->ShrinkIconTitles)
t->icon->title_shrunk = True;
}
if (t->iconmanagerlist) {
WList *wl;
for (wl = t->iconmanagerlist; wl != NULL; wl = wl->nextv)
XUnmapWindow(dpy, wl->icon);
}
t->isicon = FALSE;
t->icon_on = FALSE;
WMapDeIconify(t);
}
static void ReMapTransients(TwmWindow *tmp_win)
{
TwmWindow *t;
/* find t such that it is a transient or group member window */
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t != tmp_win &&
((t->transient && t->transientfor == tmp_win->w) ||
(t->group == tmp_win->w && t->isicon))) {
ReMapOne(t, tmp_win);
}
}
}
void DeIconify(TwmWindow *tmp_win)
{
TwmWindow *t = tmp_win;
int isicon = FALSE;
/* de-iconify the main window */
if (Scr->WindowMask)
XRaiseWindow (dpy, Scr->WindowMask);
if (tmp_win && tmp_win->isicon)
{
isicon = TRUE;
if (tmp_win->icon_on && tmp_win->icon && tmp_win->icon->w)
Zoom(tmp_win->icon->w, tmp_win->frame);
else if (tmp_win->group != (Window) 0)
{
t = GetTwmWindow(tmp_win->group);
if (t && t->icon_on && t->icon && t->icon->w)
{
Zoom(t->icon->w, tmp_win->frame);
}
}
}
ReMapOne(tmp_win, t);
if (isicon &&
(Scr->WarpCursor ||
LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)))
WarpToWindow (tmp_win, 0);
/* now de-iconify and window group transients */
ReMapTransients(tmp_win);
if (! Scr->WindowMask && Scr->DeIconifyFunction.func != 0) {
char *action;
XEvent event;
action = Scr->DeIconifyFunction.item ?
Scr->DeIconifyFunction.item->action : NULL;
ExecuteFunction (Scr->DeIconifyFunction.func, action,
(Window) 0, tmp_win, &event, C_ROOT, FALSE);
}
XSync (dpy, 0);
}
static void UnmapTransients(TwmWindow *tmp_win, int iconify, unsigned long eventMask)
{
TwmWindow *t;
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t != tmp_win &&
((t->transient && t->transientfor == tmp_win->w) ||
t->group == tmp_win->w)) {
if (iconify && tmp_win->icon) {
if (t->icon_on)
Zoom(t->icon->w, tmp_win->icon->w);
else
Zoom(t->frame, tmp_win->icon->w);
}
/*
* Prevent the receipt of an UnmapNotify, since that would
* cause a transition to the Withdrawn state.
*/
t->mapped = FALSE;
XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
XUnmapWindow(dpy, t->w);
XUnmapWindow(dpy, t->frame);
XSelectInput(dpy, t->w, eventMask);
if (t->icon && t->icon->w) XUnmapWindow(dpy, t->icon->w);
SetMapStateProp(t, IconicState);
if (t == Scr->Focus) {
SetFocus ((TwmWindow *) NULL, LastTimestamp());
if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE;
}
if (t->iconmanagerlist)
XMapWindow(dpy, t->iconmanagerlist->icon);
t->isicon = TRUE;
t->icon_on = FALSE;
WMapIconify (t);
}
}
}
void Iconify(TwmWindow *tmp_win, int def_x, int def_y)
{
TwmWindow *t;
int iconify;
XWindowAttributes winattrs;
unsigned long eventMask;
WList *wl;
Window leader = (Window)-1;
Window blanket = (Window)-1;
iconify = (!tmp_win->iconify_by_unmapping);
t = (TwmWindow*) 0;
if (tmp_win->transient) {
leader = tmp_win->transientfor;
t = GetTwmWindow(leader);
}
else
if ((leader = tmp_win->group) != 0 && leader != tmp_win->w) {
t = GetTwmWindow(leader);
}
if (t && t->icon_on) iconify = False;
if (iconify)
{
if (!tmp_win->icon || !tmp_win->icon->w)
CreateIconWindow(tmp_win, def_x, def_y);
else
IconUp(tmp_win);
if (visible (tmp_win)) {
if (Scr->WindowMask) {
XRaiseWindow (dpy, Scr->WindowMask);
XMapWindow(dpy, tmp_win->icon->w);
}
else
XMapRaised(dpy, tmp_win->icon->w);
}
}
if (tmp_win->iconmanagerlist) {
for (wl = tmp_win->iconmanagerlist; wl != NULL; wl = wl->nextv) {
XMapWindow(dpy, wl->icon);
}
}
XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
eventMask = winattrs.your_event_mask;
/* iconify transients and window group first */
UnmapTransients(tmp_win, iconify, eventMask);
if (iconify) Zoom(tmp_win->frame, tmp_win->icon->w);
/*
* Prevent the receipt of an UnmapNotify, since that would
* cause a transition to the Withdrawn state.
*/
tmp_win->mapped = FALSE;
if ((Scr->IconifyStyle != ICONIFY_NORMAL) && !Scr->WindowMask) {
XSetWindowAttributes attr;
XGetWindowAttributes(dpy, tmp_win->frame, &winattrs);
attr.backing_store = NotUseful;
attr.save_under = False;
blanket = XCreateWindow (dpy, Scr->Root, winattrs.x, winattrs.y,
winattrs.width, winattrs.height, (unsigned int) 0,
CopyFromParent, (unsigned int) CopyFromParent,
(Visual *) CopyFromParent, CWBackingStore | CWSaveUnder, &attr);
XMapWindow (dpy, blanket);
}
XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
XUnmapWindow(dpy, tmp_win->w);
XUnmapWindow(dpy, tmp_win->frame);
XSelectInput(dpy, tmp_win->w, eventMask);
SetMapStateProp(tmp_win, IconicState);
if ((Scr->IconifyStyle != ICONIFY_NORMAL) && !Scr->WindowMask) {
switch (Scr->IconifyStyle) {
case ICONIFY_MOSAIC: MosaicFade (tmp_win, blanket); break;
case ICONIFY_ZOOMIN: ZoomInWindow (tmp_win, blanket); break;
case ICONIFY_ZOOMOUT: ZoomOutWindow (tmp_win, blanket); break;
case ICONIFY_SWEEP: SweepWindow (tmp_win, blanket); break;
}
XDestroyWindow (dpy, blanket);
}
if (tmp_win == Scr->Focus) {
SetFocus ((TwmWindow *) NULL, LastTimestamp());
if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE;
}
tmp_win->isicon = TRUE;
tmp_win->icon_on = iconify ? TRUE : FALSE;
WMapIconify (tmp_win);
if (! Scr->WindowMask && Scr->IconifyFunction.func != 0) {
char *action;
XEvent event;
action = Scr->IconifyFunction.item ? Scr->IconifyFunction.item->action : NULL;
ExecuteFunction (Scr->IconifyFunction.func, action,
(Window) 0, tmp_win, &event, C_ROOT, FALSE);
}
XSync (dpy, 0);
}
void AutoSqueeze (TwmWindow *tmp_win)
{
if (tmp_win->iconmgr) return;
if (Scr->RaiseWhenAutoUnSqueeze && tmp_win->squeezed) XRaiseWindow (dpy, tmp_win->frame);
Squeeze (tmp_win);
}
void Squeeze (TwmWindow *tmp_win)
{
long fx, fy, savex, savey;
int neww, newh, south;
int grav = ((tmp_win->hints.flags & PWinGravity)
? tmp_win->hints.win_gravity : NorthWestGravity);
XWindowAttributes winattrs;
unsigned long eventMask;
#ifdef GNOME
unsigned char *prop;
unsigned long nitems, bytesafter;
Atom actual_type;
int actual_format;
long gwkspc;
#endif /* GNOME */
if (tmp_win->squeezed) {
tmp_win->squeezed = False;
#ifdef GNOME
XGetWindowAttributes (dpy, tmp_win->w, &winattrs);
eventMask = winattrs.your_event_mask;
XSelectInput (dpy, tmp_win->w, eventMask & ~PropertyChangeMask);
if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False,
XA_CARDINAL, &actual_type, &actual_format,
&nitems, &bytesafter, &prop)
!= Success || nitems == 0) {
gwkspc = 0;
} else {
gwkspc = (int)*prop;
XFree ((char *)prop);
}
gwkspc &= ~WIN_STATE_SHADED;
XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&gwkspc, 1);
XSelectInput(dpy, tmp_win->w, eventMask);
#endif /* GNOME */
if (!tmp_win->isicon) XMapWindow (dpy, tmp_win->w);
SetupWindow (tmp_win, tmp_win->actual_frame_x, tmp_win->actual_frame_y,
tmp_win->actual_frame_width, tmp_win->actual_frame_height, -1);
ReMapTransients(tmp_win);
return;
}
newh = tmp_win->title_height + 2 * tmp_win->frame_bw3D;
if (newh < 3) { XBell (dpy, 0); return; }
switch (grav) {
case SouthWestGravity :
case SouthGravity :
case SouthEastGravity :
south = True; break;
default :
south = False; break;
}
if (tmp_win->title_height && !tmp_win->AlwaysSqueezeToGravity) south = False;
tmp_win->squeezed = True;
tmp_win->actual_frame_width = tmp_win->frame_width;
tmp_win->actual_frame_height = tmp_win->frame_height;
savex = fx = tmp_win->frame_x;
savey = fy = tmp_win->frame_y;
neww = tmp_win->actual_frame_width;
if (south) fy += tmp_win->frame_height - newh;
if (tmp_win->squeeze_info) {
fx += tmp_win->title_x - tmp_win->frame_bw3D;
neww = tmp_win->title_width + 2 * (tmp_win->frame_bw + tmp_win->frame_bw3D);
}
XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
eventMask = winattrs.your_event_mask;
#ifdef GNOME
XSelectInput (dpy, tmp_win->w, eventMask & ~(StructureNotifyMask | PropertyChangeMask));
if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False,
XA_CARDINAL, &actual_type, &actual_format, &nitems,
&bytesafter, &prop)
!= Success || nitems == 0) {
gwkspc = 0;
} else {
gwkspc = (int)*prop;
XFree ((char *)prop);
}
gwkspc |= WIN_STATE_SHADED;
XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&gwkspc, 1);
#else
XSelectInput (dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
#endif /* GNOME */
XUnmapWindow(dpy, tmp_win->w);
XSelectInput(dpy, tmp_win->w, eventMask);
if (fx + neww >= Scr->rootw - Scr->BorderRight)
fx = Scr->rootw - Scr->BorderRight - neww;
if (fy + newh >= Scr->rooth - Scr->BorderBottom)
fy = Scr->rooth - Scr->BorderBottom - newh;
SetupWindow (tmp_win, fx, fy, neww, newh, -1);
tmp_win->actual_frame_x = savex;
tmp_win->actual_frame_y = savey;
/* Now make the group members disappear */
UnmapTransients(tmp_win, 0, eventMask);
}
static void Identify (TwmWindow *t)
{
int i, n, twidth, width, height;
int x, y;
unsigned int wwidth, wheight, bw, depth;
Window junk;
int px, py, dummy;
unsigned udummy;
unsigned char *prop;
unsigned long nitems, bytesafter;
Atom actual_type;
int actual_format;
XRectangle inc_rect;
XRectangle logical_rect;
Bool first = True;
n = 0;
(void) sprintf(Info[n++], "Twm version: %s", Version);
(void) sprintf(Info[n], "Compile time options :");
#ifdef XPM
(void) strcat (Info[n], " XPM");
first = False;
#endif
#ifdef IMCONV
if (!first) (void) strcat(Info[n], ", ");
(void) strcat (Info[n], "IMCONV");
first = False;
#endif
#ifdef USEM4
if (!first) (void) strcat(Info[n], ", ");
(void) strcat (Info[n], "USEM4");
first = False;
#endif
#ifdef GNOME
if (!first) (void) strcat(Info[n], ", ");
(void) strcat (Info[n], "GNOME");
first = False;
#endif
#ifdef SOUNDS
if (!first) (void) strcat(Info[n], ", ");
(void) strcat (Info[n], "SOUNDS");
first = False;
#endif
#ifdef DEBUG
if (!first) (void) strcat(Info[n], ", ");
(void) strcat (Info[n], "debug");
first = False;
#endif
if (!first) (void) strcat(Info[n], ", ");
(void) strcat (Info[n], "I18N");
first = False;
n++;
Info[n++][0] = '\0';
if (t) {
XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
&wwidth, &wheight, &bw, &depth);
(void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
&x, &y, &junk);
(void) sprintf(Info[n++], "Name = \"%s\"", t->full_name);
(void) sprintf(Info[n++], "Class.res_name = \"%s\"", t->class.res_name);
(void) sprintf(Info[n++], "Class.res_class = \"%s\"", t->class.res_class);
Info[n++][0] = '\0';
(void) sprintf(Info[n++], "Geometry/root (UL) = %dx%d+%d+%d (Inner: %dx%d+%d+%d)",
wwidth + 2 * (bw + t->frame_bw3D),
wheight + 2 * (bw + t->frame_bw3D) + t->title_height,
x - (bw + t->frame_bw3D),
y - (bw + t->frame_bw3D + t->title_height),
wwidth, wheight, x, y);
(void) sprintf(Info[n++], "Geometry/root (LR) = %dx%d-%d-%d (Inner: %dx%d-%d-%d)",
wwidth + 2 * (bw + t->frame_bw3D),
wheight + 2 * (bw + t->frame_bw3D) + t->title_height,
Scr->rootw - (x + wwidth + bw + t->frame_bw3D),
Scr->rooth - (y + wheight + bw + t->frame_bw3D),
wwidth, wheight,
Scr->rootw - (x + wwidth), Scr->rooth - (y + wheight));
(void) sprintf(Info[n++], "Border width = %d", bw);
(void) sprintf(Info[n++], "3D border width = %d", t->frame_bw3D);
(void) sprintf(Info[n++], "Depth = %d", depth);
if (XGetWindowProperty (dpy, t->w, _XA_WM_CLIENT_MACHINE, 0L, 64, False,
XA_STRING, &actual_type, &actual_format, &nitems,
&bytesafter, &prop) == Success) {
if (nitems && prop) {
(void) sprintf(Info[n++], "Client machine = %s", (char*)prop);
XFree ((char *) prop);
}
}
Info[n++][0] = '\0';
}
(void) sprintf(Info[n++], "Click to dismiss....");
/* figure out the width and height of the info window */
height = n * (Scr->DefaultFont.height+2);
width = 1;
for (i = 0; i < n; i++)
{
XmbTextExtents(Scr->DefaultFont.font_set, Info[i],
strlen(Info[i]), &inc_rect, &logical_rect);
twidth = logical_rect.width;
if (twidth > width)
width = twidth;
}
if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
width += 10; /* some padding */
height += 10; /* some padding */
if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild,
&dummy, &dummy, &px, &py, &udummy)) {
px -= (width / 2);
py -= (height / 3);
if (px + width + BW2 >= Scr->rootw)
px = Scr->rootw - width - BW2;
if (py + height + BW2 >= Scr->rooth)
py = Scr->rooth - height - BW2;
if (px < 0) px = 0;
if (py < 0) py = 0;
} else {
px = py = 0;
}
XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
XMapRaised(dpy, Scr->InfoWindow);
InfoLines = n;
InfoWidth = width;
InfoHeight = height;
}
void SetMapStateProp(TwmWindow *tmp_win, int state)
{
unsigned long data[2]; /* "suggested" by ICCCM version 1 */
data[0] = (unsigned long) state;
data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
(tmp_win->icon ? tmp_win->icon->w : None));
XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
PropModeReplace, (unsigned char *) data, 2);
}
Bool GetWMState (Window w, int *statep, Window *iwp)
{
Atom actual_type;
int actual_format;
unsigned long nitems, bytesafter;
unsigned long *datap = NULL;
Bool retval = False;
if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
&actual_type, &actual_format, &nitems, &bytesafter,
(unsigned char **) &datap) != Success || !datap)
return False;
if (nitems <= 2) { /* "suggested" by ICCCM version 1 */
*statep = (int) datap[0];
*iwp = (Window) datap[1];
retval = True;
}
XFree ((char *) datap);
return retval;
}
int WarpToScreen (int n, int inc)
{
Window dumwin;
int x, y, dumint;
unsigned int dummask;
ScreenInfo *newscr = NULL;
while (!newscr) {
/* wrap around */
if (n < 0)
n = NumScreens - 1;
else if (n >= NumScreens)
n = 0;
newscr = ScreenList[n];
if (!newscr) { /* make sure screen is managed */
if (inc) { /* walk around the list */
n += inc;
continue;
}
fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n",
ProgramName, n);
XBell (dpy, 0);
return (1);
}
}
if (Scr->screen == n) return (0); /* already on that screen */
PreviousScreen = Scr->screen;
XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
&dumint, &dumint, &dummask);
XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
Scr = newscr;
return (0);
}
/*
* BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
*/
int BumpWindowColormap (TwmWindow *tmp, int inc)
{
int i, j, previously_installed;
ColormapWindow **cwins;
if (!tmp) return (1);
if (inc && tmp->cmaps.number_cwins > 0) {
cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
tmp->cmaps.number_cwins);
if (cwins) {
if ((previously_installed =
/* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
tmp->cmaps.number_cwins))) {
for (i = tmp->cmaps.number_cwins; i-- > 0; )
tmp->cmaps.cwins[i]->colormap->state = 0;
}
for (i = 0; i < tmp->cmaps.number_cwins; i++) {
j = i - inc;
if (j >= tmp->cmaps.number_cwins)
j -= tmp->cmaps.number_cwins;
else if (j < 0)
j += tmp->cmaps.number_cwins;
cwins[j] = tmp->cmaps.cwins[i];
}
free((char *) tmp->cmaps.cwins);
tmp->cmaps.cwins = cwins;
if (tmp->cmaps.number_cwins > 1)
memset (tmp->cmaps.scoreboard, 0,
ColormapsScoreboardLength(&tmp->cmaps));
if (previously_installed) {
InstallColormaps(PropertyNotify, NULL);
}
}
} else
FetchWmColormapWindows (tmp);
return (1);
}
void ShowIconManager (void)
{
IconMgr *i;
WorkSpace *wl;
if (! Scr->workSpaceManagerActive) return;
if (Scr->NoIconManagers) return;
for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
for (i = wl->iconmgr; i != NULL; i = i->next) {
if (i->count == 0) continue;
if (visible (i->twm_win)) {
SetMapStateProp (i->twm_win, NormalState);
XMapWindow (dpy, i->twm_win->w);
MapRaised (i->twm_win);
if (i->twm_win->icon && i->twm_win->icon->w)
XUnmapWindow (dpy, i->twm_win->icon->w);
}
i->twm_win->mapped = TRUE;
i->twm_win->isicon = FALSE;
}
}
}
void HideIconManager (void)
{
IconMgr *i;
WorkSpace *wl;
if (Scr->NoIconManagers) return;
for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
for (i = wl->iconmgr; i != NULL; i = i->next) {
SetMapStateProp (i->twm_win, WithdrawnState);
XUnmapWindow(dpy, i->twm_win->frame);
if (i->twm_win->icon && i->twm_win->icon->w) XUnmapWindow (dpy, i->twm_win->icon->w);
i->twm_win->mapped = FALSE;
i->twm_win->isicon = TRUE;
}
}
}
void DestroyMenu (MenuRoot *menu)
{
MenuItem *item;
if (menu->w) {
XDeleteContext (dpy, menu->w, MenuContext);
XDeleteContext (dpy, menu->w, ScreenContext);
if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
XDestroyWindow(dpy, menu->w);
}
for (item = menu->first; item; ) {
MenuItem *tmp = item;
item = item->next;
free ((char *) tmp);
}
}
/*
* warping routines
*/
void WarpAlongRing (XButtonEvent *ev, Bool forward)
{
TwmWindow *r, *head;
if (Scr->RingLeader)
head = Scr->RingLeader;
else if (!(head = Scr->Ring))
return;
if (forward) {
for (r = head->ring.next; r != head; r = r->ring.next) {
if (!r) break;
if (r->mapped && (Scr->WarpRingAnyWhere || visible (r))) break;
}
} else {
for (r = head->ring.prev; r != head; r = r->ring.prev) {
if (!r) break;
if (r->mapped && (Scr->WarpRingAnyWhere || visible (r))) break;
}
}
/* Note: (Scr->Focus != r) is necessary when we move to a workspace that
has a single window and we want warping to warp to it. */
if (r && (r != head || Scr->Focus != r)) {
TwmWindow *p = Scr->RingLeader, *t;
Scr->RingLeader = r;
WarpToWindow (r, 1);
if (p && p->mapped &&
(t = GetTwmWindow(ev->window)) &&
p == t) {
p->ring.cursor_valid = True;
p->ring.curs_x = ev->x_root - t->frame_x;
p->ring.curs_y = ev->y_root - t->frame_y;
#ifdef DEBUG
fprintf(stderr, "WarpAlongRing: cursor_valid := True; x := %d (%d-%d), y := %d (%d-%d)\n", Tmp_win->ring.curs_x, ev->x_root, t->frame_x, Tmp_win->ring.curs_y, ev->y_root, t->frame_y);
#endif
/*
* The check if the cursor position is inside the window is now
* done in WarpToWindow().
*/
}
}
}
void WarpToWindow (TwmWindow *t, int must_raise)
{
int x, y;
if (t->ring.cursor_valid) {
x = t->ring.curs_x;
y = t->ring.curs_y;
#ifdef DEBUG
fprintf(stderr, "WarpToWindow: cursor_valid; x == %d, y == %d\n", x, y);
#endif
/*
* XXX is this correct with 3D borders? Easier check possible?
* frame_bw is for the left border.
*/
if (x < t->frame_bw)
x = t->frame_bw;
if (x >= t->frame_width + t->frame_bw)
x = t->frame_width + t->frame_bw - 1;
if (y < t->title_height + t->frame_bw)
y = t->title_height + t->frame_bw;
if (y >= t->frame_height + t->frame_bw)
y = t->frame_height + t->frame_bw - 1;
#ifdef DEBUG
fprintf(stderr, "WarpToWindow: adjusted ; x := %d, y := %d\n", x, y);
#endif
} else {
x = t->frame_width / 2;
y = t->frame_height / 2;
#ifdef DEBUG
fprintf(stderr, "WarpToWindow: middle; x := %d, y := %d\n", x, y);
#endif
}
#if 0
int dest_x, dest_y;
Window child;
/*
* Check if the proposed position actually is visible. If not, raise the window.
* "If the coordinates are contained in a mapped
* child of dest_w, that child is returned to child_return."
* We'll need to check for the right child window; the frame probably.
* (What about XXX window boxes?)
*
* Alternatively, use XQueryPointer() which returns the root window
* the pointer is in, but XXX that won't work for VirtualScreens.
*/
if (XTranslateCoordinates(dpy, t->frame, Scr->Root, x, y, &dest_x, &dest_y, &child)) {
if (child != t->frame)
must_raise = 1;
}
#endif
if (t->auto_raise || must_raise) AutoRaiseWindow (t);
if (! visible (t)) {
WorkSpace *wlist;
for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
if (OCCUPY (t, wlist)) break;
}
if (wlist != NULL) GotoWorkSpace (Scr->currentvs, wlist);
}
XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0, x + t->frame_x, y + t->frame_y);
#ifdef DEBUG
{
Window root_return;
Window child_return;
int root_x_return;
int root_y_return;
int win_x_return;
int win_y_return;
unsigned int mask_return;
if (XQueryPointer(dpy, t->frame, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return)) {
fprintf(stderr, "XQueryPointer: root_return=%x, child_return=%x, root_x_return=%d, root_y_return=%d, win_x_return=%d, win_y_return=%d\n", root_return, child_return, root_x_return, root_y_return, win_x_return, win_y_return);
}
}
#endif
}
/*
* ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
* client messages will have the following form:
*
* event type ClientMessage
* message type _XA_WM_PROTOCOLS
* window tmp->w
* format 32
* data[0] message atom
* data[1] time stamp
*/
static void send_clientmessage (Window w, Atom a, Time timestamp)
{
XClientMessageEvent ev;
ev.type = ClientMessage;
ev.window = w;
ev.message_type = _XA_WM_PROTOCOLS;
ev.format = 32;
ev.data.l[0] = a;
ev.data.l[1] = timestamp;
XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
}
void SendDeleteWindowMessage (TwmWindow *tmp, Time timestamp)
{
send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
}
void SendSaveYourselfMessage (TwmWindow *tmp, Time timestamp)
{
send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
}
void SendTakeFocusMessage (TwmWindow *tmp, Time timestamp)
{
send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
}
int MoveMenu (XEvent *eventp)
{
int XW, YW, newX, newY, cont;
Bool newev;
unsigned long event_mask;
XEvent ev;
if (! ActiveMenu) return (1);
if (! ActiveMenu->pinned) return (1);
XW = eventp->xbutton.x_root - ActiveMenu->x;
YW = eventp->xbutton.y_root - ActiveMenu->y;
XGrabPointer (dpy, ActiveMenu->w, True,
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
GrabModeAsync, GrabModeAsync,
None, Scr->MoveCursor, CurrentTime);
newX = ActiveMenu->x;
newY = ActiveMenu->y;
cont = TRUE;
event_mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask | ExposureMask;
XMaskEvent (dpy, event_mask, &ev);
while (cont) {
ev.xbutton.x_root -= Scr->rootx;
ev.xbutton.y_root -= Scr->rooty;
switch (ev.xany.type) {
case ButtonRelease :
cont = FALSE;
case MotionNotify :
if (!cont) {
newev = False;
while (XCheckMaskEvent (dpy, ButtonMotionMask | ButtonReleaseMask, &ev)) {
newev = True;
if (ev.type == ButtonRelease) break;
}
if (ev.type == ButtonRelease) continue;
if (newev) {
ev.xbutton.x_root -= Scr->rootx;
ev.xbutton.y_root -= Scr->rooty;
}
}
newX = ev.xbutton.x_root - XW;
newY = ev.xbutton.y_root - YW;
if (Scr->DontMoveOff)
{
ConstrainByBorders1 (&newX, ActiveMenu->width,
&newY, ActiveMenu->height);
}
XMoveWindow (dpy, ActiveMenu->w, newX, newY);
XMaskEvent (dpy, event_mask, &ev);
break;
case ButtonPress :
cont = FALSE;
newX = ActiveMenu->x;
newY = ActiveMenu->y;
break;
case Expose:
case NoExpose:
Event = ev;
DispatchEvent ();
XMaskEvent (dpy, event_mask, &ev);
break;
}
}
XUngrabPointer (dpy, CurrentTime);
if (ev.xany.type == ButtonRelease) ButtonPressed = -1;
/*XPutBackEvent (dpy, &ev);*/
XMoveWindow (dpy, ActiveMenu->w, newX, newY);
ActiveMenu->x = newX;
ActiveMenu->y = newY;
MenuOrigins [MenuDepth - 1].x = newX;
MenuOrigins [MenuDepth - 1].y = newY;
return (1);
}
/***********************************************************************
*
* Procedure:
* DisplayPosition - display the position in the dimensions window
*
* Inputs:
* tmp_win - the current twm window
* x, y - position of the window
*
***********************************************************************
*/
void DisplayPosition (TwmWindow *tmp_win, int x, int y)
{
char str [100];
char signx = '+';
char signy = '+';
if (x < 0) {
x = -x;
signx = '-';
}
if (y < 0) {
y = -y;
signy = '-';
}
(void) sprintf (str, " %c%-4d %c%-4d ", signx, x, signy, y);
XRaiseWindow (dpy, Scr->SizeWindow);
Draw3DBorder (Scr->SizeWindow, 0, 0,
Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT,
Scr->SizeFont.height + SIZE_VINDENT * 2,
2, Scr->DefaultC, off, False, False);
FB(Scr->DefaultC.fore, Scr->DefaultC.back);
XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
Scr->NormalGC, Scr->SizeStringOffset,
Scr->SizeFont.ascent + SIZE_VINDENT , str, 13);
}
void MosaicFade (TwmWindow *tmp_win, Window blanket)
{
int srect;
int i, j, nrects;
Pixmap mask;
GC gc;
XGCValues gcv;
XRectangle *rectangles;
int width = tmp_win->frame_width;
int height = tmp_win->frame_height;
srect = (width < height) ? (width / 20) : (height / 20);
mask = XCreatePixmap (dpy, blanket, width, height, 1);
gcv.foreground = 1;
gc = XCreateGC (dpy, mask, GCForeground, &gcv);
XFillRectangle (dpy, mask, gc, 0, 0, width, height);
gcv.function = GXclear;
XChangeGC (dpy, gc, GCFunction, &gcv);
nrects = ((width * height) / (srect * srect)) / 10;
rectangles = (XRectangle*) malloc (nrects * sizeof (XRectangle));
for (j = 0; j < nrects; j++) {
rectangles [j].width = srect;
rectangles [j].height = srect;
}
for (i = 0; i < 10; i++) {
for (j = 0; j < nrects; j++) {
/* coverity[dc.weak_crypto] */
rectangles [j].x = ((lrand48 () % width) / srect) * srect;
/* coverity[dc.weak_crypto] */
rectangles [j].y = ((lrand48 () % height) / srect) * srect;
}
XFillRectangles (dpy, mask, gc, rectangles, nrects);
XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
XFlush (dpy);
waitamoment (0.020);
}
XFreePixmap (dpy, mask);
XFreeGC (dpy, gc);
free (rectangles);
}
void ZoomInWindow (TwmWindow *tmp_win, Window blanket)
{
Pixmap mask;
GC gc, gcn;
XGCValues gcv;
int i, nsteps = 20;
int w = tmp_win->frame_width;
int h = tmp_win->frame_height;
int step = (MAX (w, h)) / (2.0 * nsteps);
mask = XCreatePixmap (dpy, blanket, w, h, 1);
gcv.foreground = 1;
gc = XCreateGC (dpy, mask, GCForeground, &gcv);
gcv.function = GXclear;
gcn = XCreateGC (dpy, mask, GCForeground | GCFunction, &gcv);
for (i = 0; i < nsteps; i++) {
XFillRectangle (dpy, mask, gcn, 0, 0, w, h);
XFillArc (dpy, mask, gc, (w / 2) - ((nsteps - i) * step),
(h / 2) - ((nsteps - i) * step),
2 * (nsteps - i) * step,
2 * (nsteps - i) * step,
0, 360*64);
XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
XFlush (dpy);
waitamoment (0.020);
}
}
void ZoomOutWindow (TwmWindow *tmp_win, Window blanket)
{
Pixmap mask;
GC gc;
XGCValues gcv;
int i, nsteps = 20;
int w = tmp_win->frame_width;
int h = tmp_win->frame_height;
int step = (MAX (w, h)) / (2.0 * nsteps);
mask = XCreatePixmap (dpy, blanket, w, h, 1);
gcv.foreground = 1;
gc = XCreateGC (dpy, mask, GCForeground, &gcv);
XFillRectangle (dpy, mask, gc, 0, 0, w, h);
gcv.function = GXclear;
XChangeGC (dpy, gc, GCFunction, &gcv);
for (i = 0; i < nsteps; i++) {
XFillArc (dpy, mask, gc, (w / 2) - (i * step),
(h / 2) - (i * step),
2 * i * step,
2 * i * step,
0, 360*64);
XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
XFlush (dpy);
waitamoment (0.020);
}
}
void FadeWindow (TwmWindow *tmp_win, Window blanket)
{
Pixmap mask, stipple;
GC gc;
XGCValues gcv;
static unsigned char stipple_bits[] = { 0x0F, 0x0F,
0xF0, 0xF0,
0x0F, 0x0F,
0xF0, 0xF0,
0x0F, 0x0F,
0xF0, 0xF0,
0x0F, 0x0F,
0xF0, 0xF0,
};
int w = tmp_win->frame_width;
int h = tmp_win->frame_height;
stipple = XCreateBitmapFromData (dpy, blanket, (char *)stipple_bits, 8, 8);
mask = XCreatePixmap (dpy, blanket, w, h, 1);
gcv.background = 0;
gcv.foreground = 1;
gcv.stipple = stipple;
gcv.fill_style = FillOpaqueStippled;
gc = XCreateGC (dpy, mask, GCBackground | GCForeground | GCFillStyle | GCStipple, &gcv);
XFillRectangle (dpy, mask, gc, 0, 0, w, h);
XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
XFlush (dpy);
waitamoment (10.0);
XFreePixmap (dpy, stipple);
}
void SweepWindow (TwmWindow *tmp_win, Window blanket)
{
float step = 0.0;
int i, nsteps = 20;
int dir = 0, dist = tmp_win->frame_x, dist1;
dist1 = tmp_win->frame_y;
if (dist1 < dist) { dir = 1; dist = dist1; }
dist1 = tmp_win->vs->w - (tmp_win->frame_x + tmp_win->frame_width);
if (dist1 < dist) { dir = 2; dist = dist1; }
dist1 = tmp_win->vs->h - (tmp_win->frame_y + tmp_win->frame_height);
if (dist1 < dist) { dir = 3; dist = dist1; }
switch (dir) {
case 0: step = tmp_win->frame_x + tmp_win->frame_width; break;
case 1: step = tmp_win->frame_y + tmp_win->frame_height; break;
case 2: step = tmp_win->vs->w - tmp_win->frame_x; break;
case 3: step = tmp_win->vs->h - tmp_win->frame_y; break;
}
step /= (float) nsteps;
step /= (float) nsteps;
for (i = 0; i < 20; i++) {
int x = tmp_win->frame_x;
int y = tmp_win->frame_y;
switch (dir) {
case 0: x -= i * i * step; break;
case 1: y -= i * i * step; break;
case 2: x += i * i * step; break;
case 3: y += i * i * step; break;
}
XMoveWindow (dpy, blanket, x, y);
XFlush (dpy);
waitamoment (0.020);
}
}
void waitamoment (float timeout)
{
#ifdef VMS
lib$wait (&timeout);
#else
struct timeval timeoutstruct;
int usec = timeout * 1000000;
timeoutstruct.tv_usec = usec % (unsigned long) 1000000;
timeoutstruct.tv_sec = usec / (unsigned long) 1000000;
select (0, (void *) 0, (void *) 0, (void *) 0, &timeoutstruct);
#endif
}
void packwindow (TwmWindow *tmp_win, char *direction)
{
int cons, newx, newy;
int x, y, px, py, junkX, junkY;
unsigned int junkK;
Window junkW;
if (!strcmp (direction, "left")) {
cons = FindConstraint (tmp_win, J_LEFT);
if (cons == -1) return;
newx = cons;
newy = tmp_win->frame_y;
} else
if (!strcmp (direction, "right")) {
cons = FindConstraint (tmp_win, J_RIGHT);
if (cons == -1) return;
newx = cons;
newx -= tmp_win->frame_width + 2 * tmp_win->frame_bw;
newy = tmp_win->frame_y;
} else
if (!strcmp (direction, "top")) {
cons = FindConstraint (tmp_win, J_TOP);
if (cons == -1) return;
newx = tmp_win->frame_x;
newy = cons;
} else
if (!strcmp (direction, "bottom")) {
cons = FindConstraint (tmp_win, J_BOTTOM);
if (cons == -1) return;
newx = tmp_win->frame_x;
newy = cons;
newy -= tmp_win->frame_height + 2 * tmp_win->frame_bw;
} else return;
XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK);
px = x - tmp_win->frame_x + newx;
py = y - tmp_win->frame_y + newy;
XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, px, py);
XRaiseWindow(dpy, tmp_win->frame);
XMoveWindow (dpy, tmp_win->frame, newx, newy);
SetupWindow (tmp_win, newx, newy, tmp_win->frame_width, tmp_win->frame_height, -1);
}
void fillwindow (TwmWindow *tmp_win, char *direction)
{
int cons, newx, newy, save;
unsigned int neww, newh;
int i;
int winx = tmp_win->frame_x;
int winy = tmp_win->frame_y;
int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
if (!strcmp (direction, "left")) {
cons = FindConstraint (tmp_win, J_LEFT);
if (cons == -1) return;
newx = cons;
newy = tmp_win->frame_y;
neww = winw + winx - newx;
newh = winh;
neww -= 2 * tmp_win->frame_bw;
newh -= 2 * tmp_win->frame_bw;
ConstrainSize (tmp_win, &neww, &newh);
} else
if (!strcmp (direction, "right")) {
for (i = 0; i < 2; i++) {
cons = FindConstraint (tmp_win, J_RIGHT);
if (cons == -1) return;
newx = tmp_win->frame_x;
newy = tmp_win->frame_y;
neww = cons - winx;
newh = winh;
save = neww;
neww -= 2 * tmp_win->frame_bw;
newh -= 2 * tmp_win->frame_bw;
ConstrainSize (tmp_win, &neww, &newh);
if ((neww != winw) || (newh != winh) ||
(cons == Scr->rootw - Scr->BorderRight))
break;
neww = save;
SetupWindow (tmp_win, newx, newy, neww, newh, -1);
}
} else
if (!strcmp (direction, "top")) {
cons = FindConstraint (tmp_win, J_TOP);
if (cons == -1) return;
newx = tmp_win->frame_x;
newy = cons;
neww = winw;
newh = winh + winy - newy;
neww -= 2 * tmp_win->frame_bw;
newh -= 2 * tmp_win->frame_bw;
ConstrainSize (tmp_win, &neww, &newh);
} else
if (!strcmp (direction, "bottom")) {
for (i = 0; i < 2; i++) {
cons = FindConstraint (tmp_win, J_BOTTOM);
if (cons == -1) return;
newx = tmp_win->frame_x;
newy = tmp_win->frame_y;
neww = winw;
newh = cons - winy;
save = newh;
neww -= 2 * tmp_win->frame_bw;
newh -= 2 * tmp_win->frame_bw;
ConstrainSize (tmp_win, &neww, &newh);
if ((neww != winw) || (newh != winh) ||
(cons == Scr->rooth - Scr->BorderBottom))
break;
newh = save;
SetupWindow (tmp_win, newx, newy, neww, newh, -1);
}
}
else if (!strcmp (direction, "vertical"))
{
if (tmp_win->zoomed == ZOOM_NONE)
{
tmp_win->save_frame_height = tmp_win->frame_height;
tmp_win->save_frame_width = tmp_win->frame_width;
tmp_win->save_frame_y = tmp_win->frame_y;
tmp_win->save_frame_x = tmp_win->frame_x;
tmp_win->frame_y++;
newy = FindConstraint (tmp_win, J_TOP);
tmp_win->frame_y--;
newh = FindConstraint (tmp_win, J_BOTTOM) - newy;
newh -= 2 * tmp_win->frame_bw;
newx = tmp_win->frame_x;
neww = tmp_win->frame_width;
ConstrainSize (tmp_win, &neww, &newh);
/* if the bottom of the window has moved up
* it will be pushed down */
if (newy + newh <
tmp_win->save_frame_y + tmp_win->save_frame_height)
newy = tmp_win->save_frame_y +
tmp_win->save_frame_height - newh;
tmp_win->zoomed = F_ZOOM;
SetupWindow (tmp_win, newx, newy, neww, newh, -1);
}
else
{
fullzoom (tmp_win, tmp_win->zoomed);
}
return;
}
else return;
SetupWindow (tmp_win, newx, newy, neww, newh, -1);
}
void jump (TwmWindow *tmp_win, int direction, char *action)
{
int fx, fy, px, py, step, status, cons;
int fwidth, fheight;
int junkX, junkY;
unsigned int junkK;
Window junkW;
if (! action) return;
status = sscanf (action, "%d", &step);
if (status != 1) return;
if (step < 1) return;
fx = tmp_win->frame_x;
fy = tmp_win->frame_y;
XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
px -= fx; py -= fy;
fwidth = tmp_win->frame_width + 2 * tmp_win->frame_bw;
fheight = tmp_win->frame_height + 2 * tmp_win->frame_bw;
switch (direction) {
case J_LEFT :
cons = FindConstraint (tmp_win, J_LEFT);
if (cons == -1) return;
fx -= step * Scr->XMoveGrid;
if (fx < cons) fx = cons;
break;
case J_RIGHT :
cons = FindConstraint (tmp_win, J_RIGHT);
if (cons == -1) return;
fx += step * Scr->XMoveGrid;
if (fx + fwidth > cons) fx = cons - fwidth;
break;
case J_TOP :
cons = FindConstraint (tmp_win, J_TOP);
if (cons == -1) return;
fy -= step * Scr->YMoveGrid;
if (fy < cons) fy = cons;
break;
case J_BOTTOM :
cons = FindConstraint (tmp_win, J_BOTTOM);
if (cons == -1) return;
fy += step * Scr->YMoveGrid;
if (fy + fheight > cons) fy = cons - fheight;
break;
}
/* Pebl Fixme: don't warp if jump happens through iconmgr */
XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, fx + px, fy + py);
if (!Scr->NoRaiseMove)
XRaiseWindow (dpy, tmp_win->frame);
SetupWindow (tmp_win, fx, fy, tmp_win->frame_width, tmp_win->frame_height, -1);
}
int FindConstraint (TwmWindow *tmp_win, int direction)
{
TwmWindow *t;
int w, h;
int winx = tmp_win->frame_x;
int winy = tmp_win->frame_y;
int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
int ret;
switch (direction) {
case J_LEFT : if (winx < Scr->BorderLeft) return -1;
ret = Scr->BorderLeft; break;
case J_RIGHT : if (winx + winw > Scr->rootw - Scr->BorderRight) return -1;
ret = Scr->rootw - Scr->BorderRight; break;
case J_TOP : if (winy < Scr->BorderTop) return -1;
ret = Scr->BorderTop; break;
case J_BOTTOM : if (winy + winh > Scr->rooth - Scr->BorderBottom) return -1;
ret = Scr->rooth - Scr->BorderBottom; break;
default : return -1;
}
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t == tmp_win) continue;
if (!visible (t)) continue;
if (!t->mapped) continue;
w = t->frame_width + 2 * t->frame_bw;
h = t->frame_height + 2 * t->frame_bw;
switch (direction) {
case J_LEFT :
if (winx <= t->frame_x + w) continue;
if (winy >= t->frame_y + h) continue;
if (winy + winh <= t->frame_y ) continue;
ret = MAX (ret, t->frame_x + w);
break;
case J_RIGHT :
if (winx + winw >= t->frame_x ) continue;
if (winy >= t->frame_y + h) continue;
if (winy + winh <= t->frame_y ) continue;
ret = MIN (ret, t->frame_x);
break;
case J_TOP :
if (winy <= t->frame_y + h) continue;
if (winx >= t->frame_x + w) continue;
if (winx + winw <= t->frame_x ) continue;
ret = MAX (ret, t->frame_y + h);
break;
case J_BOTTOM :
if (winy + winh >= t->frame_y ) continue;
if (winx >= t->frame_x + w) continue;
if (winx + winw <= t->frame_x ) continue;
ret = MIN (ret, t->frame_y);
break;
}
}
return ret;
}
void TryToPack (TwmWindow *tmp_win, int *x, int *y)
{
TwmWindow *t;
int newx, newy;
int w, h;
int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
newx = *x;
newy = *y;
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t == tmp_win) continue;
if (t->winbox != tmp_win->winbox) continue;
if (t->vs != tmp_win->vs) continue;
if (!t->mapped) continue;
w = t->frame_width + 2 * t->frame_bw;
h = t->frame_height + 2 * t->frame_bw;
if (newx >= t->frame_x + w) continue;
if (newy >= t->frame_y + h) continue;
if (newx + winw <= t->frame_x) continue;
if (newy + winh <= t->frame_y) continue;
if (newx + Scr->MovePackResistance > t->frame_x + w) { /* left */
newx = MAX (newx, t->frame_x + w);
continue;
}
if (newx + winw < t->frame_x + Scr->MovePackResistance) { /* right */
newx = MIN (newx, t->frame_x - winw);
continue;
}
if (newy + Scr->MovePackResistance > t->frame_y + h) { /* top */
newy = MAX (newy, t->frame_y + h);
continue;
}
if (newy + winh < t->frame_y + Scr->MovePackResistance) { /* bottom */
newy = MIN (newy, t->frame_y - winh);
continue;
}
}
*x = newx;
*y = newy;
}
void TryToPush (TwmWindow *tmp_win, int x, int y, int dir)
{
TwmWindow *t;
int newx, newy, ndir;
Boolean move;
int w, h;
int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
for (t = Scr->FirstWindow; t != NULL; t = t->next) {
if (t == tmp_win) continue;
if (t->winbox != tmp_win->winbox) continue;
if (t->vs != tmp_win->vs) continue;
if (!t->mapped) continue;
w = t->frame_width + 2 * t->frame_bw;
h = t->frame_height + 2 * t->frame_bw;
if (x >= t->frame_x + w) continue;
if (y >= t->frame_y + h) continue;
if (x + winw <= t->frame_x) continue;
if (y + winh <= t->frame_y) continue;
move = False;
if ((dir == 0 || dir == J_LEFT) &&
(x + Scr->MovePackResistance > t->frame_x + w)) {
newx = x - w;
newy = t->frame_y;
ndir = J_LEFT;
move = True;
}
else
if ((dir == 0 || dir == J_RIGHT) &&
(x + winw < t->frame_x + Scr->MovePackResistance)) {
newx = x + winw;
newy = t->frame_y;
ndir = J_RIGHT;
move = True;
}
else
if ((dir == 0 || dir == J_TOP) &&
(y + Scr->MovePackResistance > t->frame_y + h)) {
newx = t->frame_x;
newy = y - h;
ndir = J_TOP;
move = True;
}
else
if ((dir == 0 || dir == J_BOTTOM) &&
(y + winh < t->frame_y + Scr->MovePackResistance)) {
newx = t->frame_x;
newy = y + winh;
ndir = J_BOTTOM;
move = True;
}
if (move) {
TryToPush (t, newx, newy, ndir);
TryToPack (t, &newx, &newy);
ConstrainByBorders (tmp_win,
&newx, t->frame_width + 2 * t->frame_bw,
&newy, t->frame_height + 2 * t->frame_bw);
SetupWindow (t, newx, newy, t->frame_width, t->frame_height, -1);
}
}
}
void TryToGrid (TwmWindow *tmp_win, int *x, int *y)
{
int w = tmp_win->frame_width + 2 * tmp_win->frame_bw;
int h = tmp_win->frame_height + 2 * tmp_win->frame_bw;
int grav = ((tmp_win->hints.flags & PWinGravity)
? tmp_win->hints.win_gravity : NorthWestGravity);
switch (grav) {
case ForgetGravity :
case StaticGravity :
case NorthWestGravity :
case NorthGravity :
case WestGravity :
case CenterGravity :
*x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
+ Scr->BorderLeft;
*y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid
+ Scr->BorderTop;
break;
case NorthEastGravity :
case EastGravity :
*x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
Scr->XMoveGrid) - w + Scr->BorderLeft;
*y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) *
Scr->YMoveGrid + Scr->BorderTop;
break;
case SouthWestGravity :
case SouthGravity :
*x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
+ Scr->BorderLeft;
*y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid)
- h + Scr->BorderTop;
break;
case SouthEastGravity :
*x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
Scr->XMoveGrid) - w + Scr->BorderLeft;
*y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) *
Scr->YMoveGrid) - h + Scr->BorderTop;
break;
}
}
int WarpCursorToDefaultEntry (MenuRoot *menu)
{
MenuItem *item;
Window root;
int i, x, y, xl, yt;
unsigned int w, h, bw, d;
for (i = 0, item = menu->first; item != menu->last; item = item->next) {
if (item == menu->defaultitem) break;
i++;
}
if (!XGetGeometry (dpy, menu->w, &root, &x, &y, &w, &h, &bw, &d)) return 0;
xl = x + (menu->width / 2);
yt = y + (i + 0.5) * Scr->EntryHeight;
XWarpPointer (dpy, Scr->Root, Scr->Root,
Event.xbutton.x_root, Event.xbutton.y_root,
menu->width, menu->height, xl, yt);
return 1;
}