Events.C
#include "Manager.h"
#include "Client.h"
int WindowManager::loop()
{
XEvent ev;
m_looping = True;
10
while (m_looping) {
nextEvent(&ev);
dispatchEvent(&ev);
}
release();
return m_returnCode;
}
20
void WindowManager::dispatchEvent(XEvent *ev)
{
m_currentTime = CurrentTime;
switch (ev->type) {
case ButtonPress:
eventButton(&ev->xbutton);
break;
30
case ButtonRelease:
break;
case KeyPress:
eventKeyPress(&ev->xkey); // in Buttons.C
break;
case KeyRelease:
eventKeyRelease(&ev->xkey); // in Buttons.C
40 break;
case MapRequest:
eventMapRequest(&ev->xmaprequest);
break;
case ConfigureRequest:
eventConfigureRequest(&ev->xconfigurerequest);
break;
50 case UnmapNotify:
eventUnmap(&ev->xunmap);
break;
case CreateNotify:
// eventCreate(&ev->xcreatewindow);
break;
case DestroyNotify:
eventDestroy(&ev->xdestroywindow);
60 break;
case ClientMessage:
eventClient(&ev->xclient);
break;
case ColormapNotify:
eventColormap(&ev->xcolormap);
break;
70 case PropertyNotify:
eventProperty(&ev->xproperty);
break;
case SelectionClear:
fprintf(stderr, "wmx: SelectionClear (this should not happen)\n");
break;
case SelectionNotify:
fprintf(stderr, "wmx: SelectionNotify (this should not happen)\n");
80 break;
case SelectionRequest:
fprintf(stderr, "wmx: SelectionRequest (this should not happen)\n");
break;
case EnterNotify:
case LeaveNotify:
eventEnter(&ev->xcrossing);
break;
90
case ReparentNotify:
// eventReparent(&ev->xreparent);
break;
case FocusIn:
eventFocusIn(&ev->xfocus);
break;
case Expose: // might be wm tab
100 eventExposure(&ev->xexpose);
break;
case MotionNotify:
if (CONFIG_AUTO_RAISE && m_focusChanging) {
if (!m_focusPointerMoved) m_focusPointerMoved = True;
else m_focusPointerNowStill = False;
}
break;
110 case FocusOut:
case ConfigureNotify:
case MapNotify:
case MappingNotify:
case NoExpose:
break;
default:
// if (ev->type == m_shapeEvent) eventShapeNotify((XShapeEvent *)ev);
if (ev->type == m_shapeEvent) {
120 fprintf(stderr, "wmx: shaped windows are not supported\n");
} else {
fprintf(stderr, "wmx: unsupported event type %d\n", ev->type);
}
break;
}
}
void WindowManager::nextEvent(XEvent *e)
130 {
int fd;
fd_set rfds;
struct timeval t;
int r;
if (!m_signalled) {
waiting:
140 if (m_channelChangeTime > 0) {
Time t = timestamp(True);
//!!! if (t < m_channelChangeTime || t - m_channelChangeTime > 1000) {
if (t >= m_channelChangeTime) {
instateChannel();
}
}
if (QLength(m_display) > 0) {
XNextEvent(m_display, e);
150 return;
}
fd = ConnectionNumber(m_display);
memset((void *)&rfds, 0, sizeof(fd_set)); // SGI's FD_ZERO is fucked
FD_SET(fd, &rfds);
t.tv_sec = t.tv_usec = 0;
#if CONFIG_USE_SESSION_MANAGER != False
if (m_smFD >= 0) FD_SET(m_smFD, &rfds);
160 #endif
#ifdef hpux
#define select(a,b,c,d,e) select((a),(int *)(b),(c),(d),(e))
#endif
if (select(fd + 1, &rfds, NULL, NULL, &t) > 0) {
//!!! This two-select structure is getting disgusting;
// a marginal improvement would be to put this body in
170 // another function, but it'd be better to go back and
// think hard about why the code is like this at all
#if CONFIG_USE_SESSION_MANAGER != False
if (m_smFD >= 0 && FD_ISSET(m_smFD, &rfds)) {
Bool rep;
if (IceProcessMessages(m_smIceConnection, NULL, &rep)
== IceProcessMessagesIOError) {
SmcCloseConnection(m_smConnection, 0, NULL);
m_smIceConnection = NULL;
180 m_smConnection = NULL;
}
goto waiting;
}
#endif
if (FD_ISSET(fd, &rfds)) {
XNextEvent(m_display, e);
return;
}
190 // XNextEvent(m_display, e);
// return;
}
XFlush(m_display);
FD_SET(fd, &rfds);
t.tv_sec = 0; t.tv_usec = 20000;
#if CONFIG_USE_SESSION_MANAGER != False
if (m_smFD >= 0) FD_SET(m_smFD, &rfds);
200 #endif
if ((r = select(fd + 1, &rfds, NULL, NULL,
(m_channelChangeTime > 0 || m_focusChanging) ? &t :
(struct timeval *)NULL)) > 0) {
#if CONFIG_USE_SESSION_MANAGER != False
if (m_smFD >= 0 && FD_ISSET(m_smFD, &rfds)) {
Bool rep;
if (IceProcessMessages(m_smIceConnection, NULL, &rep)
210 == IceProcessMessagesIOError) {
SmcCloseConnection(m_smConnection, 0, NULL);
m_smIceConnection = NULL;
m_smConnection = NULL;
}
goto waiting;
}
#endif
if (FD_ISSET(fd, &rfds)) {
XNextEvent(m_display, e);
220 return;
}
// return;
}
if (CONFIG_AUTO_RAISE && m_focusChanging) { // timeout on select
checkDelaysForFocus();
}
230 if (r == 0) goto waiting;
if (errno != EINTR || !m_signalled) {
perror("wmx: select failed");
m_looping = False;
}
}
fprintf(stderr, "wmx: signal caught, exiting\n");
ignoreBadWindowErrors = True;
240 m_looping = False;
m_returnCode = 0;
}
void WindowManager::checkDelaysForFocus()
{
if (!CONFIG_AUTO_RAISE) return;
int t = timestamp(True);
250
if (m_focusPointerMoved) { // only raise when pointer stops
if (t < m_focusTimestamp ||
t - m_focusTimestamp > CONFIG_POINTER_STOPPED_DELAY) {
if (m_focusPointerNowStill) {
m_focusCandidate->focusIfAppropriate(True);
// if (m_focusCandidate->isNormal()) m_focusCandidate->mapRaised();
// stopConsideringFocus();
260
} else m_focusPointerNowStill = True; // until proven false
}
} else {
if (t < m_focusTimestamp ||
t - m_focusTimestamp > CONFIG_AUTO_RAISE_DELAY) {
m_focusCandidate->focusIfAppropriate(True);
270 // if (m_focusCandidate->isNormal()) m_focusCandidate->mapRaised();
// stopConsideringFocus();
}
}
}
void WindowManager::considerFocusChange(Client *c, Window w, Time timestamp)
{
if (!CONFIG_AUTO_RAISE) return;
280
if (m_focusChanging) {
stopConsideringFocus();
}
m_focusChanging = True;
m_focusTimestamp = timestamp;
m_focusCandidate = c;
m_focusCandidateWindow = w;
290 // we need to wait until at least one pointer-motion event has
// come in before we can start to wonder if the pointer's
// stopped moving -- otherwise we'll be caught out by all the
// windows for which we don't get motion events at all
m_focusPointerMoved = False;
m_focusPointerNowStill = False;
m_focusCandidate->selectOnMotion(m_focusCandidateWindow, True);
}
300
void WindowManager::stopConsideringFocus()
{
if (!CONFIG_AUTO_RAISE) return;
m_focusChanging = False;
if (m_focusChanging && m_focusCandidateWindow) {
m_focusCandidate->selectOnMotion(m_focusCandidateWindow, False);
}
}
310
void Client::focusIfAppropriate(Boolean ifActive)
{
if (!CONFIG_AUTO_RAISE) return;
if (!m_managed || !isNormal()) return;
if (!ifActive && isActive()) return;
Window rw, cw;
int rx, ry, cx, cy;
320 unsigned int k;
XQueryPointer(display(), root(), &rw, &cw, &rx, &ry, &cx, &cy, &k);
if (hasWindow(cw)) {
activate();
mapRaised();
m_windowManager->stopConsideringFocus();
}
}
330
void WindowManager::eventConfigureRequest(XConfigureRequestEvent *e)
{
XWindowChanges wc;
Client *c = windowToClient(e->window);
e->value_mask &= ~CWSibling;
if (c) c->eventConfigureRequest(e);
else {
340
wc.x = e->x;
wc.y = e->y;
wc.width = e->width;
wc.height = e->height;
wc.border_width = 0;
wc.sibling = None;
wc.stack_mode = Above;
e->value_mask &= ~CWStackMode;
e->value_mask |= CWBorderWidth;
350
XConfigureWindow(display(), e->window, e->value_mask, &wc);
}
}
void Client::eventConfigureRequest(XConfigureRequestEvent *e)
{
XWindowChanges wc;
Boolean raise = False;
360
e->value_mask &= ~CWSibling;
gravitate(True);
if (e->value_mask & CWX) m_x = e->x;
if (e->value_mask & CWY) m_y = e->y;
if (e->value_mask & CWWidth) m_w = e->width;
if (e->value_mask & CWHeight) m_h = e->height;
if (e->value_mask & CWBorderWidth) m_bw = e->border_width;
370
gravitate(False);
if (e->value_mask & CWStackMode) {
if (e->detail == Above) raise = True;
e->value_mask &= ~CWStackMode;
}
if (parent() != root() && m_window == e->window) {
m_border->configure(m_x, m_y, m_w, m_h, e->value_mask, e->detail);
380 sendConfigureNotify();
}
if (m_managed) {
wc.x = m_border->xIndent();
wc.y = m_border->yIndent();
} else {
wc.x = e->x;
wc.y = e->y;
}
390
wc.width = e->width;
wc.height = e->height;
wc.border_width = 0;
wc.sibling = None;
wc.stack_mode = Above;
e->value_mask &= ~CWStackMode;
e->value_mask |= CWBorderWidth;
XConfigureWindow(display(), e->window, e->value_mask, &wc);
400
// if parent==root, it's not managed yet -- & it'll be raised when it is
if (raise && parent() != root()) {
if (CONFIG_AUTO_RAISE) {
m_windowManager->stopConsideringFocus();
if (!m_stubborn) { // outstubborn stubborn windows
Time popTime = windowManager()->timestamp(True);
410
if (m_lastPopTime > 0L &&
popTime > m_lastPopTime &&
popTime - m_lastPopTime < 2000) { // 2 pops in 2 seconds
m_stubborn = True;
m_lastPopTime = 0L;
fprintf(stderr, "wmx: client \"%s\" declared stubborn\n",
label());
420 } else {
m_lastPopTime = popTime;
}
mapRaised();
}
} else {
mapRaised();
if (CONFIG_CLICK_TO_FOCUS) activate();
}
430 }
}
void WindowManager::eventMapRequest(XMapRequestEvent *e)
{
Client *c = windowToClient(e->window);
// JG
if (!c) {
440 // fprintf(stderr, "wm2: start managing window %lx\n", e->window);
c = windowToClient(e->window, True);
c->eventMapRequest(e);
c->sendConfigureNotify();
} else {
c->eventMapRequest(e);
}
// some stuff for multi-screen fuckups here, omitted
450 // if (c) c->eventMapRequest(e);
// else {
// fprintf(stderr, "wmx: bad map request for window %lx\n", e->window);
// }
}
void Client::eventMapRequest(XMapRequestEvent *)
{
switch(m_state) {
460
case WithdrawnState:
if (parent() == root()) {
manage(False);
return;
}
m_border->reparent();
if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus();
470 XAddToSaveSet(display(), m_window);
if (m_channel == windowManager()->channel()) {
XMapWindow(display(), m_window);
}
mapRaised();
setState(NormalState);
if (CONFIG_CLICK_TO_FOCUS) activate();
break;
case NormalState:
480 if (m_channel == windowManager()->channel()) {
XMapWindow(display(), m_window);
}
mapRaised();
if (CONFIG_CLICK_TO_FOCUS) activate();
break;
case IconicState:
if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus();
unhide(True);
490 break;
}
}
void WindowManager::eventUnmap(XUnmapEvent *e)
{
Client *c = windowToClient(e->window);
if (c) c->eventUnmap(e);
}
500
void Client::eventUnmap(XUnmapEvent *e)
{
if (e->window != m_window) return;
if (m_unmappedForChannel) {
setState(NormalState);
return;
}
510
switch (m_state) {
case IconicState:
if (e->send_event) {
unhide(False);
withdraw();
}
break;
520 case NormalState:
if (isActive()) m_windowManager->clearFocus();
if (!m_reparenting) withdraw();
break;
}
// When unmapped transient window. Should change a focus to not
// transient window.
if (transientFor()) {
Client* c = windowManager()->windowToClient(transientFor());
530 if (c && !c->isActive() && !CONFIG_CLICK_TO_FOCUS) {
c->activate();
if (CONFIG_AUTO_RAISE) {
c->windowManager()->considerFocusChange(this, c->m_window, windowManager()->timestamp(False));
} else if (CONFIG_RAISE_ON_FOCUS) {
c->mapRaised();
}
}
}
540 m_reparenting = False;
m_stubborn = False;
}
void WindowManager::eventCreate(XCreateWindowEvent *e)
{
// not currently used! windows created on first MapRequest instead
// if (e->override_redirect) return;
// Client *c = windowToClient(e->window, True);
550 }
void WindowManager::eventDestroy(XDestroyWindowEvent *e)
{
Client *c = windowToClient(e->window);
if (c) {
if (CONFIG_AUTO_RAISE && m_focusChanging && c == m_focusCandidate) {
560 m_focusChanging = False;
}
for (int i = m_clients.count()-1; i >= 0; --i) {
if (m_clients.item(i) == c) {
m_clients.remove(i);
break;
}
}
570 checkChannel(c->channel());
c->release();
ignoreBadWindowErrors = True;
XSync(display(), False);
ignoreBadWindowErrors = False;
}
}
580 void WindowManager::eventClient(XClientMessageEvent *e)
{
Client *c = windowToClient(e->window);
if (e->message_type == Atoms::wm_changeState) {
if (c && e->format == 32 && e->data.l[0] == IconicState && c != 0) {
if (c->isNormal()) c->hide();
return;
}
}
590
fprintf(stderr, "wmx: unexpected XClientMessageEvent, type 0x%lx, "
"window 0x%lx\n", e->message_type, e->window);
}
void WindowManager::eventColormap(XColormapEvent *e)
{
Client *c = windowToClient(e->window);
int i;
600
if (e->c_new) { // this field is called "new" in the old C++-unaware Xlib
if (c) c->eventColormap(e);
else {
for (i = 0; i < m_clients.count(); ++i) {
m_clients.item(i)->eventColormap(e);
}
}
}
610 }
void Client::eventColormap(XColormapEvent *e)
{
if (e->window == m_window || e->window == parent()) {
m_colormap = e->colormap;
if (isActive()) installColormap();
620 } else {
for (int i = 0; i < m_colormapWinCount; ++i) {
if (m_colormapWindows[i] == e->window) {
m_windowColormaps[i] = e->colormap;
if (isActive()) installColormap();
return;
}
}
}
630 }
void WindowManager::eventProperty(XPropertyEvent *e)
{
Client *c = windowToClient(e->window);
if (c) c->eventProperty(e);
}
640 void Client::eventProperty(XPropertyEvent *e)
{
Atom a = e->atom;
Boolean shouldDelete = (e->state == PropertyDelete);
switch (a) {
case XA_WM_ICON_NAME:
if (m_iconName) XFree((char *)m_iconName);
m_iconName = shouldDelete ? 0 : getProperty(a);
650 if (setLabel()) rename();
return;
case XA_WM_NAME:
if (m_name) XFree((char *)m_name);
m_name = shouldDelete ? 0 : getProperty(a);
if (setLabel()) rename();
return;
case XA_WM_TRANSIENT_FOR:
660 getTransient();
return;
}
if (a == Atoms::wm_colormaps) {
getColormaps();
if (isActive()) installColormap();
}
}
670
void WindowManager::eventReparent(XReparentEvent *e)
{
// not currently used! map events used instead, only
// if (e->override_redirect) return;
// (void)windowToClient(e->window, True); // create if absent
// odd screen complications, omitted
}
680
void WindowManager::eventEnter(XCrossingEvent *e)
{
// quick hack for multi-screen stuff; although it still only
// manages one screen, it will now allow focus on others.
// thanks to Johan Danielsson
if (e->type != EnterNotify) {
if (e->same_screen == 0) {
if (m_activeClient) m_activeClient->deactivate();
690 m_activeClient = 0;
XSetInputFocus(m_display, PointerRoot, None, timestamp(False));
}
return;
}
while (XCheckMaskEvent(m_display, EnterWindowMask, (XEvent *)e));
m_currentTime = e->time; // not CurrentTime
Client *c = windowToClient(e->window);
700 if (c) c->eventEnter(e);
}
void Client::eventEnter(XCrossingEvent *e)
{
// first, big checks so as not to allow focus to change "through"
// the hole in the tab
if (!isActive() && activeClient() && activeClient()->isNormal() &&
710 !activeClient()->isTransient()) {
int x, y;
Window c;
XTranslateCoordinates
(display(), activeClient()->parent(), e->window, 0, 0, &x, &y, &c);
if (activeClient()->coordsInHole(e->x - x, e->y - y)) return;
}
720
if (e->type == EnterNotify) {
if (!isActive() && !CONFIG_CLICK_TO_FOCUS) {
activate();
if (CONFIG_AUTO_RAISE) {
windowManager()->considerFocusChange(this, m_window, e->time);
} else if (CONFIG_RAISE_ON_FOCUS) {
mapRaised();
}
}
730 }
}
Boolean Client::coordsInHole(int x, int y) // relative to parent
{
return m_border->coordsInHole(x, y);
}
740 Boolean Border::coordsInHole(int x, int y) // this is all a bit of a hack
{
return (x > 1 && x < m_tabWidth-1 &&
y > 1 && y < m_tabWidth-1);
}
void WindowManager::eventFocusIn(XFocusInEvent *e)
{
if (e->detail != NotifyNonlinearVirtual) return;
750 Client *c = windowToClient(e->window);
if (c) c->eventFocusIn(e);
}
void Client::eventFocusIn(XFocusInEvent *e)
{
if (m_window == e->window && !isActive()) {
activate();
760 mapRaised();
}
}
void WindowManager::eventExposure(XExposeEvent *e)
{
if (e->count != 0) return;
Client *c = windowToClient(e->window);
if (c) c->eventExposure(e);
770 }
void Client::eventExposure(XExposeEvent *e)
{
if (m_border->hasWindow(e->window)) {
m_border->expose(e);
}
}
780