xenocara/app/wm2/Events.C

661 lines
13 KiB
C

#include "Manager.h"
#include "Client.h"
int WindowManager::loop()
{
XEvent ev;
m_looping = True;
while (m_looping) {
nextEvent(&ev);
m_currentTime = CurrentTime;
switch (ev.type) {
case ButtonPress:
eventButton(&ev.xbutton);
break;
case ButtonRelease:
break;
case MapRequest:
eventMapRequest(&ev.xmaprequest);
break;
case ConfigureRequest:
eventConfigureRequest(&ev.xconfigurerequest);
break;
case UnmapNotify:
eventUnmap(&ev.xunmap);
break;
case CreateNotify:
eventCreate(&ev.xcreatewindow);
break;
case DestroyNotify:
eventDestroy(&ev.xdestroywindow);
break;
case ClientMessage:
eventClient(&ev.xclient);
break;
case ColormapNotify:
eventColormap(&ev.xcolormap);
break;
case PropertyNotify:
eventProperty(&ev.xproperty);
break;
case SelectionClear:
fprintf(stderr, "wm2: SelectionClear (this should not happen)\n");
break;
case SelectionNotify:
fprintf(stderr, "wm2: SelectionNotify (this should not happen)\n");
break;
case SelectionRequest:
fprintf(stderr, "wm2: SelectionRequest (this should not happen)\n");
break;
case EnterNotify:
case LeaveNotify:
eventEnter(&ev.xcrossing);
break;
case ReparentNotify:
eventReparent(&ev.xreparent);
break;
case FocusIn:
eventFocusIn(&ev.xfocus);
break;
case Expose: // might be wm tab
eventExposure(&ev.xexpose);
break;
case MotionNotify:
if (CONFIG_AUTO_RAISE && m_focusChanging) {
if (!m_focusPointerMoved) m_focusPointerMoved = True;
else m_focusPointerNowStill = False;
}
break;
case FocusOut:
case ConfigureNotify:
case MapNotify:
case MappingNotify:
break;
default:
// if (ev.type == m_shapeEvent) eventShapeNotify((XShapeEvent *)&ev);
if (ev.type == m_shapeEvent) {
fprintf(stderr, "wm2: shaped windows are not supported\n");
} else {
fprintf(stderr, "wm2: unsupported event type %d\n", ev.type);
}
break;
}
}
release();
return m_returnCode;
}
void WindowManager::nextEvent(XEvent *e)
{
int fd;
fd_set rfds;
struct timeval t;
int r;
if (!m_signalled) {
waiting:
if (QLength(m_display) > 0) {
XNextEvent(m_display, e);
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;
#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) == 1) {
XNextEvent(m_display, e);
return;
}
XFlush(m_display);
FD_SET(fd, &rfds);
t.tv_sec = 0; t.tv_usec = 20000;
if ((r = select(fd + 1, &rfds, NULL, NULL,
(m_focusChanging) ? &t :
(struct timeval *)NULL)) == 1) {
XNextEvent(m_display, e);
return;
}
if (CONFIG_AUTO_RAISE && m_focusChanging) { // timeout on select
checkDelaysForFocus();
}
if (r == 0) goto waiting;
if (errno != EINTR || !m_signalled) {
perror("wm2: select failed");
m_looping = False;
}
}
fprintf(stderr, "wm2: signal caught, exiting\n");
m_looping = False;
m_returnCode = 0;
}
void WindowManager::checkDelaysForFocus()
{
if (!CONFIG_AUTO_RAISE) return;
int t = timestamp(True);
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();
} else m_focusPointerNowStill = True; // until proven false
}
} else {
if (t < m_focusTimestamp ||
t - m_focusTimestamp > CONFIG_AUTO_RAISE_DELAY) {
m_focusCandidate->focusIfAppropriate(True);
// if (m_focusCandidate->isNormal()) m_focusCandidate->mapRaised();
// stopConsideringFocus();
}
}
}
void WindowManager::considerFocusChange(Client *c, Window w, Time timestamp)
{
if (!CONFIG_AUTO_RAISE) return;
if (m_focusChanging) {
stopConsideringFocus();
}
m_focusChanging = True;
m_focusTimestamp = timestamp;
m_focusCandidate = c;
m_focusCandidateWindow = w;
// 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);
}
void WindowManager::stopConsideringFocus()
{
if (!CONFIG_AUTO_RAISE) return;
m_focusChanging = False;
if (m_focusChanging && m_focusCandidateWindow) {
m_focusCandidate->selectOnMotion(m_focusCandidateWindow, False);
}
}
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;
unsigned int k;
XQueryPointer(display(), root(), &rw, &cw, &rx, &ry, &cx, &cy, &k);
if (hasWindow(cw)) {
activate();
mapRaised();
m_windowManager->stopConsideringFocus();
}
}
void WindowManager::eventConfigureRequest(XConfigureRequestEvent *e)
{
XWindowChanges wc;
Client *c = windowToClient(e->window);
e->value_mask &= ~CWSibling;
if (c) c->eventConfigureRequest(e);
else {
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;
XConfigureWindow(display(), e->window, e->value_mask, &wc);
}
}
void Client::eventConfigureRequest(XConfigureRequestEvent *e)
{
XWindowChanges wc;
Boolean raise = False;
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;
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);
sendConfigureNotify();
}
if (m_managed) {
wc.x = m_border->xIndent();
wc.y = m_border->yIndent();
} else {
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;
XConfigureWindow(display(), e->window, e->value_mask, &wc);
// 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);
if (m_lastPopTime > 0L &&
popTime > m_lastPopTime &&
popTime - m_lastPopTime < 2000) { // 2 pops in 2 seconds
m_stubborn = True;
m_lastPopTime = 0L;
fprintf(stderr, "wm2: client \"%s\" declared stubborn\n",
label());
} else {
m_lastPopTime = popTime;
}
mapRaised();
}
} else {
mapRaised();
if (CONFIG_CLICK_TO_FOCUS) activate();
}
}
}
void WindowManager::eventMapRequest(XMapRequestEvent *e)
{
Client *c = windowToClient(e->window);
// some stuff for multi-screen fuckups here, omitted
if (c) c->eventMapRequest(e);
else {
fprintf(stderr, "wm2: bad map request for window %lx\n", e->window);
}
}
void Client::eventMapRequest(XMapRequestEvent *)
{
switch(m_state) {
case WithdrawnState:
if (parent() == root()) {
manage(False);
return;
}
m_border->reparent();
if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus();
XAddToSaveSet(display(), m_window);
XMapWindow(display(), m_window);
mapRaised();
setState(NormalState);
if (CONFIG_CLICK_TO_FOCUS) activate();
break;
case NormalState:
XMapWindow(display(), m_window);
mapRaised();
if (CONFIG_CLICK_TO_FOCUS) activate();
break;
case IconicState:
if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus();
unhide(True);
break;
}
}
void WindowManager::eventUnmap(XUnmapEvent *e)
{
Client *c = windowToClient(e->window);
if (c) c->eventUnmap(e);
}
void Client::eventUnmap(XUnmapEvent *e)
{
switch (m_state) {
case IconicState:
if (e->send_event) {
unhide(False);
withdraw();
}
break;
case NormalState:
if (isActive()) m_windowManager->clearFocus();
if (!m_reparenting) withdraw();
break;
}
m_reparenting = False;
m_stubborn = False;
}
void WindowManager::eventCreate(XCreateWindowEvent *e)
{
if (e->override_redirect) return;
Client *c = windowToClient(e->window, True);
}
void WindowManager::eventDestroy(XDestroyWindowEvent *e)
{
Client *c = windowToClient(e->window);
if (c) {
if (CONFIG_AUTO_RAISE && m_focusChanging && c == m_focusCandidate) {
m_focusChanging = False;
}
for (int i = m_clients.count()-1; i >= 0; --i) {
if (m_clients.item(i) == c) {
m_clients.remove(i);
break;
}
}
c->release();
ignoreBadWindowErrors = True;
XSync(display(), False);
ignoreBadWindowErrors = False;
}
}
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;
}
}
fprintf(stderr, "wm2: 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;
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);
}
}
}
}
void Client::eventColormap(XColormapEvent *e)
{
if (e->window == m_window || e->window == parent()) {
m_colormap = e->colormap;
if (isActive()) installColormap();
} else {
for (int i = 0; i < m_colormapWinCount; ++i) {
if (m_colormapWindows[i] == e->window) {
m_windowColormaps[i] = e->colormap;
if (isActive()) installColormap();
return;
}
}
}
}
void WindowManager::eventProperty(XPropertyEvent *e)
{
Client *c = windowToClient(e->window);
if (c) c->eventProperty(e);
}
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);
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:
getTransient();
return;
}
if (a == Atoms::wm_colormaps) {
getColormaps();
if (isActive()) installColormap();
}
}
void WindowManager::eventReparent(XReparentEvent *e)
{
if (e->override_redirect) return;
(void)windowToClient(e->window, True); // create if absent
// odd screen complications, omitted
}
void WindowManager::eventEnter(XCrossingEvent *e)
{
if (e->type != EnterNotify) return;
while (XCheckMaskEvent(m_display, EnterWindowMask, (XEvent *)e));
m_currentTime = e->time; // not CurrentTime
Client *c = windowToClient(e->window);
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() &&
!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;
}
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();
}
}
}
}
Boolean Client::coordsInHole(int x, int y) // relative to parent
{
return m_border->coordsInHole(x, y);
}
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;
Client *c = windowToClient(e->window);
if (c) c->eventFocusIn(e);
}
void Client::eventFocusIn(XFocusInEvent *e)
{
if (m_window == e->window && !isActive()) {
activate();
mapRaised();
}
}
void WindowManager::eventExposure(XExposeEvent *e)
{
if (e->count != 0) return;
Client *c = windowToClient(e->window);
if (c) c->eventExposure(e);
}
void Client::eventExposure(XExposeEvent *e)
{
if (m_border->hasWindow(e->window)) {
m_border->expose(e);
}
}