/****************************************************************************
* This module is based on Twm, but has been siginificantly modified
* by Rob Nation
*
* slightly modified by Bo Yang
*
****************************************************************************/
/*****************************************************************************/
/** 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. **/
/*****************************************************************************/
/**************************************************************************
*
* Assorted odds and ends
*
**************************************************************************/
#include "../configure.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <limits.h>
#include "afterstep.h"
#include <X11/Xatom.h>
#include "menus.h"
#include "misc.h"
#include "parse.h"
#include "screen.h"
#include "module.h"
XGCValues Globalgcv;
unsigned long Globalgcm;
/**************************************************************************
*
* Releases dynamically allocated space used to store window/icon names
*
**************************************************************************/
void free_window_names (ASWindow *tmp, Bool nukename, Bool nukeicon)
{
if (!tmp)
return;
if (nukename && nukeicon)
{
if (tmp->name == tmp->icon_name)
{
if (tmp->name != NoName)
XFree (tmp->name);
tmp->name = NULL;
tmp->icon_name = NULL;
}
else
{
if (tmp->name != NoName)
XFree (tmp->name);
tmp->name = NULL;
if (tmp->icon_name != NoName)
XFree (tmp->icon_name);
tmp->icon_name = NULL;
}
}
else if (nukename)
{
if (tmp->name != tmp->icon_name && tmp->name != NoName)
XFree (tmp->name);
tmp->name = NULL;
}
else
{ /* if (nukeicon) */
if (tmp->icon_name != tmp->name && tmp->icon_name != NoName)
XFree (tmp->icon_name);
tmp->icon_name = NULL;
}
return;
}
/***************************************************************************
*
* Handles destruction of a window
*
****************************************************************************/
void Destroy(ASWindow *Tmp_win)
{
int i;
extern ASWindow *ButtonWindow;
extern ASWindow *colormap_win;
/*
* Warning, this is also called by HandleUnmapNotify; if it ever needs to
* look at the event, HandleUnmapNotify will have to mash the UnmapNotify
* into a DestroyNotify.
*/
if(!Tmp_win)
return;
XUnmapWindow(dpy, Tmp_win->frame);
XSync(dpy,0);
if(Tmp_win == Scr.Hilite)
Scr.Hilite = NULL;
Broadcast(M_DESTROY_WINDOW,3,Tmp_win->w,Tmp_win->frame,
(unsigned long)Tmp_win,0,0,0,0);
if(Scr.PreviousFocus == Tmp_win)
Scr.PreviousFocus = NULL;
if(ButtonWindow == Tmp_win)
ButtonWindow = NULL;
if((Tmp_win == Scr.Focus)&&(Scr.flags & ClickToFocus))
{
ASWindow *t, *tn = NULL;
long best = LONG_MIN;
for (t = Scr.ASRoot.next; t != NULL; t = t->next)
{
if ((t->focus_sequence > best) && (t != Tmp_win))
{
best = t->focus_sequence;
tn = t;
}
}
if (tn)
SetFocus(tn->w, tn, False);
else
SetFocus(Scr.NoFocusWin, NULL, False);
}
if(Scr.Focus == Tmp_win)
SetFocus(Scr.NoFocusWin, NULL, False);
if(Tmp_win == Scr.pushed_window)
Scr.pushed_window = NULL;
if(Tmp_win == colormap_win)
colormap_win = NULL;
XDestroyWindow(dpy, Tmp_win->frame);
XDeleteContext(dpy, Tmp_win->frame, ASContext);
XDestroyWindow(dpy, Tmp_win->Parent);
XDeleteContext(dpy, Tmp_win->Parent, ASContext);
XDeleteContext(dpy, Tmp_win->w, ASContext);
#ifndef NO_PAGER
if ((Scr.Pager_w)&& !(Tmp_win->flags & STICKY))
XDestroyWindow(dpy, Tmp_win->pager_view);
#endif
if((Tmp_win->flags &ICON_OURS)&&(Tmp_win->icon_pixmap_w != None))
XDestroyWindow(dpy, Tmp_win->icon_pixmap_w);
if(Tmp_win->icon_pixmap_w != None)
XDeleteContext(dpy, Tmp_win->icon_pixmap_w, ASContext);
if (Tmp_win->flags & TITLE)
{
XDeleteContext(dpy, Tmp_win->title_w, ASContext);
for(i=0;i<Scr.nr_left_buttons;i++)
XDeleteContext(dpy, Tmp_win->left_w[i], ASContext);
for(i=0;i<Scr.nr_right_buttons;i++)
if(Tmp_win->right_w[i] != None)
XDeleteContext(dpy, Tmp_win->right_w[i], ASContext);
}
if (Tmp_win->flags & BORDER)
{
XDeleteContext(dpy, Tmp_win->side, ASContext);
for(i=0;i<2;i++)
XDeleteContext(dpy, Tmp_win->corners[i], ASContext);
}
Tmp_win->prev->next = Tmp_win->next;
if (Tmp_win->next != NULL)
Tmp_win->next->prev = Tmp_win->prev;
free_window_names (Tmp_win, 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);
if(Tmp_win->mwm_hints)
XFree((char *)Tmp_win->mwm_hints);
if(Tmp_win->cmap_windows != (Window *)NULL)
XFree((void *)Tmp_win->cmap_windows);
#ifdef ENABLE_TEXTURE
if (Tmp_win->backPixmap != None)
XFreePixmap(dpy, Tmp_win->backPixmap);
if (Tmp_win->backPixmap2 != None)
XFreePixmap(dpy, Tmp_win->backPixmap2);
#endif
free((char *)Tmp_win);
#ifndef NO_PAGER
RedrawPager();
#endif
XSync(dpy,0);
return;
}
/**************************************************************************
*
* Removes expose events for a specific window from the queue
*
*************************************************************************/
int flush_expose (Window w)
{
XEvent dummy;
int i=0;
while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy))i++;
return i;
}
/***********************************************************************
*
* Procedure:
* RestoreWithdrawnLocation
*
* Puts windows back where they were before afterstep took over
*
************************************************************************/
void RestoreWithdrawnLocation (ASWindow *tmp,Bool restart)
{
int a,b,w2,h2;
unsigned int bw,mask;
XWindowChanges xwc;
if(!tmp)
return;
if (XGetGeometry (dpy, tmp->w, &JunkRoot, &xwc.x, &xwc.y,
&JunkWidth, &JunkHeight, &bw, &JunkDepth))
{
XTranslateCoordinates(dpy,tmp->frame,Scr.Root,xwc.x,xwc.y,
&a,&b,&JunkChild);
xwc.x = a + tmp->xdiff;
xwc.y = b + tmp->ydiff;
xwc.border_width = tmp->old_bw;
mask = (CWX | CWY|CWBorderWidth);
/* We can not assume that the window is currently on the screen.
* Although this is normally the case, it is not always true. The
* most common example is when the user does something in an
* application which will, after some amount of computational delay,
* cause the window to be unmapped, but then switches screens before
* this happens. The XTranslateCoordinates call above will set the
* window coordinates to either be larger than the screen, or negative.
* This will result in the window being placed in odd, or even
* unviewable locations when the window is remapped. The followin code
* forces the "relative" location to be within the bounds of the display.
*
* gpw -- 11/11/93
*
* Unfortunately, this does horrendous things during re-starts,
* hence the "if(restart) clause (RN)
*
* Also, fixed so that it only does this stuff if a window is more than
* half off the screen. (RN)
*/
if(!restart)
{
/* Don't mess with it if its partially on the screen now */
if((tmp->frame_x < 0)||(tmp->frame_y<0)||
(tmp->frame_x >= Scr.MyDisplayWidth)||
(tmp->frame_y >= Scr.MyDisplayHeight))
{
w2 = (tmp->frame_width>>1);
h2 = (tmp->frame_height>>1);
if (( xwc.x < -w2) || (xwc.x > (Scr.MyDisplayWidth-w2 )))
{
xwc.x = xwc.x % Scr.MyDisplayWidth;
if ( xwc.x < -w2 )
xwc.x += Scr.MyDisplayWidth;
}
if ((xwc.y < -h2) || (xwc.y > (Scr.MyDisplayHeight-h2 )))
{
xwc.y = xwc.y % Scr.MyDisplayHeight;
if ( xwc.y < -h2 )
xwc.y += Scr.MyDisplayHeight;
}
}
}
XReparentWindow (dpy, tmp->w,Scr.Root,xwc.x,xwc.y);
if((tmp->flags & ICONIFIED)&&(!(tmp->flags & SUPPRESSICON)))
{
if (tmp->icon_pixmap_w)
XUnmapWindow(dpy, tmp->icon_pixmap_w);
}
XConfigureWindow (dpy, tmp->w, mask, &xwc);
XSync(dpy,0);
}
}
/***************************************************************************
*
* Start/Stops the auto-raise timer
*
****************************************************************************/
void SetTimer(int delay)
{
#ifdef HAVE_SETITIMER
struct itimerval value;
value.it_value.tv_usec = 1000*(delay%1000);
value.it_value.tv_sec = delay/1000;
value.it_interval.tv_usec = 0;
value.it_interval.tv_sec = 0;
setitimer(ITIMER_REAL,&value,NULL);
#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
*
****************************************************************************/
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);
}
/****************************************************************************
*
* Records the time of the last processed event. Used in XSetInputFocus
*
****************************************************************************/
Time lastTimestamp = CurrentTime; /* until Xlib does this for us */
Bool StashEventTime (XEvent *ev)
{
Time NewTimestamp = CurrentTime;
switch (ev->type)
{
case KeyPress:
case KeyRelease:
NewTimestamp = ev->xkey.time;
break;
case ButtonPress:
case ButtonRelease:
NewTimestamp = ev->xbutton.time;
break;
case MotionNotify:
NewTimestamp = ev->xmotion.time;
break;
case EnterNotify:
case LeaveNotify:
NewTimestamp = ev->xcrossing.time;
break;
case PropertyNotify:
NewTimestamp = ev->xproperty.time;
break;
case SelectionClear:
NewTimestamp = ev->xselectionclear.time;
break;
case SelectionRequest:
NewTimestamp = ev->xselectionrequest.time;
break;
case SelectionNotify:
NewTimestamp = ev->xselection.time;
break;
default:
return False;
}
if(NewTimestamp > lastTimestamp)
lastTimestamp = NewTimestamp;
return True;
}
/******************************************************************************
*
* Move a window to the top (dir 1) or bottom (dir -1) of the circulate seq.
*
*****************************************************************************/
void SetCirculateSequence(ASWindow* tw, int dir)
{
ASWindow *t;
long best = (dir == -1) ? LONG_MAX : LONG_MIN;
t = Scr.ASRoot.next;
if (t)
{
do
{
if ((dir == -1) ? (t->circulate_sequence < best)
: (t->circulate_sequence > best))
best = t->circulate_sequence;
} while ((t = t->next));
}
else
best = 0;
tw->circulate_sequence = best + dir;
}
/******************************************************************************
*
* Versions of grab primitives that circumvent modifier problems
*
*****************************************************************************/
unsigned mygrabs_no_mods[] = { 0 };
void MyXGrabButton(Display* display, unsigned button, unsigned modifiers,
Window grab_window, Bool owner_events, unsigned event_mask,
int pointer_mode, int keyboard_mode, Window confine_to,
Cursor cursor)
{
unsigned mod, *mods;
mods = (modifiers != AnyModifier) ? Scr.lock_mods : mygrabs_no_mods;
do {
mod = *mods++;
XGrabButton(display, button, modifiers | mod, grab_window,
owner_events, event_mask, pointer_mode, keyboard_mode,
confine_to, cursor);
} while (mod);
}
void MyXUngrabButton(Display* display, unsigned button, unsigned modifiers,
Window grab_window)
{
unsigned mod, *mods;
mods = (modifiers != AnyModifier) ? Scr.lock_mods : mygrabs_no_mods;
do {
mod = *mods++;
XUngrabButton(display, button, modifiers | mod, grab_window);
} while (mod);
}
void MyXGrabKey(Display* display, int keycode, unsigned modifiers,
Window grab_window, Bool owner_events, int pointer_mode,
int keyboard_mode)
{
unsigned mod, *mods;
mods = (modifiers != AnyModifier) ? Scr.lock_mods : mygrabs_no_mods;
do {
mod = *mods++;
XGrabKey(display, keycode, modifiers | mod, grab_window, owner_events,
pointer_mode, keyboard_mode);
} while (mod);
}
/******************************************************************************
*
* Grab ClickToRaise button press events for a window
*
*****************************************************************************/
void GrabRaiseClick(ASWindow* t)
{
int b;
for (b = 1; b <= MAX_BUTTONS; b++)
{
if (Scr.RaiseButtons & (1<<b))
MyXGrabButton(dpy, b, 0, t->w, True, ButtonPressMask, GrabModeSync,
GrabModeAsync, None, Scr.ASCursors[TITLE_CURSOR]);
}
}
/******************************************************************************
*
* Ungrab ClickToRaise button press events to allow their use in applications
*
*****************************************************************************/
void UngrabRaiseClick(ASWindow* t)
{
int b;
for (b = 1; b <= MAX_BUTTONS; b++)
{
if (Scr.RaiseButtons & (1<<b))
MyXUngrabButton(dpy, b, 0, t->w);
}
}
/******************************************************************************
*
* Recalculate the visibility flags
*
*****************************************************************************/
void UpdateVisibility(void)
{
ASWindow *t, *s, *tbase;
int tx1, ty1, tx2, ty2;
int ontop = 1, visible;
tbase = Scr.ASRoot.next;
for (t = Scr.ASRoot.next; t != NULL; t = t->next)
{
if (t->flags & MAPPED)
{
tx1 = t->frame_x;
ty1 = t->frame_y;
tx2 = t->frame_x + t->frame_width;
ty2 = t->frame_y + t->frame_height;
}
else if (t->flags & ICONIFIED)
{
tx1 = t->icon_x_loc;
ty1 = t->icon_y_loc;
tx2 = t->icon_x_loc + t->icon_p_width;
ty2 = t->icon_y_loc + t->icon_p_height;
}
else if (t->flags & SHADED)
{
tx1 = t->frame_x;
ty1 = t->frame_y;
tx2 = t->frame_x + t->frame_width;
ty2 = t->frame_y + NS_TITLE_HEIGHT;
}
else continue;
if (ontop && !(t->flags & ONTOP))
{
ontop = 0;
tbase = t;
}
if ((tx2 > 0) && (tx1 < Scr.MyDisplayWidth) &&
(ty2 > 0) && (ty1 < Scr.MyDisplayHeight))
{
visible = VISIBLE;
for (s = tbase; s != t; s = s->next)
{
if ((s->flags & TRANSIENT) && (s->transientfor == t->w))
continue;
if (s->flags & MAPPED)
{
if ((tx2 > s->frame_x)&&(tx1 < s->frame_x+s->frame_width)&&
(ty2 > s->frame_y)&&(ty1 < s->frame_y+s->frame_height))
{
visible = 0;
break;
}
}
else if (s->flags & ICONIFIED)
{
if ((tx2 > s->icon_x_loc)&&(tx1 < s->icon_x_loc+s->icon_p_width) &&
(ty2 > s->icon_y_loc)&&(ty1 < s->icon_y_loc+s->icon_p_height))
{
visible = 0;
break;
}
}
else if (s->flags & SHADED)
{
if ((tx2 > s->frame_x)&&(tx1 < s->frame_x+s->frame_width)&&
(ty2 > s->frame_y)&&(ty1 < s->frame_y+NS_TITLE_HEIGHT))
{
visible = 0;
break;
}
}
}
}
else
visible = 0;
if ((t->flags & VISIBLE) != visible)
{
t->flags ^= VISIBLE;
if ((Scr.flags & ClickToRaise) && ! (Scr.flags & ClickToFocus)
&& (t->flags & MAPPED))
{
if (visible)
UngrabRaiseClick(t);
else
GrabRaiseClick(t);
}
}
}
}
/******************************************************************************
*
* Get the correct window stacking order from the X server and
* make sure everything that depends on the order is fine and dandy
*
*****************************************************************************/
void CorrectStackOrder(void)
{
Window root, parent, *children, *cp;
unsigned nchildren;
ASWindow *t;
if (XQueryTree(dpy, Scr.ASRoot.w, &root, &parent, &children,
&nchildren))
{
for (cp = children; nchildren-- > 0; cp++)
{
if ((XFindContext(dpy, *cp, ASContext, (caddr_t*) &t) == XCSUCCESS)
&& (t->frame == *cp))
{
if (t != Scr.ASRoot.next)
{
t->prev->next = t->next;
if (t->next) t->next->prev = t->prev;
t->next = Scr.ASRoot.next;
t->prev = &Scr.ASRoot;
Scr.ASRoot.next->prev = t;
Scr.ASRoot.next = t;
}
}
}
XFree(children);
}
else
{
fprintf(stderr, "CorrectStackOrder(): XQueryTree failed!\n");
}
t = Scr.ASRoot.next;
if (t)
{
if (t->flags & ONTOP)
{
do { t = t->next; } while (t && (t->flags & ONTOP));
if (t)
{
do { t = t->next; } while (t && ! (t->flags & ONTOP));
if (t) RaiseWindow(Scr.ASRoot.next);
}
}
else
{
do { t = t->next; } while (t && ! (t->flags & ONTOP));
if (t) RaiseWindow(t);
}
}
UpdateVisibility();
}
syntax highlighted by Code2HTML, v. 0.9.1