mlvwm/mlvwm/event.c

1976 lines
54 KiB
C

/****************************************************************************/
/* This module is based on fvwm, but has been siginificantly modified */
/* by TakaC Hasegawa (tac.hasegawa@gmail.com) */
/****************************************************************************/
/****************************************************************************
* This module is based on Twm, but has been siginificantly modified
* by Rob Nation (nation@rocket.sanders.lockheed.com)
****************************************************************************/
/*****************************************************************************/
/** 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. **/
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <X11/Xatom.h>
#include "mlvwm.h"
#include "screen.h"
#include "menus.h"
#include "borders.h"
#include "add_window.h"
#include "functions.h"
#include "misc.h"
#include "balloon.h"
#include <X11/extensions/shape.h>
#define MAX_NAME_LEN 200L /* truncate to this many */
extern int ShapeEventBase;
extern void handle_expose( XEvent * );
MlvwmWindow *ColormapWindow = &Scr.MlvwmRoot;
void send_clientmessage( Window w, Atom a, Time timestamp)
{
MlvwmWindow *tmp_win;
XClientMessageEvent ev;
if( XFindContext ( dpy, w, MlvwmContext, (caddr_t *)&tmp_win )
== XCNOENT )
tmp_win = NULL;
ev.type = ClientMessage;
ev.window = w;
ev.message_type = _XA_WM_PROTOCOLS;
ev.format = 32;
ev.data.l[0] = a;
ev.data.l[1] = timestamp;
XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
}
void InstallWindowColormaps (MlvwmWindow *tmp)
{
XWindowAttributes attributes;
static Colormap last_cmap;
ColormapWindow = tmp;
/* Save the colormap to be loaded for when force loading of
* root colormap(s) ends.
*/
Scr.pushed_window = tmp;
/* Don't load any new colormap if root colormap(s) has been
* force loaded.
*/
if (Scr.root_pushes) return;
XGetWindowAttributes(dpy,tmp->w,&attributes);
if(last_cmap != attributes.colormap){
last_cmap = attributes.colormap;
XInstallColormap(dpy,attributes.colormap);
}
}
void InstallRootColormap( void )
{
MlvwmWindow *tmp;
if (Scr.root_pushes == 0){
tmp = Scr.pushed_window;
InstallWindowColormaps(&Scr.MlvwmRoot);
Scr.pushed_window = tmp;
}
Scr.root_pushes++;
return;
}
void UninstallRootColormap( void )
{
if (Scr.root_pushes)
Scr.root_pushes--;
if (!Scr.root_pushes)
InstallWindowColormaps(Scr.pushed_window);
return;
}
Bool GrabEvent( int cursor )
{
int i=0, val=0;
unsigned int mask;
XSync( dpy, 0 );
if(Scr.PreviousActive == NULL)
Scr.PreviousActive = Scr.ActiveWin;
XSetInputFocus( dpy, Scr.NoFocusWin, RevertToParent, CurrentTime );
Scr.ActiveWin = NULL;
mask = ButtonPressMask | ButtonReleaseMask
| ButtonMotionMask | PointerMotionMask
| PointerMotionHintMask;
while((i<1000)&&(val=XGrabPointer(dpy, Scr.Root, True, mask,
GrabModeAsync, GrabModeAsync, Scr.Root,
Scr.MlvwmCursors[cursor], CurrentTime)!=
GrabSuccess)){
i++;
sleep_a_little(1000);
}
XSync( dpy, 0 );
if(val!=GrabSuccess)
return False;
else
return True;
}
void UnGrabEvent( void )
{
XSync( dpy, 0 );
XUngrabPointer( dpy, CurrentTime );
if(Scr.PreviousActive != NULL) {
SetFocus( Scr.PreviousActive );
Scr.PreviousActive = NULL;
}
XSync( dpy, 0 );
}
void RestoreWithdrawnLocation( MlvwmWindow *tmp, Bool restart )
{
XWindowChanges xwc;
Window root, child;
int rx, ry;
unsigned int width, height, bw, depth;
unsigned int mask;
if(!tmp) return;
if (XGetGeometry (dpy, tmp->w, &root, &xwc.x, &xwc.y,
&width, &height, &bw, &depth)){
XTranslateCoordinates(dpy,tmp->frame,Scr.Root,xwc.x,xwc.y,
&rx,&ry,&child);
xwc.x = rx + tmp->diff_x;
xwc.y = ry + tmp->diff_y;
xwc.border_width = tmp->old_bw;
mask = (CWX | CWY | CWBorderWidth);
if( !restart ){
if( xwc.y>=Scr.MyDisplayHeight )
xwc.y %= Scr.MyDisplayHeight;
if( xwc.y<0 )
xwc.y = (tmp->frame_y+Scr.MyDisplayHeight*Scr.n_desktop)
%Scr.MyDisplayHeight;
}
XReparentWindow (dpy, tmp->w, Scr.Root, xwc.x, xwc.y );
XConfigureWindow (dpy, tmp->w, mask, &xwc);
XSync(dpy,0);
}
}
int GetContext( MlvwmWindow *t, XEvent *e, Window *w )
{
int Context;
if(!t) return C_ROOT;
Context = C_NO_CONTEXT;
*w = e->xany.window;
if( *w == Scr.NoFocusWin ) return C_ROOT;
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->frame) Context = C_FRAME;
if((*w == t->w)||(*w==t->Parent)) Context = C_WINDOW;
if(t->flags&TITLE && *w == t->title_w) Context = C_TITLE;
if(t->flags&CLOSER && *w == t->close_b) Context = C_CLOSE;
if(t->flags&MINMAXR && *w == t->minmax_b) Context = C_MINMAX;
if(t->flags&RESIZER && *w == t->resize_b) Context = C_RESIZE;
if(t->flags&SHADER && *w == t->shade_b ) Context = C_SHADE;
if( t->flags&SBARV ){
if(*w == t->scroll_v[0] ) Context = C_SBAR_V;
if(*w == t->scroll_v[1] ) Context = C_SBAR_UP;
if(*w == t->scroll_v[2] ) Context = C_SBAR_DOWN;
if(*w == t->scroll_v[3] ) Context = C_SBAR_V_AN;
}
if( t->flags&SBARH ){
if(*w == t->scroll_h[0] ) Context = C_SBAR_H;
if(*w == t->scroll_h[1] ) Context = C_SBAR_LEFT;
if(*w == t->scroll_h[2] ) Context = C_SBAR_RIGHT;
if(*w == t->scroll_h[3] ) Context = C_SBAR_H_AN;
}
}
return Context;
}
MlvwmWindow *NextActiveWin( MlvwmWindow *t )
{
int lp;
Window parent, *children;
unsigned nchildren;
MlvwmWindow *NextActive;
XQueryTree( dpy, Scr.Root, &Scr.Root, &parent, &children, &nchildren );
for( lp=nchildren-1; lp>-1; lp-- ){
if( XFindContext( dpy, children[lp], MlvwmContext,
(caddr_t *)&NextActive )
!=XCNOENT &&
NextActive->w!=t->w &&
!(NextActive->flags&HIDED) &&
!(NextActive->flags&NOWINLIST) &&
!(NextActive->flags&SKIPSELECT) &&
!(NextActive->flags&NOFOCUS) &&
(!t->wmhints || t->wmhints->input!=False) &&
NextActive->Desk==Scr.currentdesk)
break;
}
if( lp==-1 )
NextActive = NULL;
XFree( children );
return NextActive;
}
void SetMapStateProp( MlvwmWindow *tmp_win, int state)
{
unsigned long data[2]; /* "suggested" by ICCCM version 1 */
data[0] = (unsigned long) state;
data[1] = (unsigned long) None;
XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
PropModeReplace, (unsigned char *) data, 2);
}
int GetMapStateProp( MlvwmWindow *tmp_win )
{
Atom *protocols = NULL;
Atom atype;
int aformat;
unsigned long bytes_remain,nitems;
if( XGetWindowProperty( dpy, tmp_win->w, _XA_WM_STATE,
0L, 2L, False,
_XA_WM_STATE, &atype, &aformat,
&nitems, &bytes_remain,
(unsigned char **)&protocols ) == Success &&
protocols )
return
(int) protocols[0];
else
return WithdrawnState;
}
void Destroy( MlvwmWindow *t )
{
MlvwmWindow *NextActive;
int lp;
NextActive = NextActiveWin( t );
XDestroyWindow( dpy, t->Parent );
XDestroyWindow( dpy, t->frame );
XDeleteContext( dpy, t->Parent, MlvwmContext );
XDeleteContext( dpy, t->frame, MlvwmContext );
XDeleteContext( dpy, t->w, MlvwmContext );
if( t->flags&CLOSER )
XDeleteContext( dpy, t->close_b, MlvwmContext );
if( t->flags&MINMAXR )
XDeleteContext( dpy, t->minmax_b, MlvwmContext );
if( t->flags&SHADER )
XDeleteContext( dpy, t->shade_b, MlvwmContext );
if( t->flags&TITLE )
XDeleteContext( dpy, t->title_w, MlvwmContext );
if( t->flags&SBARV )
for( lp=0; lp<4; lp++ )
XDeleteContext( dpy, t->scroll_v[lp], MlvwmContext );
if( t->flags&SBARH )
for( lp=0; lp<4; lp++ )
XDeleteContext( dpy, t->scroll_h[lp], MlvwmContext );
if( t->flags&RESIZER )
XDeleteContext( dpy, t->resize_b, MlvwmContext );
if( Scr.n_desktop>1 )
for( lp=0; lp<Scr.n_desktop; lp++ )
if( Scr.LastActive[lp]==t )
Scr.LastActive[lp] = NULL;
t->prev->next = t->next;
if( t->next != NULL ) t->next->prev = t->prev;
if( t==Scr.ActiveWin ){
if( Scr.PreviousActive == Scr.ActiveWin )
Scr.PreviousActive = NULL;
if( !(Scr.flags & FOLLOWTOMOUSE) || !(Scr.flags&SLOPPYFOCUS) ){
if( Scr.PreviousActive )
SetFocus( Scr.PreviousActive );
else
SetFocus( NextActive );
}
else
SetFocus( NULL );
if( Scr.ActiveWin &&
(!(Scr.flags & FOLLOWTOMOUSE) || !(Scr.flags&SLOPPYFOCUS)) )
RaiseMlvwmWindow( Scr.ActiveWin );
}
if( t->wmhints ) XFree( t->wmhints );
if ( t->name != NoName) XFree ( t->name );
t->name = NULL;
if( t->class.res_name && t->class.res_name != NoName )
XFree((char *)t->class.res_name);
if( t->class.res_class && t->class.res_class != NoName )
XFree((char *)t->class.res_class);
free( t );
XSync( dpy, 0 );
}
void HandleDestroy( XEvent *ev )
{
MlvwmWindow *tmp_win;
Window w;
char action[24];
/* w = ev->xany.window;*/
XFlush(dpy);
w = ev->xdestroywindow.window;
if( XFindContext( dpy, w, MlvwmContext, (caddr_t *)&tmp_win )==XCNOENT )
return;
if( !(tmp_win->flags & NOWINLIST) && !(tmp_win->flags&TRANSIENT)
&& tmp_win->flags&MAPPED ){
sprintf( action, "Select %lX", (unsigned long)tmp_win );
DelMenuItem( &(Scr.IconMenu), action );
}
Destroy( tmp_win );
}
void handle_configure_request( XEvent *ev )
{
XWindowChanges wc;
unsigned long xwcm;
MlvwmWindow *tmp_win;
XConfigureRequestEvent *xcr = &ev->xconfigurerequest;
int x, y, width, height, old_x, old_y;
int title_height, sbar_v, sbar_h;
Bool notify=False;
ev->xany.window = xcr->window; /* mash parent field */
if (XFindContext (dpy, xcr->window, MlvwmContext, (caddr_t *) &tmp_win) ==
XCNOENT)
tmp_win = NULL;
if( !tmp_win ){
wc.x = xcr->x;
wc.y = xcr->y;
wc.width = xcr->width;
wc.height = xcr->height;
wc.sibling = wc.stack_mode = TopIf;
xwcm = xcr->value_mask & (CWX | CWY | CWWidth | CWHeight);
XConfigureWindow( dpy, ev->xany.window, xwcm, &wc );
return;
}
{
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;
}
title_height = tmp_win->flags & TITLE ? TITLE_HEIGHT : -1;
sbar_v = tmp_win->flags & SBARV ? SBAR_WH+2: 1;
sbar_h = tmp_win->flags & SBARH ? SBAR_WH+2: 1;
x = tmp_win->frame_x;
y = tmp_win->frame_y;
old_x = x;
old_y = y;
width = tmp_win->frame_w;
height = tmp_win->frame_h;
if( tmp_win->flags&(TITLE|SBARV|SBARH|RESIZER) ){
if (xcr->value_mask & CWX) x = xcr->x - 1;
if (xcr->value_mask & CWY) y = xcr->y - title_height - 2;
if (xcr->value_mask & CWWidth) width = xcr->width+1+sbar_v;
if (xcr->value_mask & CWHeight)
height = xcr->height+2+sbar_h+title_height;
if( Scr.flags&SYSTEM8 ){
if (xcr->value_mask & CWX) x -= 6;
if (xcr->value_mask & CWWidth) width += 12;
if (xcr->value_mask & CWHeight) height += 6;
}
}
else{
if (xcr->value_mask & CWX) x = xcr->x-6;
if (xcr->value_mask & CWY) y = xcr->y-6;
if (xcr->value_mask & CWWidth) width = xcr->width+12;
if (xcr->value_mask & CWHeight) height = xcr->height+12;
}
/*
tmp_win->frame_x = x<0 ? 0 : x;
tmp_win->frame_y = y<MENUB_H ? MENUB_H : y;
*/
tmp_win->win_w = width;
tmp_win->win_h = height;
if( old_x!=x || old_y!=y ) notify = True;
if( !(tmp_win->flags&SCROLL) ||
tmp_win->frame_w>tmp_win->win_w || !(tmp_win->flags&SBARH) )
tmp_win->frame_w = tmp_win->win_w;
if( !(tmp_win->flags&SCROLL) ||
tmp_win->frame_h>tmp_win->win_h || !(tmp_win->flags&SBARV) )
tmp_win->frame_h = tmp_win->win_h;
SetUpFrame(tmp_win, tmp_win->frame_x, tmp_win->frame_y,
tmp_win->frame_w, tmp_win->frame_h, notify );
if( tmp_win==Scr.ActiveWin ){
Scr.ActiveWin = NULL;
SetFocus( tmp_win );
}
KeepOnTop();
}
void MoveWindow( MlvwmWindow *mw, XEvent *evp )
{
Bool isEnd = False;
int pre_x, pre_y, drag_x, drag_y, last_x;
int x, y, JunkX, JunkY;
unsigned int JunkMask, emask;
Window JunkRoot, JunkChild;
XEvent ev;
pre_x = evp->xbutton.x_root;
pre_y = evp->xbutton.y_root;
last_x = -1;
drag_x = 0;
drag_y = 0;
XSync( dpy, 0 );
while(XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask |
ButtonReleaseMask, &ev))
if( ev.type == ButtonRelease) return;
if( !(Scr.flags&OPAQUEMOVE) ){
XGrabServer( dpy );
XDrawRectangle( dpy, Scr.Root, Scr.RobberGC, mw->frame_x, mw->frame_y,
mw->frame_w, mw->frame_h );
}
XSync( dpy, 0 );
if( !GrabEvent( MOVE ) ){
XBell( dpy, 30 );
return;
}
while( !isEnd ){
emask = ButtonReleaseMask|ButtonMotionMask|PointerMotionMask;
if( Scr.flags&OPAQUEMOVE )
emask |= ExposureMask;
XMaskEvent( dpy, emask, &ev );
if ( ev.type == MotionNotify )
while(XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask |
ButtonReleaseMask, &ev))
if( ev.type == ButtonRelease) break;
switch( ev.type ){
case Expose: handle_expose( &ev ); break;
case ButtonRelease:
if( !(Scr.flags&OPAQUEMOVE) )
XDrawRectangle( dpy, Scr.Root, Scr.RobberGC, mw->frame_x-drag_x,
mw->frame_y-drag_y, mw->frame_w, mw->frame_h );
XSync( dpy, 0 );
mw->frame_x = mw->frame_x-drag_x;
mw->frame_y = mw->frame_y-drag_y;
SetUpFrame( mw, mw->frame_x, mw->frame_y,
mw->frame_w, mw->frame_h, True );
isEnd = True;
break;
case MotionNotify:
XQueryPointer( dpy, ev.xany.window,&JunkRoot, &JunkChild,
&x, &y,&JunkX, &JunkY,&JunkMask);
if( drag_x==pre_x-x && drag_y==pre_y-y ) continue;
if( !(Scr.flags&OPAQUEMOVE) )
XDrawRectangle( dpy, Scr.Root, Scr.RobberGC,
mw->frame_x-drag_x, mw->frame_y-drag_y,
mw->frame_w, mw->frame_h );
/* Calc. edge resistance */
/* edge inside the menu bar */
if( mw->frame_y-pre_y+y<MENUB_H ){
if( last_x==-1 ) last_x = x;
}
/* edge<0 */
if( y<MENUB_H ) x=last_x;
else{
last_x = -1;
if( pre_x-x>0 && Scr.resist_x>abs(mw->frame_x-pre_x+x) &&
mw->frame_x-pre_x+x<0 )
x = pre_x-mw->frame_x;
/* edge>display width */
if( x-pre_x>0 && Scr.resist_x+Scr.MyDisplayWidth>
abs(mw->frame_x+mw->frame_w-pre_x+x) &&
mw->frame_x+mw->frame_w-pre_x+x>Scr.MyDisplayWidth )
x = pre_x-mw->frame_x+Scr.MyDisplayWidth-mw->frame_w;
/* edge>display height */
if( y-pre_y>0 && Scr.resist_y+Scr.MyDisplayHeight>
abs(mw->frame_y+mw->frame_h-pre_y+y) &&
mw->frame_y+mw->frame_h-pre_y+y>Scr.MyDisplayHeight )
y = pre_y-mw->frame_y+Scr.MyDisplayHeight-mw->frame_h;
XWarpPointer( dpy, None, ev.xany.window, 0, 0, 0, 0, x, y );
if( mw->frame_y-pre_y+y<MENUB_H ) y=pre_y-mw->frame_y+MENUB_H;
drag_x = pre_x-x;
drag_y = pre_y-y;
if( Scr.flags&OPAQUEMOVE )
XMoveWindow( dpy, mw->frame,
mw->frame_x-drag_x, mw->frame_y-drag_y );
else
XDrawRectangle( dpy, Scr.Root, Scr.RobberGC,
mw->frame_x-drag_x, mw->frame_y-drag_y,
mw->frame_w, mw->frame_h );
XSync( dpy, 0 );
}
break;
}
}
if( !(Scr.flags&OPAQUEMOVE) ) XUngrabServer( dpy );
UnGrabEvent();
KeepOnTop();
}
void DisplayPush( Window win )
{
XSegment lines_a[4], lines_b[4];
XClearWindow( dpy, win );
if( Scr.flags&SYSTEM8 ){
XFillRectangle( dpy, win, Scr.Gray3GC,
0, 0, BOXSIZE-1, BOXSIZE-1 );
XDrawRectangle( dpy, win, Scr.BlackGC,
1, 1, BOXSIZE-3, BOXSIZE-3 );
DrawShadowBox( 0, 0, BOXSIZE, BOXSIZE, win, 1,
Scr.Gray3GC, Scr.WhiteGC, SHADOW_ALL );
DrawShadowBox( 4, 4, BOXSIZE-6, BOXSIZE-6, win, BOXSIZE/2-2,
Scr.Gray4GC, Scr.Gray4GC,
SHADOW_BOTTOM|SHADOW_RIGHT );
DrawShadowBox( 2, 2, BOXSIZE-6, BOXSIZE-6, win, BOXSIZE/2-2,
Scr.Gray2GC, Scr.WhiteGC,
SHADOW_TOP|SHADOW_LEFT );
DrawShadowBox( 2, 2, 3, 3, win, 2,
Scr.Gray1GC, Scr.WhiteGC,
SHADOW_TOP|SHADOW_LEFT );
}
else{
SetSegment( 2, 4, 2, 4, lines_a );
SetSegment( 2, 4, BOXSIZE-3, BOXSIZE-5, lines_a+1 );
SetSegment( BOXSIZE-5, BOXSIZE-3, BOXSIZE-5, BOXSIZE-3, lines_a+2 );
SetSegment( BOXSIZE-3, BOXSIZE-5, 2, 4, lines_a+3 );
SetSegment( 1, 4, 6, 6, lines_b );
SetSegment( 6, 6, BOXSIZE-6, BOXSIZE-2, lines_b+1 );
SetSegment( BOXSIZE-5, BOXSIZE-2, 6, 6, lines_b+2 );
SetSegment( 6, 6, 1, 5, lines_b+3 );
XDrawSegments( dpy, win, Scr.Gray1GC, lines_a, 4 );
XDrawSegments( dpy, win, Scr.BlackGC, lines_b, 4 );
XDrawRectangle( dpy, win, Scr.BlackGC, 0, 0, BOXSIZE-1, BOXSIZE-1 );
}
XSync( dpy, 0 );
}
void CloseWindow( MlvwmWindow *mw, XEvent *evp )
{
Bool isEnd = False, isIn = True;
XEvent ev;
int JunkX, JunkY;
Window JunkRoot;
unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth;
DisplayPush( mw->close_b );
while( !isEnd ){
XMaskEvent( dpy,ButtonReleaseMask|EnterWindowMask|LeaveWindowMask, &ev );
switch( ev.type ){
case ButtonRelease:
isEnd = True;
break;
case EnterNotify:
if( ev.xcrossing.window==mw->close_b ){
DisplayPush( mw->close_b );
isIn = True;
}
break;
case LeaveNotify:
if( ev.xcrossing.window==mw->close_b ){
DrawCloseBox( mw, True );
isIn = False;
}
break;
}
}
if( isIn ){
if ( mw->flags & DoesWmDeleteWindow)
send_clientmessage( mw->w, _XA_WM_DELETE_WINDOW, CurrentTime);
else if (XGetGeometry(dpy, mw->w, &JunkRoot, &JunkX, &JunkY,
&JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)
== 0)
Destroy( mw );
else
XKillClient(dpy, mw->w);
}
XSync( dpy, 0 );
}
void DrawResizeFrame( int x, int y, int w, int h, MlvwmWindow *t )
{
XSegment lines[10];
int nl=0;
SetSegment( x, x+w, y, y, lines+nl ); nl++;
SetSegment( x+w, x+w, y, y+h, lines+nl ); nl++;
SetSegment( x, x+w, y+h, y+h, lines+nl ); nl++;
SetSegment( x, x, y, y+h, lines+nl ); nl++;
if( Scr.flags&SYSTEM8 ){
SetSegment( x+6, x+6, y+TITLE_HEIGHT+1, y+h-6, lines+nl ); nl++;
SetSegment( x+w-6, x+w-6,
y+TITLE_HEIGHT+1, y+h-6-(t->flags&RESIZER?SBAR_WH:0),
lines+nl );
nl++;
SetSegment( x+6, x+w-6-(t->flags&RESIZER?SBAR_WH:0),
y+h-6, y+h-6, lines+nl );
nl++;
if( t->flags&RESIZER ){
SetSegment( x+w-SBAR_WH-6, x+w-SBAR_WH-6,
y+h-SBAR_WH-6, y+h-6, lines+nl );
nl++;
SetSegment( x+w-SBAR_WH-6, x+w-6,
y+h-SBAR_WH-6, y+h-SBAR_WH-6, lines+nl );
nl++;
}
if( t->flags&TITLE ){
SetSegment( x+6, x+w-6,
y+TITLE_HEIGHT+1, y+TITLE_HEIGHT+1, lines+nl );
nl++;
}
}
else{
if( t->flags&SBARH ){
SetSegment( x, x+w, y+h-2-SBAR_WH, y+h-2-SBAR_WH, lines+nl );
nl++;
}
if( t->flags&SBARV ){
SetSegment( x+w-2-SBAR_WH, x+w-2-SBAR_WH,
y+(t->flags&TITLE ? TITLE_HEIGHT : -1 )+1, y+h,
lines+nl );
nl++;
}
if( t->flags&TITLE ){
SetSegment( x, x+w, y+TITLE_HEIGHT+1, y+TITLE_HEIGHT+1, lines+nl );
nl++;
}
}
XDrawSegments( dpy, Scr.Root, Scr.RobberGC, lines, nl );
XSync( dpy, 0 );
}
void ConstrainSize( MlvwmWindow *tmp_win, int *widthp, int *heightp )
{
#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
#define _min(a,b) (((a) < (b)) ? (a) : (b))
int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
int baseWidth, baseHeight;
int dwidth, dheight;
int title_height, sbar_v, sbar_h;
title_height = tmp_win->flags & TITLE ? TITLE_HEIGHT : -1;
sbar_v = tmp_win->flags & SBARV ? SBAR_WH+2 : 1;
sbar_h = tmp_win->flags & SBARH ? SBAR_WH+2: 1;
if( tmp_win->flags & ( TITLE | SBARV | SBARH | RESIZER ) ){
dwidth = *widthp-1-sbar_v;
dheight = *heightp-2-sbar_h-title_height;
if( Scr.flags&SYSTEM8 ){
dwidth -= 12;
dheight -= 6;
}
}
else{
dwidth = *widthp-12;
dheight = *heightp-12;
}
if (tmp_win->hints.flags & PMinSize) {
minWidth = tmp_win->hints.min_width;
minHeight = tmp_win->hints.min_height;
} else if (tmp_win->hints.flags & PBaseSize) {
minWidth = tmp_win->hints.base_width;
minHeight = tmp_win->hints.base_height;
} else
minWidth = minHeight = 1;
if (tmp_win->hints.flags & PBaseSize) {
baseWidth = tmp_win->hints.base_width;
baseHeight = tmp_win->hints.base_height;
}
else if (tmp_win->hints.flags & PMinSize) {
baseWidth = tmp_win->hints.min_width;
baseHeight = tmp_win->hints.min_height;
}
else
baseWidth = baseHeight = 0;
if (tmp_win->hints.flags & PMinSize) {
baseWidth = tmp_win->hints.min_width;
baseHeight = tmp_win->hints.min_height;
}
else
baseWidth = baseHeight = 0;
if (tmp_win->hints.flags & PMaxSize) {
maxWidth = tmp_win->hints.max_width;
maxHeight = tmp_win->hints.max_height;
}
else {
maxWidth = MAX_WINDOW_WIDTH;
maxHeight = MAX_WINDOW_HEIGHT;
}
if (tmp_win->hints.flags & PResizeInc) {
xinc = tmp_win->hints.width_inc;
yinc = tmp_win->hints.height_inc;
} else
xinc = yinc = 1;
/*
* First, clamp to min and max values
*/
if (dwidth < minWidth) dwidth = minWidth;
if (dheight < minHeight) dheight = minHeight;
if (dwidth > maxWidth) dwidth = maxWidth;
if (dheight > maxHeight) dheight = maxHeight;
/*
* Second, fit to base + N * inc
*/
dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
/*
* Third, adjust for aspect ratio
*/
#define maxAspectX tmp_win->hints.max_aspect.x
#define maxAspectY tmp_win->hints.max_aspect.y
#define minAspectX tmp_win->hints.min_aspect.x
#define minAspectY tmp_win->hints.min_aspect.y
/*
* The math looks like this:
*
* minAspectX dwidth maxAspectX
* ---------- <= ------- <= ----------
* minAspectY dheight maxAspectY
*
* If that is multiplied out, then the width and height are
* invalid in the following situations:
*
* minAspectX * dheight > minAspectY * dwidth
* maxAspectX * dheight < maxAspectY * dwidth
*
*/
if (tmp_win->hints.flags & PAspect){
if (minAspectX * dheight > minAspectY * dwidth){
delta = makemult(minAspectX * dheight / minAspectY - dwidth,
xinc);
if (dwidth + delta <= maxWidth) dwidth += delta;
else{
delta = makemult(dheight - dwidth*minAspectY/minAspectX,
yinc);
if (dheight - delta >= minHeight) dheight -= delta;
}
}
if (maxAspectX * dheight < maxAspectY * dwidth){
delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
yinc);
if (dheight + delta <= maxHeight) dheight += delta;
else{
delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
xinc);
if (dwidth - delta >= minWidth) dwidth -= delta;
}
}
}
/*
* Fourth, account for border width and title height
*/
if( tmp_win->flags & ( TITLE | SBARV | SBARH | RESIZER ) ){
if( Scr.flags&SYSTEM8 ){
dwidth += 12;
dheight += 6;
}
*widthp = dwidth + sbar_v + 1;
*heightp = dheight + sbar_h + title_height + 2;
}
else{
*widthp = dwidth + 12;
*heightp = dheight + 12;
}
}
void ResizeWindow( MlvwmWindow *mw, XEvent *evp, Bool s_move )
{
Bool isEnd = False;
int pre_x, pre_y, new_w, new_h, org_w, org_h;
int x, y, JunkX, JunkY;
unsigned int JunkMask, evmask;
int xmotion, ymotion;
Window JunkRoot, JunkChild;
XEvent ev;
pre_x = evp->xbutton.x_root;
pre_y = evp->xbutton.y_root;
org_w = new_w = mw->frame_w;
org_h = new_h = mw->frame_h;
if( s_move ){
xmotion=1;
ymotion=1;
}
else{
xmotion=0;
ymotion=0;
}
if( !GrabEvent( MOVE ) ){
XBell( dpy, 30 );
return;
}
if( !(Scr.flags&OPAQUERESIZE) ){
XGrabServer( dpy );
DrawResizeFrame(mw->frame_x,mw->frame_y,mw->frame_w,mw->frame_h,mw);
}
while( !isEnd ){
evmask = ButtonReleaseMask|ButtonMotionMask|PointerMotionMask;
if( Scr.flags&OPAQUERESIZE ) evmask |= ExposureMask;
XMaskEvent( dpy, evmask, &ev);
if ( ev.type == MotionNotify )
while(XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask |
ButtonReleaseMask, &ev))
if( ev.type == ButtonRelease) break;
switch( ev.type ){
case Expose: handle_expose( &ev ); break;
case ButtonRelease:
if( !(Scr.flags&OPAQUERESIZE) )
DrawResizeFrame( mw->frame_x, mw->frame_y, new_w, new_h, mw );
XSync( dpy, 0 );
mw->frame_w = new_w;
mw->frame_h = new_h;
SetUpFrame( mw, mw->frame_x, mw->frame_y,
mw->frame_w, mw->frame_h, False );
isEnd = True;
break;
case MotionNotify:
XQueryPointer( dpy, ev.xany.window,&JunkRoot, &JunkChild,
&x, &y,&JunkX, &JunkY,&JunkMask);
if( xmotion==0 && x<=mw->frame_x ){
xmotion=-1;
pre_x = mw->frame_x;
}
if( xmotion==0 && x>mw->frame_x + mw->frame_w ){
xmotion=1;
pre_x = x;
}
if( ymotion==0 && y<=mw->frame_y ){
ymotion=-1;
pre_y = mw->frame_y;
}
if( ymotion==0 && y>=mw->frame_y + mw->frame_h ){
ymotion=1;
pre_y = y;
}
if( xmotion!=0 || ymotion!=0 ){
if( !(Scr.flags&OPAQUERESIZE) )
DrawResizeFrame(mw->frame_x,mw->frame_y,new_w,new_h,mw);
if( xmotion!=0 )
new_w = org_w + (x - pre_x)*xmotion;
if( ymotion!=0 )
new_h = org_h + (y - pre_y)*ymotion;
if( new_w<(mw->flags&SBARH?4*SBAR_WH:0) )
new_w = (mw->flags*SBARH?4*SBAR_WH:0)+1;
if( new_h<(mw->flags&SBARV?4*SBAR_WH:0)+
(mw->flags&TITLE?TITLE_HEIGHT:0) )
new_h = (mw->flags&SBARV?4*SBAR_WH:0)+
(mw->flags&TITLE?TITLE_HEIGHT:0)+1;
ConstrainSize( mw, &new_w, &new_h );
if( xmotion==-1 ) mw->frame_x = pre_x+mw->frame_w-new_w;
if( ymotion==-1 ) mw->frame_y = pre_y+mw->frame_h-new_h;
if( Scr.flags&OPAQUERESIZE ){
if( mw->frame_w!=new_w ) mw->frame_w = new_w;
if( mw->frame_h!=new_h ) mw->frame_h = new_h;
SetUpFrame( mw,mw->frame_x,mw->frame_y,new_w,new_h,False );
}
else
DrawResizeFrame( mw->frame_x, mw->frame_y, new_w, new_h, mw );
}
break;
}
}
if( !(Scr.flags&OPAQUERESIZE) )
XUngrabServer( dpy );
UnGrabEvent();
}
void MinMaxWindow( MlvwmWindow *mw, XEvent *evp )
{
Bool isEnd = False, isIn = True;
XEvent ev;
DisplayPush( mw->minmax_b );
XDrawRectangle( dpy, mw->minmax_b, Scr.BlackGC,
1, 1, BOXSIZE-6, BOXSIZE-6 );
while( !isEnd ){
XMaskEvent( dpy,
ButtonReleaseMask|EnterWindowMask|LeaveWindowMask, &ev );
switch( ev.type ){
case ButtonRelease:
DrawMinMax( mw, True );
XSync( dpy, 0 );
isEnd = True;
break;
case EnterNotify:
if( ev.xcrossing.window==mw->minmax_b ){
DisplayPush( mw->minmax_b );
XDrawRectangle( dpy, mw->minmax_b, Scr.BlackGC,
1, 1, BOXSIZE-6, BOXSIZE-6 );
isIn = True;
}
break;
case LeaveNotify:
if( ev.xcrossing.window==mw->minmax_b ){
DrawMinMax( mw, True );
XSync( dpy, 0 );
isIn = False;
}
break;
}
}
if( isIn ){
if( mw->flags &SHADE )
UnShadeWindow( mw );
if( mw->flags & MAXIMAIZED ){
if( mw->flags&SCROLL ){
mw->win_x = mw->orig_win_x;
mw->win_y = mw->orig_win_y;
}
mw->frame_x = mw->orig_x;
mw->frame_y = mw->orig_y;
mw->frame_w = mw->orig_w;
mw->frame_h = mw->orig_h;
mw->flags &= ~MAXIMAIZED;
}
else{
mw->orig_x = mw->frame_x;
mw->orig_y = mw->frame_y;
mw->orig_w = mw->frame_w;
mw->orig_h = mw->frame_h;
mw->frame_x = 0;
mw->frame_y = MENUB_H;
if( mw->flags&SCROLL ){
mw->orig_win_x = mw->win_x;
mw->orig_win_y = mw->win_y;
mw->win_x = 0;
mw->win_y = 0;
}
if( mw->flags&SCROLL &&
(mw->frame_w<mw->win_w ||
mw->frame_h<mw->win_h) ){
mw->frame_w = mw->win_w;
mw->frame_h = mw->win_h;
}
else{
mw->frame_w = mw->size_w;
mw->frame_h = mw->size_h;
}
ConstrainSize( mw, &(mw->frame_w), &(mw->frame_h) );
mw->flags |= MAXIMAIZED;
}
SetUpFrame( mw, mw->frame_x, mw->frame_y,
mw->frame_w, mw->frame_h, True );
}
}
void ShadeBox( MlvwmWindow *mw, XEvent *evp )
{
Bool isEnd = False, isIn = True;
XEvent ev;
DisplayPush( mw->shade_b );
XDrawLine( dpy, mw->shade_b, Scr.BlackGC,
1, BOXSIZE/2-1, BOXSIZE-3, BOXSIZE/2-1 );
XDrawLine( dpy, mw->shade_b, Scr.BlackGC,
1, BOXSIZE/2+1, BOXSIZE-3, BOXSIZE/2+1 );
while( !isEnd ){
XMaskEvent( dpy,
ButtonReleaseMask|EnterWindowMask|LeaveWindowMask, &ev );
switch( ev.type ){
case ButtonRelease:
DrawShadeR( mw, True );
XSync( dpy, 0 );
isEnd = True;
break;
case EnterNotify:
if( ev.xcrossing.window==mw->shade_b ){
DisplayPush( mw->shade_b );
XDrawLine( dpy, mw->shade_b, Scr.BlackGC,
1, BOXSIZE/2-1, BOXSIZE-3, BOXSIZE/2-1 );
XDrawLine( dpy, mw->shade_b, Scr.BlackGC,
1, BOXSIZE/2+1, BOXSIZE-3, BOXSIZE/2+1 );
isIn = True;
}
break;
case LeaveNotify:
if( ev.xcrossing.window==mw->shade_b ){
DrawShadeR( mw, True );
XSync( dpy, 0 );
isIn = False;
}
break;
}
}
if( isIn ){
if( mw->flags&SHADE )
UnShadeWindow( mw );
else
ShadeWindow( mw );
}
}
void DoubleClickEvent( XEvent *ev )
{
MlvwmWindow *Tmp_win;
int context;
Window win;
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&Tmp_win )
!= XCNOENT ){
context = GetContext( Tmp_win, ev, &win );
if( context == C_TITLE ){
if( Tmp_win->flags&SHADE )
UnShadeWindow( Tmp_win );
else
ShadeWindow( Tmp_win );
}
}
}
/***
isHbar if scroll bar is Horizontal, then true
***/
void PressSbarAnker( Bool isHbar, MlvwmWindow *tmp_win )
{
Window JunkRoot, JunkChild, bar, anker;
XEvent ev;
XWindowAttributes winattrs;
Bool isEnd = False;
int *mouse_p, *mouse_w, zero=0, *anker_x, *anker_y, *vector, anker_end;
int x, y, JunkX, JunkY;
unsigned int JunkMask;
int sub_edge=0, anker_calc, init_posi, hide_size;
if( !(tmp_win->flags&SCROLL) ||
(tmp_win->frame_w>=tmp_win->win_w && isHbar) ||
(tmp_win->frame_h>=tmp_win->win_h && !isHbar) )
return;
if( isHbar ){
XGetWindowAttributes( dpy, tmp_win->scroll_h[3], &winattrs);
init_posi = winattrs.x;
mouse_p = &x;
mouse_w = &y;
anker = tmp_win->scroll_h[3];
bar = tmp_win->scroll_h[0];
anker_x = &anker_calc;
anker_y = &zero;
XGetWindowAttributes( dpy, tmp_win->scroll_h[0], &winattrs);
anker_end = winattrs.width-SBAR_WH-1-SBAR_WH;
vector = &(tmp_win->win_x);
hide_size = tmp_win->frame_w-tmp_win->win_w;
}
else{
XGetWindowAttributes( dpy, tmp_win->scroll_v[3], &winattrs);
init_posi = winattrs.y;
mouse_w = &x;
mouse_p = &y;
anker = tmp_win->scroll_v[3];
bar = tmp_win->scroll_v[0];
anker_x = &zero;
anker_y = &anker_calc;
XGetWindowAttributes( dpy, tmp_win->scroll_v[0], &winattrs);
anker_end = winattrs.height-SBAR_WH-1-SBAR_WH;
vector = &(tmp_win->win_y);
hide_size = tmp_win->frame_h-tmp_win->win_h;
}
if( XQueryPointer( dpy, bar, &JunkRoot, &JunkChild,
&JunkX, &JunkY, &x, &y, &JunkMask ) )
sub_edge = *mouse_p-init_posi;
if( !GrabEvent( DEFAULT ) ){
XBell( dpy, 30 );
return;
}
XDrawRectangle( dpy, anker, Scr.BlackGC, 0, 0, SBAR_WH-1, SBAR_WH-1 );
XSync( dpy, 0 );
do{
if( XCheckMaskEvent( dpy, ButtonReleaseMask | ExposureMask |
ButtonMotionMask | PointerMotionMask |
PointerMotionHintMask, &ev ) ){
if( ev.type==MotionNotify )
while( XCheckMaskEvent( dpy, PointerMotionMask |
ButtonMotionMask | ButtonReleaseMask,
&ev ) )
if( ev.type == ButtonRelease ) break;
switch( ev.type ){
case ButtonRelease: isEnd = True;
break;
case MotionNotify:
if( XQueryPointer( dpy, bar, &JunkRoot, &JunkChild,
&JunkX, &JunkY, &x, &y, &JunkMask ) &&
*mouse_w>-2*SBAR_WH && *mouse_w<3*SBAR_WH){
anker_calc = *mouse_p-sub_edge;
if( anker_calc<=SBAR_WH+1 ) anker_calc = SBAR_WH+1;
if( anker_calc>anker_end ) anker_calc = anker_end;
XMoveWindow( dpy, anker, *anker_x, *anker_y );
}
}
}
}
while( !isEnd );
*vector = (double)((anker_calc-SBAR_WH-1)*hide_size)/
(double)(anker_end-SBAR_WH-1);
SetUpFrame( tmp_win, tmp_win->frame_x, tmp_win->frame_y,
tmp_win->frame_w, tmp_win->frame_h, True );
UnGrabEvent();
}
/***
isHbar if scroll bar is Horizontal, then true
***/
void PressSbar( Bool isHbar, Window pressedwin, MlvwmWindow *tmp_win )
{
int *vector, pushd, pre_vector, direction=0;
Bool isEnd = False, isSelect = True;
int view, world, inc_view, inc=1;
int x, y, JunkX, JunkY;
unsigned int JunkMask;
int *check_axis, *anker_check, timeout=1;
struct timeval tp, current;
Window JunkRoot, JunkChild, bar, anker;
XWindowAttributes winattrs, winattrs_a;
int ignore=1;
XEvent ev;
if( !(tmp_win->flags&SCROLL) ||
(tmp_win->frame_w>=tmp_win->win_w && isHbar) ||
(tmp_win->frame_h>=tmp_win->win_h && !isHbar) )
return;
XGetWindowAttributes(dpy, tmp_win->Parent, &winattrs);
if( isHbar ){
vector = &(tmp_win->win_x);
view = tmp_win->frame_w;
world = tmp_win->win_w;
for( pushd=0; pushd<4 &&
tmp_win->scroll_h[pushd]!=pressedwin; pushd++ );
if( pushd==1 ) direction = C_SBAR_LEFT;
if( pushd==2 ) direction = C_SBAR_RIGHT;
bar = tmp_win->scroll_h[0];
if (tmp_win->hints.flags & PResizeInc)
inc = tmp_win->hints.width_inc;
inc_view = winattrs.width;
check_axis = &x;
anker_check = &(winattrs_a.x);
anker = tmp_win->scroll_h[3];
}
else{
vector = &(tmp_win->win_y);
view = tmp_win->frame_h;
world = tmp_win->win_h;
for( pushd=0; pushd<4 &&
tmp_win->scroll_v[pushd]!=pressedwin; pushd++ );
if( pushd==1 ) direction = C_SBAR_UP;
if( pushd==2 ) direction = C_SBAR_DOWN;
bar = tmp_win->scroll_v[0];
if( tmp_win->hints.flags & PResizeInc )
inc = tmp_win->hints.height_inc;
inc_view = winattrs.height;
check_axis = &y;
anker_check = &(winattrs_a.y);
anker = tmp_win->scroll_v[3];
}
if( pushd!=0 ){
DrawArrow( pressedwin, direction, Scr.BlackGC );
XSync( dpy, 0 );
}
pre_vector = *vector;
tp.tv_usec = 0;
tp.tv_sec = 0;
do{
if( timeout && isSelect && !isEnd ){
switch( pushd ){
case 1: (*vector)+=inc; break;
case 2: (*vector)-=inc; break;
case 0:
XQueryPointer( dpy, pressedwin,&JunkRoot, &JunkChild,
&JunkX, &JunkY, &x, &y, &JunkMask);
XGetWindowAttributes(dpy, anker, &winattrs_a);
if( *check_axis>*anker_check+SBAR_WH ) (*vector)-=inc_view;
if( *check_axis<*anker_check ) (*vector)+=inc_view;
break;
}
*vector = view-world > *vector ? view-world : *vector;
*vector = *vector>0 ? 0 : *vector;
if( pre_vector != *vector ){
SetUpFrame( tmp_win, tmp_win->frame_x, tmp_win->frame_y,
tmp_win->frame_w, tmp_win->frame_h, True );
XSync( dpy, 0 );
pre_vector = *vector;
}
}
if( XPending(dpy)){
if(XCheckMaskEvent( dpy, ButtonReleaseMask|EnterWindowMask|
LeaveWindowMask|ExposureMask, &ev ) ){
switch( ev.type ){
case ButtonRelease:
isEnd = True;
timeout = 1;
break;
case EnterNotify:
if( ev.xcrossing.window==pressedwin ){
if( !isSelect )
DrawArrow( pressedwin, direction, Scr.BlackGC );
isSelect = True;
}
break;
case LeaveNotify:
if( ev.xcrossing.window==pressedwin ){
if( isSelect )
DrawArrow( pressedwin, direction, Scr.Gray3GC );
isSelect = False;
}
break;
}
}
}
if( timeout ){
gettimeofday( &tp, NULL );
if( ignore ){
tp.tv_usec += 1000000;
ignore = 0;
}
else
tp.tv_usec += 100000;
tp.tv_sec += tp.tv_usec/1000000;
tp.tv_usec = tp.tv_usec%1000000;
timeout = 0;
}
gettimeofday( &current, NULL );
if( (tp.tv_sec-current.tv_sec)*1000000-(tp.tv_usec-current.tv_usec)<0 ){
timeout = 1;
}
else{
if( !isEnd ) sleep_a_little( 20000 );
}
}
while( !isEnd );
if( pushd!=0 )
DrawArrow( pressedwin, direction, Scr.Gray3GC );
XSync( dpy, 0 );
}
void handle_button_press( XEvent *ev )
{
MlvwmWindow *Tmp_win;
MenuLabel *tmp_menu;
Window win;
static Time PressTime=0;
static int Click_x, Click_y;
int context;
Bool newactive=False;
if( ev->xbutton.time-PressTime<Scr.double_click_time &&
ev->xbutton.x>Click_x-4 && ev->xbutton.x<Click_x+4 &&
ev->xbutton.y>Click_y-4 && ev->xbutton.y<Click_y+4 &&
ev->xbutton.button == Button1 ){
DoubleClickEvent( ev );
PressTime=0;
return;
}
else{
PressTime = ev->xbutton.time;
Click_x = ev->xbutton.x;
Click_y = ev->xbutton.y;
}
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&Tmp_win )
!= XCNOENT ){
context = GetContext( Tmp_win, ev, &win );
XGrabServer( dpy );
if( (Tmp_win!=Scr.ActiveWin || Scr.flags&FOLLOWTOMOUSE) )
RaiseMlvwmWindow( Tmp_win );
XUngrabServer( dpy );
if( Tmp_win != Scr.ActiveWin ){
SetFocus( Tmp_win );
PressTime = 0;
newactive = True;
if( ev->xbutton.subwindow!=None ){
ev->xany.window = ev->xbutton.subwindow;
context = GetContext( Tmp_win, ev, &win );
}
XAllowEvents(dpy, AsyncPointer, CurrentTime );
}
else
XAllowEvents(dpy, ReplayPointer, CurrentTime );
XSync(dpy,0);
if( newactive && context!=C_TITLE ) return;
if( ev->xbutton.button != Button1 ) return;
switch( context ){
case C_TITLE: MoveWindow( Tmp_win, ev ); break;
case C_CLOSE: CloseWindow( Tmp_win, ev ); break;
case C_MINMAX: MinMaxWindow( Tmp_win, ev ); break;
case C_SHADE: ShadeBox( Tmp_win, ev ); break;
case C_RESIZE: ResizeWindow( Tmp_win, ev, True ); break;
case C_SBAR_V:
case C_SBAR_UP:
case C_SBAR_DOWN:
PressSbar( False, ev->xany.window, Tmp_win );
break;
case C_SBAR_H:
case C_SBAR_LEFT:
case C_SBAR_RIGHT:
PressSbar( True, ev->xany.window, Tmp_win );
break;
case C_SBAR_V_AN: PressSbarAnker( False, Tmp_win ); break;
case C_SBAR_H_AN: PressSbarAnker( True, Tmp_win ); break;
case C_FRAME:
if( Scr.flags&SYSTEM8)MoveWindow( Tmp_win, ev ); break;
}
}
else{
if( ev->xbutton.button != Button1 ) return;
if( XFindContext( dpy, ev->xany.window,
MenuContext, (caddr_t *)&tmp_menu )==XCNOENT )
tmp_menu = NULL;
if( ev->xbutton.y<=MENUB_H )
press_menu( tmp_menu );
}
if( !(Scr.flags&FOLLOWTOMOUSE) && Scr.ActiveWin != NULL &&
GetContext( Scr.ActiveWin, ev, &win )==C_ROOT )
SetFocus( NULL );
if( Scr.flags&SLOPPYFOCUS && Scr.ActiveWin != NULL &&
GetContext( Scr.ActiveWin, ev, &win )==C_ROOT )
SetFocus( NULL );
KeepOnTop();
}
void handle_expose( XEvent *ev )
{
MlvwmWindow *Tmp_win, *ActiveWin;
MenuLabel *Tmp_menu;
int context;
Window win;
if( Scr.ActiveWin==NULL && Scr.PreviousActive!=NULL )
ActiveWin = Scr.PreviousActive;
else
ActiveWin = Scr.ActiveWin;
if( ev->xexpose.count != 0 ) return;
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&Tmp_win )
!= XCNOENT ){
context = GetContext( Tmp_win, ev, &win );
switch( context ){
case C_TITLE:
SetTitleBar( Tmp_win, (ActiveWin==Tmp_win?True:False) );
break;
case C_SBAR_V:
DrawSbarBar( Tmp_win, C_SBAR_V, (ActiveWin==Tmp_win?True:False) );
break;
case C_SBAR_UP: case C_SBAR_DOWN:
case C_SBAR_LEFT: case C_SBAR_RIGHT:
DrawSbarArrow( Tmp_win, context, (ActiveWin==Tmp_win?True:False) );
break;
case C_SBAR_V_AN:
DrawSbarAnk(Tmp_win, C_SBAR_V_AN ,(ActiveWin==Tmp_win?True:False));
break;
case C_SBAR_H:
DrawSbarBar( Tmp_win, C_SBAR_H, (ActiveWin==Tmp_win?True:False) );
break;
case C_SBAR_H_AN:
DrawSbarAnk(Tmp_win, C_SBAR_H_AN ,(ActiveWin==Tmp_win?True:False));
break;
case C_RESIZE:
DrawResizeBox( Tmp_win, (ActiveWin==Tmp_win?True:False));
break;
case C_FRAME:
DrawFrameShadow( Tmp_win, (ActiveWin==Tmp_win?True:False) );
break;
}
}
if( ev->xany.window == Scr.MenuBar )
RedrawMenuBar();
if( XFindContext( dpy, ev->xany.window, MenuContext, (caddr_t *)&Tmp_menu )
!= XCNOENT )
RedrawMenu( Tmp_menu, False );
}
void HandleEnterNotify( XEvent *ev )
{
MlvwmWindow *tmp_win;
XEnterWindowEvent *ewp = &(ev->xcrossing);
XEvent d;
if(XCheckTypedWindowEvent (dpy, ewp->window, LeaveNotify, &d))
if((d.xcrossing.mode==NotifyNormal)&&(d.xcrossing.detail!=NotifyInferior))
return;
if( ev->xany.window == Scr.Root ){
if ( Scr.flags&FOLLOWTOMOUSE && !(Scr.flags&SLOPPYFOCUS))
SetFocus( NULL );
InstallWindowColormaps( &Scr.MlvwmRoot );
return;
}
if( XFindContext ( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
!= XCNOENT ){
if( Scr.flags&FOLLOWTOMOUSE ) SetFocus( tmp_win );
if( ev->xcrossing.window==tmp_win->w )
InstallWindowColormaps( tmp_win );
}
}
void HandleLeaveNotify( XEvent *ev )
{
MlvwmWindow *tmp_win;
XEvent dummy;
if( ev->xcrossing.window == Scr.Root) return;
if(XCheckTypedWindowEvent (dpy, ev->xcrossing.window, EnterNotify, &dummy))
return;
if( XFindContext ( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
== XCNOENT )
return;
if ( ev->xcrossing.detail != NotifyInferior ){
if( ev->xcrossing.window==tmp_win->frame ){
if( (Scr.flags & FOLLOWTOMOUSE) && !(Scr.flags&SLOPPYFOCUS) ){
if( Scr.ActiveWin == tmp_win )
SetFocus( NULL );
}
InstallWindowColormaps (&Scr.MlvwmRoot);
}
else{
if( ev->xcrossing.window==tmp_win->w )
InstallWindowColormaps( &Scr.MlvwmRoot );
}
}
}
void HandleShapeNotify ( XEvent *ev )
{
MlvwmWindow *Tmp_win;
XShapeEvent *sev = (XShapeEvent *) ev;
if( XFindContext ( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&Tmp_win )
== XCNOENT )
return;
if (sev->kind != ShapeBounding)
return;
Tmp_win->wShaped = sev->shaped;
SetShape(Tmp_win,Tmp_win->frame_w);
}
void handle_unmap_request( XEvent *ev )
{
int dstx, dsty;
Window dumwin;
XEvent dummy;
MlvwmWindow *tmp_win;
Bool reparented;
if( ev->xunmap.event != ev->xunmap.window ) return;
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
==XCNOENT ){
ev->xany.window = ev->xunmap.window;
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
==XCNOENT )
return;
}
if ( !(tmp_win->flags & MAPPED) ) return;
XGrabServer( dpy );
if(XCheckTypedWindowEvent (dpy, ev->xunmap.window, DestroyNotify, &dummy)){
/* ev->xany.window = ev->xunmap.window;*/
ev->xdestroywindow.window = ev->xunmap.window;
HandleDestroy( ev );
XUngrabServer( dpy );
return;
}
if( XTranslateCoordinates ( dpy, ev->xunmap.window, Scr.Root,
0, 0, &dstx, &dsty, &dumwin ) ){
reparented = XCheckTypedWindowEvent (dpy, ev->xunmap.window,
ReparentNotify, &dummy);
SetMapStateProp (tmp_win, WithdrawnState);
if( !reparented )
RestoreWithdrawnLocation (tmp_win,False);
XRemoveFromSaveSet (dpy, ev->xunmap.window);
XSelectInput (dpy, ev->xunmap.window, NoEventMask);
/* ev->xany.window = ev->xunmap.window;*/
ev->xdestroywindow.window = ev->xunmap.window;
HandleDestroy( ev );
}
XUngrabServer( dpy );
XFlush (dpy);
}
void handle_property_request( XEvent *ev )
{
MlvwmWindow *tmp_win;
unsigned char *prop = NULL;
Atom actual = None;
int actual_format;
unsigned long nitems, bytesafter;
int JunkX = 0, JunkY = 0;
Window JunkRoot; /* junk window */
XTextProperty text_prop;
unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth;
char desk[8], *str, action[24];
#ifdef USE_LOCALE
int num;
char **list;
#endif
char *oldWinName, *winname;
if( ev->xproperty.atom==_XA_WM_DESKTOP && ev->xany.window==Scr.Root ){
if ((XGetWindowProperty(dpy, Scr.Root, _XA_WM_DESKTOP, 0L, 1L, True,
_XA_WM_DESKTOP, &actual, &actual_format, &nitems,
&bytesafter, &prop))==Success){
if(prop != NULL){
sprintf( desk, "Desk %ld", *(unsigned long *)prop );
ChangeDesk( desk );
}
}
return;
}
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
==XCNOENT ) return;
if ( XGetGeometry( dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
& JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0 )
return;
switch( ev->xproperty.atom ){
case XA_WM_NAME:
oldWinName = WinListName( tmp_win );
if( XGetWMName( dpy, tmp_win->w, &text_prop) != 0 ){
#ifdef USE_LOCALE
if(text_prop.value)
text_prop.nitems = strlen(text_prop.value);
if(XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
&& num > 0 && *list)
tmp_win->name = *list;
#else
tmp_win->name = (char *)text_prop.value;
#endif
}
else
tmp_win->name = NoName;
winname = WinListName( tmp_win );
sprintf( action, "Select %lX", (unsigned long)tmp_win );
ChangeMenuItemLabel( "ICON", oldWinName, winname,
action, M_ALLSET, M_AND );
if( tmp_win==Scr.ActiveWin ){
str = calloc( strlen( tmp_win->name )+6, 1 );
sprintf( str, "Hide %s", tmp_win->name );
ChangeMenuItemLabel( "ICON", Scr.IconMenu.m_item->label,
str, NULL, SELECTON, M_COPY );
free( str );
}
free( oldWinName );
free( winname );
SetTitleBar( tmp_win, (Scr.ActiveWin==tmp_win?True:False) );
break;
case XA_WM_ICON_NAME:
break;
case XA_WM_HINTS:
break;
case XA_WM_NORMAL_HINTS:
GetWindowSizeHints( tmp_win );
break;
default:
if( ev->xproperty.atom == _XA_WM_PROTOCOLS)
FetchWmProtocols( tmp_win );
break;
}
}
void HandleMapNotify( XEvent *ev )
{
MlvwmWindow *tmp_win;
char action[24];
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
==XCNOENT )
tmp_win = NULL;
if (!tmp_win){
if( (ev->xmap.override_redirect == True) &&
(ev->xmap.window != Scr.NoFocusWin))
XSelectInput( dpy, ev->xmap.window,FocusChangeMask);
return;
}
if( ev->xmap.event != ev->xmap.window)
return;
XGrabServer (dpy);
XMapSubwindows(dpy, tmp_win->frame);
if( !(tmp_win->flags & MAPPED)){
if( !(tmp_win->flags & NOWINLIST) &&
!(tmp_win->flags & TRANSIENT) ){
sprintf( action, "Select %lX", (unsigned long)tmp_win );
AddMenuItem( &(Scr.IconMenu), WinListName( tmp_win ), action,
NULL, tmp_win->miniicon, NULL,
SELECTON );
}
if( tmp_win->flags&STARTICONIC ){
if( Scr.flags&ICONIFYSHADE && !(tmp_win->flags&SHADE ))
ShadeWindow( tmp_win );
if( Scr.flags&ICONIFYHIDE && !(tmp_win->flags&HIDED ))
HideWindow( tmp_win );
tmp_win->flags &= ~STARTICONIC;
}
}
if(tmp_win->Desk == Scr.currentdesk && !(tmp_win->flags&HIDED)){
if( Scr.flags&STARTING )
XLowerWindow( dpy, tmp_win->frame );
else
RaiseMlvwmWindow( tmp_win );
XMapWindow(dpy, tmp_win->frame);
if( !(Scr.flags & FOLLOWTOMOUSE) &&
!(Scr.flags&SLOPPYFOCUS) &&
(!tmp_win->wmhints || tmp_win->wmhints->input!=False) &&
!(tmp_win->flags&NOFOCUS) )
SetFocus( tmp_win );
}
tmp_win->flags |= MAPPED;
XSync( dpy, 0 );
XUngrabServer (dpy);
XFlush (dpy);
/*
KeepOnTop();
*/
}
void HandleMapRequest( Window win )
{
MlvwmWindow *tmp_win;
if(XFindContext(dpy, win, MlvwmContext,
(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( win );
if( !tmp_win ) return;
}
if (!(tmp_win->flags & ICON)){
int state;
if( (!(Scr.flags&RSTPREVSTATE) ||
(state = GetMapStateProp( tmp_win ))==WithdrawnState) &&
tmp_win->wmhints && (tmp_win->wmhints->flags & StateHint) )
state = tmp_win->wmhints->initial_state;
else
state = NormalState;
XGrabServer( dpy );
XMapWindow(dpy, tmp_win->w);
switch (state){
case DontCareState:
case NormalState:
case InactiveState:
SetMapStateProp(tmp_win, NormalState);
break;
case IconicState:
tmp_win->flags |= STARTICONIC;
break;
}
XSync( dpy, 0 );
XUngrabServer( dpy );
}
KeepOnTop();
}
void HandleKeyPress( XEvent *ev )
{
MlvwmWindow *tmp_win;
ShortCut *key;
unsigned int mods_used = (ShiftMask | ControlMask | Mod1Mask |
Mod2Mask| Mod3Mask| Mod4Mask| Mod5Mask);
unsigned int modifier;
if(XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
==XCNOENT)
tmp_win=NULL;
modifier = (ev->xkey.state & mods_used);
for (key = Scr.ShortCutRoot; key != NULL; key = key->next){
ev->xkey.keycode =
XKeysymToKeycode(dpy, XKeycodeToKeysym(dpy,ev->xkey.keycode,0));
if ((key->keycode == ev->xkey.keycode) &&
((key->mods == modifier)||(key->mods == AnyModifier))){
ExecuteFunction( key->action );
return;
}
}
if( tmp_win ){
if( ev->xkey.window != tmp_win->w){
ev->xkey.window = tmp_win->w;
XSendEvent(dpy, tmp_win->w, False, KeyPressMask, ev );
}
}
}
void HandleClientMessage( XEvent *ev )
{
MlvwmWindow *tmp_win;
XWindowAttributes winattrs;
unsigned long eventMask;
MlvwmWindow *NextActive;
char action[24];
if( XFindContext( dpy, ev->xany.window, MlvwmContext, (caddr_t *)&tmp_win )
== XCNOENT ) return;
if( ev->xclient.message_type==_XA_WM_CHANGE_STATE ){
XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
eventMask = winattrs.your_event_mask;
switch( ev->xclient.data.l[0] ){
case IconicState:
XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
if( Scr.flags&ICONIFYSHADE && !(tmp_win->flags&SHADE )){
ShadeWindow( tmp_win );
XUnmapWindow( dpy, tmp_win->w );
}
if( Scr.flags&ICONIFYHIDE && !(tmp_win->flags&HIDED )){
NextActive = NextActiveWin( tmp_win );
XUnmapWindow( dpy, tmp_win->w );
HideWindow( tmp_win );
if( !(Scr.flags & FOLLOWTOMOUSE) ){
SetFocus( NextActive );
if( NextActive )
RaiseMlvwmWindow( NextActive );
}
ChangeMenuItemLabel( "ICON", "Show All", "Show All",
NULL, SELECTON, M_COPY );
}
XSelectInput(dpy, tmp_win->w, eventMask);
break;
case NormalState:
if( Scr.flags&ICONIFYSHADE && !(tmp_win->flags&SHADE ))
UnShadeWindow( tmp_win );
if( Scr.flags&ICONIFYHIDE && !(tmp_win->flags&HIDED )){
sprintf( action, "Select %lX", (unsigned long)tmp_win );
SelectWindow( action );
}
break;
}
return;
}
if( ev->xclient.window != tmp_win->w){
ev->xclient.window = tmp_win->w;
XSendEvent(dpy, tmp_win->w, False, NoEventMask, ev );
}
}
void HandleEvents( XEvent ev )
{
strcpy( Scr.ErrorFunc, "HandleEvents" );
switch( ev.type ){
case Expose:
strcpy( Scr.ErrorFunc, "Expose" );
handle_expose( &ev );
strcpy( Scr.ErrorFunc, "Expose End" );
break;
case DestroyNotify:
strcpy( Scr.ErrorFunc, "DestroyNotify" );
HandleDestroy( &ev );
strcpy( Scr.ErrorFunc, "DestroyNotify End" );
break;
case MapRequest:
strcpy( Scr.ErrorFunc, "MapRequest" );
HandleMapRequest( ev.xmaprequest.window );
strcpy( Scr.ErrorFunc, "MapRequest End" );
break;
case MapNotify:
strcpy( Scr.ErrorFunc, "MapNotify" );
HandleMapNotify( &ev );
strcpy( Scr.ErrorFunc, "MapNotify End" );
break;
case UnmapNotify:
strcpy( Scr.ErrorFunc, "UnmapNotify" );
handle_unmap_request( &ev );
strcpy( Scr.ErrorFunc, "UnmapNotify End" );
break;
case ButtonPress:
strcpy( Scr.ErrorFunc, "ButtonPress" );
handle_button_press( &ev );
strcpy( Scr.ErrorFunc, "ButtonPress End" );
break;
case EnterNotify:
strcpy( Scr.ErrorFunc, "EnterNotify" );
HandleEnterNotify( &ev );
strcpy( Scr.ErrorFunc, "EnterNotify End" );
break;
case LeaveNotify:
strcpy( Scr.ErrorFunc, "LeaveNotify" );
HandleLeaveNotify( &ev );
strcpy( Scr.ErrorFunc, "LeaveNotify End" );
break;
case FocusIn:
strcpy( Scr.ErrorFunc, "FocusIn" );
break;
case ConfigureRequest:
strcpy( Scr.ErrorFunc, "ConfigureRequest" );
handle_configure_request( &ev );
strcpy( Scr.ErrorFunc, "ConfigureRequest End" );
break;
case ClientMessage:
strcpy( Scr.ErrorFunc, "ClientMessage" );
HandleClientMessage( &ev );
break;
case PropertyNotify:
strcpy( Scr.ErrorFunc, "PropertyNotify" );
handle_property_request( &ev );
strcpy( Scr.ErrorFunc, "PropertyNotify End" );
break;
case KeyPress:
strcpy( Scr.ErrorFunc, "KeyPress" );
HandleKeyPress( &ev );
strcpy( Scr.ErrorFunc, "KeyPress End" );
break;
case ColormapNotify:
strcpy( Scr.ErrorFunc, "ColormapNotify" );
break;
default:
strcpy( Scr.ErrorFunc, "default" );
if( ev.type == (ShapeEventBase + ShapeNotify)){
strcpy( Scr.ErrorFunc, "Shape" );
HandleShapeNotify( &ev );
strcpy( Scr.ErrorFunc, "Shape End" );
}
strcpy( Scr.ErrorFunc, "default End" );
break;
}
strcpy( Scr.ErrorFunc, "Leave Handle Events" );
}
void WaitEvents( void )
{
extern int xfd;
XEvent ev;
struct timeval value;
fd_set in_fdset;
value.tv_usec = 0;
value.tv_sec = 1;
FD_ZERO( &in_fdset );
FD_SET( xfd, &in_fdset );
strcpy( Scr.ErrorFunc, "WaitEvents" );
XFlush( dpy );
if( XPending( dpy ) ){
XNextEvent( dpy, &ev );
HandleEvents( ev );
return;
}
XFlush( dpy );
ReapChildren();
strcpy( Scr.ErrorFunc, "WaitEvents End" );
if( Scr.flags & DEBUGOUT ) fprintf( stderr, "Return WaitEvents\n" );
#ifdef __hpux
if( select( xfd+1, (int *)&in_fdset, 0, 0, &value ) == 0){
#else
if( select( xfd+1, &in_fdset, 0, 0, &value ) == 0){
#endif
if( Scr.flags&BALLOONON ) BalloonHelp();
}
}