#include <stdio.h>
#include "twm.h"
#include <X11/Xatom.h>
#include "iconmgr.h"
#include "add_window.h"
#include "menus.h"
#include "events.h"
#include "resize.h"
#include "parse.h"
#include "gram.h"
#include "util.h"
#include "screen.h"
#include "icons.h"
#include "version.h"
#define MAX_X_EVENT 256
event_proc EventHandler[MAX_X_EVENT];
char *Action;
int Context = C_NO_CONTEXT;
TwmWindow *ButtonWindow;
XEvent ButtonEvent;
XEvent Event;
TwmWindow *Tmp_win;
TwmWindow *UnHighLight_win = NULL;
Window DragWindow;
int origDragX;
int origDragY;
int DragX;
int DragY;
int DragWidth;
int DragHeight;
int CurrentDragX;
int CurrentDragY;
static int enter_flag;
static int ColortableThrashing;
static TwmWindow *enter_win, *raise_win;
static void free_window_names ( TwmWindow *tmp, Bool nukefull, Bool nukename, Bool nukeicon );
static void remove_window_from_ring ( TwmWindow *tmp );
static void do_menu ( MenuRoot *menu, Window w );
static Bool HENQueueScanner ( Display *dpy, XEvent *ev, char *args );
static Bool HLNQueueScanner ( Display *dpy, XEvent *ev, char *args );
static void flush_expose ( Window w );
static Bool UninstallRootColormapQScanner ( Display *dpy, XEvent *ev, char *args );
int ButtonPressed = -1;
int Cancel = FALSE;
void AutoRaiseWindow (tmp)
TwmWindow *tmp;
{
XRaiseWindow (dpy, tmp->frame);
XSync (dpy, 0);
enter_win = NULL;
enter_flag = TRUE;
raise_win = tmp;
}
void SetRaiseWindow (tmp)
TwmWindow *tmp;
{
enter_flag = TRUE;
enter_win = NULL;
raise_win = tmp;
XSync (dpy, 0);
}
void
InitEvents()
{
int i;
ResizeWindow = (Window) 0;
DragWindow = (Window) 0;
enter_flag = FALSE;
enter_win = raise_win = NULL;
for (i = 0; i < MAX_X_EVENT; i++)
EventHandler[i] = HandleUnknown;
EventHandler[Expose] = HandleExpose;
EventHandler[CreateNotify] = HandleCreateNotify;
EventHandler[DestroyNotify] = HandleDestroyNotify;
EventHandler[MapRequest] = HandleMapRequest;
EventHandler[MapNotify] = HandleMapNotify;
EventHandler[UnmapNotify] = HandleUnmapNotify;
EventHandler[MotionNotify] = HandleMotionNotify;
EventHandler[ButtonRelease] = HandleButtonRelease;
EventHandler[ButtonPress] = HandleButtonPress;
EventHandler[EnterNotify] = HandleEnterNotify;
EventHandler[LeaveNotify] = HandleLeaveNotify;
EventHandler[ConfigureRequest] = HandleConfigureRequest;
EventHandler[ClientMessage] = HandleClientMessage;
EventHandler[PropertyNotify] = HandlePropertyNotify;
EventHandler[KeyPress] = HandleKeyPress;
EventHandler[ColormapNotify] = HandleColormapNotify;
EventHandler[VisibilityNotify] = HandleVisibilityNotify;
if (HasShape)
EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
}
Time lastTimestamp = CurrentTime;
Bool StashEventTime (ev)
register XEvent *ev;
{
switch (ev->type) {
case KeyPress:
case KeyRelease:
lastTimestamp = ev->xkey.time;
return True;
case ButtonPress:
case ButtonRelease:
lastTimestamp = ev->xbutton.time;
return True;
case MotionNotify:
lastTimestamp = ev->xmotion.time;
return True;
case EnterNotify:
case LeaveNotify:
lastTimestamp = ev->xcrossing.time;
return True;
case PropertyNotify:
lastTimestamp = ev->xproperty.time;
return True;
case SelectionClear:
lastTimestamp = ev->xselectionclear.time;
return True;
case SelectionRequest:
lastTimestamp = ev->xselectionrequest.time;
return True;
case SelectionNotify:
lastTimestamp = ev->xselection.time;
return True;
}
return False;
}
Window WindowOfEvent (e)
XEvent *e;
{
switch (e->type) {
case KeyPress:
case KeyRelease: return e->xkey.window;
case ButtonPress:
case ButtonRelease: return e->xbutton.window;
case MotionNotify: return e->xmotion.window;
case EnterNotify:
case LeaveNotify: return e->xcrossing.window;
case FocusIn:
case FocusOut: return e->xfocus.window;
case KeymapNotify: return e->xkeymap.window;
case Expose: return e->xexpose.window;
case GraphicsExpose: return e->xgraphicsexpose.drawable;
case NoExpose: return e->xnoexpose.drawable;
case VisibilityNotify: return e->xvisibility.window;
case CreateNotify: return e->xcreatewindow.window;
case DestroyNotify: return e->xdestroywindow.window;
case UnmapNotify: return e->xunmap.window;
case MapNotify: return e->xmap.window;
case MapRequest: return e->xmaprequest.window;
case ReparentNotify: return e->xreparent.window;
case ConfigureNotify: return e->xconfigure.window;
case ConfigureRequest: return e->xconfigurerequest.window;
case GravityNotify: return e->xgravity.window;
case ResizeRequest: return e->xresizerequest.window;
case CirculateNotify: return e->xcirculate.window;
case CirculateRequest: return e->xcirculaterequest.window;
case PropertyNotify: return e->xproperty.window;
case SelectionClear: return e->xselectionclear.window;
case SelectionRequest: return e->xselectionrequest.requestor;
case SelectionNotify: return e->xselection.requestor;
case ColormapNotify: return e->xcolormap.window;
case ClientMessage: return e->xclient.window;
case MappingNotify: return None;
}
return None;
}
Bool DispatchEvent2 ()
{
Window w = Event.xany.window;
StashEventTime (&Event);
if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
Tmp_win = NULL;
if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
Scr = FindScreenInfo (WindowOfEvent (&Event));
}
if (!Scr) return False;
if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose)
HandleExpose();
if (!menuFromFrameOrWindowOrTitlebar && Event.type>= 0 && Event.type < MAX_X_EVENT) {
(*EventHandler[Event.type])();
}
return True;
}
Bool DispatchEvent ()
{
Window w = Event.xany.window;
StashEventTime (&Event);
if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
Tmp_win = NULL;
if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
Scr = FindScreenInfo (WindowOfEvent (&Event));
}
if (!Scr) return False;
if (Event.type>= 0 && Event.type < MAX_X_EVENT) {
(*EventHandler[Event.type])();
}
return True;
}
void
HandleEvents()
{
while (TRUE)
{
if (enter_flag && !QLength(dpy)) {
if (enter_win && enter_win != raise_win) {
AutoRaiseWindow (enter_win);
} else {
enter_flag = FALSE;
}
}
if (ColortableThrashing && !QLength(dpy) && Scr) {
InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
}
WindowMoved = FALSE;
XtAppNextEvent(appContext, &Event);
if (Event.type>= 0 && Event.type < MAX_X_EVENT)
(void) DispatchEvent ();
else
XtDispatchEvent (&Event);
}
}
void
HandleColormapNotify()
{
XColormapEvent *cevent = (XColormapEvent *) &Event;
ColormapWindow *cwin, **cwins;
TwmColormap *cmap;
int lost, won, n, number_cwins;
if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
return;
cmap = cwin->colormap;
if (cevent->new)
{
if (XFindContext(dpy, cevent->colormap, ColormapContext,
(caddr_t *)&cwin->colormap) == XCNOENT)
cwin->colormap = CreateTwmColormap(cevent->colormap);
else
cwin->colormap->refcnt++;
cmap->refcnt--;
if (cevent->state == ColormapUninstalled)
cmap->state &= ~CM_INSTALLED;
else
cmap->state |= CM_INSTALLED;
if (cmap->state & CM_INSTALLABLE)
InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
if (cmap->refcnt == 0)
{
XDeleteContext(dpy, cmap->c, ColormapContext);
free((char *) cmap);
}
return;
}
if (cevent->state == ColormapUninstalled &&
(cmap->state & CM_INSTALLABLE))
{
if (!(cmap->state & CM_INSTALLED))
return;
cmap->state &= ~CM_INSTALLED;
if (!ColortableThrashing)
{
ColortableThrashing = TRUE;
XSync(dpy, 0);
}
if (cevent->serial >= Scr->cmapInfo.first_req)
{
number_cwins = Scr->cmapInfo.cmaps->number_cwins;
cwins = Scr->cmapInfo.cmaps->cwins;
for (lost = won = -1, n = 0;
(lost == -1 || won == -1) && n < number_cwins;
n++)
{
if (lost == -1 && cwins[n] == cwin)
{
lost = n;
continue;
}
if (won == -1 &&
cwins[n]->colormap->install_req == cevent->serial)
{
won = n;
continue;
}
}
if (won != -1) {
if (lost != -1)
{
if (lost > won)
n = lost*(lost-1)/2 + won;
else
n = won*(won-1)/2 + lost;
Scr->cmapInfo.cmaps->scoreboard[n] = 1;
} else
{
cmap->state |= CM_INSTALLED;
}
} else if (lost != -1) {
InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
}
}
}
else if (cevent->state == ColormapUninstalled)
cmap->state &= ~CM_INSTALLED;
else if (cevent->state == ColormapInstalled)
cmap->state |= CM_INSTALLED;
}
void
HandleVisibilityNotify()
{
XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
ColormapWindow *cwin;
TwmColormap *cmap;
if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
return;
cmap = cwin->colormap;
if ((cmap->state & CM_INSTALLABLE) &&
vevent->state != cwin->visibility &&
(vevent->state == VisibilityFullyObscured ||
cwin->visibility == VisibilityFullyObscured) &&
cmap->w == cwin->w) {
cwin->visibility = vevent->state;
InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
} else
cwin->visibility = vevent->state;
}
int MovedFromKeyPress = False;
void
HandleKeyPress()
{
KeySym ks;
FuncKey *key;
int len;
unsigned int modifier;
if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
Context = C_NO_CONTEXT;
if (Event.xany.window == Scr->Root)
Context = C_ROOT;
if (Tmp_win)
{
if (Event.xany.window == Tmp_win->title_w)
Context = C_TITLE;
if (Event.xany.window == Tmp_win->w)
Context = C_WINDOW;
if (Event.xany.window == Tmp_win->icon_w)
Context = C_ICON;
if (Event.xany.window == Tmp_win->frame)
Context = C_FRAME;
if (Tmp_win->list && Event.xany.window == Tmp_win->list->w)
Context = C_ICONMGR;
if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon)
Context = C_ICONMGR;
}
modifier = (Event.xkey.state & mods_used);
ks = XLookupKeysym((XKeyEvent *) &Event, 0);
for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
{
if (key->keysym == ks &&
key->mods == modifier &&
(key->cont == Context || key->cont == C_NAME))
{
if (key->func == F_RESIZE)
return;
if (key->func == F_MOVE || key->func == F_FORCEMOVE)
MovedFromKeyPress = True;
if (key->cont != C_NAME)
{
ExecuteFunction(key->func, key->action, Event.xany.window,
Tmp_win, &Event, Context, FALSE);
XUngrabPointer(dpy, CurrentTime);
return;
}
else
{
int matched = FALSE;
len = strlen(key->win_name);
for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
Tmp_win = Tmp_win->next)
{
if (!strncmp(key->win_name, Tmp_win->name, len))
{
matched = TRUE;
ExecuteFunction(key->func, key->action, Tmp_win->frame,
Tmp_win, &Event, C_FRAME, FALSE);
XUngrabPointer(dpy, CurrentTime);
}
}
if (!matched)
for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
Tmp_win = Tmp_win->next)
{
if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
{
matched = TRUE;
ExecuteFunction(key->func, key->action, Tmp_win->frame,
Tmp_win, &Event, C_FRAME, FALSE);
XUngrabPointer(dpy, CurrentTime);
}
}
if (!matched)
for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
Tmp_win = Tmp_win->next)
{
if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
{
matched = TRUE;
ExecuteFunction(key->func, key->action, Tmp_win->frame,
Tmp_win, &Event, C_FRAME, FALSE);
XUngrabPointer(dpy, CurrentTime);
}
}
if (matched)
return;
}
}
}
if (Tmp_win)
{
if (Event.xany.window == Tmp_win->icon_w ||
Event.xany.window == Tmp_win->frame ||
Event.xany.window == Tmp_win->title_w ||
(Tmp_win->list && (Event.xany.window == Tmp_win->list->w)))
{
Event.xkey.window = Tmp_win->w;
XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
}
}
}
static void
free_window_names (tmp, nukefull, nukename, nukeicon)
TwmWindow *tmp;
Bool nukefull, nukename, nukeicon;
{
if (tmp->name == tmp->full_name) nukefull = False;
if (tmp->icon_name == tmp->name) nukename = False;
if (nukefull && tmp->full_name) free (tmp->full_name);
if (nukename && tmp->name) free (tmp->name);
if (nukeicon && tmp->icon_name) free (tmp->icon_name);
return;
}
void
free_cwins (tmp)
TwmWindow *tmp;
{
int i;
TwmColormap *cmap;
if (tmp->cmaps.number_cwins) {
for (i = 0; i < tmp->cmaps.number_cwins; i++) {
if (--tmp->cmaps.cwins[i]->refcnt == 0) {
cmap = tmp->cmaps.cwins[i]->colormap;
if (--cmap->refcnt == 0) {
XDeleteContext(dpy, cmap->c, ColormapContext);
free((char *) cmap);
}
XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
free((char *) tmp->cmaps.cwins[i]);
}
}
free((char *) tmp->cmaps.cwins);
if (tmp->cmaps.number_cwins > 1) {
free(tmp->cmaps.scoreboard);
tmp->cmaps.scoreboard = NULL;
}
tmp->cmaps.number_cwins = 0;
}
}
void
HandlePropertyNotify()
{
char *name = NULL;
unsigned long valuemask;
XSetWindowAttributes attributes;
Pixmap pm;
if (Event.xproperty.window == Scr->Root) {
XStandardColormap *maps = NULL;
int nmaps;
switch (Event.xproperty.state) {
case PropertyNewValue:
if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps,
Event.xproperty.atom)) {
InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
}
return;
case PropertyDelete:
RemoveRGBColormap (Event.xproperty.atom);
return;
}
}
if (!Tmp_win) return;
#define MAX_NAME_LEN 200L
#define MAX_ICON_NAME_LEN 200L
switch (Event.xproperty.atom) {
case XA_WM_NAME:
if (!I18N_FetchName(dpy, Tmp_win->w, &name)) return;
free_window_names (Tmp_win, True, True, False);
Tmp_win->full_name = strdup(name ? name : NoName);
Tmp_win->name = strdup(name ? name : NoName);
if (name) free(name);
Tmp_win->nameChanged = 1;
Tmp_win->name_width = MyFont_TextWidth (&Scr->TitleBarFont,
Tmp_win->name,
strlen (Tmp_win->name));
SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
Tmp_win->frame_width, Tmp_win->frame_height, -1);
if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
if (Tmp_win->icon_name == NoName) {
Tmp_win->icon_name = Tmp_win->name;
RedoIconName();
}
break;
case XA_WM_ICON_NAME:
if (!I18N_GetIconName(dpy, Tmp_win->w, &name)) return;
free_window_names (Tmp_win, False, False, True);
Tmp_win->icon_name = strdup(name ? name : NoName);
if (name) free(name);
RedoIconName();
break;
case XA_WM_HINTS:
if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint))
Tmp_win->group = Tmp_win->wmhints->window_group;
if (Tmp_win->icon_not_ours && Tmp_win->wmhints &&
!(Tmp_win->wmhints->flags & IconWindowHint)) {
int icon_x = 0, icon_y = 0;
XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot,
&icon_x, &icon_y,
&JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
XSelectInput (dpy, Tmp_win->icon_w, None);
XDeleteContext (dpy, Tmp_win->icon_w, TwmContext);
XDeleteContext (dpy, Tmp_win->icon_w, ScreenContext);
CreateIconWindow(Tmp_win, icon_x, icon_y);
break;
}
if (!Tmp_win->forced && Tmp_win->wmhints &&
Tmp_win->wmhints->flags & IconWindowHint) {
if (Tmp_win->icon_w) {
int icon_x, icon_y;
if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
&icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
icon_y);
}
if (Tmp_win->icon)
XMapWindow(dpy, Tmp_win->wmhints->icon_window);
if (Tmp_win->icon_not_ours) {
if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window)
XUnmapWindow(dpy, Tmp_win->icon_w);
} else
XDestroyWindow(dpy, Tmp_win->icon_w);
XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
Tmp_win->icon_not_ours = TRUE;
Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
XSelectInput (dpy, Tmp_win->icon_w,
KeyPressMask | ButtonPressMask | ButtonReleaseMask);
XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
}
}
if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
(Tmp_win->wmhints->flags & IconPixmapHint)) {
if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
&JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width,
(unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) {
return;
}
pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width,
Tmp_win->icon_height, Scr->d_depth);
FB(Tmp_win->iconc.fore, Tmp_win->iconc.back);
XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm,
Scr->NormalGC,
0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
valuemask = CWBackPixmap;
attributes.background_pixmap = pm;
if (Tmp_win->icon_bm_w)
XDestroyWindow(dpy, Tmp_win->icon_bm_w);
Tmp_win->icon_bm_w =
XCreateWindow (dpy, Tmp_win->icon_w, 0, 0,
(unsigned int) Tmp_win->icon_width,
(unsigned int) Tmp_win->icon_height,
(unsigned int) 0, Scr->d_depth,
(unsigned int) CopyFromParent, Scr->d_visual,
valuemask, &attributes);
XFreePixmap (dpy, pm);
RedoIconName();
}
break;
case XA_WM_NORMAL_HINTS:
GetWindowSizeHints (Tmp_win);
break;
default:
if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
FetchWmColormapWindows (Tmp_win);
break;
} else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
FetchWmProtocols (Tmp_win);
break;
}
break;
}
}
void
RedoIconName()
{
int x, y;
if (Tmp_win->list)
{
XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True);
if (Scr->SortIconMgr)
SortIconManager(Tmp_win->list->iconmgr);
}
if (Tmp_win->icon_w == (Window) 0)
return;
if (Tmp_win->icon_not_ours)
return;
Tmp_win->icon_w_width = MyFont_TextWidth(&Scr->IconFont,
Tmp_win->icon_name, strlen(Tmp_win->icon_name));
Tmp_win->icon_w_width += 6;
if (Tmp_win->icon_w_width < Tmp_win->icon_width)
{
Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2;
Tmp_win->icon_x += 3;
Tmp_win->icon_w_width = Tmp_win->icon_width;
}
else
{
Tmp_win->icon_x = 3;
}
if (Tmp_win->icon_w_width == Tmp_win->icon_width)
x = 0;
else
x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2;
y = 0;
Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4;
Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height;
XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width,
Tmp_win->icon_w_height);
if (Tmp_win->icon_bm_w)
{
XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y);
XMapWindow(dpy, Tmp_win->icon_bm_w);
}
if (Tmp_win->icon)
{
XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
}
}
void
HandleClientMessage()
{
if (Event.xclient.message_type == _XA_WM_CHANGE_STATE)
{
if (Tmp_win != NULL)
{
if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon)
{
XEvent button;
XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild,
&(button.xmotion.x_root),
&(button.xmotion.y_root),
&JunkX, &JunkY, &JunkMask);
ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
Tmp_win, &button, FRAME, FALSE);
XUngrabPointer(dpy, CurrentTime);
}
}
}
}
void
HandleExpose()
{
MenuRoot *tmp;
if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0)
{
PaintMenu(tmp, &Event);
return;
}
if (Event.xexpose.count != 0)
return;
if (Event.xany.window == Scr->InfoWindow && InfoLines)
{
int i;
int height;
MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back,
&Scr->DefaultFont);
height = Scr->DefaultFont.height+2;
for (i = 0; i < InfoLines; i++)
{
MyFont_DrawString(dpy, Scr->InfoWindow, &Scr->DefaultFont,
Scr->NormalGC, 5, (i*height) + Scr->DefaultFont.y, Info[i],
strlen(Info[i]));
}
flush_expose (Event.xany.window);
}
else if (Tmp_win != NULL)
{
if (Event.xany.window == Tmp_win->title_w)
{
MyFont_ChangeGC(Tmp_win->title.fore, Tmp_win->title.back,
&Scr->TitleBarFont);
MyFont_DrawString (dpy, Tmp_win->title_w, &Scr->TitleBarFont,
Scr->NormalGC, Scr->TBInfo.titlex, Scr->TitleBarFont.y,
Tmp_win->name, strlen(Tmp_win->name));
flush_expose (Event.xany.window);
}
else if (Event.xany.window == Tmp_win->icon_w)
{
MyFont_ChangeGC(Tmp_win->iconc.fore, Tmp_win->iconc.back,
&Scr->IconFont);
MyFont_DrawString (dpy, Tmp_win->icon_w, &Scr->IconFont,
Scr->NormalGC, Tmp_win->icon_x, Tmp_win->icon_y,
Tmp_win->icon_name, strlen(Tmp_win->icon_name));
flush_expose (Event.xany.window);
return;
} else if (Tmp_win->titlebuttons) {
int i;
Window w = Event.xany.window;
register TBWindow *tbw;
int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
if (w == tbw->window) {
register TitleButton *tb = tbw->info;
FB(Tmp_win->title.fore, Tmp_win->title.back);
XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC,
tb->srcx, tb->srcy, tb->width, tb->height,
tb->dstx, tb->dsty, 1);
flush_expose (w);
return;
}
}
}
if (Tmp_win->list) {
if (Event.xany.window == Tmp_win->list->w)
{
MyFont_ChangeGC(Tmp_win->list->fore, Tmp_win->list->back,
&Scr->IconManagerFont);
MyFont_DrawString (dpy, Event.xany.window,
&Scr->IconManagerFont, Scr->NormalGC,
iconmgr_textx, Scr->IconManagerFont.y+4,
Tmp_win->icon_name, strlen(Tmp_win->icon_name));
DrawIconManagerBorder(Tmp_win->list);
flush_expose (Event.xany.window);
return;
}
if (Event.xany.window == Tmp_win->list->icon)
{
FB(Tmp_win->list->fore, Tmp_win->list->back);
XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon,
Scr->NormalGC,
0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
flush_expose (Event.xany.window);
return;
}
}
}
}
static void remove_window_from_ring (tmp)
TwmWindow *tmp;
{
TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next;
if (enter_win == tmp) {
enter_flag = FALSE;
enter_win = NULL;
}
if (raise_win == Tmp_win) raise_win = NULL;
if (prev) prev->ring.next = next;
if (next) next->ring.prev = prev;
if (Scr->Ring == tmp)
Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL);
if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring;
}
void
HandleDestroyNotify()
{
int i;
if (Tmp_win == NULL)
return;
if (Tmp_win == Scr->Focus)
{
FocusOnRoot();
}
XDeleteContext(dpy, Tmp_win->w, TwmContext);
XDeleteContext(dpy, Tmp_win->w, ScreenContext);
XDeleteContext(dpy, Tmp_win->frame, TwmContext);
XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
if (Tmp_win->icon_w)
{
XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
}
if (Tmp_win->title_height)
{
int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
if (Tmp_win->hilite_w)
{
XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext);
XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext);
}
if (Tmp_win->titlebuttons) {
for (i = 0; i < nb; i++) {
XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
TwmContext);
XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
ScreenContext);
}
}
}
if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps)
InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot);
if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
XDestroyWindow(dpy, Tmp_win->frame);
if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
XDestroyWindow(dpy, Tmp_win->icon_w);
IconDown (Tmp_win);
}
RemoveIconManager(Tmp_win);
Tmp_win->prev->next = Tmp_win->next;
if (Tmp_win->next != NULL)
Tmp_win->next->prev = Tmp_win->prev;
if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
free_window_names (Tmp_win, True, True, True);
if (Tmp_win->wmhints)
XFree ((char *)Tmp_win->wmhints);
if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName)
XFree ((char *)Tmp_win->class.res_name);
if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName)
XFree ((char *)Tmp_win->class.res_class);
free_cwins (Tmp_win);
if (Tmp_win->titlebuttons)
free ((char *) Tmp_win->titlebuttons);
remove_window_from_ring (Tmp_win);
if (UnHighLight_win == Tmp_win)
UnHighLight_win = NULL;
free((char *)Tmp_win);
}
void
HandleCreateNotify()
{
#ifdef DEBUG_EVENTS
fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
fflush(stderr);
Bell(XkbBI_Info,0,Event.xcreatewindow.window);
XSync(dpy, 0);
#endif
}
void
HandleMapRequest()
{
int stat;
int zoom_save;
Event.xany.window = Event.xmaprequest.window;
stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win);
if (stat == XCNOENT)
Tmp_win = NULL;
if (Tmp_win == NULL)
{
Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
if (Tmp_win == NULL)
return;
}
else
{
if (Tmp_win->list == NULL)
(void) AddIconManager (Tmp_win);
}
if ((! Tmp_win->icon) &&
Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
{
int state;
Window icon;
if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
(state == NormalState || state == IconicState)))
state = Tmp_win->wmhints->initial_state;
switch (state)
{
case DontCareState:
case NormalState:
case ZoomState:
case InactiveState:
XMapWindow(dpy, Tmp_win->w);
XMapWindow(dpy, Tmp_win->frame);
SetMapStateProp(Tmp_win, NormalState);
SetRaiseWindow (Tmp_win);
break;
case IconicState:
zoom_save = Scr->DoZoom;
Scr->DoZoom = FALSE;
Iconify(Tmp_win, 0, 0);
Scr->DoZoom = zoom_save;
break;
}
}
else
{
DeIconify(Tmp_win);
SetRaiseWindow (Tmp_win);
}
}
void SimulateMapRequest (w)
Window w;
{
Event.xmaprequest.window = w;
HandleMapRequest ();
}
void
HandleMapNotify()
{
if (Tmp_win == NULL)
return;
XGrabServer (dpy);
if (Tmp_win->icon_w)
XUnmapWindow(dpy, Tmp_win->icon_w);
if (Tmp_win->title_w)
XMapSubwindows(dpy, Tmp_win->title_w);
XMapSubwindows(dpy, Tmp_win->frame);
if (Scr->Focus != Tmp_win && Tmp_win->hilite_w)
XUnmapWindow(dpy, Tmp_win->hilite_w);
XMapWindow(dpy, Tmp_win->frame);
XUngrabServer (dpy);
XFlush (dpy);
Tmp_win->mapped = TRUE;
Tmp_win->icon = FALSE;
Tmp_win->icon_on = FALSE;
}
void
HandleUnmapNotify()
{
int dstx, dsty;
Window dumwin;
if (Tmp_win == NULL)
{
Event.xany.window = Event.xunmap.window;
if (XFindContext(dpy, Event.xany.window,
TwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
Tmp_win = NULL;
}
if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon))
return;
XGrabServer (dpy);
if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
0, 0, &dstx, &dsty, &dumwin)) {
XEvent ev;
Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window,
ReparentNotify, &ev);
SetMapStateProp (Tmp_win, WithdrawnState);
if (reparented) {
if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
Event.xunmap.window,
Tmp_win->old_bw);
if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
} else {
XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
dstx, dsty);
RestoreWithdrawnLocation (Tmp_win);
}
XRemoveFromSaveSet (dpy, Event.xunmap.window);
XSelectInput (dpy, Event.xunmap.window, NoEventMask);
HandleDestroyNotify ();
}
XUngrabServer (dpy);
XFlush (dpy);
}
void
HandleMotionNotify()
{
if (ResizeWindow != (Window) 0)
{
XQueryPointer( dpy, Event.xany.window,
&(Event.xmotion.root), &JunkChild,
&(Event.xmotion.x_root), &(Event.xmotion.y_root),
&(Event.xmotion.x), &(Event.xmotion.y),
&JunkMask);
if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
|| abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
WindowMoved = TRUE;
XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win);
DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
}
}
void
HandleButtonRelease()
{
int xl, xr, yt, yb, w, h;
unsigned mask;
if (InfoLines)
if (Context == C_IDENTIFY) {
XUnmapWindow(dpy, Scr->InfoWindow);
InfoLines = 0;
Context = C_NO_CONTEXT;
}
if (DragWindow != None)
{
MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win);
if (DragWindow == Tmp_win->frame)
{
xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
w = DragWidth + 2 * Tmp_win->frame_bw;
h = DragHeight + 2 * Tmp_win->frame_bw;
}
else
{
xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth;
yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth;
w = DragWidth + 2 * Scr->IconBorderWidth;
h = DragHeight + 2 * Scr->IconBorderWidth;
}
if (ConstMove)
{
if (ConstMoveDir == MOVE_HORIZ)
yt = ConstMoveY;
if (ConstMoveDir == MOVE_VERT)
xl = ConstMoveX;
if (ConstMoveDir == MOVE_NONE)
{
yt = ConstMoveY;
xl = ConstMoveX;
}
}
if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
{
xr = xl + w;
yb = yt + h;
if (xl < 0)
xl = 0;
if (xr > Scr->MyDisplayWidth)
xl = Scr->MyDisplayWidth - w;
if (yt < 0)
yt = 0;
if (yb > Scr->MyDisplayHeight)
yt = Scr->MyDisplayHeight - h;
}
CurrentDragX = xl;
CurrentDragY = yt;
if (DragWindow == Tmp_win->frame)
SetupWindow (Tmp_win, xl, yt,
Tmp_win->frame_width, Tmp_win->frame_height, -1);
else
XMoveWindow (dpy, DragWindow, xl, yt);
if (!Scr->NoRaiseMove && !Scr->OpaqueMove)
XRaiseWindow(dpy, DragWindow);
if (!Scr->OpaqueMove)
UninstallRootColormap();
else
XSync(dpy, 0);
if (Scr->NumAutoRaises) {
enter_flag = TRUE;
enter_win = NULL;
raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
? Tmp_win : NULL);
}
DragWindow = (Window) 0;
ConstMove = FALSE;
}
if (ResizeWindow != (Window) 0)
{
EndResize();
}
if (ActiveMenu != NULL && RootFunction == 0)
{
if (ActiveItem != NULL)
{
int func = ActiveItem->func;
Action = ActiveItem->action;
switch (func) {
case F_MOVE:
case F_FORCEMOVE:
ButtonPressed = -1;
break;
case F_WARPTOSCREEN:
XUngrabPointer(dpy, CurrentTime);
case F_CIRCLEUP:
case F_CIRCLEDOWN:
case F_REFRESH:
PopDownMenu();
break;
default:
break;
}
ExecuteFunction(func, Action,
ButtonWindow ? ButtonWindow->frame : None,
ButtonWindow, &Event, Context, TRUE);
Context = C_NO_CONTEXT;
ButtonWindow = NULL;
if (RootFunction == 0)
{
PopDownMenu();
}
}
else
PopDownMenu();
}
mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
switch (Event.xbutton.button)
{
case Button1: mask &= ~Button1Mask; break;
case Button2: mask &= ~Button2Mask; break;
case Button3: mask &= ~Button3Mask; break;
case Button4: mask &= ~Button4Mask; break;
case Button5: mask &= ~Button5Mask; break;
}
if (RootFunction != 0 ||
ResizeWindow != None ||
DragWindow != None)
ButtonPressed = -1;
if (RootFunction == 0 &&
(Event.xbutton.state & mask) == 0 &&
DragWindow == None &&
ResizeWindow == None)
{
XUngrabPointer(dpy, CurrentTime);
XUngrabServer(dpy);
XFlush(dpy);
EventHandler[EnterNotify] = HandleEnterNotify;
EventHandler[LeaveNotify] = HandleLeaveNotify;
ButtonPressed = -1;
if (DownIconManager)
{
DownIconManager->down = FALSE;
if (Scr->Highlight) DrawIconManagerBorder(DownIconManager);
DownIconManager = NULL;
}
Cancel = FALSE;
}
}
static void
do_menu (menu, w)
MenuRoot *menu;
Window w;
{
int x = Event.xbutton.x_root;
int y = Event.xbutton.y_root;
Bool center;
if (!Scr->NoGrabServer)
XGrabServer(dpy);
if (w) {
int h = Scr->TBInfo.width - Scr->TBInfo.border;
Window child;
(void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
center = False;
} else {
center = True;
}
if (PopUpMenu (menu, x, y, center)) {
UpdateMenu();
} else {
Bell(XkbBI_MinorError,0,w);
}
}
void
HandleButtonPress()
{
unsigned int modifier;
Cursor cur;
if (Event.xbutton.button > MAX_BUTTONS)
return;
if (ActiveMenu != NULL)
PopDownMenu();
XSync(dpy, 0);
if (ButtonPressed != -1 && !InfoLines)
{
Cancel = TRUE;
CurrentDragX = origDragX;
CurrentDragY = origDragY;
if (!menuFromFrameOrWindowOrTitlebar) {
if (Scr->OpaqueMove && DragWindow != None) {
XMoveWindow (dpy, DragWindow, origDragX, origDragY);
} else {
MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
}
}
XUnmapWindow(dpy, Scr->SizeWindow);
if (!Scr->OpaqueMove)
UninstallRootColormap();
ResizeWindow = None;
DragWindow = None;
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;
}
else
ButtonPressed = Event.xbutton.button;
if (ResizeWindow != None ||
DragWindow != None ||
ActiveMenu != NULL)
return;
if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons)
{
register int i;
register TBWindow *tbw;
int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
if (Event.xany.window == tbw->window) {
if (tbw->info->func == F_MENU) {
Context = C_TITLE;
ButtonEvent = Event;
ButtonWindow = Tmp_win;
do_menu (tbw->info->menuroot, tbw->window);
} else {
ExecuteFunction (tbw->info->func, tbw->info->action,
Event.xany.window, Tmp_win, &Event,
C_TITLE, FALSE);
}
return;
}
}
}
Context = C_NO_CONTEXT;
if (Event.xany.window == Scr->InfoWindow)
Context = C_IDENTIFY;
if (Event.xany.window == Scr->Root)
Context = C_ROOT;
if (Tmp_win)
{
if (Tmp_win->list && RootFunction != 0 &&
(Event.xany.window == Tmp_win->list->w ||
Event.xany.window == Tmp_win->list->icon))
{
Tmp_win = Tmp_win->list->iconmgr->twm_win;
XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
Event.xbutton.x, Event.xbutton.y,
&JunkX, &JunkY, &JunkChild);
Event.xbutton.x = JunkX;
Event.xbutton.y = JunkY - Tmp_win->title_height;
Event.xany.window = Tmp_win->w;
Context = C_WINDOW;
}
else if (Event.xany.window == Tmp_win->title_w)
{
Context = C_TITLE;
}
else if (Event.xany.window == Tmp_win->w)
{
printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
Context = C_WINDOW;
}
else if (Event.xany.window == Tmp_win->icon_w)
{
Context = C_ICON;
}
else if (Event.xany.window == Tmp_win->frame)
{
if (Event.xbutton.subwindow == Tmp_win->w) {
Event.xbutton.window = Tmp_win->w;
Event.xbutton.y -= Tmp_win->title_height;
Context = C_WINDOW;
}
else Context = C_FRAME;
}
else if (Tmp_win->list &&
(Event.xany.window == Tmp_win->list->w ||
Event.xany.window == Tmp_win->list->icon))
{
Tmp_win->list->down = TRUE;
if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list);
DownIconManager = Tmp_win->list;
Context = C_ICONMGR;
}
}
if (RootFunction != 0)
{
if (Event.xany.window == Scr->Root)
{
XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
Event.xbutton.x,
Event.xbutton.y,
&JunkX, &JunkY, &Event.xany.window);
if (Event.xany.window == 0 ||
(XFindContext(dpy, Event.xany.window, TwmContext,
(caddr_t *)&Tmp_win) == XCNOENT))
{
RootFunction = 0;
Bell(XkbBI_MinorError,0,Event.xany.window);
return;
}
XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
Event.xbutton.x,
Event.xbutton.y,
&JunkX, &JunkY, &JunkChild);
Event.xbutton.x = JunkX;
Event.xbutton.y = JunkY;
Context = C_WINDOW;
}
if (Event.xany.window != Scr->InfoWindow)
ExecuteFunction(RootFunction, Action, Event.xany.window,
Tmp_win, &Event, Context, FALSE);
RootFunction = 0;
return;
}
ButtonEvent = Event;
ButtonWindow = Tmp_win;
modifier = (Event.xbutton.state & mods_used);
if (Context == C_NO_CONTEXT)
return;
RootFunction = 0;
if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU)
{
do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu,
(Window) None);
}
else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != 0)
{
Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ?
Scr->Mouse[Event.xbutton.button][Context][modifier].item->action : NULL;
ExecuteFunction(Scr->Mouse[Event.xbutton.button][Context][modifier].func,
Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
}
else if (Scr->DefaultFunction.func != 0)
{
if (Scr->DefaultFunction.func == F_MENU)
{
do_menu (Scr->DefaultFunction.menu, (Window) None);
}
else
{
Action = Scr->DefaultFunction.item ?
Scr->DefaultFunction.item->action : NULL;
ExecuteFunction(Scr->DefaultFunction.func, Action,
Event.xany.window, Tmp_win, &Event, Context, FALSE);
}
}
}
typedef struct HENScanArgs {
Window w;
Bool leaves;
Bool inferior;
Bool enters;
} HENScanArgs;
static Bool
HENQueueScanner(dpy, ev, args)
Display *dpy;
XEvent *ev;
char *args;
{
if (ev->type == LeaveNotify) {
if (ev->xcrossing.window == ((HENScanArgs *) args)->w &&
ev->xcrossing.mode == NotifyNormal) {
((HENScanArgs *) args)->leaves = True;
((HENScanArgs *) args)->inferior =
(ev->xcrossing.detail == NotifyInferior);
}
} else if (ev->type == EnterNotify) {
if (ev->xcrossing.mode == NotifyUngrab)
((HENScanArgs *) args)->enters = True;
}
return (False);
}
void
HandleEnterNotify()
{
MenuRoot *mr;
XEnterWindowEvent *ewp = &Event.xcrossing;
HENScanArgs scanArgs;
XEvent dummy;
if (UnHighLight_win && ewp->window != UnHighLight_win->w) {
SetBorder (UnHighLight_win, False);
if (UnHighLight_win->list)
NotActiveIconManager(UnHighLight_win->list);
}
if (ewp->window == Scr->Root)
UnHighLight_win = NULL;
else if (Tmp_win)
UnHighLight_win = Tmp_win;
if (!ActiveMenu) {
if (ewp->mode == NotifyGrab)
return;
scanArgs.w = ewp->window;
scanArgs.leaves = scanArgs.enters = False;
(void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
if (ewp->window == Scr->Root) {
if (!scanArgs.leaves && !scanArgs.enters)
InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
return;
}
if (Tmp_win) {
if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
if (Tmp_win->list) ActiveIconManager(Tmp_win->list);
if (Tmp_win->mapped) {
if (Scr->Focus &&
Scr->Focus != Tmp_win && Tmp_win->hilite_w)
XUnmapWindow(dpy, Scr->Focus->hilite_w);
if (ewp->window == Tmp_win->frame ||
(Tmp_win->list && ewp->window == Tmp_win->list->w)) {
if (Tmp_win->hilite_w)
XMapWindow (dpy, Tmp_win->hilite_w);
if (!scanArgs.leaves && !scanArgs.enters)
InstallWindowColormaps (EnterNotify,
&Scr->TwmRoot);
SetBorder (Tmp_win, True);
if (Tmp_win->title_w && Scr->TitleFocus &&
Tmp_win->wmhints && Tmp_win->wmhints->input)
SetFocus (Tmp_win, ewp->time);
if (Scr->NoTitlebar && Scr->TitleFocus &&
Tmp_win->wmhints && Tmp_win->wmhints->input)
SetFocus (Tmp_win, ewp->time);
if (Tmp_win->protocols & DoesWmTakeFocus)
SendTakeFocusMessage (Tmp_win, ewp->time);
Scr->Focus = Tmp_win;
} else if (ewp->window == Tmp_win->w) {
if (!scanArgs.leaves || scanArgs.inferior)
InstallWindowColormaps(EnterNotify, Tmp_win);
}
}
if (Tmp_win->wmhints != NULL &&
ewp->window == Tmp_win->wmhints->icon_window &&
(!scanArgs.leaves || scanArgs.inferior))
InstallWindowColormaps(EnterNotify, Tmp_win);
}
if (Tmp_win->auto_raise) {
enter_win = Tmp_win;
if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
} else if (enter_flag && raise_win == Tmp_win)
enter_win = Tmp_win;
if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
Scr->RingLeader = Tmp_win;
XSync (dpy, 0);
return;
}
}
if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return;
mr->entered = TRUE;
if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == 0) {
if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
XUnmapWindow (dpy, ActiveMenu->w);
ActiveMenu->mapped = UNMAPPED;
UninstallRootColormap ();
if (ActiveItem) {
ActiveItem->state = 0;
PaintEntry (ActiveMenu, ActiveItem, False);
}
ActiveItem = NULL;
ActiveMenu = mr;
MenuDepth--;
}
return;
}
typedef struct HLNScanArgs {
Window w;
Bool enters;
Bool matches;
} HLNScanArgs;
static Bool
HLNQueueScanner(dpy, ev, args)
Display *dpy;
XEvent *ev;
char *args;
{
if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
((HLNScanArgs *) args)->enters = True;
if (ev->xcrossing.window == ((HLNScanArgs *) args)->w)
((HLNScanArgs *) args)->matches = True;
}
return (False);
}
void
HandleLeaveNotify()
{
HLNScanArgs scanArgs;
XEvent dummy;
if (Tmp_win != NULL)
{
Bool inicon;
if (Event.xcrossing.mode != NotifyNormal)
return;
inicon = (Tmp_win->list &&
Tmp_win->list->w == Event.xcrossing.window);
if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
(Event.xcrossing.detail != NotifyInferior &&
Event.xcrossing.window != Tmp_win->w)) {
if (!inicon) {
if (Tmp_win->mapped) {
Tmp_win->ring.cursor_valid = False;
} else {
Tmp_win->ring.cursor_valid = True;
Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
Tmp_win->frame_x);
Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
Tmp_win->frame_y);
}
}
Scr->RingLeader = (TwmWindow *) NULL;
}
if (Scr->FocusRoot) {
if (Event.xcrossing.detail != NotifyInferior) {
scanArgs.w = Event.xcrossing.window;
scanArgs.enters = scanArgs.matches = False;
(void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
(char *) &scanArgs);
if ((Event.xcrossing.window == Tmp_win->frame &&
!scanArgs.matches) || inicon) {
if (Tmp_win->list) NotActiveIconManager(Tmp_win->list);
if (Tmp_win->hilite_w)
XUnmapWindow (dpy, Tmp_win->hilite_w);
SetBorder (Tmp_win, False);
if (Scr->TitleFocus ||
Tmp_win->protocols & DoesWmTakeFocus)
SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
Scr->Focus = NULL;
} else if (Event.xcrossing.window == Tmp_win->w &&
!scanArgs.enters) {
InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot);
}
}
}
XSync (dpy, 0);
return;
}
}
void
HandleConfigureRequest()
{
XWindowChanges xwc;
unsigned long xwcm;
int x, y, width, height, bw;
int gravx, gravy;
XConfigureRequestEvent *cre = &Event.xconfigurerequest;
#ifdef DEBUG_EVENTS
fprintf(stderr, "ConfigureRequest\n");
if (cre->value_mask & CWX)
fprintf(stderr, " x = %d\n", cre->x);
if (cre->value_mask & CWY)
fprintf(stderr, " y = %d\n", cre->y);
if (cre->value_mask & CWWidth)
fprintf(stderr, " width = %d\n", cre->width);
if (cre->value_mask & CWHeight)
fprintf(stderr, " height = %d\n", cre->height);
if (cre->value_mask & CWSibling)
fprintf(stderr, " above = 0x%x\n", cre->above);
if (cre->value_mask & CWStackMode)
fprintf(stderr, " stack = %d\n", cre->detail);
#endif
Event.xany.window = cre->window;
if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) ==
XCNOENT)
Tmp_win = NULL;
if (!Tmp_win || Tmp_win->icon_w == cre->window) {
xwcm = cre->value_mask &
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
xwc.x = cre->x;
xwc.y = cre->y;
xwc.width = cre->width;
xwc.height = cre->height;
xwc.border_width = cre->border_width;
XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
return;
}
if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
TwmWindow *otherwin;
xwc.sibling = (((cre->value_mask & CWSibling) &&
(XFindContext (dpy, cre->above, TwmContext,
(caddr_t *) &otherwin) == XCSUCCESS))
? otherwin->frame : cre->above);
xwc.stack_mode = cre->detail;
XConfigureWindow (dpy, Tmp_win->frame,
cre->value_mask & (CWSibling | CWStackMode), &xwc);
}
x = Tmp_win->frame_x;
y = Tmp_win->frame_y;
width = Tmp_win->frame_width;
height = Tmp_win->frame_height;
bw = Tmp_win->frame_bw;
GetGravityOffsets (Tmp_win, &gravx, &gravy);
if (cre->value_mask & CWBorderWidth) {
int bwdelta = cre->border_width - Tmp_win->old_bw;
if (bwdelta && Scr->ClientBorderWidth) {
x += gravx * bwdelta;
y += gravy * bwdelta;
bw = cre->border_width;
if (Tmp_win->title_height) height += bwdelta;
x += (gravx < 0) ? bwdelta : -bwdelta;
y += (gravy < 0) ? bwdelta : -bwdelta;
}
Tmp_win->old_bw = cre->border_width;
}
if (cre->value_mask & CWX) {
x = cre->x - bw;
}
if (cre->value_mask & CWY) {
y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
}
if (cre->value_mask & CWWidth) {
width = cre->width;
}
if (cre->value_mask & CWHeight) {
height = cre->height + Tmp_win->title_height;
}
if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
Tmp_win->zoomed = ZOOM_NONE;
SetupWindow (Tmp_win, x, y, width, height, bw);
}
void
HandleShapeNotify ()
{
XShapeEvent *sev = (XShapeEvent *) &Event;
if (Tmp_win == NULL)
return;
if (sev->kind != ShapeBounding)
return;
if (!Tmp_win->wShaped && sev->shaped) {
XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
ShapeSet);
}
Tmp_win->wShaped = sev->shaped;
SetFrameShape (Tmp_win);
}
void
HandleUnknown()
{
#ifdef DEBUG_EVENTS
fprintf(stderr, "type = %d\n", Event.type);
#endif
}
int
Transient(w, propw)
Window w, *propw;
{
return (XGetTransientForHint(dpy, w, propw));
}
ScreenInfo *
FindScreenInfo(w)
Window w;
{
XWindowAttributes attr;
int scrnum;
attr.screen = NULL;
if (XGetWindowAttributes(dpy, w, &attr)) {
for (scrnum = 0; scrnum < NumScreens; scrnum++) {
if (ScreenList[scrnum] != NULL &&
(ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
attr.screen))
return ScreenList[scrnum];
}
}
return NULL;
}
static void flush_expose (w)
Window w;
{
XEvent dummy;
while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
}
void
InstallWindowColormaps (type, tmp)
int type;
TwmWindow *tmp;
{
int i, j, n, number_cwins, state;
ColormapWindow **cwins, *cwin, **maxcwin = NULL;
TwmColormap *cmap;
char *row, *scoreboard;
switch (type) {
case EnterNotify:
case LeaveNotify:
case DestroyNotify:
default:
Scr->cmapInfo.pushed_window = tmp;
if (Scr->cmapInfo.root_pushes)
return;
if (Scr->cmapInfo.cmaps == &tmp->cmaps)
return;
if (Scr->cmapInfo.cmaps)
for (i = Scr->cmapInfo.cmaps->number_cwins,
cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++)
(*cwins)->colormap->state &= ~CM_INSTALLABLE;
Scr->cmapInfo.cmaps = &tmp->cmaps;
break;
case PropertyNotify:
case VisibilityNotify:
case ColormapNotify:
break;
}
number_cwins = Scr->cmapInfo.cmaps->number_cwins;
cwins = Scr->cmapInfo.cmaps->cwins;
scoreboard = Scr->cmapInfo.cmaps->scoreboard;
ColortableThrashing = FALSE;
state = CM_INSTALLED;
for (i = n = 0; i < number_cwins; i++) {
cwin = cwins[i];
cmap = cwin->colormap;
cmap->state |= CM_INSTALLABLE;
cmap->state &= ~CM_INSTALL;
cmap->w = cwin->w;
}
for (i = n = 0; i < number_cwins; i++) {
cwin = cwins[i];
cmap = cwin->colormap;
if (cwin->visibility != VisibilityFullyObscured &&
n < Scr->cmapInfo.maxCmaps) {
row = scoreboard + (i*(i-1)/2);
for (j = 0; j < i; j++)
if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
break;
if (j != i)
continue;
n++;
maxcwin = &cwins[i];
state &= (cmap->state & CM_INSTALLED);
cmap->state |= CM_INSTALL;
}
}
Scr->cmapInfo.first_req = NextRequest(dpy);
for ( ; n > 0 && maxcwin >= cwins; maxcwin--) {
cmap = (*maxcwin)->colormap;
if (cmap->state & CM_INSTALL) {
cmap->state &= ~CM_INSTALL;
if (!(state & CM_INSTALLED)) {
cmap->install_req = NextRequest(dpy);
XInstallColormap(dpy, cmap->c);
}
cmap->state |= CM_INSTALLED;
n--;
}
}
}
void
InstallRootColormap()
{
TwmWindow *tmp;
if (Scr->cmapInfo.root_pushes == 0) {
tmp = Scr->cmapInfo.pushed_window;
InstallWindowColormaps(0, &Scr->TwmRoot);
Scr->cmapInfo.pushed_window = tmp;
}
Scr->cmapInfo.root_pushes++;
}
static Bool
UninstallRootColormapQScanner(dpy, ev, args)
Display *dpy;
XEvent *ev;
char *args;
{
if (!*args) {
if (ev->type == EnterNotify) {
if (ev->xcrossing.mode != NotifyGrab)
*args = 1;
} else if (ev->type == LeaveNotify) {
if (ev->xcrossing.mode == NotifyNormal)
*args = 1;
}
}
return (False);
}
void
UninstallRootColormap()
{
char args;
XEvent dummy;
if (Scr->cmapInfo.root_pushes)
Scr->cmapInfo.root_pushes--;
if (!Scr->cmapInfo.root_pushes) {
XSync (dpy, 0);
args = 0;
(void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
if (!args)
InstallWindowColormaps(0, Scr->cmapInfo.pushed_window);
}
}
#ifdef TRACE
void
dumpevent (e)
XEvent *e;
{
char *name = NULL;
switch (e->type) {
case KeyPress: name = "KeyPress"; break;
case KeyRelease: name = "KeyRelease"; break;
case ButtonPress: name = "ButtonPress"; break;
case ButtonRelease: name = "ButtonRelease"; break;
case MotionNotify: name = "MotionNotify"; break;
case EnterNotify: name = "EnterNotify"; break;
case LeaveNotify: name = "LeaveNotify"; break;
case FocusIn: name = "FocusIn"; break;
case FocusOut: name = "FocusOut"; break;
case KeymapNotify: name = "KeymapNotify"; break;
case Expose: name = "Expose"; break;
case GraphicsExpose: name = "GraphicsExpose"; break;
case NoExpose: name = "NoExpose"; break;
case VisibilityNotify: name = "VisibilityNotify"; break;
case CreateNotify: name = "CreateNotify"; break;
case DestroyNotify: name = "DestroyNotify"; break;
case UnmapNotify: name = "UnmapNotify"; break;
case MapNotify: name = "MapNotify"; break;
case MapRequest: name = "MapRequest"; break;
case ReparentNotify: name = "ReparentNotify"; break;
case ConfigureNotify: name = "ConfigureNotify"; break;
case ConfigureRequest: name = "ConfigureRequest"; break;
case GravityNotify: name = "GravityNotify"; break;
case ResizeRequest: name = "ResizeRequest"; break;
case CirculateNotify: name = "CirculateNotify"; break;
case CirculateRequest: name = "CirculateRequest"; break;
case PropertyNotify: name = "PropertyNotify"; break;
case SelectionClear: name = "SelectionClear"; break;
case SelectionRequest: name = "SelectionRequest"; break;
case SelectionNotify: name = "SelectionNotify"; break;
case ColormapNotify: name = "ColormapNotify"; break;
case ClientMessage: name = "ClientMessage"; break;
case MappingNotify: name = "MappingNotify"; break;
}
if (name) {
printf ("event: %s, %d remaining\n", name, QLength(dpy));
} else {
printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy));
}
}
#endif