mirror of
https://github.com/NishiOwO/fvwm1.git
synced 2025-04-21 08:44:39 +00:00
1461 lines
38 KiB
C
1461 lines
38 KiB
C
/****************************************************************************
|
|
* This module is based on Twm, but has been siginificantly modified
|
|
* by Rob Nation
|
|
****************************************************************************/
|
|
/*****************************************************************************/
|
|
/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
|
|
/** Salt Lake City, Utah **/
|
|
/** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
|
|
/** Cambridge, Massachusetts **/
|
|
/** **/
|
|
/** All Rights Reserved **/
|
|
/** **/
|
|
/** Permission to use, copy, modify, and distribute this software and **/
|
|
/** its documentation for any purpose and without fee is hereby **/
|
|
/** granted, provided that the above copyright notice appear in all **/
|
|
/** copies and that both that copyright notice and this permis- **/
|
|
/** sion notice appear in supporting documentation, and that the **/
|
|
/** names of Evans & Sutherland and M.I.T. not be used in advertising **/
|
|
/** in publicity pertaining to distribution of the software without **/
|
|
/** specific, written prior permission. **/
|
|
/** **/
|
|
/** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
|
|
/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
|
|
/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
|
|
/** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
|
|
/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
|
|
/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
|
|
/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
|
|
/** OR PERFORMANCE OF THIS SOFTWARE. **/
|
|
/*****************************************************************************/
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* fvwm event handling
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "../configure.h"
|
|
|
|
#ifdef ISC
|
|
#include <sys/bsdtypes.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
/* Some people say that AIX and AIXV3 need 3 preceding underscores, other say
|
|
* no. I'll do both */
|
|
#if defined ___AIX || defined _AIX || defined __QNX__ || defined ___AIXV3 || defined AIXV3 || defined _SEQUENT_
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
#include "fvwm.h"
|
|
#include <X11/Xatom.h>
|
|
#include "menus.h"
|
|
#include "misc.h"
|
|
#include "parse.h"
|
|
#include "screen.h"
|
|
#ifdef SHAPE
|
|
#include <X11/extensions/shape.h>
|
|
#endif /* SHAPE */
|
|
#include "module.h"
|
|
|
|
#ifndef NO_PAGER
|
|
extern FvwmWindow *FindCounterpart(Window target);
|
|
#endif /* NO_PAGER */
|
|
|
|
unsigned int mods_used = (ShiftMask | ControlMask | Mod1Mask |
|
|
Mod2Mask| Mod3Mask| Mod4Mask| Mod5Mask);
|
|
extern int menuFromFrameOrWindowOrTitlebar;
|
|
|
|
|
|
int Context = C_NO_CONTEXT; /* current button press context */
|
|
int Button = 0;
|
|
FvwmWindow *ButtonWindow; /* button press window structure */
|
|
XEvent Event; /* the current event */
|
|
FvwmWindow *Tmp_win; /* the current fvwm window */
|
|
|
|
int last_event_type=0;
|
|
Window last_event_window=0;
|
|
|
|
#ifdef SHAPE
|
|
extern int ShapeEventBase;
|
|
void HandleShapeNotify(void);
|
|
#endif /* SHAPE */
|
|
|
|
Window PressedW;
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* DispatchEvent - handle a single X event stored in global var Event
|
|
*
|
|
************************************************************************/
|
|
void DispatchEvent()
|
|
{
|
|
Window w = Event.xany.window;
|
|
|
|
StashEventTime(&Event);
|
|
|
|
if (XFindContext (dpy, w, FvwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
|
|
Tmp_win = NULL;
|
|
last_event_type = Event.type;
|
|
last_event_window = w;
|
|
|
|
switch(Event.type)
|
|
{
|
|
case Expose:
|
|
HandleExpose();
|
|
break;
|
|
case DestroyNotify:
|
|
HandleDestroyNotify();
|
|
break;
|
|
case MapRequest:
|
|
HandleMapRequest();
|
|
break;
|
|
case MapNotify:
|
|
HandleMapNotify();
|
|
break;
|
|
case UnmapNotify:
|
|
HandleUnmapNotify();
|
|
break;
|
|
case MotionNotify:
|
|
HandleMotionNotify();
|
|
break;
|
|
case ButtonPress:
|
|
HandleButtonPress();
|
|
break;
|
|
case ButtonRelease:
|
|
HandleButtonRelease();
|
|
break;
|
|
case EnterNotify:
|
|
HandleEnterNotify();
|
|
break;
|
|
case LeaveNotify:
|
|
HandleLeaveNotify();
|
|
break;
|
|
case FocusIn:
|
|
HandleFocusIn();
|
|
break;
|
|
case ConfigureRequest:
|
|
HandleConfigureRequest();
|
|
break;
|
|
case ClientMessage:
|
|
HandleClientMessage();
|
|
break;
|
|
case PropertyNotify:
|
|
HandlePropertyNotify();
|
|
break;
|
|
case KeyPress:
|
|
HandleKeyPress();
|
|
break;
|
|
case VisibilityNotify:
|
|
HandleVisibilityNotify();
|
|
break;
|
|
case ColormapNotify:
|
|
HandleColormapNotify();
|
|
break;
|
|
default:
|
|
#ifdef SHAPE
|
|
if(Event.type == (ShapeEventBase + ShapeNotify))
|
|
HandleShapeNotify();
|
|
#endif /* SHAPE */
|
|
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleEvents - handle X events
|
|
*
|
|
************************************************************************/
|
|
void HandleEvents()
|
|
{
|
|
while (TRUE)
|
|
{
|
|
last_event_type = 0;
|
|
if(My_XNextEvent(dpy, &Event))
|
|
{
|
|
DispatchEvent ();
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* Find the Fvwm context for the Event.
|
|
*
|
|
************************************************************************/
|
|
int GetContext(FvwmWindow *t, XEvent *e, Window *w)
|
|
{
|
|
int Context,i;
|
|
|
|
if(!t)
|
|
return C_ROOT;
|
|
|
|
Context = C_NO_CONTEXT;
|
|
*w= e->xany.window;
|
|
|
|
if(*w == Scr.NoFocusWin)
|
|
return C_ROOT;
|
|
|
|
/* Since key presses and button presses are grabbed in the frame
|
|
* when we have re-parented windows, we need to find out the real
|
|
* window where the event occured */
|
|
if((e->type == KeyPress)&&(e->xkey.subwindow != None))
|
|
*w = e->xkey.subwindow;
|
|
|
|
if((e->type == ButtonPress)&&(e->xbutton.subwindow != None)&&
|
|
((e->xbutton.subwindow == t->w)||(e->xbutton.subwindow == t->Parent)))
|
|
*w = e->xbutton.subwindow;
|
|
|
|
if (*w == Scr.Root)
|
|
Context = C_ROOT;
|
|
if (t)
|
|
{
|
|
if (*w == t->title_w)
|
|
Context = C_TITLE;
|
|
if ((*w == t->w)||(*w == t->Parent))
|
|
Context = C_WINDOW;
|
|
if (*w == t->icon_w)
|
|
Context = C_ICON;
|
|
if (*w == t->icon_pixmap_w)
|
|
Context = C_ICON;
|
|
if (*w == t->frame)
|
|
Context = C_SIDEBAR;
|
|
for(i=0;i<4;i++)
|
|
if(*w == t->corners[i])
|
|
{
|
|
Context = C_FRAME;
|
|
Button = i;
|
|
}
|
|
for(i=0;i<4;i++)
|
|
if(*w == t->sides[i])
|
|
{
|
|
Context = C_SIDEBAR;
|
|
Button = i;
|
|
}
|
|
for(i=0;i<Scr.nr_left_buttons;i++)
|
|
{
|
|
if(*w == t->left_w[i])
|
|
{
|
|
Context = (1<<i)*C_L1;
|
|
Button = i;
|
|
}
|
|
}
|
|
for(i=0;i<Scr.nr_right_buttons;i++)
|
|
{
|
|
if(*w == t->right_w[i])
|
|
{
|
|
Context = (1<<i)*C_R1;
|
|
Button = i;
|
|
}
|
|
}
|
|
}
|
|
return Context;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleFocusIn - handles focus in events
|
|
*
|
|
************************************************************************/
|
|
void HandleFocusIn()
|
|
{
|
|
XEvent d;
|
|
Window w;
|
|
|
|
w= Event.xany.window;
|
|
while(XCheckTypedEvent(dpy,FocusIn,&d))
|
|
{
|
|
w = d.xany.window;
|
|
}
|
|
if (XFindContext (dpy, w, FvwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
|
|
{
|
|
Tmp_win = NULL;
|
|
}
|
|
|
|
if(!Tmp_win)
|
|
{
|
|
SetBorder(Scr.Hilite,False,True,True,None);
|
|
Broadcast(M_FOCUS_CHANGE,3,0,0,0,0,0,0,0);
|
|
}
|
|
else if(Tmp_win != Scr.Hilite)
|
|
{
|
|
SetBorder(Tmp_win,True,True,True,None);
|
|
Broadcast(M_FOCUS_CHANGE,3,Tmp_win->w,
|
|
Tmp_win->frame,(unsigned long)Tmp_win,0,0,0,0);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleKeyPress - key press event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleKeyPress()
|
|
{
|
|
FuncKey *key;
|
|
unsigned int modifier;
|
|
Window dummy;
|
|
|
|
Context = GetContext(Tmp_win,&Event,&dummy);
|
|
|
|
modifier = (Event.xkey.state & mods_used);
|
|
for (key = Scr.FuncKeyRoot.next; key != NULL; key = key->next)
|
|
{
|
|
ButtonWindow = Tmp_win;
|
|
/* Here's a real hack - some systems have two keys with the
|
|
* same keysym and different keycodes. This converts all
|
|
* the cases to one keycode. */
|
|
Event.xkey.keycode =
|
|
XKeysymToKeycode(dpy,XKeycodeToKeysym(dpy,Event.xkey.keycode,0));
|
|
if ((key->keycode == Event.xkey.keycode) &&
|
|
((key->mods == (modifier&(~LockMask)))||
|
|
(key->mods == AnyModifier)) &&
|
|
(key->cont & Context))
|
|
{
|
|
ExecuteFunction(key->func, key->action, Event.xany.window,Tmp_win,
|
|
&Event,Context,key->val1,key->val2,
|
|
key->val1_unit,key->val2_unit,
|
|
key->menu,-1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* if we get here, no function key was bound to the key. Send it
|
|
* to the client if it was in a window we know about.
|
|
*/
|
|
if (Tmp_win)
|
|
{
|
|
if(Event.xkey.window != Tmp_win->w)
|
|
{
|
|
Event.xkey.window = Tmp_win->w;
|
|
XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
|
|
}
|
|
}
|
|
ButtonWindow = NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandlePropertyNotify - property notify event handler
|
|
*
|
|
***********************************************************************/
|
|
#define MAX_NAME_LEN 200L /* truncate to this many */
|
|
#define MAX_ICON_NAME_LEN 200L /* ditto */
|
|
|
|
void HandlePropertyNotify()
|
|
{
|
|
char *prop = NULL;
|
|
Atom actual = None;
|
|
int actual_format;
|
|
unsigned long nitems, bytesafter;
|
|
|
|
if ((!Tmp_win)||(XGetGeometry(dpy, Tmp_win->w, &JunkRoot, &JunkX, &JunkY,
|
|
&JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0))
|
|
return;
|
|
|
|
switch (Event.xproperty.atom)
|
|
{
|
|
case XA_WM_NAME:
|
|
if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L,
|
|
MAX_NAME_LEN, False, XA_STRING, &actual,
|
|
&actual_format, &nitems, &bytesafter,
|
|
(unsigned char **) &prop) != Success ||
|
|
actual == None)
|
|
return;
|
|
if (!prop) prop = NoName;
|
|
free_window_names (Tmp_win, True, False);
|
|
|
|
Tmp_win->name = prop;
|
|
BroadcastName(M_WINDOW_NAME,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,Tmp_win->name);
|
|
|
|
/* fix the name in the title bar */
|
|
if(!(Tmp_win->flags & ICONIFIED))
|
|
SetTitleBar(Tmp_win,(Scr.Hilite==Tmp_win),True);
|
|
|
|
/*
|
|
* if the icon name is NoName, set the name of the icon to be
|
|
* the same as the window
|
|
*/
|
|
if (Tmp_win->icon_name == NoName)
|
|
{
|
|
Tmp_win->icon_name = Tmp_win->name;
|
|
BroadcastName(M_ICON_NAME,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,Tmp_win->icon_name);
|
|
RedoIconName(Tmp_win);
|
|
}
|
|
break;
|
|
|
|
case XA_WM_ICON_NAME:
|
|
if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0,
|
|
MAX_ICON_NAME_LEN, False, XA_STRING, &actual,
|
|
&actual_format, &nitems, &bytesafter,
|
|
(unsigned char **) &prop) != Success ||
|
|
actual == None)
|
|
return;
|
|
if (!prop) prop = NoName;
|
|
free_window_names (Tmp_win, False, True);
|
|
Tmp_win->icon_name = prop;
|
|
BroadcastName(M_ICON_NAME,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,Tmp_win->icon_name);
|
|
RedoIconName(Tmp_win);
|
|
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 == NULL)
|
|
return;
|
|
|
|
if((Tmp_win->wmhints->flags & IconPixmapHint)||
|
|
(Tmp_win->wmhints->flags & IconWindowHint))
|
|
if(Tmp_win->icon_bitmap_file == Scr.DefaultIcon)
|
|
Tmp_win->icon_bitmap_file = (char *)0;
|
|
|
|
if((Tmp_win->wmhints->flags & IconPixmapHint)||
|
|
(Tmp_win->wmhints->flags & IconWindowHint))
|
|
{
|
|
if (!(Tmp_win->flags & SUPPRESSICON))
|
|
{
|
|
if (Tmp_win->icon_w)
|
|
XDestroyWindow(dpy,Tmp_win->icon_w);
|
|
XDeleteContext(dpy, Tmp_win->icon_w, FvwmContext);
|
|
if(Tmp_win->flags & ICON_OURS)
|
|
{
|
|
if(Tmp_win->icon_pixmap_w != None)
|
|
{
|
|
XDestroyWindow(dpy,Tmp_win->icon_pixmap_w);
|
|
XDeleteContext(dpy, Tmp_win->icon_pixmap_w, FvwmContext);
|
|
}
|
|
}
|
|
else
|
|
XUnmapWindow(dpy,Tmp_win->icon_pixmap_w);
|
|
}
|
|
Tmp_win->icon_w = None;
|
|
Tmp_win->icon_pixmap_w = None;
|
|
Tmp_win->iconPixmap = (Window)NULL;
|
|
if(Tmp_win->flags & ICONIFIED)
|
|
{
|
|
Tmp_win->flags &= ~ICONIFIED;
|
|
Tmp_win->flags &= ~ICON_UNMAPPED;
|
|
CreateIconWindow(Tmp_win,Tmp_win->icon_x_loc,Tmp_win->icon_y_loc);
|
|
Broadcast(M_ICONIFY,7,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,
|
|
Tmp_win->icon_x_loc,
|
|
Tmp_win->icon_y_loc,
|
|
Tmp_win->icon_w_width,
|
|
Tmp_win->icon_w_height);
|
|
BroadcastConfig(M_CONFIGURE_WINDOW,Tmp_win);
|
|
|
|
if (!(Tmp_win->flags & SUPPRESSICON))
|
|
{
|
|
LowerWindow(Tmp_win);
|
|
AutoPlace(Tmp_win);
|
|
if(Tmp_win->Desk == Scr.CurrentDesk)
|
|
{
|
|
if(Tmp_win->icon_w)
|
|
XMapWindow(dpy, Tmp_win->icon_w);
|
|
if(Tmp_win->icon_pixmap_w != None)
|
|
XMapWindow(dpy, Tmp_win->icon_pixmap_w);
|
|
}
|
|
}
|
|
Tmp_win->flags |= ICONIFIED;
|
|
DrawIconWindow(Tmp_win);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case XA_WM_NORMAL_HINTS:
|
|
GetWindowSizeHints (Tmp_win);
|
|
BroadcastConfig(M_CONFIGURE_WINDOW,Tmp_win);
|
|
break;
|
|
|
|
default:
|
|
if(Event.xproperty.atom == _XA_WM_PROTOCOLS)
|
|
FetchWmProtocols (Tmp_win);
|
|
else if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS)
|
|
{
|
|
FetchWmColormapWindows (Tmp_win); /* frees old data */
|
|
ReInstallActiveColormap();
|
|
}
|
|
else if(Event.xproperty.atom == _XA_WM_STATE)
|
|
{
|
|
if((Scr.flags & ClickToFocus)&&(Tmp_win == Scr.Focus)&&
|
|
(Tmp_win != NULL))
|
|
{
|
|
Scr.Focus = NULL;
|
|
SetFocus(Tmp_win->w,Tmp_win);
|
|
ClearCirculatedFlag();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleClientMessage - client message event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleClientMessage()
|
|
{
|
|
XEvent button;
|
|
|
|
if ((Event.xclient.message_type == _XA_WM_CHANGE_STATE)&&
|
|
(Tmp_win)&&(Event.xclient.data.l[0]==IconicState)&&
|
|
!(Tmp_win->flags & ICONIFIED))
|
|
{
|
|
XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
|
|
&(button.xmotion.x_root),
|
|
&(button.xmotion.y_root),
|
|
&JunkX, &JunkY, &JunkMask);
|
|
button.type = 0;
|
|
ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
|
|
Tmp_win, &button, C_FRAME,0,0, 0,0,
|
|
(MenuRoot *)0,-1);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleExpose - expose event handler
|
|
*
|
|
***********************************************************************/
|
|
void HandleExpose()
|
|
{
|
|
if (Event.xexpose.count != 0)
|
|
return;
|
|
|
|
if (Tmp_win)
|
|
{
|
|
#ifndef NO_PAGER
|
|
if((Tmp_win->w == Scr.Pager_w)||
|
|
(Tmp_win->w == Scr.CPagerWin))
|
|
{
|
|
ReallyRedrawPager();
|
|
}
|
|
#endif
|
|
if ((Event.xany.window == Tmp_win->title_w))
|
|
{
|
|
SetTitleBar(Tmp_win,(Scr.Hilite == Tmp_win),False);
|
|
}
|
|
else
|
|
{
|
|
SetBorder(Tmp_win,(Scr.Hilite == Tmp_win),True,True,Event.xany.window);
|
|
}
|
|
}
|
|
#ifndef NO_PAGER
|
|
else
|
|
{
|
|
if(FindCounterpart(Event.xany.window))
|
|
ReallyRedrawPager();
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleDestroyNotify - DestroyNotify event handler
|
|
*
|
|
***********************************************************************/
|
|
void HandleDestroyNotify()
|
|
{
|
|
Destroy(Tmp_win);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleMapRequest - MapRequest event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleMapRequest()
|
|
{
|
|
extern long isIconicState;
|
|
|
|
Event.xany.window = Event.xmaprequest.window;
|
|
|
|
if(XFindContext(dpy, Event.xany.window, FvwmContext,
|
|
(caddr_t *)&Tmp_win)==XCNOENT)
|
|
Tmp_win = NULL;
|
|
|
|
XFlush(dpy);
|
|
|
|
/* If the window has never been mapped before ... */
|
|
if(!Tmp_win)
|
|
{
|
|
/* Add decorations. */
|
|
Tmp_win = AddWindow(Event.xany.window);
|
|
if (Tmp_win == NULL)
|
|
return;
|
|
}
|
|
|
|
/* If it's not merely iconified, and we have hints, use them. */
|
|
if (!(Tmp_win->flags & ICONIFIED))
|
|
{
|
|
int state;
|
|
|
|
if(Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
|
|
state = Tmp_win->wmhints->initial_state;
|
|
else
|
|
state = NormalState;
|
|
|
|
if(Tmp_win->flags & STARTICONIC)
|
|
state = IconicState;
|
|
|
|
if(isIconicState != DontCareState)
|
|
state = isIconicState;
|
|
|
|
XGrabServer (dpy);
|
|
switch (state)
|
|
{
|
|
case DontCareState:
|
|
case NormalState:
|
|
case InactiveState:
|
|
default:
|
|
if (Tmp_win->Desk == Scr.CurrentDesk)
|
|
{
|
|
XMapWindow(dpy, Tmp_win->w);
|
|
XMapWindow(dpy, Tmp_win->frame);
|
|
Tmp_win->flags |= MAP_PENDING;
|
|
SetMapStateProp(Tmp_win, NormalState);
|
|
if(Scr.flags & ClickToFocus)
|
|
{
|
|
SetFocus(Tmp_win->w,Tmp_win);
|
|
ClearCirculatedFlag();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XMapWindow(dpy, Tmp_win->w);
|
|
SetMapStateProp(Tmp_win, NormalState);
|
|
}
|
|
break;
|
|
|
|
case IconicState:
|
|
Iconify(Tmp_win, 0, 0);
|
|
break;
|
|
}
|
|
XSync(dpy,0);
|
|
XUngrabServer(dpy);
|
|
}
|
|
/* If no hints, or currently an icon, just "deiconify" */
|
|
else
|
|
{
|
|
DeIconify(Tmp_win);
|
|
}
|
|
KeepOnTop();
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleMapNotify - MapNotify event handler
|
|
*
|
|
***********************************************************************/
|
|
void HandleMapNotify()
|
|
{
|
|
if (!Tmp_win)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Need to do the grab to avoid race condition of having server send
|
|
* MapNotify to client before the frame gets mapped; this is bad because
|
|
* the client would think that the window has a chance of being viewable
|
|
* when it really isn't.
|
|
*/
|
|
XGrabServer (dpy);
|
|
if (Tmp_win->icon_w)
|
|
XUnmapWindow(dpy, Tmp_win->icon_w);
|
|
if(Tmp_win->icon_pixmap_w != None)
|
|
XUnmapWindow(dpy, Tmp_win->icon_pixmap_w);
|
|
XMapSubwindows(dpy, Tmp_win->frame);
|
|
|
|
if(Tmp_win->Desk == Scr.CurrentDesk)
|
|
{
|
|
XMapWindow(dpy, Tmp_win->frame);
|
|
}
|
|
|
|
if(Tmp_win->flags & ICONIFIED)
|
|
Broadcast(M_DEICONIFY,3,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,0,0,0,0);
|
|
else
|
|
{
|
|
Broadcast(M_MAP,3,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,0,0,0,0);
|
|
}
|
|
|
|
if(Scr.flags & ClickToFocus)
|
|
{
|
|
SetFocus(Tmp_win->w,Tmp_win);
|
|
ClearCirculatedFlag();
|
|
}
|
|
if((!(Tmp_win->flags &(BORDER|TITLE)))&&(Tmp_win->boundary_width <2))
|
|
{
|
|
SetBorder(Tmp_win,False,True,True,Tmp_win->frame);
|
|
}
|
|
XSync(dpy,0);
|
|
XUngrabServer (dpy);
|
|
XFlush (dpy);
|
|
Tmp_win->flags |= MAPPED;
|
|
Tmp_win->flags &= ~MAP_PENDING;
|
|
Tmp_win->flags &= ~ICONIFIED;
|
|
Tmp_win->flags &= ~ICON_UNMAPPED;
|
|
KeepOnTop();
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleUnmapNotify - UnmapNotify event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleUnmapNotify()
|
|
{
|
|
int dstx, dsty;
|
|
Window dumwin;
|
|
XEvent dummy;
|
|
extern FvwmWindow *colormap_win;
|
|
|
|
/*
|
|
* The July 27, 1988 ICCCM spec states that a client wishing to switch
|
|
* to WithdrawnState should send a synthetic UnmapNotify with the
|
|
* event field set to (pseudo-)root, in case the window is already
|
|
* unmapped (which is the case for fvwm for IconicState). Unfortunately,
|
|
* we looked for the FvwmContext using that field, so try the window
|
|
* field also.
|
|
*/
|
|
if (!Tmp_win)
|
|
{
|
|
Event.xany.window = Event.xunmap.window;
|
|
if (XFindContext(dpy, Event.xany.window,
|
|
FvwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
|
|
Tmp_win = NULL;
|
|
}
|
|
|
|
if(!Tmp_win)
|
|
return;
|
|
|
|
if(Tmp_win == Scr.Hilite)
|
|
Scr.Hilite = NULL;
|
|
|
|
if(Scr.PreviousFocus == Tmp_win)
|
|
Scr.PreviousFocus = NULL;
|
|
|
|
if((Tmp_win == Scr.Focus)&&(Scr.flags & ClickToFocus))
|
|
{
|
|
if(Tmp_win->next)
|
|
SetFocus(Tmp_win->next->w,Tmp_win->next);
|
|
else
|
|
SetFocus(Scr.NoFocusWin,NULL);
|
|
}
|
|
|
|
if(Scr.Focus == Tmp_win)
|
|
SetFocus(Scr.NoFocusWin,NULL);
|
|
|
|
if(Tmp_win == Scr.pushed_window)
|
|
Scr.pushed_window = NULL;
|
|
|
|
ClearCirculatedFlag();
|
|
if(Tmp_win == colormap_win)
|
|
colormap_win = NULL;
|
|
|
|
if ((!(Tmp_win->flags & MAPPED)&&!(Tmp_win->flags&ICONIFIED)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
XGrabServer(dpy);
|
|
|
|
if(XCheckTypedWindowEvent (dpy, Event.xunmap.window, DestroyNotify,&dummy))
|
|
{
|
|
Destroy(Tmp_win);
|
|
XUngrabServer (dpy);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The program may have unmapped the client window, from either
|
|
* NormalState or IconicState. Handle the transition to WithdrawnState.
|
|
*
|
|
* We need to reparent the window back to the root (so that fvwm exiting
|
|
* won't cause it to get mapped) and then throw away all state (pretend
|
|
* that we've received a DestroyNotify).
|
|
*/
|
|
if (XTranslateCoordinates (dpy, Event.xunmap.window, Scr.Root,
|
|
0, 0, &dstx, &dsty, &dumwin))
|
|
{
|
|
XEvent ev;
|
|
Bool reparented;
|
|
|
|
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->flags & SUPPRESSICON))&&
|
|
(Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint)))
|
|
XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
|
|
}
|
|
else
|
|
{
|
|
RestoreWithdrawnLocation (Tmp_win,False);
|
|
}
|
|
XRemoveFromSaveSet (dpy, Event.xunmap.window);
|
|
XSelectInput (dpy, Event.xunmap.window, NoEventMask);
|
|
Destroy(Tmp_win); /* do not need to mash event before */
|
|
/*
|
|
* Flush any pending events for the window.
|
|
*/
|
|
/* Bzzt! it could be about to re-map */
|
|
/* while(XCheckWindowEvent(dpy, Event.xunmap.window,
|
|
StructureNotifyMask | PropertyChangeMask |
|
|
ColormapChangeMask | VisibilityChangeMask |
|
|
EnterWindowMask | LeaveWindowMask, &dummy));
|
|
*/
|
|
} /* else window no longer exists and we'll get a destroy notify */
|
|
XUngrabServer (dpy);
|
|
|
|
XFlush (dpy);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleMotionNotify - MotionNotify event handler
|
|
*
|
|
**********************************************************************/
|
|
void HandleMotionNotify()
|
|
{
|
|
#ifndef NO_PAGER
|
|
extern Bool EnablePagerRedraw;
|
|
|
|
/* here is the code for dragging the viewport around within the pager.*/
|
|
if((Tmp_win)&&(Tmp_win->w == Scr.Pager_w)&&
|
|
(!(Tmp_win->flags & ICONIFIED)))
|
|
{
|
|
if(Event.xmotion.state == Button3MotionMask)
|
|
{
|
|
EnablePagerRedraw = False;
|
|
SwitchPages(FALSE,FALSE);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleButtonPress - ButtonPress event handler
|
|
*
|
|
***********************************************************************/
|
|
void HandleButtonPress()
|
|
{
|
|
#ifndef NO_PAGER
|
|
extern Bool EnablePagerRedraw;
|
|
#endif
|
|
unsigned int modifier;
|
|
MouseButton *MouseEntry;
|
|
char *Action;
|
|
Window x;
|
|
int LocalContext;
|
|
|
|
/* click to focus stuff goes here */
|
|
if((Scr.flags & ClickToFocus)&&(Tmp_win != Scr.Ungrabbed)&&
|
|
((Event.xbutton.state&
|
|
(ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) == 0))
|
|
{
|
|
if(Tmp_win)
|
|
{
|
|
SetFocus(Tmp_win->w,Tmp_win);
|
|
ClearCirculatedFlag();
|
|
if(Scr.AutoRaiseDelay > 0)
|
|
{
|
|
SetTimer(Scr.AutoRaiseDelay);
|
|
}
|
|
else
|
|
{
|
|
#ifdef CLICKY_MODE_1
|
|
if((Event.xany.window != Tmp_win->w)&&
|
|
(Event.xbutton.subwindow != Tmp_win->w)&&
|
|
(Event.xany.window != Tmp_win->Parent)&&
|
|
(Event.xbutton.subwindow != Tmp_win->Parent))
|
|
#endif
|
|
{
|
|
if(Scr.AutoRaiseDelay == 0)
|
|
RaiseWindow(Tmp_win);
|
|
}
|
|
}
|
|
|
|
KeepOnTop();
|
|
|
|
/* Why is this here? Seems to cause breakage with
|
|
* non-focusing windows! */
|
|
if(!(Tmp_win->flags & ICONIFIED))
|
|
{
|
|
XSync(dpy,0);
|
|
XAllowEvents(dpy,ReplayPointer,CurrentTime);
|
|
XSync(dpy,0);
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
XSync(dpy,0);
|
|
XAllowEvents(dpy,ReplayPointer,CurrentTime);
|
|
XSync(dpy,0);
|
|
|
|
/* here is the code for moving windows in the pager.*/
|
|
#ifndef NO_PAGER
|
|
if((Tmp_win)&&(Tmp_win->w == Event.xbutton.window)&&
|
|
(Tmp_win->w == Scr.Pager_w)&&(Event.xbutton.button == Button2))
|
|
{
|
|
PagerMoveWindow();
|
|
return;
|
|
}
|
|
if((Tmp_win)&&(Tmp_win->w == Scr.Pager_w)&&
|
|
(!(Tmp_win->flags & ICONIFIED))&&
|
|
(Event.xbutton.button == Button3)&&
|
|
(Event.xany.window == Scr.Pager_w))
|
|
{
|
|
#ifndef NO_PAGER
|
|
EnablePagerRedraw = False;
|
|
#endif
|
|
SwitchPages(FALSE,FALSE);
|
|
}
|
|
#endif
|
|
|
|
Context = GetContext(Tmp_win,&Event, &PressedW);
|
|
LocalContext = Context;
|
|
x= PressedW;
|
|
if(Context == C_TITLE)
|
|
SetTitleBar(Tmp_win,(Scr.Hilite == Tmp_win),False);
|
|
else
|
|
SetBorder(Tmp_win,(Scr.Hilite == Tmp_win),True,True,PressedW);
|
|
|
|
ButtonWindow = Tmp_win;
|
|
|
|
/* we have to execute a function or pop up a menu
|
|
*/
|
|
|
|
modifier = (Event.xbutton.state & mods_used);
|
|
/* need to search for an appropriate mouse binding */
|
|
MouseEntry = Scr.MouseButtonRoot;
|
|
while(MouseEntry != (MouseButton *)0)
|
|
{
|
|
if(((MouseEntry->Button == Event.xbutton.button)||(MouseEntry->Button == 0))&&
|
|
(MouseEntry->Context & Context)&&
|
|
((MouseEntry->Modifier == AnyModifier)||
|
|
(MouseEntry->Modifier == (modifier& (~LockMask)))))
|
|
{
|
|
/* got a match, now process it */
|
|
if (MouseEntry->func != (int)NULL)
|
|
{
|
|
Action = MouseEntry->item ? MouseEntry->item->action : NULL;
|
|
ExecuteFunction(MouseEntry->func, Action, Event.xany.window,
|
|
Tmp_win, &Event, Context,MouseEntry->val1,
|
|
MouseEntry->val2,
|
|
MouseEntry->val1_unit,MouseEntry->val2_unit,
|
|
MouseEntry->menu,-1);
|
|
break;
|
|
}
|
|
}
|
|
MouseEntry = MouseEntry->NextButton;
|
|
}
|
|
PressedW = None;
|
|
if(LocalContext!=C_TITLE)
|
|
SetBorder(ButtonWindow,(Scr.Hilite == ButtonWindow),True,True,x);
|
|
else
|
|
SetTitleBar(ButtonWindow,(Scr.Hilite==ButtonWindow),False);
|
|
ButtonWindow = NULL;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleButtonRelease - ButtonRelease event handler
|
|
*
|
|
***********************************************************************/
|
|
void HandleButtonRelease()
|
|
{
|
|
#ifndef NO_PAGER
|
|
extern Bool EnablePagerRedraw;
|
|
if((Tmp_win)&&(Event.xany.window == Scr.Pager_w)&&
|
|
(!(Tmp_win->flags & ICONIFIED)))
|
|
{
|
|
switch(Event.xbutton.button)
|
|
{
|
|
default:
|
|
case Button1:
|
|
SwitchPages(TRUE,TRUE);
|
|
break;
|
|
case Button3:
|
|
EnablePagerRedraw = True;
|
|
SwitchPages(FALSE,FALSE);
|
|
RedrawPager();
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleEnterNotify - EnterNotify event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleEnterNotify()
|
|
{
|
|
XEnterWindowEvent *ewp = &Event.xcrossing;
|
|
XEvent d;
|
|
|
|
/* look for a matching leaveNotify which would nullify this enterNotify */
|
|
if(XCheckTypedWindowEvent (dpy, ewp->window, LeaveNotify, &d))
|
|
{
|
|
StashEventTime(&d);
|
|
if((d.xcrossing.mode==NotifyNormal)&&
|
|
(d.xcrossing.detail!=NotifyInferior))
|
|
return;
|
|
}
|
|
|
|
/* an EnterEvent in one of the PanFrameWindows activates the Paging */
|
|
#ifndef NON_VIRTUAL
|
|
if (ewp->window==Scr.PanFrameTop.win
|
|
|| ewp->window==Scr.PanFrameLeft.win
|
|
|| ewp->window==Scr.PanFrameRight.win
|
|
|| ewp->window==Scr.PanFrameBottom.win )
|
|
{
|
|
int delta_x=0, delta_y=0;
|
|
/* this was in the HandleMotionNotify before, HEDU */
|
|
HandlePaging(Scr.EdgeScrollX,Scr.EdgeScrollY,
|
|
&Event.xcrossing.x_root,&Event.xcrossing.y_root,
|
|
&delta_x,&delta_y,True);
|
|
return;
|
|
}
|
|
#endif /* NON_VIRTUAL */
|
|
|
|
if(Event.xany.window == Scr.Root)
|
|
{
|
|
if((!(Scr.flags & ClickToFocus))&&(!(Scr.flags & SloppyFocus)))
|
|
{
|
|
SetFocus(Scr.NoFocusWin,NULL);
|
|
ClearCirculatedFlag();
|
|
}
|
|
InstallWindowColormaps(NULL);
|
|
return;
|
|
}
|
|
|
|
/* make sure its for one of our windows */
|
|
if (!Tmp_win)
|
|
return;
|
|
|
|
if(!(Scr.flags & ClickToFocus))
|
|
{
|
|
if(Scr.Focus != Tmp_win)
|
|
{
|
|
if((Scr.AutoRaiseDelay > 0)&&(!(Tmp_win->flags & VISIBLE)))
|
|
SetTimer(Scr.AutoRaiseDelay);
|
|
SetFocus(Tmp_win->w,Tmp_win);
|
|
ClearCirculatedFlag();
|
|
}
|
|
else
|
|
SetFocus(Tmp_win->w,Tmp_win);
|
|
}
|
|
if((!(Tmp_win->flags & ICONIFIED))&&(Event.xany.window == Tmp_win->w))
|
|
InstallWindowColormaps(Tmp_win);
|
|
else
|
|
InstallWindowColormaps(NULL);
|
|
return;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleLeaveNotify - LeaveNotify event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleLeaveNotify()
|
|
{
|
|
/* If we leave the root window, then we're really moving
|
|
* another screen on a multiple screen display, and we
|
|
* need to de-focus and unhighlight to make sure that we
|
|
* don't end up with more than one highlighted window at a time */
|
|
if(Event.xcrossing.window == Scr.Root)
|
|
{
|
|
if(Event.xcrossing.mode == NotifyNormal)
|
|
{
|
|
if (Event.xcrossing.detail != NotifyInferior)
|
|
{
|
|
if(Scr.Focus != NULL)
|
|
{
|
|
SetFocus(Scr.NoFocusWin,NULL);
|
|
}
|
|
if(Scr.Hilite != NULL)
|
|
SetBorder(Scr.Hilite,False,True,True,None);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleConfigureRequest - ConfigureRequest event handler
|
|
*
|
|
************************************************************************/
|
|
void HandleConfigureRequest()
|
|
{
|
|
XWindowChanges xwc;
|
|
unsigned long xwcm;
|
|
int x, y, width, height;
|
|
XConfigureRequestEvent *cre = &Event.xconfigurerequest;
|
|
|
|
/*
|
|
* Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
|
|
* be wrong
|
|
*/
|
|
Event.xany.window = cre->window; /* mash parent field */
|
|
if (XFindContext (dpy, cre->window, FvwmContext, (caddr_t *) &Tmp_win) ==
|
|
XCNOENT)
|
|
Tmp_win = NULL;
|
|
|
|
/*
|
|
* According to the July 27, 1988 ICCCM draft, we should ignore size and
|
|
* position fields in the WM_NORMAL_HINTS property when we map a window.
|
|
* Instead, we'll read the current geometry. Therefore, we should respond
|
|
* to configuration requests for windows which have never been mapped.
|
|
*/
|
|
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;
|
|
if((Tmp_win)&&((Tmp_win->icon_w == cre->window)))
|
|
{
|
|
Tmp_win->icon_xl_loc = cre->x;
|
|
Tmp_win->icon_x_loc = cre->x +
|
|
(Tmp_win->icon_w_width - Tmp_win->icon_p_width)/2;
|
|
Tmp_win->icon_y_loc = cre->y - Tmp_win->icon_p_height;
|
|
if(!(Tmp_win->flags & ICON_UNMAPPED))
|
|
Broadcast(M_ICON_LOCATION,7,Tmp_win->w,Tmp_win->frame,
|
|
(unsigned long)Tmp_win,
|
|
Tmp_win->icon_x_loc,Tmp_win->icon_y_loc,
|
|
Tmp_win->icon_w_width,
|
|
Tmp_win->icon_w_height + Tmp_win->icon_p_height);
|
|
}
|
|
xwc.width = cre->width;
|
|
xwc.height = cre->height;
|
|
xwc.border_width = cre->border_width;
|
|
XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
|
|
|
|
if(Tmp_win)
|
|
{
|
|
xwc.x = Tmp_win->icon_x_loc;
|
|
xwc.y = Tmp_win->icon_y_loc - Tmp_win->icon_p_height;
|
|
xwcm = cre->value_mask & (CWX | CWY);
|
|
if(Tmp_win->icon_pixmap_w != None)
|
|
XConfigureWindow(dpy, Tmp_win->icon_pixmap_w, xwcm, &xwc);
|
|
xwc.x = Tmp_win->icon_x_loc;
|
|
xwc.y = Tmp_win->icon_y_loc;
|
|
xwcm = cre->value_mask & (CWX | CWY);
|
|
if(Tmp_win->icon_w != None)
|
|
XConfigureWindow(dpy, Tmp_win->icon_w, xwcm, &xwc);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (cre->value_mask & CWStackMode)
|
|
{
|
|
FvwmWindow *otherwin;
|
|
|
|
xwc.sibling = (((cre->value_mask & CWSibling) &&
|
|
(XFindContext (dpy, cre->above, FvwmContext,
|
|
(caddr_t *) &otherwin) == XCSUCCESS))
|
|
? otherwin->frame : cre->above);
|
|
xwc.stack_mode = cre->detail;
|
|
XConfigureWindow (dpy, Tmp_win->frame,
|
|
cre->value_mask & (CWSibling | CWStackMode), &xwc);
|
|
}
|
|
|
|
#ifdef SHAPE
|
|
{
|
|
int xws, yws, xbs, ybs;
|
|
unsigned wws, hws, wbs, hbs;
|
|
int boundingShaped, clipShaped;
|
|
|
|
XShapeQueryExtents (dpy, Tmp_win->w,&boundingShaped, &xws, &yws, &wws,
|
|
&hws,&clipShaped, &xbs, &ybs, &wbs, &hbs);
|
|
Tmp_win->wShaped = boundingShaped;
|
|
}
|
|
#endif /* SHAPE */
|
|
|
|
/* Don't modify frame_XXX fields before calling SetupWindow! */
|
|
x = Tmp_win->frame_x;
|
|
y = Tmp_win->frame_y;
|
|
width = Tmp_win->frame_width;
|
|
height = Tmp_win->frame_height;
|
|
|
|
/* for restoring */
|
|
if (cre->value_mask & CWBorderWidth)
|
|
{
|
|
Tmp_win->old_bw = cre->border_width;
|
|
}
|
|
/* override even if border change */
|
|
|
|
if (cre->value_mask & CWX)
|
|
x = cre->x - Tmp_win->boundary_width - Tmp_win->bw;
|
|
if (cre->value_mask & CWY)
|
|
y = cre->y - Tmp_win->boundary_width - Tmp_win->title_height - Tmp_win->bw;
|
|
if (cre->value_mask & CWWidth)
|
|
width = cre->width + 2*Tmp_win->boundary_width;
|
|
if (cre->value_mask & CWHeight)
|
|
height = cre->height+Tmp_win->title_height+2*Tmp_win->boundary_width;
|
|
|
|
/*
|
|
* SetupWindow (x,y) are the location of the upper-left outer corner and
|
|
* are passed directly to XMoveResizeWindow (frame). The (width,height)
|
|
* are the inner size of the frame. The inner width is the same as the
|
|
* requested client window width; the inner height is the same as the
|
|
* requested client window height plus any title bar slop.
|
|
*/
|
|
SetupFrame (Tmp_win, x, y, width, height,FALSE);
|
|
KeepOnTop();
|
|
|
|
#ifndef NO_PAGER
|
|
RedrawPager();
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleShapeNotify - shape notification event handler
|
|
*
|
|
***********************************************************************/
|
|
#ifdef SHAPE
|
|
void HandleShapeNotify (void)
|
|
{
|
|
XShapeEvent *sev = (XShapeEvent *) &Event;
|
|
|
|
if (!Tmp_win)
|
|
return;
|
|
if (sev->kind != ShapeBounding)
|
|
return;
|
|
Tmp_win->wShaped = sev->shaped;
|
|
SetShape(Tmp_win,Tmp_win->frame_width);
|
|
}
|
|
#endif /* SHAPE*/
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* HandleVisibilityNotify - record fully visible windows for
|
|
* use in the RaiseLower function and the OnTop type windows.
|
|
*
|
|
************************************************************************/
|
|
void HandleVisibilityNotify()
|
|
{
|
|
XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
|
|
|
|
if(Tmp_win)
|
|
{
|
|
if(vevent->state == VisibilityUnobscured)
|
|
Tmp_win->flags |= VISIBLE;
|
|
else
|
|
Tmp_win->flags &= ~VISIBLE;
|
|
|
|
/* For the most part, we'll raised partially obscured ONTOP windows
|
|
* here. The exception is ONTOP windows that are obscured by
|
|
* other ONTOP windows, which are raised in KeepOnTop(). This
|
|
* complicated set-up saves us from continually re-raising
|
|
* every on top window */
|
|
if(((vevent->state == VisibilityPartiallyObscured)||
|
|
(vevent->state == VisibilityFullyObscured))&&
|
|
(Tmp_win->flags&ONTOP)&&(Tmp_win->flags & RAISED))
|
|
{
|
|
RaiseWindow(Tmp_win);
|
|
Tmp_win->flags &= ~RAISED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
*
|
|
* For auto-raising windows, this routine is called
|
|
*
|
|
*************************************************************************/
|
|
volatile int alarmed;
|
|
void enterAlarm(int nonsense)
|
|
{
|
|
alarmed = True;
|
|
signal(SIGALRM, enterAlarm);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Waits for next X event, or for an auto-raise timeout.
|
|
*
|
|
****************************************************************************/
|
|
int My_XNextEvent(Display *dpy, XEvent *event)
|
|
{
|
|
extern int fd_width, x_fd;
|
|
struct itimerval value;
|
|
fd_set in_fdset,out_fdset;
|
|
Window child;
|
|
Window targetWindow;
|
|
int i,count;
|
|
int retval;
|
|
|
|
/* Do this prior to the select() call, in case the timer already expired,
|
|
* in which case the select would never return. */
|
|
if(alarmed)
|
|
{
|
|
alarmed = False;
|
|
XQueryPointer(dpy,Scr.Root,&JunkRoot,&child,&JunkX,&JunkY,&JunkX,
|
|
&JunkY,&JunkMask );
|
|
if((Scr.Focus != NULL)&&(child == Scr.Focus->frame))
|
|
{
|
|
if(!(Scr.Focus->flags & VISIBLE))
|
|
{
|
|
RaiseWindow(Scr.Focus);
|
|
KeepOnTop();
|
|
#ifndef NO_PAGER
|
|
RedrawPager();
|
|
#endif
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifndef HAVE_GETITIMER
|
|
value.it_value.tv_usec = 0;
|
|
value.it_value.tv_sec = 0;
|
|
#else
|
|
getitimer(ITIMER_REAL,&value);
|
|
#endif
|
|
|
|
FD_ZERO(&in_fdset);
|
|
FD_SET(x_fd,&in_fdset);
|
|
FD_ZERO(&out_fdset);
|
|
for(i=0; i<npipes; i++)
|
|
{
|
|
if(readPipes[i]>=0)
|
|
{
|
|
FD_SET(readPipes[i], &in_fdset);
|
|
}
|
|
}
|
|
|
|
for(i=0; i<npipes; i++)
|
|
{
|
|
if(pipeQueue[i]!= NULL)
|
|
{
|
|
FD_SET(writePipes[i], &out_fdset);
|
|
}
|
|
}
|
|
|
|
|
|
/* Do this IMMEDIATELY prior to select, to prevent any nasty
|
|
* queued up X events from just hanging around waiting to be
|
|
* flushed */
|
|
XFlush(dpy);
|
|
if(XPending(dpy))
|
|
{
|
|
XNextEvent(dpy,event);
|
|
StashEventTime(event);
|
|
return 1;
|
|
}
|
|
|
|
/* Zap all those zombies! */
|
|
/* If we get to here, then there are no X events waiting to be processed.
|
|
* Just take a moment to check for dead children. */
|
|
ReapChildren();
|
|
|
|
XFlush(dpy);
|
|
if((value.it_value.tv_usec != 0)||
|
|
(value.it_value.tv_sec != 0))
|
|
#ifdef __hpux
|
|
retval=select(fd_width,(int *)&in_fdset, 0, 0, &value.it_value);
|
|
#else
|
|
retval=select(fd_width,&in_fdset, 0, 0, &value.it_value);
|
|
#endif
|
|
else
|
|
#ifdef __hpux
|
|
retval=select(fd_width,(int *)&in_fdset, (int *)&out_fdset,
|
|
0, NULL);
|
|
#else
|
|
retval=select(fd_width,&in_fdset, &out_fdset, 0, NULL);
|
|
#endif
|
|
|
|
/* Check for module input. */
|
|
for(i=0;i<npipes;i++)
|
|
{
|
|
if(readPipes[i] >= 0)
|
|
{
|
|
if((retval>0)&&(FD_ISSET(readPipes[i], &in_fdset)))
|
|
{
|
|
if((count =
|
|
read(readPipes[i],&targetWindow, sizeof(Window))) >0)
|
|
{
|
|
HandleModuleInput(targetWindow,i);
|
|
}
|
|
if(count <= 0)
|
|
{
|
|
KillModule(i,10);
|
|
}
|
|
}
|
|
}
|
|
if(writePipes[i] >= 0)
|
|
{
|
|
if((retval>0)&&(FD_ISSET(writePipes[i], &out_fdset)))
|
|
{
|
|
FlushQueue(i);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|