Files
amiwm-neo/main.c
Lucas de Sena a8f92b4e5b Make fullscreen work on GTK applications
This commit implements the _NET_SUPPORTING_WM_CHECK property, defined
by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which
indicates that a EWMH-compliant window manager is running.

A GTK application, when set to go fullscreen, first checks root window's
_NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant
window manager is running; and then checks the _NET_SUPPORTED property
to determine the supported protocols.

_NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK
was not.


This commit also fixes a misconception of the code related to screens.

The code deals with two different, unrelated concepts of screens: the
X11 screen, and the AmiWM screen.

The X11 screen, created by the X server independently of whether a
window manager is running, is a kind of “subdisplay”.  A X11 display
structure, which describes a connection to the X server, has one or more
screens.  Each X11 screen has its own root window and its own set of
clients that are specific to it, and cannot move to another X11 screen.
The user can even run two different window managers at the same time in
the same display, given that each is run in a different X11 screen.
Usually, there is only one X11 screen.

The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set
on the root window of each screen that AmiWM is managing.  Previously,
however, they were set everytime an AmiWM screen (a totally different
concept) was realized.  So, if i had 4 AmiWM screens configured in my
~/.amiwmrc file, setsupports() were called four times, even if i only
have a single X11 screen.

[1]: https://specifications.freedesktop.org/wm/latest/index.html
2026-01-10 02:58:39 +00:00

