Buttons.C
#include "Manager.h"
#include "Client.h"
#include "Menu.h"
#include <X11/keysym.h>
#include <sys/time.h>
void WindowManager::eventButton(XButtonEvent *e)
10 {
Client *c = windowToClient(e->window);
if (e->button == Button3 && m_channelChangeTime == 0) {
if (dConfig.rightCirculate())
circulate(e->window == e->root);
else if (dConfig.rightLower())
if (e->window != e->root) c->lower();
return;
}
20
if (e->window == e->root) {
if (e->button == Button1 && m_channelChangeTime == 0) {
ClientMenu menu(this, (XEvent *)e);
} else if (e->x > DisplayWidth(display(), screen()) -
CONFIG_CHANNEL_CLICK_SIZE &&
e->y < CONFIG_CHANNEL_CLICK_SIZE) {
30 if (e->button == Button2) {
if (m_channelChangeTime == 0) flipChannel(True, False, False,0);
else flipChannel(False, False, False, 0);
} else if (e->button == Button1 && m_channelChangeTime != 0) {
flipChannel(False, True, False, 0);
}
40 } else if (e->button == Button2 && m_channelChangeTime == 0) {
dConfig.scan();
CommandMenu menu(this, (XEvent *)e);
}
} else if (c) {
if (e->button == Button2 && CONFIG_CHANNEL_SURF) {
if (m_channelChangeTime == 0) flipChannel(True, False, False, 0);
else flipChannel(False, False, False, c);
50 return;
}
c->eventButton(e);
return;
}
}
void WindowManager::circulate(Boolean activeFirst)
60 {
Client *c = 0;
if (m_clients.count() == 0) return;
if (activeFirst) c = m_activeClient;
if (!c) {
int i, j;
if (!m_activeClient) i = -1;
70 else {
for (i = 0; i < m_clients.count(); ++i) {
if (m_clients.item(i)->channel() != channel()) continue;
if (m_clients.item(i) == m_activeClient) break;
}
if (i >= m_clients.count()-1) i = -1;
}
for (j = i + 1;
80 (!m_clients.item(j)->isNormal() ||
m_clients.item(j)->isTransient() ||
m_clients.item(j)->channel() != channel()); ++j) {
if (j >= m_clients.count() - 1) j = -1;
if (j == i) return; // no suitable clients
}
c = m_clients.item(j);
}
90
c->activateAndWarp();
}
void WindowManager::eventKeyPress(XKeyEvent *ev)
{
KeySym key = XKeycodeToKeysym(display(), ev->keycode, 0);
if (CONFIG_USE_KEYBOARD) {
100 Client *c = windowToClient(ev->window);
if (key == CONFIG_QUICKRAISE_KEY && c) {
if (isTop(c) && (CONFIG_QUICKRAISE_ALSO_LOWERS == True)) {
c->lower();
} else {
c->mapRaised();
}
110 } else if (key == CONFIG_QUICKHIDE_KEY && c) {
c->hide();
} else if (key == CONFIG_QUICKHEIGHT_KEY && c) {
if (c->isFullHeight()) {
c->normalHeight();
} else {
c->fullHeight();
}
120
} else if (ev->state & CONFIG_ALT_KEY_MASK) {
if (key >= XK_F1 && key <= XK_F12 &&
CONFIG_CHANNEL_SURF && CONFIG_USE_CHANNEL_KEYS) {
int channel = key - XK_F1 + 1;
if (channel == m_currentChannel) {
130 flipChannel(True, False, False, 0);
} else if (channel > 0 && channel <= m_channels) {
while (m_currentChannel != channel) {
if (m_currentChannel < channel) {
flipChannel(False, False, True, 0);
} else {
flipChannel(False, True, True, 0);
}
140 XSync(display(), False);
}
}
} else {
// These key names also appear in Client::manage(), so
// when adding a key it must be added in both places
switch (key) {
150
case CONFIG_FLIP_DOWN_KEY:
flipChannel(False, True, False, 0);
break;
case CONFIG_FLIP_UP_KEY:
flipChannel(False, False, False, 0);
break;
case CONFIG_CIRCULATE_KEY:
160 circulate(False);
break;
case CONFIG_HIDE_KEY:
if (c) c->hide();
break;
case CONFIG_DESTROY_KEY:
if (c) c->kill();
break;
170
case CONFIG_RAISE_KEY:
if (c) c->mapRaised();
break;
case CONFIG_LOWER_KEY:
if (c) c->lower();
break;
case CONFIG_FULLHEIGHT_KEY:
180 if (c) c->fullHeight();
break;
case CONFIG_NORMALHEIGHT_KEY:
if (c) c->normalHeight();
break;
case CONFIG_STICKY_KEY:
if (c) c->setSticky(!(c->isSticky()));
break;
190
case CONFIG_MENU_KEY:
if (CONFIG_WANT_KEYBOARD_MENU) {
ClientMenu menu(this, (XEvent *)ev);
break;
}
default:
return;
}
200 }
}
XSync(display(), False);
XUngrabKeyboard(display(), CurrentTime);
}
return;
}
210 void WindowManager::eventKeyRelease(XKeyEvent *ev)
{
return;
}
void Client::activateAndWarp()
{
mapRaised();
ensureVisible();
warpPointer();
220 activate();
}
void Client::eventButton(XButtonEvent *e)
{
if (e->type != ButtonPress) return;
Boolean wasTop = windowManager()->isTop(this);
230 mapRaised();
if (e->button == Button1) {
if (m_border->hasWindow(e->window)) {
m_border->eventButton(e);
}
}
if (CONFIG_RAISELOWER_ON_CLICK && wasTop && !doSomething)
240 lower();
if (!isNormal() || isActive() || e->send_event) return;
activate();
}
int WindowManager::attemptGrab(Window w, Window constrain, int mask, int t)
{
int status;
250 if (t == 0) t = timestamp(False);
status = XGrabPointer(display(), w, False, mask, GrabModeAsync,
GrabModeAsync, constrain, None, t);
return status;
}
int WindowManager::attemptGrabKey(Window w, int t)
{
if (t == 0) t = timestamp(False);
260 return XGrabKeyboard(display(), w, False, GrabModeAsync, GrabModeAsync, t);
}
void WindowManager::releaseGrab(XButtonEvent *e)
{
XEvent ev;
if (!nobuttons(e)) {
for (;;) {
XMaskEvent(display(), ButtonMask | ButtonMotionMask, &ev);
270 if (ev.type == MotionNotify) continue;
e = &ev.xbutton;
if (nobuttons(e)) break;
}
}
XUngrabPointer(display(), e->time);
m_currentTime = e->time;
}
280
void WindowManager::releaseGrabKeyMode(XButtonEvent *e)
{
XEvent ev;
if (!nobuttons(e)) {
for (;;) {
XMaskEvent(display(), ButtonMask | ButtonMotionMask, &ev);
if (ev.type == MotionNotify) continue;
e = &ev.xbutton;
if (nobuttons(e)) break;
290 }
}
XUngrabPointer(display(), e->time);
m_currentTime = e->time;
XUngrabKeyboard(display(), e->time);
m_currentTime = e->time;
}
300
void WindowManager::releaseGrabKeyMode(XKeyEvent* e)
{
XUngrabPointer(display(), e->time);
XUngrabKeyboard(display(), e->time);
m_currentTime = e->time;
}
void Client::move(XButtonEvent *e)
310 {
int x = -1, y = -1;
Boolean done = False;
ShowGeometry geometry(m_windowManager, (XEvent *)e);
if (m_windowManager->attemptGrab
(root(), None, DragMask, e->time) != GrabSuccess) {
return;
}
320 int mx = DisplayWidth (display(), windowManager()->screen()) - 1;
int my = DisplayHeight(display(), windowManager()->screen()) - 1;
int xi = m_border->xIndent();
int yi = m_border->yIndent();
XEvent event;
Boolean found;
struct timeval sleepval;
doSomething = False;
330 while (!done) {
found = False;
while (XCheckMaskEvent(display(), DragMask | ExposureMask, &event)) {
found = True;
if (event.type != MotionNotify) break;
}
if (!found) {
340 sleepval.tv_sec = 0;
sleepval.tv_usec = 50000;
select(0, 0, 0, 0, &sleepval);
continue;
}
switch (event.type) {
default:
fprintf(stderr, "wmx: unknown event type %d\n", event.type);
350 break;
case Expose:
// m_windowManager->eventExposure(&event.xexpose);
m_windowManager->dispatchEvent(&event);
break;
case ButtonPress:
// don't like this
XUngrabPointer(display(), event.xbutton.time);
360 doSomething = False;
done = True;
break;
case ButtonRelease:
if (!nobuttons(&event.xbutton)) doSomething = False;
m_windowManager->releaseGrab(&event.xbutton);
done = True;
370 break;
case MotionNotify:
int nx = event.xbutton.x - e->x;
int ny = event.xbutton.y - e->y;
if (nx != x || ny != y) {
if (doSomething) { // so x,y have sensible values already
380
// bumping!
if (nx < x && nx <= 0 && nx > -CONFIG_BUMP_DISTANCE) nx = 0;
if (ny < y && ny <= 0 && ny > -CONFIG_BUMP_DISTANCE) ny = 0;
if (nx > x && nx >= mx - m_w - xi &&
nx < mx - m_w - xi + CONFIG_BUMP_DISTANCE)
nx = mx - m_w - xi;
if (ny > y && ny >= my - m_h - yi &&
390 ny < my - m_h - yi + CONFIG_BUMP_DISTANCE)
ny = my - m_h - yi;
}
x = nx;
y = ny;
geometry.update(x, y);
m_border->moveTo(x + xi, y + yi);
doSomething = True;
400 }
break;
}
}
geometry.remove();
if (doSomething) {
m_x = x + xi;
m_y = y + yi;
410 }
if (CONFIG_CLICK_TO_FOCUS) activate();
m_border->moveTo(m_x, m_y);
sendConfigureNotify();
}
void Client::fixResizeDimensions(int &w, int &h, int &dw, int &dh)
{
420 if (w < 50) w = 50;
if (h < 50) h = 50;
if (m_sizeHints.flags & PResizeInc) {
w = m_minWidth + (((w - m_minWidth) / m_sizeHints.width_inc) *
m_sizeHints.width_inc);
h = m_minHeight + (((h - m_minHeight) / m_sizeHints.height_inc) *
m_sizeHints.height_inc);
dw = (w - m_minWidth) / m_sizeHints.width_inc;
430 dh = (h - m_minHeight) / m_sizeHints.height_inc;
} else {
dw = w; dh = h;
}
if (m_sizeHints.flags & PMaxSize) {
if (w > m_sizeHints.max_width) w = m_sizeHints.max_width;
if (h > m_sizeHints.max_height) h = m_sizeHints.max_height;
}
440 if (w < m_minWidth) w = m_minWidth;
if (h < m_minHeight) h = m_minHeight;
}
void Client::resize(XButtonEvent *e, Boolean horizontal, Boolean vertical)
{
if (isFixedSize()) return;
ShowGeometry geometry(m_windowManager, (XEvent *)e);
450 if (m_windowManager->attemptGrab
(root(), None, DragMask, e->time) != GrabSuccess) {
return;
}
if (vertical && horizontal)
m_windowManager->installCursor(WindowManager::DownrightCursor);
else if (vertical)
m_windowManager->installCursor(WindowManager::DownCursor);
else
460 m_windowManager->installCursor(WindowManager::RightCursor);
Window dummy;
XTranslateCoordinates(display(), e->window, parent(),
e->x, e->y, &e->x, &e->y, &dummy);
int xorig = e->x;
int yorig = e->y;
int x = xorig;
int y = yorig;
470 int w = m_w, h = m_h;
int prevW, prevH;
int dw, dh;
XEvent event;
Boolean found;
Boolean done = False;
struct timeval sleepval;
doSomething = False;
480 while (!done) {
found = False;
while (XCheckMaskEvent(display(), DragMask | ExposureMask, &event)) {
found = True;
if (event.type != MotionNotify) break;
}
if (!found) {
490 sleepval.tv_sec = 0;
sleepval.tv_usec = 50000;
select(0, 0, 0, 0, &sleepval);
continue;
}
switch (event.type) {
default:
fprintf(stderr, "wmx: unknown event type %d\n", event.type);
500 break;
case Expose:
// m_windowManager->eventExposure(&event.xexpose);
m_windowManager->dispatchEvent(&event);
break;
case ButtonPress:
// don't like this
XUngrabPointer(display(), event.xbutton.time);
510 done = True;
break;
case ButtonRelease:
x = event.xbutton.x; y = event.xbutton.y;
if (!nobuttons(&event.xbutton)) x = -1;
m_windowManager->releaseGrab(&event.xbutton);
520 done = True;
break;
case MotionNotify:
x = event.xbutton.x; y = event.xbutton.y;
if (vertical && horizontal) {
prevH = h; h = y - m_y;
prevW = w; w = x - m_x;
fixResizeDimensions(w, h, dw, dh);
530 if (h == prevH && w == prevW) break;
m_border->configure(m_x, m_y, w, h, CWWidth | CWHeight, 0);
if (CONFIG_RESIZE_UPDATE)
XResizeWindow(display(), m_window, w, h);
geometry.update(dw, dh);
doSomething = True;
} else if (vertical) {
prevH = h; h = y - m_y;
fixResizeDimensions(w, h, dw, dh);
540 if (h == prevH) break;
m_border->configure(m_x, m_y, w, h, CWHeight, 0);
if (CONFIG_RESIZE_UPDATE)
XResizeWindow(display(), m_window, w, h);
geometry.update(dw, dh);
doSomething = True;
} else {
prevW = w; w = x - m_x;
fixResizeDimensions(w, h, dw, dh);
550 if (w == prevW) break;
m_border->configure(m_x, m_y, w, h, CWWidth, 0);
if (CONFIG_RESIZE_UPDATE)
XResizeWindow(display(), m_window, w, h);
geometry.update(dw, dh);
doSomething = True;
}
break;
}
560 }
if (doSomething) {
geometry.remove();
if (vertical && horizontal) {
m_w = x - m_x;
m_h = y - m_y;
fixResizeDimensions(m_w, m_h, dw, dh);
570 m_border->configure(m_x, m_y, m_w, m_h, CWWidth|CWHeight, 0, True);
} else if (vertical) {
m_h = y - m_y;
fixResizeDimensions(m_w, m_h, dw, dh);
m_border->configure(m_x, m_y, m_w, m_h, CWHeight, 0, True);
} else {
m_w = x - m_x;
fixResizeDimensions(m_w, m_h, dw, dh);
m_border->configure(m_x, m_y, m_w, m_h, CWWidth, 0, True);
}
580
XMoveResizeWindow(display(), m_window,
m_border->xIndent(), m_border->yIndent(), m_w, m_h);
if (vertical) makeThisNormalHeight(); // in case it was full-height
sendConfigureNotify();
}
m_windowManager->installCursor(WindowManager::NormalCursor);
}
590
void Client::moveOrResize(XButtonEvent *e)
{
if (e->x < m_border->xIndent() && e->y > m_h) {
resize(e, False, True);
} else if (e->y < m_border->yIndent() &&
e->x > m_w + m_border->xIndent() - m_border->yIndent()) { //hack
resize(e, True, False);
} else {
600 move(e);
}
}
void Border::eventButton(XButtonEvent *e)
{
if (e->window == m_parent) {
if (!m_client->isActive()) return;
610 if (isTransient()) {
if (e->x >= xIndent() && e->y >= yIndent()) {
return;
} else {
m_client->move(e);
return;
}
}
m_client->moveOrResize(e);
620 return;
} else if (e->window == m_tab) {
m_client->move(e);
return;
}
if (e->window == m_resize) {
m_client->resize(e, True, True);
return;
630 }
if (e->window != m_button || e->type == ButtonRelease) return;
if (windowManager()->attemptGrab(m_button, None, MenuGrabMask, e->time)
!= GrabSuccess) {
return;
}
XEvent event;
640 Boolean found;
Boolean done = False;
struct timeval sleepval;
unsigned long tdiff = 0L;
int x = e->x;
int y = e->y;
int action = 1;
int buttonSize = m_tabWidth - TAB_TOP_HEIGHT*2 - 4;
XFillRectangle(display(), m_button, m_drawGC, 0, 0, buttonSize, buttonSize);
650
while (!done) {
found = False;
if (tdiff > CONFIG_DESTROY_WINDOW_DELAY && action == 1) {
windowManager()->installCursor(WindowManager::DeleteCursor);
action = 2;
}
660 while (XCheckMaskEvent(display(), MenuMask, &event)) {
found = True;
if (event.type != MotionNotify) break;
}
if (!found) {
sleepval.tv_sec = 0;
sleepval.tv_usec = 50000;
select(0, 0, 0, 0, &sleepval);
tdiff += 50;
670 continue;
}
switch (event.type) {
default:
fprintf(stderr, "wmx: unknown event type %d\n", event.type);
break;
case Expose:
680 // windowManager()->eventExposure(&event.xexpose);
windowManager()->dispatchEvent(&event);
break;
case ButtonPress:
break;
case ButtonRelease:
if (!nobuttons(&event.xbutton)) {
690 action = 0;
}
if (x < 0 || y < 0 || x >= buttonSize || y >= buttonSize) {
action = 0;
}
windowManager()->releaseGrab(&event.xbutton);
done = True;
break;
700
case MotionNotify:
tdiff = event.xmotion.time - e->time;
if (tdiff > 5000L) tdiff = 5001L; // in case of overflow!
x = event.xmotion.x;
y = event.xmotion.y;
if (action == 0 || action == 2) {
if (x < 0 || y < 0 || x >= buttonSize || y >= buttonSize) {
710 windowManager()->installCursor(WindowManager::NormalCursor);
action = 0;
} else {
windowManager()->installCursor(WindowManager::DeleteCursor);
action = 2;
}
}
break;
}
720 }
XClearWindow(display(), m_button);
windowManager()->installCursor(WindowManager::NormalCursor);
if (tdiff > 5000L) { // do nothing, they dithered too long
return;
}
if (action == 1) m_client->hide();
730 else if (action == 2) m_client->kill();
}