1616 lines
42 KiB
C

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/Xproto.h>
#include <X11/Xresource.h>
#include <X11/keysym.h>
#include <X11/Xmu/Error.h>
#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
#include <X11/extensions/shape.h>
#endif
#ifdef AMIGAOS
#include <x11/xtrans.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef USE_FONTSETS
#include <locale.h>
#endif
#include "drawinfo.h"
#include "screen.h"
#include "icon.h"
#include "client.h"
#include "prefs.h"
#include "module.h"
#include "icc.h"
#include "libami.h"
#ifdef AMIGAOS
#include <pragmas/xlib_pragmas.h>
extern struct Library *XLibBase;
struct timeval {
long tv_sec;
long tv_usec;
};
#define fd_set XTransFdset
#undef FD_ZERO
#undef FD_SET
#define FD_ZERO XTransFdZero
#define FD_SET XTransFdSet
#define select XTransSelect
#endif
#define HYSTERESIS 5
typedef struct _DragIcon {
Icon *icon;
Window w;
Pixmap pm;
int x, y;
} DragIcon;
Display *dpy = NULL;
char *progname;
Cursor wm_curs;
int signalled=0, forcemoving=0;
Client *activeclient=NULL, *dragclient=NULL, *resizeclient=NULL;
Client *rubberclient=NULL, *clickclient=NULL, *doubleclient=NULL;
Scrn *boundingscr=NULL; Window boundingwin=None;
DragIcon *dragiconlist=NULL;
int numdragicons=0;
Window clickwindow=None;
int rubberx, rubbery, rubberh, rubberw, rubberx0, rubbery0, olddragx, olddragy;
Time last_icon_click=0, last_double=0;
int initting=0;
static int ignore_badwindow=0;
int dblClickTime=1500;
XContext client_context, screen_context, icon_context, menu_context, vroot_context;
Scrn *dragscreen=NULL, *menuactive=NULL;
static int d_offset=0;
static fd_set master_fd_set;
static int max_fd=0;
static Window *checkwins;
char *free_screentitle=NULL;
char *x_server=NULL;
int shape_event_base, shape_error_base, shape_extn=0;
int server_grabs=0;
unsigned int meta_mask, switch_mask;
static char **main_argv;
extern Scrn *mbdclick, *mbdscr;
extern void reparent(Client *);
extern void redraw(Client *, Window);
extern void redrawclient(Client *);
extern void redrawmenubar(Scrn *, Window);
extern void gadgetclicked(Client *c, Window w, XEvent *e);
extern void gadgetunclicked(Client *c, XEvent *e);
extern void gadgetaborted(Client *c);
extern void clickenter(void);
extern void clickleave(void);
extern void menu_on(void);
extern void menu_off(void);
extern void menubar_enter(Window);
extern void menubar_leave(Window);
extern void *getitembyhotkey(KeySym);
extern void menuaction(void *);
extern Scrn *getscreenbyroot(Window);
extern void assimilate(Window, int, int);
extern void deselect_all_icons(Scrn *);
extern void reparenticon(Icon *, Scrn *, int, int);
extern void handle_client_message(Client *, XClientMessageEvent *);
extern void handle_module_input(fd_set *);
extern int dispatch_event_to_broker(XEvent *, unsigned long, struct module *);
extern XEvent *mkcmessage(Window w, Atom a, long x);
extern void reshape_frame(Client *c);
extern void read_rc_file(char *filename, int manage_all);
extern void init_modules();
extern void flushmodules();
extern void raiselowerclient(Client *, int);
#ifndef AMIGAOS
void restart_amiwm()
{
flushmodules();
flushclients();
XFlush(dpy);
XCloseDisplay(dpy);
execvp(main_argv[0], main_argv);
}
#endif
int handler(Display *d, XErrorEvent *e)
{
if (initting && (e->request_code == X_ChangeWindowAttributes) &&
(e->error_code == BadAccess)) {
fprintf(stderr, "%s: Another window manager is already running. Not started.\n", progname);
exit(1);
}
if (ignore_badwindow &&
(e->error_code == BadWindow || e->error_code == BadColor))
return 0;
if ((e->error_code == BadMatch && e->request_code == X_ChangeSaveSet) ||
(e->error_code == BadWindow && e->request_code == X_ChangeProperty) ||
(e->error_code == BadWindow && e->request_code == X_GetProperty) ||
(e->error_code == BadWindow && e->request_code == X_GetWindowAttributes) ||
(e->error_code == BadWindow && e->request_code == X_ChangeWindowAttributes) ||
(e->error_code == BadDrawable && e->request_code == X_GetGeometry) ||
(e->error_code == BadWindow && e->request_code == X_SendEvent))
return 0;
XmuPrintDefaultErrorMessage(d, e, stderr);
if (initting) {
fprintf(stderr, "%s: failure during initialisation; aborting\n",
progname);
exit(1);
}
return 0;
}
static struct coevent {
struct coevent *next;
struct timeval when;
void (*what)(void *);
void *with;
} *eventlist=NULL;
#define FIXUPTV(tv) { \
while((tv).tv_usec<0) { (tv).tv_usec+=1000000; (tv).tv_sec--; } \
while((tv).tv_usec>=1000000) { (tv).tv_usec-=1000000; (tv).tv_sec++; } \
}
void remove_call_out(void (*what)(void *), void *with)
{
struct coevent *ee, **e=&eventlist;
while(*e && ((*e)->what != what || (*e)->with != with))
e=&(*e)->next;
if((ee=*e)) {
*e=(*e)->next;
free(ee);
}
}
#ifdef BSD_STYLE_GETTIMEOFDAY
#define GETTIMEOFDAY(tp) gettimeofday(tp, NULL)
#else
#define GETTIMEOFDAY(tp) gettimeofday(tp)
#endif
void call_out(int howlong_s, int howlong_u, void (*what)(void *), void *with)
{
struct coevent *ce=malloc(sizeof(struct coevent));
if(ce) {
struct coevent **e=&eventlist;
GETTIMEOFDAY(&ce->when);
ce->when.tv_sec+=howlong_s;
ce->when.tv_usec+=howlong_u;
FIXUPTV(ce->when);
ce->what=what;
ce->with=with;
while(*e && ((*e)->when.tv_sec<ce->when.tv_sec ||
((*e)->when.tv_sec==ce->when.tv_sec &&
(*e)->when.tv_usec<=ce->when.tv_usec)))
e=&(*e)->next;
ce->next=*e;
*e=ce;
}
}
static void call_call_out()
{
struct timeval now;
struct coevent *e;
GETTIMEOFDAY(&now);
FIXUPTV(now);
while((e=eventlist) && (e->when.tv_sec<now.tv_sec ||
(e->when.tv_sec==now.tv_sec &&
e->when.tv_usec<=now.tv_usec))) {
eventlist=e->next;
(e->what)(e->with);
free(e);
}
}
static void fill_in_call_out(struct timeval *tv)
{
GETTIMEOFDAY(tv);
tv->tv_sec=eventlist->when.tv_sec-tv->tv_sec;
tv->tv_usec=eventlist->when.tv_usec-tv->tv_usec;
FIXUPTV(*tv);
if(tv->tv_sec<0)
tv->tv_sec = tv->tv_usec = 0;
}
void add_fd_to_set(int fd)
{
FD_SET(fd, &master_fd_set);
if(fd>=max_fd)
max_fd=fd+1;
}
void remove_fd_from_set(int fd)
{
FD_CLR(fd, &master_fd_set);
}
void lookup_keysyms(Display *dpy, unsigned int *meta_mask,
unsigned int *switch_mask)
{
int i,j,k,maxsym,mincode,maxcode;
XModifierKeymap *map=XGetModifierMapping(dpy);
KeySym *kp, *kmap;
unsigned int alt_mask = 0;
*meta_mask=0, *switch_mask=0;
XDisplayKeycodes(dpy, &mincode, &maxcode);
kmap=XGetKeyboardMapping(dpy, mincode, maxcode-mincode+1, &maxsym);
for(i=3; i<8; i++)
for(j=0; j<map->max_keypermod; j++)
if(map->modifiermap[i*map->max_keypermod+j] >= mincode)
for(kp=kmap+(map->modifiermap[i*map->max_keypermod+j]-mincode)*maxsym,
k=0; k<maxsym; k++)
switch(*kp++) {
case XK_Meta_L:
case XK_Meta_R:
*meta_mask|=1<<i;
break;
case XK_Mode_switch:
*switch_mask|=1<<i;
break;
case XK_Alt_L:
case XK_Alt_R:
alt_mask|=1<<i;
break;
}
XFree(kmap);
XFreeModifiermap(map);
if(*meta_mask == 0)
*meta_mask = (alt_mask? alt_mask :
(*switch_mask? *switch_mask : Mod1Mask));
}
void restorescreentitle(Scrn *s)
{
(scr=s)->title=s->deftitle;
XClearWindow(dpy, s->menubar);
redrawmenubar(s, s->menubar);
if(free_screentitle) {
free(free_screentitle);
free_screentitle=NULL;
}
}
void wberror(Scrn *s, char *message)
{
remove_call_out((void(*)(void *))restorescreentitle, s);
(scr=s)->title=message;
XClearWindow(dpy, s->menubar);
redrawmenubar(s, s->menubar);
XBell(dpy, 100);
call_out(2, 0, (void(*)(void *))restorescreentitle, s);
}
void setfocus(Window w)
{
if(w == None && prefs.focus != FOC_CLICKTOTYPE)
w = PointerRoot;
XSetInputFocus(dpy, w, (prefs.focus==FOC_CLICKTOTYPE? RevertToNone:RevertToPointerRoot), CurrentTime);
}
static void update_clock(void *dontcare);
void grab_server()
{
if(!server_grabs++)
XGrabServer(dpy);
}
void ungrab_server()
{
if(!--server_grabs) {
XUngrabServer(dpy);
if(prefs.titlebarclock) {
remove_call_out(update_clock, NULL);
update_clock(NULL);
}
}
}
void drawrubber()
{
if(rubberclient)
XDrawRectangle(dpy, rubberclient->scr->back, rubberclient->scr->rubbergc,
rubberx, rubbery, rubberw-1, rubberh-1);
else if(boundingwin) {
const char dash_list[] = { 6 };
int x=rubberx, y=rubbery, w=rubberw, h=rubberh;
if(w<0) { x+=w; w=-w; }
if(h<0) { y+=h; h=-h; }
if(w>=HYSTERESIS || h>=HYSTERESIS) {
XSetDashes(dpy, boundingscr->rubbergc, d_offset,
dash_list, sizeof(dash_list));
XSetLineAttributes(dpy, boundingscr->rubbergc, 0, LineOnOffDash,
CapButt, JoinMiter);
XDrawRectangle(dpy, boundingwin, boundingscr->rubbergc, x, y, w, h);
XSetLineAttributes(dpy, boundingscr->rubbergc, 0, LineSolid,
CapButt, JoinMiter);
}
}
}
static void move_dashes(void *dontcare)
{
call_out(0, 50000, move_dashes, dontcare);
drawrubber();
if((--d_offset)<0)
d_offset=11;
drawrubber();
}
void endrubber()
{
if(rubberclient) {
if((!prefs.opaquemove||dragclient==NULL) &&
(!prefs.opaqueresize||resizeclient==NULL))
drawrubber();
rubberclient=NULL;
} else if(boundingwin) {
if((!prefs.opaquemove||dragclient==NULL) &&
(!prefs.opaqueresize||resizeclient==NULL))
drawrubber();
boundingwin=None;
}
}
void initrubber(int x0, int y0, Client *c)
{
endrubber();
rubberx=c->x;
rubbery=c->y;
rubberw=c->pwidth;
rubberh=c->pheight;
rubberx0=x0;
rubbery0=y0;
rubberclient=c;
}
void abortrubber()
{
if(rubberclient) {
endrubber();
dragclient=resizeclient=NULL;
ungrab_server();
XUngrabPointer(dpy, CurrentTime);
} else if(boundingwin) {
endrubber();
boundingwin=None;
boundingscr=NULL;
ungrab_server();
XUngrabPointer(dpy, CurrentTime);
}
}
void startbounding(Scrn *s, Window w, XEvent *e)
{
last_icon_click=e->xbutton.time;
boundingscr=s;
boundingwin=w;
XGrabPointer(dpy, w, False, Button1MotionMask|ButtonPressMask|
ButtonReleaseMask, GrabModeAsync, GrabModeAsync, s->back, None,
CurrentTime);
grab_server();
rubberx=e->xbutton.x;
rubbery=e->xbutton.y;
rubberx0=e->xbutton.x_root;
rubbery0=e->xbutton.y_root;
rubberw=0;
rubberh=0;
drawrubber();
call_out(0, 0, move_dashes, NULL);
}
void endbounding(XEvent *e)
{
Icon *i;
int bx, by;
Window cc;
if(boundingscr) {
remove_call_out(move_dashes, NULL);
endrubber();
if(!(e->xbutton.state & ShiftMask))
deselect_all_icons(boundingscr);
if(rubberw<0) {
rubberx+=rubberw;
rubberw=-rubberw;
}
if(rubberh<0) {
rubbery+=rubberh;
rubberh=-rubberh;
}
if(rubberw>=HYSTERESIS || rubberh>=HYSTERESIS)
for(i=boundingscr->icons; i; i=i->next)
if(i->window && i->mapped &&
XTranslateCoordinates(dpy, i->parent, scr->back, i->x, i->y,
&bx, &by, &cc) &&
bx<rubberx+rubberw && by<rubbery+rubberh &&
bx+i->width>rubberx && by+i->height>rubbery)
selecticon(i);
boundingscr=NULL;
ungrab_server();
XUngrabPointer(dpy, CurrentTime);
}
}
void startdragging(Client *c, XEvent *e)
{
scr=c->scr;
dragclient=c;
XGrabPointer(dpy, c->drag, False, Button1MotionMask|ButtonPressMask|
ButtonReleaseMask, GrabModeAsync, GrabModeAsync, scr->back,
None, CurrentTime);
if(!prefs.opaquemove)
grab_server();
initrubber(e->xbutton.x_root, e->xbutton.y_root, c);
rubberx0-=rubberx;
rubbery0-=rubbery;
if(!forcemoving) {
if(rubberx+rubberw>scr->width)
rubberx=scr->width-rubberw;
if(rubbery+rubberh>scr->height)
rubbery=scr->height-rubberh;
if(rubberx<0)
rubberx=0;
if(rubbery<0)
rubbery=0;
}
if(!prefs.opaquemove)
drawrubber();
}
void startscreendragging(Scrn *s, XEvent *e)
{
dragscreen=s;
XGrabPointer(dpy, s->menubar, False, Button1MotionMask|ButtonPressMask|
ButtonReleaseMask, GrabModeAsync, GrabModeAsync, s->root, None,
CurrentTime);
olddragy=rubbery=s->y;
rubbery0=e->xbutton.y_root-rubbery;
}
void endscreendragging()
{
Scrn *s;
if((s=dragscreen)) {
#ifndef ASSIMILATE_WINDOWS
scrsendconfig(dragscreen);
#endif
dragscreen=NULL;
XUngrabPointer(dpy, CurrentTime);
}
}
void abortscreendragging()
{
if(dragscreen) {
XMoveWindow(dpy, dragscreen->back, -dragscreen->bw,
(dragscreen->y=olddragy)-dragscreen->bw);
endscreendragging();
}
}
void aborticondragging()
{
if(numdragicons) {
int i;
for(i=0; i<numdragicons; i++) {
XDestroyWindow(dpy, dragiconlist[i].w);
if(dragiconlist[i].pm)
XFreePixmap(dpy, dragiconlist[i].pm);
}
numdragicons=0;
free(dragiconlist);
dragiconlist=NULL;
XUngrabPointer(dpy, CurrentTime);
}
}
void badicondrop()
{
wberror(dragiconlist[0].icon->scr,
"Icon can't be moved into this window");
aborticondragging();
}
void endicondragging(XEvent *e)
{
int i;
Client *c;
int wx, wy;
Window ch;
scr=get_front_scr();
for(;;) {
if(scr->root == e->xbutton.root && e->xbutton.y_root>=scr->y)
break;
if((scr=scr->behind)==get_front_scr()) {
badicondrop();
return;
}
}
if (!scr->deftitle) {
badicondrop();
return;
}
if(XTranslateCoordinates(dpy, scr->root, scr->back,
e->xbutton.x_root, e->xbutton.y_root,
&wx, &wy, &ch) && ch!=None) {
if(XFindContext(dpy, ch, client_context, (XPointer*)&c) ||
c->scr != scr || c->state != NormalState)
c = NULL;
} else
c = NULL;
if(c) {
if(c->module) {
extern Atom amiwm_appwindowmsg;
XTranslateCoordinates(dpy, scr->back, c->window, -4, -4, &wx, &wy, &ch);
for(i=0; i<numdragicons; i++) {
XEvent *e=mkcmessage(c->window, amiwm_appwindowmsg,
dragiconlist[i].icon->window);
e->xclient.data.l[2] = dragiconlist[i].x+wx;
e->xclient.data.l[3] = dragiconlist[i].y+wy;
dispatch_event_to_broker(e, 0, c->module);
}
aborticondragging();
} else
badicondrop();
return;
}
for(i=0; i<numdragicons; i++)
dragiconlist[i].icon->mapped=0;
for(i=0; i<numdragicons; i++) {
if(dragiconlist[i].icon->scr!=scr)
reparenticon(dragiconlist[i].icon, scr,
dragiconlist[i].x-4, dragiconlist[i].y-4-scr->y);
else
XMoveWindow(dpy, dragiconlist[i].icon->window,
dragiconlist[i].icon->x = dragiconlist[i].x-4,
dragiconlist[i].icon->y = dragiconlist[i].y-4-scr->y);
dragiconlist[i].icon->mapped=1;
adjusticon(dragiconlist[i].icon);
}
aborticondragging();
}
void starticondragging(Scrn *scr, XEvent *e)
{
XWindowAttributes xwa;
XSetWindowAttributes xswa;
Icon *i;
Window ww;
aborticondragging();
for(i=scr->firstselected; i; i=i->nextselected)
numdragicons++;
if(!numdragicons)
return;
if(!(dragiconlist=calloc(numdragicons, sizeof(DragIcon)))) {
numdragicons=0;
XBell(dpy, 100);
return;
}
for(numdragicons=0, i=scr->firstselected; i; i=i->nextselected) {
dragiconlist[numdragicons].icon = i;
XGetWindowAttributes(dpy, i->window, &xwa);
if(i->parent!=scr->back)
XTranslateCoordinates(dpy, i->parent, scr->back, xwa.x, xwa.y,
&xwa.x, &xwa.y, &ww);
dragiconlist[numdragicons].x = xwa.x+4;
dragiconlist[numdragicons].y = xwa.y+4+scr->y;
xswa.save_under=True;
xswa.override_redirect=True;
if(i->innerwin) {
XGetWindowAttributes(dpy, i->innerwin, &xwa);
xswa.background_pixmap = dragiconlist[numdragicons].pm =
XCreatePixmap(dpy, i->innerwin, xwa.width, xwa.height, xwa.depth);
XCopyArea(dpy, i->innerwin, dragiconlist[numdragicons].pm, scr->gc,
0, 0, xwa.width, xwa.height, 0, 0);
} else {
if(i->secondpm) {
xswa.background_pixmap = i->secondpm;
XGetGeometry(dpy, i->secondpm, &xwa.root, &xwa.x, &xwa.y,
(unsigned int *)&xwa.width, (unsigned int *)&xwa.height,
(unsigned int *)&xwa.border_width,
(unsigned int *)&xwa.depth);
} else if(i->iconpm) {
xswa.background_pixmap = i->iconpm;
XGetGeometry(dpy, i->iconpm, &xwa.root, &xwa.x, &xwa.y,
(unsigned int *)&xwa.width, (unsigned int *)&xwa.height,
(unsigned int *)&xwa.border_width,
(unsigned int *)&xwa.depth);
}
if(xwa.depth!=scr->depth) {
dragiconlist[numdragicons].pm =
XCreatePixmap(dpy, i->window, xwa.width, xwa.height, scr->depth);
XSetForeground(dpy, scr->gc, scr->dri.dri_Pens[SHADOWPEN]);
XSetBackground(dpy, scr->gc, scr->dri.dri_Pens[BACKGROUNDPEN]);
XCopyPlane(dpy, xswa.background_pixmap, dragiconlist[numdragicons].pm,
scr->gc, 0, 0, xwa.width, xwa.height, 0, 0, 1);
xswa.background_pixmap = dragiconlist[numdragicons].pm;
xwa.depth = scr->depth;
}
}
xswa.colormap=xwa.colormap;
dragiconlist[numdragicons].w =
XCreateWindow(dpy, scr->root,
dragiconlist[numdragicons].x,
dragiconlist[numdragicons].y,
xwa.width, xwa.height, 0,
xwa.depth, xwa.class, xwa.visual,
CWBackPixmap|CWOverrideRedirect|CWSaveUnder|CWColormap,
&xswa);
#ifdef HAVE_XSHAPE
if(shape_extn) {
if(i->innerwin) {
int bShaped, xbs, ybs, cShaped, xcs, ycs;
unsigned int wbs, hbs, wcs, hcs;
XShapeQueryExtents(dpy, i->innerwin, &bShaped, &xbs, &ybs, &wbs, &hbs,
&cShaped, &xcs, &ycs, &wcs, &hcs);
if(bShaped)
XShapeCombineShape(dpy, dragiconlist[numdragicons].w, ShapeBounding,
0, 0, i->innerwin, ShapeBounding, ShapeSet);
} else if(i->maskpm) {
XShapeCombineMask(dpy, dragiconlist[numdragicons].w, ShapeBounding,
0, 0, i->maskpm, ShapeSet);
}
}
#endif
XMapRaised(dpy, dragiconlist[numdragicons].w);
numdragicons++;
}
XGrabPointer(dpy, scr->back, False, Button1MotionMask|ButtonPressMask|
ButtonReleaseMask, GrabModeAsync, GrabModeAsync, scr->root,
None, CurrentTime);
olddragx = rubberx0 = e->xbutton.x_root;
olddragy = rubbery0 = e->xbutton.y_root;
}
void enddragging()
{
if(dragclient) {
Client *c=dragclient;
endrubber();
if(rubbery<=-(c->scr->bh))
rubbery=1-(c->scr->bh);
XMoveWindow(dpy, c->parent, c->x=rubberx, c->y=rubbery);
dragclient=NULL;
if(!prefs.opaquemove)
ungrab_server();
XUngrabPointer(dpy, CurrentTime);
sendconfig(c);
}
}
void do_icon_double_click(Scrn *scr)
{
extern Atom amiwm_appiconmsg;
Icon *i, *next;
Client *c;
for(i=scr->firstselected; i; i=next) {
next=i->nextselected;
if(i->module) {
dispatch_event_to_broker(mkcmessage(i->window, amiwm_appiconmsg, 0),
0, i->module);
} else {
if(i->labelwin)
XUnmapWindow(dpy, i->labelwin);
if(i->window)
XUnmapWindow(dpy, i->window);
i->mapped=0;
deselecticon(i);
if((c=(i->client))) {
XMapWindow(dpy, c->window);
if(c->parent!=c->scr->root && !c->fullscreen)
XMapRaised(dpy, c->parent);
setclientstate(c, NormalState);
}
}
}
}
void startresizing(Client *c, XEvent *e)
{
resizeclient=c;
XGrabPointer(dpy, c->resize, False, Button1MotionMask|ButtonPressMask|
ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
c->scr->back, None, CurrentTime);
if(!prefs.opaqueresize)
grab_server();
initrubber(e->xbutton.x_root, e->xbutton.y_root, c);
rubberx0-=rubberw;
rubbery0-=rubberh;
if(!prefs.opaqueresize)
drawrubber();
}
void endresizing()
{
extern void resizeclientwindow(Client *c, int, int);
if(resizeclient) {
Client *c=resizeclient;
endrubber();
if(!prefs.opaqueresize)
ungrab_server();
resizeclientwindow(c, rubberw, rubberh);
resizeclient=NULL;
XUngrabPointer(dpy, CurrentTime);
}
}
void abortfocus()
{
if(activeclient) {
activeclient->active=False;
redrawclient(activeclient);
if(prefs.focus==FOC_CLICKTOTYPE)
XGrabButton(dpy, Button1, AnyModifier, activeclient->parent,
True, ButtonPressMask, GrabModeSync, GrabModeAsync,
None, wm_curs);
activeclient = NULL;
}
setfocus(None);
}
RETSIGTYPE sighandler(int sig)
{
signalled=1;
signal(sig, SIG_IGN);
}
static void instcmap(Colormap c)
{
XInstallColormap(dpy, (c == None) ? scr->cmap : c);
}
void internal_broker(XEvent *e)
{
/*
* XXX this is one of the things that the code in module.c
* is abusing to overload display with some numeric
* values. Surely there's a better way to do this?
*/
uintptr_t event_loc=(uintptr_t)e->xany.display;
e->xany.display=dpy;
if(event_loc==1) {
XSendEvent(dpy, e->xany.window, False, 0, e);
} else switch(e->type) {
case MappingNotify:
if(e->xmapping.request==MappingKeyboard ||
e->xmapping.request==MappingModifier)
XRefreshKeyboardMapping(&e->xmapping);
lookup_keysyms(dpy, &meta_mask, &switch_mask);
break;
case KeyPress:
if(e->xkey.state & meta_mask) {
KeySym ks=XLookupKeysym(&e->xkey,
((e->xkey.state & ShiftMask)?1:0)+
((e->xkey.state & switch_mask)?2:0));
void *item;
if((item=getitembyhotkey(ks)))
menuaction(item);
}
break;
}
}
static void update_clock(void *dontcare)
{
Scrn *scr;
if(server_grabs)
return;
call_out(prefs.titleclockinterval, 0, update_clock, dontcare);
scr = get_front_scr();
do {
redrawmenubar(scr, scr->menubar);
scr=scr->behind;
} while(scr != get_front_scr());
}
void cleanup()
{
int sc;
extern void free_prefs();
struct coevent *e;
flushmodules();
flushclients();
scr = get_front_scr();
for(sc=0; checkwins!=NULL && sc<ScreenCount(dpy); sc++)
XDestroyWindow(dpy, checkwins[sc]);
free(checkwins);
while(scr)
closescreen();
free_prefs();
if(dpy) {
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XFlush(dpy);
XCloseDisplay(dpy);
}
while((e = eventlist)) {
eventlist = e->next;
free(e);
}
if(x_server)
free(x_server);
}
int main(int argc, char *argv[])
{
int x_fd, sc;
static Argtype array[3];
struct RDArgs *ra;
#ifdef USE_FONTSETS
setlocale(LC_CTYPE, "");
setlocale(LC_TIME, "");
#endif
main_argv=argv;
progname=argv[0];
atexit(cleanup);
memset(array, 0, sizeof(array));
initargs(argc, argv);
if(!(ra=ReadArgs((UBYTE *)"RCFILE,DISPLAY/K,SINGLE/S",
(LONG *)array, NULL))) {
PrintFault(IoErr(), (UBYTE *)progname);
exit(1);
}
x_server = strdup(XDisplayName(array[1].ptr));
XrmInitialize();
if(!(dpy = XOpenDisplay(array[1].ptr))) {
fprintf(stderr, "%s: cannot connect to X server %s\n", progname, x_server);
FreeArgs(ra);
exit(1);
}
if(array[1].ptr) {
char *env=malloc(strlen((char *)array[1].ptr)+10);
sprintf(env, "DISPLAY=%s", (char *)array[1].ptr);
putenv(env);
}
client_context = XUniqueContext();
screen_context = XUniqueContext();
icon_context = XUniqueContext();
menu_context = XUniqueContext();
vroot_context = XUniqueContext();
wm_curs=XCreateFontCursor(dpy, XC_top_left_arrow);
FD_ZERO(&master_fd_set);
x_fd=ConnectionNumber(dpy);
FD_SET(x_fd, &master_fd_set);
max_fd=x_fd+1;
initting = 1;
XSetErrorHandler(handler);
#ifdef HAVE_XSHAPE
if(XShapeQueryExtension(dpy, &shape_event_base, &shape_error_base))
shape_extn = 1;
#endif
XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
XSync(dpy, False);
XSelectInput(dpy, DefaultRootWindow(dpy), NoEventMask);
init_modules();
read_rc_file(array[0].ptr, !array[2].num);
if( prefs.titleclockinterval < 1 ) prefs.titleclockinterval = 1;
FreeArgs(ra);
if (signal(SIGTERM, sighandler) == SIG_IGN)
signal(SIGTERM, SIG_IGN);
if (signal(SIGINT, sighandler) == SIG_IGN)
signal(SIGINT, SIG_IGN);
#ifdef SIGHUP
if (signal(SIGHUP, sighandler) == SIG_IGN)
signal(SIGHUP, SIG_IGN);
#endif
init_atoms();
#ifndef AMIGAOS
if((fcntl(ConnectionNumber(dpy), F_SETFD, 1)) == -1)
fprintf(stderr, "%s: child cannot disinherit TCP fd\n", progname);
#endif
lookup_keysyms(dpy, &meta_mask, &switch_mask);
checkwins = calloc(ScreenCount(dpy), sizeof(*checkwins));
for(sc=0; sc<ScreenCount(dpy); sc++) {
if(sc==DefaultScreen(dpy) || prefs.manage_all) {
Window root = RootWindow(dpy, sc);
checkwins[sc] = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, 1, 1);
setsupports(scr->root, checkwins[sc]);
if(!getscreenbyroot(root)) {
char buf[64];
sprintf(buf, "Screen.%d", sc);
openscreen((sc? strdup(buf):"Workbench Screen"), root);
}
}
}
/*
if(!front)
openscreen("Workbench Screen", DefaultRootWindow(dpy));
*/
realizescreens();
setfocus(None);
initting = 0;
if(prefs.titlebarclock)
call_out(0, 0, update_clock, NULL);
while(!signalled) {
fd_set rfds;
struct timeval t;
XEvent event;
Window dummy_root;
int dummy_x, dummy_y;
unsigned int dummy_w, dummy_h, dummy_bw, dummy_d;
while((!signalled) && QLength(dpy)>0) {
Client *c; Icon *i;
int motionx, motiony;
XNextEvent(dpy, &event);
if(!XFindContext(dpy, event.xany.window, client_context,
(XPointer*)&c)) {
scr=c->scr;
} else {
c = NULL;
if(XFindContext(dpy, event.xany.window, screen_context,
(XPointer*)&scr))
scr = get_front_scr();
}
if(XFindContext(dpy, event.xany.window, icon_context, (XPointer*)&i))
i=NULL;
else
scr=i->scr;
switch(event.type) {
case Expose:
if(!event.xexpose.count) {
if((rubberclient || boundingscr)&&!prefs.opaquemove
&&!prefs.opaqueresize)
drawrubber();
if(c)
redraw(c, event.xexpose.window);
else if(i)
redrawicon(i, event.xexpose.window);
else if(scr)
redrawmenubar(scr, event.xexpose.window);
if((rubberclient || boundingscr)&&!prefs.opaquemove) drawrubber();
}
break;
case CreateNotify:
if(!XFindContext(dpy, event.xcreatewindow.window, client_context,
(XPointer *)&c)) {
break;
}
if(!event.xcreatewindow.override_redirect) {
if(!(scr=getscreenbyroot(event.xcreatewindow.parent)))
scr = get_front_scr();
createclient(event.xcreatewindow.window);
}
#ifdef ASSIMILATE_WINDOWS
else if(XFindContext(dpy, event.xcreatewindow.window, screen_context, (XPointer*)&scr)
&& (scr=getscreenbyroot(event.xcreatewindow.parent))) {
XGetWindowAttributes(dpy, event.xcreatewindow.window, &attr);
assimilate(event.xcreatewindow.window, attr.x, attr.y);
}
#endif
break;
case DestroyNotify:
if(!XFindContext(dpy, event.xdestroywindow.window, client_context,
(XPointer*)&c)) {
ignore_badwindow = 1;
rmclient(c);
XSync(dpy, False);
ignore_badwindow = 0;
} else if(!XFindContext(dpy, event.xdestroywindow.window, icon_context,
(XPointer*)&i)) {
ignore_badwindow = 1;
if(i->client)
i->client->icon=NULL;
rmicon(i);
XSync(dpy, False);
ignore_badwindow = 0;
} else if(event.xdestroywindow.window)
XDeleteContext(dpy, event.xdestroywindow.window, screen_context);
break;
case UnmapNotify:
if(c && c->active && (event.xunmap.window==c->parent) &&
!(c->fullscreen && c->state == NormalState)) {
c->active=False;
activeclient = NULL;
redrawclient(c);
if(prefs.focus == FOC_CLICKTOTYPE)
XGrabButton(dpy, Button1, AnyModifier, c->parent, True,
ButtonPressMask, GrabModeSync, GrabModeAsync,
None, wm_curs);
if(!menuactive)
setfocus(None);
}
if(c && (event.xunmap.window==c->window)) {
if((!c->reparenting) && c->parent != c->scr->root) {
Icon *i=c->icon;
XUnmapWindow(dpy, c->parent);
if(i) {
if(i->labelwin)
XUnmapWindow(dpy, i->labelwin);
if(i->window)
XUnmapWindow(dpy, i->window);
i->mapped=0;
deselecticon(i);
}
setclientstate(c, WithdrawnState);
}
c->reparenting = 0;
}
break;
case ConfigureNotify:
if((!XFindContext(dpy, event.xconfigure.window, icon_context,
(XPointer *)&i)) &&
event.xconfigure.window == i->window){
i->x=event.xconfigure.x; i->y=event.xconfigure.y;
i->width=event.xconfigure.width; i->height=event.xconfigure.height;
if(i->labelwin) {
XWindowChanges xwc;
xwc.x=i->x+(i->width>>1)-(i->labelwidth>>1);
xwc.y=i->y+i->height+1;
xwc.sibling=i->window;
xwc.stack_mode=Below;
XConfigureWindow(dpy, i->labelwin, CWX|CWY|CWSibling|CWStackMode,
&xwc);
}
}
break;
case ReparentNotify:
if((!XFindContext(dpy, event.xreparent.window, icon_context,
(XPointer *)&i)) &&
event.xreparent.window == i->window){
i->parent=event.xreparent.parent;
i->x=event.xreparent.x; i->y=event.xreparent.y;
if(i->labelwin) {
XWindowChanges xwc;
XReparentWindow(dpy, i->labelwin, i->parent,
i->x+(i->width>>1)-(i->labelwidth>>1),
i->y+i->height+1);
xwc.sibling=i->window;
xwc.stack_mode=Below;
XConfigureWindow(dpy, i->labelwin, CWSibling|CWStackMode, &xwc);
}
}
break;
case CirculateNotify:
case GravityNotify:
case NoExpose:
case GraphicsExpose:
break;
case ClientMessage:
if(c)
handle_client_message(c, &event.xclient);
break;
case ColormapNotify:
if(event.xcolormap.new && c)
if(c->colormap!=event.xcolormap.colormap) {
c->colormap=event.xcolormap.colormap;
if(c->active)
instcmap(c->colormap);
}
break;
case ConfigureRequest:
if(XFindContext(dpy, event.xconfigurerequest.window, client_context,
(XPointer*)&c))
c = NULL;
if(c && event.xconfigurerequest.window==c->window &&
c->parent!=c->scr->root) {
extern void resizeclientwindow(Client *c, int, int);
if(event.xconfigurerequest.value_mask&CWBorderWidth)
c->old_bw=event.xconfigurerequest.border_width;
resizeclientwindow(c, (event.xconfigurerequest.value_mask&CWWidth)?
event.xconfigurerequest.width+c->framewidth:c->pwidth,
(event.xconfigurerequest.value_mask&CWHeight)?
event.xconfigurerequest.height+c->frameheight:c->pheight);
if((event.xconfigurerequest.value_mask&(CWX|CWY)) &&
c->state==WithdrawnState)
XMoveWindow(dpy, c->parent,
c->x=((event.xconfigurerequest.value_mask&CWX)?
event.xconfigurerequest.x:c->x),
c->y=((event.xconfigurerequest.value_mask&CWY)?
event.xconfigurerequest.y:c->y));
} else {
if(!XFindContext(dpy, event.xconfigurerequest.window,
screen_context, (XPointer *)&scr))
if((event.xconfigurerequest.y-=scr->y)<0)
event.xconfigurerequest.y=0;
XConfigureWindow(dpy, event.xconfigurerequest.window,
event.xconfigurerequest.value_mask,
(XWindowChanges *)&event.xconfigurerequest.x);
}
break;
case CirculateRequest:
if(XFindContext(dpy, event.xcirculaterequest.window, client_context, (XPointer*)&c))
if(event.xcirculaterequest.place==PlaceOnTop)
XRaiseWindow(dpy, event.xcirculaterequest.window);
else {
Client *c2;
Window r,p,*children;
unsigned int nchildren;
if(XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren)) {
int n;
for(n=0; n<nchildren; n++)
if((!XFindContext(dpy, children[n], client_context, (XPointer*)&c2)) &&
children[n]==c2->parent)
break;
if(n<nchildren) {
Window ws[2];
ws[0]=children[n];
ws[1]=event.xcirculaterequest.window;
XRestackWindows(dpy, ws, 2);
}
}
}
else
raiselowerclient(c, event.xcirculaterequest.place);
break;
case MapRequest:
if(XFindContext(dpy, event.xmaprequest.window, client_context, (XPointer*)&c)) {
if(!(scr=getscreenbyroot(event.xmaprequest.parent)))
scr = get_front_scr();
c=createclient(event.xmaprequest.window);
}
{
XWMHints *xwmh;
if(c->parent==c->scr->root && (xwmh=XGetWMHints(dpy, c->window))) {
if(c->state==WithdrawnState && (xwmh->flags&StateHint)
&& xwmh->initial_state==IconicState)
c->state=IconicState;
XFree(xwmh);
}
switch(c->state) {
case WithdrawnState:
if(c->parent == c->scr->root)
reparent(c);
case NormalState:
XMapWindow(dpy, c->window);
if (!c->fullscreen)
XMapRaised(dpy, c->parent);
setclientstate(c, NormalState);
break;
case IconicState:
if(c->parent == c->scr->root)
reparent(c);
if(!(c->icon))
createicon(c);
adjusticon(c->icon);
XMapWindow(dpy, c->icon->window);
if(c->icon->labelwidth)
XMapWindow(dpy, c->icon->labelwin);
c->icon->mapped=1;
setclientstate(c, IconicState);
break;
}
}
break;
case MapNotify:
if(prefs.focus == FOC_CLICKTOTYPE && c &&
event.xmap.window == c->parent && c->parent != c->scr->root &&
(!c->active)) {
if(activeclient) {
XGrabButton(dpy, Button1, AnyModifier, activeclient->parent,
True, ButtonPressMask, GrabModeSync, GrabModeAsync,
None, wm_curs);
activeclient->active=False;
redrawclient(activeclient);
}
c->active=True;
activeclient = c;
XUngrabButton(dpy, Button1, AnyModifier, c->parent);
redrawclient(c);
setfocus(c->window);
}
break;
case EnterNotify:
if(menuactive) {
scr=menuactive;
menubar_enter(event.xcrossing.window);
} else if(clickwindow && event.xcrossing.window == clickwindow)
clickenter();
else if(c) {
if((!c->active) && (c->state==NormalState) &&
prefs.focus!=FOC_CLICKTOTYPE) {
if(activeclient) {
activeclient->active=False;
redrawclient(activeclient);
}
setfocus(c->window);
c->active=True;
activeclient = c;
redrawclient(c);
if(prefs.autoraise && c->parent!=c->scr->root)
XRaiseWindow(dpy, c->parent);
}
if(event.xcrossing.window==c->window)
instcmap(c->colormap);
}
break;
case LeaveNotify:
if(menuactive) {
scr=menuactive;
menubar_leave(event.xcrossing.window);
} else if(clickwindow && event.xcrossing.window == clickwindow)
clickleave();
else if(c) {
if(c->active && event.xcrossing.window==c->parent &&
event.xcrossing.detail!=NotifyInferior &&
prefs.focus == FOC_FOLLOWMOUSE) {
if(!menuactive)
setfocus(None);
c->active=False;
activeclient = NULL;
instcmap(None);
redrawclient(c);
} else if(event.xcrossing.window==c->window &&
event.xcrossing.detail!=NotifyInferior &&
event.xcrossing.mode==NotifyNormal)
instcmap(None);
}
break;
case ButtonPress:
if(!rubberclient && !boundingscr && clickwindow==None &&
!dragiconlist && event.xbutton.button==Button1 &&
!dragscreen && !menuactive)
if(c) {
if((!c->active) && prefs.focus==FOC_CLICKTOTYPE &&
(c->state==NormalState)) {
if(activeclient) {
activeclient->active=False;
redrawclient(activeclient);
XGrabButton(dpy, Button1, AnyModifier, activeclient->parent,
True, ButtonPressMask, GrabModeSync, GrabModeAsync,
None, wm_curs);
}
setfocus(c->window);
c->active=True;
activeclient = c;
redrawclient(c);
XUngrabButton(dpy, Button1, AnyModifier, c->parent);
if(prefs.autoraise && c->parent!=c->scr->root)
XRaiseWindow(dpy, c->parent);
}
if(event.xbutton.window!=c->depth &&
event.xbutton.window!=c->window) {
if(c==doubleclient && (event.xbutton.time-last_double)<
dblClickTime) {
XRaiseWindow(dpy, c->parent);
} else {
doubleclient=c;
last_double=event.xbutton.time;
}
}
if(event.xbutton.window==c->drag) {
forcemoving=(prefs.forcemove==FM_ALWAYS) ||
(event.xbutton.state & ShiftMask);
startdragging(c, &event);
} else if(event.xbutton.window==c->resize)
startresizing(c, &event);
else if(event.xbutton.window==c->window ||
event.xbutton.window==c->parent)
;
else
gadgetclicked(c, event.xbutton.window, &event);
} else if(i && event.xbutton.window==i->window) {
abortfocus();
if(i->selected && (event.xbutton.time-last_icon_click)<dblClickTime) {
do_icon_double_click(i->scr);
} else {
if(!(event.xbutton.state & ShiftMask))
deselect_all_icons(i->scr);
last_icon_click=event.xbutton.time;
selecticon(i);
starticondragging(i->scr, &event);
}
} else if(scr&&event.xbutton.window==scr->menubardepth) {
clickwindow=scr->menubardepth;
mbdclick=mbdscr=scr;
redrawmenubar(scr, scr->menubardepth);
} else if(scr&&event.xbutton.window==scr->menubar &&
scr->back!=scr->root) {
startscreendragging(scr, &event);
}
else if(scr&&scr->back==event.xbutton.window) {
abortfocus();
startbounding(scr, scr->back, &event);
} else ;
else if(event.xbutton.button==3) {
if(rubberclient || boundingscr)
abortrubber();
else if(scr&&(scr==mbdscr)&&clickwindow==scr->menubardepth) {
mbdclick=NULL;
clickwindow=None;
redrawmenubar(scr, scr->menubardepth);
} else if(clickclient)
gadgetaborted(clickclient);
else if(dragiconlist)
aborticondragging();
else if(dragscreen)
abortscreendragging();
else if(scr&&!menuactive) {
menu_on();
menuactive=scr;
}
}
if(prefs.focus == FOC_CLICKTOTYPE && !menuactive) {
XSync(dpy,0);
XAllowEvents(dpy,ReplayPointer,CurrentTime);
XSync(dpy,0);
}
break;
case ButtonRelease:
if(event.xbutton.button==Button1) {
if(rubberclient) {
if(dragclient) enddragging();
else if(resizeclient) endresizing();
} else if(boundingwin)
endbounding(&event);
else if(clickclient)
gadgetunclicked(clickclient, &event);
else if(dragiconlist) {
endicondragging(&event);
} else if(dragscreen)
endscreendragging();
else if((scr=mbdscr)&& clickwindow==scr->menubardepth) {
if(mbdclick) {
mbdclick=NULL;
redrawmenubar(scr, scr->menubardepth);
screentoback();
}
clickwindow=None;
}
} else if(event.xbutton.button==Button3 && (scr=menuactive)) {
menu_off();
menuactive=NULL;
}
break;
case MotionNotify:
do {
motionx=event.xmotion.x_root;
motiony=event.xmotion.y_root;
} while(XCheckTypedEvent(dpy, MotionNotify, &event));
if(dragclient) {
scr=dragclient->scr;
if(!prefs.opaquemove)
drawrubber();
rubberx=motionx-rubberx0;
rubbery=motiony-rubbery0;
if(!forcemoving) {
if(prefs.forcemove==FM_AUTO &&
(rubberx+rubberw-scr->width>(rubberw>>2) ||
rubbery+rubberh-scr->height>(rubberh>>2) ||
-rubberx>(rubberw>>2)||
-rubbery>(rubberh>>2)))
forcemoving=1;
else {
if(rubberx+rubberw>scr->width)
rubberx=scr->width-rubberw;
if(rubbery+rubberh>scr->height)
rubbery=scr->height-rubberh;
if(rubberx<0)
rubberx=0;
if(rubbery<0)
rubbery=0;
}
}
if(prefs.opaquemove) {
if(rubbery<=-(c->scr->bh))
rubbery=1-(c->scr->bh);
XMoveWindow(dpy, c->parent, c->x=rubberx, c->y=rubbery);
} else {
drawrubber();
}
} else if(resizeclient) {
int rw=rubberw, rh=rubberh;
scr=resizeclient->scr;
if(resizeclient->sizehints->width_inc) {
rw=motionx-rubberx0-resizeclient->sizehints->base_width-
resizeclient->framewidth;
rw-=rw%resizeclient->sizehints->width_inc;
rw+=resizeclient->sizehints->base_width;
if(rw>resizeclient->sizehints->max_width)
rw=resizeclient->sizehints->max_width;
if(rw<resizeclient->sizehints->min_width)
rw=resizeclient->sizehints->min_width;
rw+=resizeclient->framewidth;
}
if(resizeclient->sizehints->height_inc) {
rh=motiony-rubbery0-resizeclient->sizehints->base_height-
resizeclient->frameheight;
rh-=rh%resizeclient->sizehints->height_inc;
rh+=resizeclient->sizehints->base_height;
if(rh>resizeclient->sizehints->max_height)
rh=resizeclient->sizehints->max_height;
if(rh<resizeclient->sizehints->min_height)
rh=resizeclient->sizehints->min_height;
rh+=resizeclient->frameheight;
}
if(rw!=rubberw || rh!=rubberh) {
if(prefs.opaqueresize) {
Client *c = resizeclient;
extern void resizeclientwindow(Client *c, int, int);
rubberw=rw;
rubberh=rh;
resizeclientwindow(c, rubberw, rubberh);
} else {
drawrubber();
rubberw=rw;
rubberh=rh;
drawrubber();
}
}
} else if(dragiconlist) {
int i;
for(i=0; i<numdragicons; i++)
XMoveWindow(dpy, dragiconlist[i].w,
dragiconlist[i].x+=motionx-rubberx0,
dragiconlist[i].y+=motiony-rubbery0);
rubberx0=motionx;
rubbery0=motiony;
} else if(dragscreen) {
rubbery=motiony-rubbery0;
if(rubbery<0)
rubbery=0;
else if(rubbery>=dragscreen->height)
rubbery=dragscreen->height-1;
XMoveWindow(dpy, dragscreen->back, -dragscreen->bw,
(dragscreen->y=rubbery)-dragscreen->bw);
} else if(boundingscr) {
drawrubber();
rubberw=motionx-rubberx0;
rubberh=motiony-rubbery0;
drawrubber();
}
break;
case KeyPress:
if(!dispatch_event_to_broker(&event, KeyPressMask, modules))
internal_broker(&event);
break;
case KeyRelease:
if(!dispatch_event_to_broker(&event, KeyPressMask, modules))
internal_broker(&event);
break;
case MappingNotify:
if(!dispatch_event_to_broker(&event, 0, modules))
internal_broker(&event);
break;
case PropertyNotify:
if(event.xproperty.atom != None && c &&
event.xproperty.window==c->window &&
XGetGeometry(dpy, c->window, &dummy_root, &dummy_x, &dummy_y,
&dummy_w, &dummy_h, &dummy_bw, &dummy_d))
propertychange(c, event.xproperty.atom);
break;
case FocusOut:
/* Ignore */
break;
case FocusIn:
if(event.xfocus.detail == NotifyDetailNone &&
prefs.focus == FOC_CLICKTOTYPE &&
(scr = getscreenbyroot(event.xfocus.window))) {
Window w;
int rt;
XGetInputFocus(dpy, &w, &rt);
if(w == None)
setfocus(scr->inputbox);
}
break;
default:
#ifdef HAVE_XSHAPE
if(shape_extn && event.type == shape_event_base + ShapeNotify) {
XShapeEvent *s = (XShapeEvent *) &event;
if(c && s->kind == ShapeBounding) {
c->shaped = s->shaped;
reshape_frame(c);
}
break;
}
#endif
fprintf(stderr, "%s: got unexpected event type %d.\n",
progname, event.type);
}
}
if(signalled) break;
rfds = master_fd_set;
t.tv_sec = t.tv_usec = 0;
if (select(max_fd, &rfds, NULL, NULL, &t) > 0) {
handle_module_input(&rfds);
if(FD_ISSET(x_fd, &rfds))
XPeekEvent(dpy, &event);
continue;
}
if(signalled) break;
XFlush(dpy);
rfds = master_fd_set;
if(eventlist)
fill_in_call_out(&t);
if(select(max_fd, &rfds, NULL, NULL, (eventlist? &t:NULL))<0) {
if (errno != EINTR) {
perror("select");
break;
}
} else {
call_call_out();
handle_module_input(&rfds);
if(FD_ISSET(x_fd, &rfds))
XPeekEvent(dpy, &event);
}
}
if(prefs.titlebarclock)
remove_call_out(update_clock, NULL);
if(signalled)
fprintf(stderr, "%s: exiting on signal\n", progname);
exit(signalled? 0:1);
}