/* Event.cc
Copyright © 2003 David Reveman.
This file is part of Waimea.
Waimea is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Waimea is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with Waimea; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
extern "C" {
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <cairo.h>
#ifdef SHAPE
# include <X11/extensions/shape.h>
#endif // SHAPE
#ifdef RANDR
# include <X11/extensions/Xrandr.h>
#endif // RANDR
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif // HAVE_STDIO_H
#ifdef LIMITS_H
# include <limits.h>
#endif // LIMITS_H
#ifdef HAVE_UNISTD_H
# include <sys/types.h>
# include <unistd.h>
#endif // HAVE_UNISTD_H
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif // HAVE_SYS_SELECT_H
#ifdef HAVE_SYS_WAIT_H
# include <sys/types.h>
# include <sys/wait.h>
#endif // HAVE_SYS_WAIT_H
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif // HAVE_SIGNAL_H
}
#include "Event.hh"
#include "Timer.hh"
#include "Action.hh"
#include "Window.hh"
EventHandler::EventHandler(Waimea *wa) {
waimea = wa;
focused = last_click_win = action_manager_window = None;
move_resize = EndMoveResizeType;
last_button = 0;
action_manager_screen = NULL;
moveresize_return_mask.insert(MotionNotify);
moveresize_return_mask.insert(ButtonPress);
moveresize_return_mask.insert(ButtonRelease);
moveresize_return_mask.insert(KeyPress);
moveresize_return_mask.insert(KeyRelease);
moveresize_return_mask.insert(MapRequest);
moveresize_return_mask.insert(UnmapNotify);
moveresize_return_mask.insert(DestroyNotify);
moveresize_return_mask.insert(EnterNotify);
moveresize_return_mask.insert(LeaveNotify);
moveresize_return_mask.insert(ConfigureRequest);
menu_viewport_move_return_mask.insert(MotionNotify);
menu_viewport_move_return_mask.insert(ButtonPress);
menu_viewport_move_return_mask.insert(ButtonRelease);
menu_viewport_move_return_mask.insert(KeyPress);
menu_viewport_move_return_mask.insert(KeyRelease);
menu_viewport_move_return_mask.insert(MapRequest);
menu_viewport_move_return_mask.insert(EnterNotify);
menu_viewport_move_return_mask.insert(LeaveNotify);
xfd = ConnectionNumber(waimea->display);
}
EventHandler::~EventHandler(void) {
moveresize_return_mask.clear();
menu_viewport_move_return_mask.clear();
}
void EventHandler::eventLoop(set<int> *return_mask, XEvent *event) {
fd_set rfds;
for (;;) {
if (XPending(waimea->display)) {
XNextEvent(waimea->display, event);
if (return_mask->find(event->type) != return_mask->end()) return;
handleEvent(event);
} else if (waimea->quit_signal) {
quit(EXIT_SUCCESS);
} else if (waimea->restart_signal) {
restart(NULL);
} else if (waimea->unknown_signal) {
quit(EXIT_FAILURE);
} else if (waimea->timer->timer_signal) {
waimea->timer->handleTimeout();
waimea->timer->timer_signal = 0;
} else if (! doings.empty()) {
do {
doings.front()->envoke();
delete doings.front();
doings.pop_front();
} while (! doings.empty());
} else if (
#ifdef THREAD
(! __render_thread_count) &&
#endif // THREAD
(! __render_list.empty())) {
DWindowObject *dw = __render_list.front();
if (! dw) continue;
__render_list.pop_front();
list<DWindowObject *>::iterator it = __render_list.begin();
while (it != __render_list.end()) {
if (*it == dw) it = __render_list.erase(it);
else it++;
}
static cairo_t *cr = NULL;
if (cr == NULL) {
/* XXX: cairo need a call to this function for text
support to be initialized, will probably dissapear soon. */
cairo_surface_t *surface =
cairo_xlib_surface_create(waimea->display,
DefaultRootWindow(waimea->display),
DefaultVisual(waimea->display, DefaultScreen(waimea->display)),
DisplayWidth(waimea->display, DefaultScreen(waimea->display)),
DisplayHeight(waimea->display, DefaultScreen(waimea->display)));
cr = cairo_create(surface);
}
dw->renderWindow(cr);
} else {
FD_ZERO(&rfds);
FD_SET(xfd, &rfds);
select(xfd + 1, &rfds, 0, 0, NULL);
}
}
}
void EventHandler::handleEvent(XEvent *event) {
Window w;
int i, rx, ry;
EventDetail ed;
ed.x = ed.y = INT_MAX;
ed.type = ed.detail = ed.x11mod = ed.wamod = 0;
switch (event->type) {
case ConfigureRequest:
evConfigureRequest(&event->xconfigurerequest); break;
case PropertyNotify:
evProperty(&event->xproperty); break;
case UnmapNotify:
if (event->xunmap.event != event->xunmap.window) return;
case ReparentNotify:
case DestroyNotify:
evUnmapDestroy(event); break;
case FocusOut:
case FocusIn:
evFocus(&event->xfocus);
break;
case LeaveNotify:
case EnterNotify:
if (event->xcrossing.mode == NotifyGrab) break;
ed.type = event->type;
ed.x11mod = event->xcrossing.state;
ed.detail = 0;
evAct(event, event->xcrossing.window, &ed);
break;
case KeyPress:
case KeyRelease:
ed.type = event->type;
ed.x11mod = event->xkey.state;
ed.detail = event->xkey.keycode;
evAct(event, event->xkey.window, &ed);
break;
case ButtonPress:
ed.type = ButtonPress;
if (waimea->double_click) {
if (! waimea->timer->exitsInterrupt(DOUBLECLICK_TIMER_ID)) {
Action *double_click_action = new Action;
double_click_action->delay = waimea->double_click;
double_click_action->timer_id = DOUBLECLICK_TIMER_ID;
double_click_action->periodic_timer = false;
double_click_action->func = &AWindowObject::nop;
Interrupt *i = new Interrupt(double_click_action,
event, (Window) 0);
double_click_action->unref();
waimea->timer->addInterrupt(i);
last_click_win = event->xbutton.window;
last_button = event->xbutton.button;
} else {
if (last_click_win == event->xbutton.window &&
last_button == event->xbutton.button) {
waimea->timer->removeInterrupt(DOUBLECLICK_TIMER_ID);
ed.type = DoubleClick;
last_click_win = (Window) 0;
last_button = 0;
}
}
}
case ButtonRelease:
if (event->type == ButtonRelease) ed.type = ButtonRelease;
ed.x11mod = event->xbutton.state;
ed.detail = event->xbutton.button;
ed.x = event->xbutton.x;
ed.y = event->xbutton.y;
evAct(event, event->xbutton.window, &ed);
break;
case ColormapNotify:
evColormap(&event->xcolormap); break;
case MapRequest: {
WindowObject *wo = evMapRequest(&event->xmaprequest);
if (wo) {
XQueryPointer(waimea->display, event->xmaprequest.parent,
&w, &w, &rx, &ry, &i, &i, &(ed.x11mod));
ed.detail = 0;
event->xbutton.x_root = rx;
event->xbutton.y_root = ry;
if (wo->type == WindowType) {
WaWindow *ww = (WaWindow *) wo;
ed.type = event->type;
evAct(event, event->xmaprequest.window, &ed);
if (! ww->mapped) {
ww->net->setState(ww, ww->state);
ww->net->setVirtualPos(ww);
}
} else if (wo->type == DockAppType) {
ed.type = DockappAddRequest;
evAct(event, ((Dockapp *) wo)->id, &ed);
if (! ((Dockapp *) wo)->dh)
wo->ws->addDockapp((Dockapp *) wo, NULL);
}
}
} break;
case ClientMessage:
if (event->xclient.message_type ==
waimea->net->waimea_net_event_notify) {
ed.type = event->xclient.data.l[1];
ed.detail = event->xclient.data.l[2];
ed.x = event->xclient.data.l[2];
ed.y = event->xclient.data.l[3];
XQueryPointer(waimea->display, event->xclient.window,
&w, &w, &rx, &ry, &i, &i, &(ed.x11mod));
evAct(event, event->xclient.data.l[0], &ed);
} else
evClientMessage(event, &ed);
break;
default:
#ifdef SHAPE
if (waimea->shape && event->type == waimea->shape_event) {
XShapeEvent *e = (XShapeEvent *) event;
WaWindow *ww = (WaWindow *)
waimea->findWin(e->window, WindowType);
if (ww && waimea->shape)
ww->shapeEvent();
}
#endif // SHAPE
#ifdef RANDR
if (waimea->randr && event->type == waimea->randr_event) {
XRRScreenChangeNotifyEvent *e =
(XRRScreenChangeNotifyEvent *) event;
WaScreen *ws = (WaScreen *)
waimea->findWin(e->window, RootType);
if (ws) {
ws->width = e->width;
ws->height = e->height;
ws->rrUpdate();
}
}
#endif // RANDR
break;
}
}
void EventHandler::evProperty(XPropertyEvent *e) {
WaWindow *ww;
if (e->atom == XA_WM_NAME) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getXaName(ww);
ww->drawDecor();
}
}
else if (e->atom == XA_WM_CLASS) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getClassHint(ww);
ww->drawDecor();
}
}
else if (e->atom == waimea->net->net_wm_pid) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWmPid(ww);
ww->drawDecor();
}
}
else if (e->atom == waimea->net->net_wm_user_time) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWmUserTime(ww);
}
}
else if (e->atom == XA_WM_CLIENT_MACHINE) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWMClientMachineHint(ww);
ww->drawDecor();
}
}
else if (e->atom == XA_WM_TRANSIENT_FOR) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getTransientForHint(ww);
}
}
else if (e->atom == XA_WM_HINTS) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWMHints(ww);
}
}
else if (e->atom == XA_WM_NORMAL_HINTS) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
unsigned int w, h;
waimea->net->getWMNormalHints(ww);
ww->incSizeCheck(ww->attrib.width, ww->attrib.height, &w, &h);
if (w != ww->attrib.width || h != ww->attrib.height) {
ww->attrib.width = w;
ww->attrib.height = h;
ww->redrawWindow();
}
}
}
else if (e->atom == waimea->net->wm_protocols) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWMProtocols(ww);
}
}
else if (e->atom == waimea->net->mwm_hints) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getMWMHints(ww);
}
}
else if (e->atom == waimea->net->net_wm_name) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
if (! waimea->net->getNetName(ww)) waimea->net->getXaName(ww);
ww->drawDecor();
}
}
else if (e->atom == waimea->net->net_wm_icon ||
e->atom == waimea->net->net_wm_icon_image) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWmIconImage(ww);
}
}
else if (e->atom == waimea->net->net_wm_icon_svg) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
waimea->net->getWmIconSvg(ww);
}
}
else if (e->atom == waimea->net->net_wm_strut) {
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType)))
waimea->net->getWmStrut(ww);
}
else if (e->atom == waimea->net->xrootpmap_id) {
if (WaScreen *ws = (WaScreen *) waimea->findWin(e->window, RootType))
waimea->net->getXRootPMapId(ws);
}
}
void EventHandler::evFocus(XFocusChangeEvent *e) {
WindowObject *wo;
WaScreen *ws = NULL;
EventDetail ed;
Window w;
int i, rx, ry;
bool newfocus = false;
if (e->type == FocusIn && e->window != focused) {
if ((wo = waimea->findWin(e->window,
WindowType | MenuItemType | RootType))) {
if (wo->type == RootType) {
ws = (WaScreen *) wo;
ws->focused = true;
waimea->net->setActiveWindow(ws, NULL);
}
else if (wo->type == MenuItemType) {
((MenuItem *) wo)->focused = true;
ws = ((MenuItem *) wo)->ws;
waimea->net->setActiveWindow(ws, NULL);
}
else if (wo->type == WindowType) {
WaWindow *wa = ((WaWindow *) wo);
wa->has_focus = true;
ws = wa->ws;
waimea->net->setActiveWindow(ws, wa);
}
waimea->addToFocusHistory(e->window);
newfocus = true;
XQueryPointer(waimea->display, ws->id, &w, &w, &rx, &ry, &i, &i,
&(ed.x11mod));
ed.type = FocusIn;
ed.detail = 0;
ed.x = ed.y = INT_MAX;
evAct((XEvent *) e, wo->id, &ed);
}
if ((wo = waimea->findWin(focused,
WindowType | MenuItemType | RootType))) {
if (wo->type == RootType) {
ws = (WaScreen *) wo;
ws->focused = false;
}
else if (wo->type == MenuItemType) {
((MenuItem *) wo)->focused = false;
if (((MenuItem *) wo)->menu->focus == ((MenuItem *) wo)->id)
((MenuItem *) wo)->menu->focus = 0;
ws = ((MenuItem *) wo)->ws;
}
else if (wo->type == WindowType) {
WaWindow *wa = ((WaWindow *) wo);
wa->has_focus = false;
ws = wa->ws;
}
if (! newfocus)
XQueryPointer(waimea->display, ws->id, &w, &w, &rx, &ry, &i,
&i, &(ed.x11mod));
ed.type = FocusOut;
ed.detail = 0;
ed.x = ed.y = INT_MAX;
evAct((XEvent *) e, wo->id, &ed);
}
focused = e->window;
}
}
void EventHandler::evConfigureRequest(XConfigureRequestEvent *e) {
WindowObject *wo;
WaWindow *ww;
Dockapp *da;
XWindowChanges wc;
wc.x = e->x;
wc.y = e->y;
wc.width = e->width;
wc.height = e->height;
wc.sibling = e->above;
wc.stack_mode = e->detail;
wc.border_width = e->border_width;
if ((wo = waimea->findWin(e->window, WindowType | DockAppType))) {
if (wo->type == WindowType) {
ww = (WaWindow *) wo;
if (e->value_mask & CWBorderWidth) ww->old_bw = e->border_width;
if (e->value_mask & (CWX | CWY)) {
if (e->value_mask & CWX) ww->attrib.x = e->x;
if (e->value_mask & CWY) ww->attrib.y = e->y;
ww->gravitate(ApplyGravity);
}
if (e->value_mask & CWWidth)
ww->attrib.width = e->width;
if (e->value_mask & CWHeight)
ww->attrib.height = e->height;
if (e->value_mask & CWWidth)
ww->old_attrib.width = ww->attrib.width + 1;
if (e->value_mask & CWHeight)
ww->old_attrib.height = ww->attrib.height + 1;
ww->redrawWindow();
if (e->value_mask & CWStackMode) {
switch (e->detail) {
case Above:
ww->raise();
break;
case Below:
ww->lower();
break;
case TopIf:
ww->alwaysontopOn();
break;
case BottomIf:
ww->alwaysatbottomOn();
break;
case Opposite:
if (ww->wstate & StateAlwaysOnTopMask)
ww->alwaysatbottomOn();
else if (ww->wstate & StateAlwaysAtBottomMask)
ww->alwaysontopOn();
}
}
return;
}
else if (wo->type == DockAppType) {
da = (Dockapp *) wo;
if (e->value_mask & CWWidth) da->width = e->width;
if (e->value_mask & CWHeight) da->height = e->height;
XConfigureWindow(e->display, da->id, e->value_mask, &wc);
if (da->dh) da->dh->update();
return;
}
}
XConfigureWindow(e->display, e->window, e->value_mask, &wc);
}
void EventHandler::evColormap(XColormapEvent *e) {
XInstallColormap(e->display, e->colormap);
}
WindowObject *EventHandler::evMapRequest(XMapRequestEvent *e) {
XWindowAttributes attr;
WindowObject *wo = NULL;
WaScreen *ws = NULL;
XWMHints *wm_hints = NULL;
WaWindow *ww = NULL;
if ((ww = (WaWindow *) waimea->findWin(e->window, WindowType))) {
if (ww->wstate & StateMinimizedMask) ww->unMinimize();
} else {
int status = 0;
int state = -1;
ws = (WaScreen *) waimea->findWin(e->parent, RootType);
status = XGetWindowAttributes(e->display, e->window, &attr);
if (! status) return NULL;
wm_hints = XGetWMHints(e->display, e->window);
if (wm_hints) {
if (wm_hints->flags & StateHint)
state = wm_hints->initial_state;
XFree(wm_hints);
}
if (! ws) {
ws = (WaScreen *) waimea->findWin(attr.root, RootType);
if (! ws) return NULL;
}
if (status && attr.screen && (! attr.override_redirect)) {
if (ws->net->isSystrayWindow(e->window)) {
if (! waimea->findWin(e->window, SystrayType)) {
XSelectInput(ws->display, e->window,
StructureNotifyMask);
SystrayWindow *stw = new SystrayWindow(e->window, ws);
waimea->window_table.insert(make_pair(e->window, stw));
ws->systray_window_list.push_back(e->window);
ws->net->setSystrayWindows(ws);
}
} else {
if (state == WithdrawnState) {
Dockapp *d = new Dockapp(ws, e->window);
wo = d;
} else {
ww = new WaWindow(e->window, ws);
ws->net->setClientList(ws);
ws->net->setClientListStacking(ws);
wo = ww;
}
}
}
}
return wo;
}
void EventHandler::evUnmapDestroy(XEvent *e) {
DockappHandler *dh;
WindowObject *wo;
if ((wo = waimea->findWin((e->type == UnmapNotify)?
e->xunmap.window:
(e->type == DestroyNotify)?
e->xdestroywindow.window:
e->xreparent.window,
WindowType | DockAppType | SystrayType))) {
if (wo->type == WindowType) {
if (e->type == UnmapNotify && ((WaWindow *) wo)->pending_unmaps) {
((WaWindow *) wo)->pending_unmaps -= 1;
return;
}
((WaWindow *) wo)->deleted = false;
if (e->type == DestroyNotify)
((WaWindow *) wo)->deleted = true;
else if (e->type == ReparentNotify) {
if (e->xreparent.window != ((WaWindow *) wo)->id ||
e->xreparent.parent == ((WaWindow *) wo)->frame->id)
return;
XEvent ev;
ev.xreparent = e->xreparent;
XPutBackEvent(waimea->display, &ev);
((WaWindow *) wo)->remap = true;
}
delete ((WaWindow *) wo);
}
else if (wo->type == DockAppType) {
if (e->type == DestroyNotify)
((Dockapp *) wo)->deleted = true;
dh = ((Dockapp *) wo)->dh;
if (dh) dh->dockapp_list.remove(((Dockapp *) wo));
((Dockapp *) wo)->unref();
dh->update();
}
else if (wo->type == SystrayType) {
SystrayWindow *stw = (SystrayWindow *) wo;
waimea->window_table.erase(stw->id);
XSelectInput(stw->ws->display, stw->id, NoEventMask);
stw->ws->systray_window_list.remove(stw->id);
stw->ws->net->setSystrayWindows(stw->ws);
delete stw;
}
}
}
void EventHandler::evClientMessage(XEvent *e, EventDetail *ed) {
Window w;
int i, rx, ry;
WaWindow *ww;
if (e->xclient.message_type == waimea->net->net_active_window) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
ww->raise();
waimea->focusNew(ww->id);
}
}
else if (e->xclient.message_type == waimea->net->waimea_net_restart) {
restart(NULL);
}
else if (e->xclient.message_type == waimea->net->waimea_net_shutdown) {
quit(EXIT_SUCCESS);
}
else if (e->xclient.message_type == waimea->net->net_wm_name) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
waimea->net->getNetName(ww);
ww->drawDecor();
}
}
else if (e->xclient.message_type == waimea->net->wm_change_state) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
if ((unsigned int) e->xclient.data.l[0] == IconicState)
ww->minimize();
else if ((unsigned int) e->xclient.data.l[0] == NormalState)
ww->unMinimize();
else if ((unsigned int) e->xclient.data.l[0] == WithdrawnState)
delete ww;
}
}
else if (e->xclient.message_type == waimea->net->net_wm_desktop) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
if ((unsigned int) e->xclient.data.l[0] == 0xffffffff ||
(unsigned int) e->xclient.data.l[0] == 0xfffffffe) {
ww->desktop_mask = (1L << 16) - 1;
ww->show();
ww->net->setDesktop(ww);
ww->net->setDesktopMask(ww);
}
else if ((unsigned int) e->xclient.data.l[0] <
ww->ws->config.desktops) {
ww->desktop_mask =
(1L << (unsigned int) e->xclient.data.l[0]);
if (ww->desktop_mask &
(1L << ww->ws->current_desktop->number))
ww->show();
else
ww->hide();
ww->net->setDesktop(ww);
ww->net->setDesktopMask(ww);
}
}
}
else if (e->xclient.message_type ==
waimea->net->waimea_net_wm_desktop_mask) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
if (e->xclient.data.l[0] <
((1L << ww->ws->config.desktops) - 1) &&
e->xclient.data.l[0] >= 0) {
ww->desktop_mask = e->xclient.data.l[0];
if (ww->desktop_mask &
(1L << ww->ws->current_desktop->number))
ww->show();
else
ww->hide();
ww->net->setDesktop(ww);
ww->net->setDesktopMask(ww);
}
}
}
else if (e->xclient.message_type == waimea->net->net_wm_state) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
bool max_done = false;
for (int i = 1; i < 3; i++) {
if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_sticky) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->unSticky(); break;
case _NET_WM_STATE_ADD:
ww->sticky(); break;
case _NET_WM_STATE_TOGGLE:
ww->toggleSticky(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_shaded) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->unShade(); break;
case _NET_WM_STATE_ADD:
ww->shade(); break;
case _NET_WM_STATE_TOGGLE:
ww->toggleShade(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_hidden) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->unMinimize(); break;
case _NET_WM_STATE_ADD:
ww->minimize(); break;
case _NET_WM_STATE_TOGGLE:
ww->toggleMinimize(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_maximized_vert ||
(unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_maximized_horz) {
if (max_done) break;
max_done = true;
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->unMaximize(); break;
case _NET_WM_STATE_ADD:
ww->maximize(); break;
case _NET_WM_STATE_TOGGLE:
ww->toggleMaximize(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_above ||
(unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_stays_on_top) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->alwaysontopOff(); break;
case _NET_WM_STATE_ADD:
ww->alwaysontopOn(); break;
case _NET_WM_STATE_TOGGLE:
ww->alwaysontopToggle(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_below ||
(unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_stays_at_bottom) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->alwaysatbottomOff(); break;
case _NET_WM_STATE_ADD:
ww->alwaysatbottomOn(); break;
case _NET_WM_STATE_TOGGLE:
ww->alwaysatbottomToggle(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_skip_taskbar) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->wstate &= ~StateTasklistMask; break;
case _NET_WM_STATE_ADD:
ww->wstate |= StateTasklistMask; break;
case _NET_WM_STATE_TOGGLE:
if (ww->wstate & StateTasklistMask)
ww->wstate &= ~StateTasklistMask;
else
ww->wstate |= StateTasklistMask;
break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_wm_state_fullscreen) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->fullscreenOff();
ww->unMaximize();
ww->alwaysontopOff();
ww->decorAllOn();
break;
case _NET_WM_STATE_ADD:
ww->decorAllOff();
ww->alwaysontopOn();
ww->raise();
ww->fullscreenOn();
ww->maximize();
break;
case _NET_WM_STATE_TOGGLE:
if (ww->wstate & StateFullscreenMask) {
ww->fullscreenOff();
ww->unMaximize();
ww->alwaysontopOff();
ww->decorAllOn();
} else {
ww->decorAllOff();
ww->alwaysontopOn();
ww->raise();
ww->fullscreenOn();
ww->maximize();
}
break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->waimea_net_wm_state_decor) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->decorAllOff(); break;
case _NET_WM_STATE_ADD:
ww->decorAllOn(); break;
case _NET_WM_STATE_TOGGLE:
if (ww->wstate & StateDecorAllMask)
ww->decorAllOff();
else ww->decorAllOn();
break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->waimea_net_wm_state_decortitle) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->decorTitleOff(); break;
case _NET_WM_STATE_ADD:
ww->decorTitleOn(); break;
case _NET_WM_STATE_TOGGLE:
ww->decorTitleToggle(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->waimea_net_wm_state_decorborder) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->decorBorderOff(); break;
case _NET_WM_STATE_ADD:
ww->decorBorderOn(); break;
case _NET_WM_STATE_TOGGLE:
ww->decorBorderToggle(); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->waimea_net_wm_state_decorhandles) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->decorHandlesOff(); break;
case _NET_WM_STATE_ADD:
ww->decorHandlesOn(); break;
case _NET_WM_STATE_TOGGLE:
ww->decorHandlesToggle(); break;
}
}
}
}
}
else if (e->xclient.message_type == waimea->net->xdndenter ||
e->xclient.message_type == waimea->net->xdndleave) {
if (e->xclient.message_type == waimea->net->xdndenter) {
e->type = EnterNotify;
ed->type = EnterNotify;
} else {
e->type = LeaveNotify;
ed->type = LeaveNotify;
}
if (WaScreen *ws = (WaScreen *) waimea->findWin(e->xclient.window,
RootType)) {
XQueryPointer(ws->display, ws->id, &w, &w, &rx, &ry, &i, &i,
&(ed->x11mod));
} else {
rx = 0;
ry = 0;
}
ed->detail = 0;
e->xcrossing.x_root = rx;
e->xcrossing.y_root = ry;
evAct(e, e->xclient.window, ed);
}
else if (e->xclient.message_type == waimea->net->net_desktop_viewport) {
if (WaScreen *ws = (WaScreen *) waimea->findWin(e->xclient.window,
RootType))
ws->moveViewportTo(e->xclient.data.l[0], e->xclient.data.l[1]);
}
else if (e->xclient.message_type == waimea->net->net_close_window) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window, WindowType)))
ww->close();
}
else if (e->xclient.message_type == waimea->net->net_current_desktop) {
if (WaScreen *ws = (WaScreen *) waimea->findWin(e->xclient.window,
RootType))
ws->goToDesktop(e->xclient.data.l[0]);
}
else if (e->xclient.message_type == waimea->net->net_moveresize_window) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
char gravity = (char) e->xclient.data.l[0];
if (gravity == 0) gravity = (char) ww->size.win_gravity;
int x = ww->attrib.x;
int y = ww->attrib.y;
int width = ww->attrib.width;
int height = ww->attrib.height;
if (e->xclient.data.l[0] & (1L << 8)) x = e->xclient.data.l[1];
if (e->xclient.data.l[0] & (1L << 9)) y = e->xclient.data.l[2];
if (e->xclient.data.l[0] & (1L << 10))
width = e->xclient.data.l[3];
if (e->xclient.data.l[0] & (1L << 11))
height = e->xclient.data.l[4];
ww->incSizeCheck(width, height, &ww->attrib.width,
&ww->attrib.height);
if (gravity != StaticGravity)
ww->gravitate(RemoveGravity);
if (gravity == NorthEastGravity ||
gravity == EastGravity ||
gravity == SouthEastGravity)
ww->attrib.x = ww->ws->width - x - ww->attrib.width;
else ww->attrib.x = x;
if (gravity == SouthWestGravity ||
gravity == SouthGravity ||
gravity == SouthEastGravity)
ww->attrib.y = ww->ws->height - y - ww->attrib.height;
else ww->attrib.y = y;
if (gravity == NorthGravity ||
gravity == SouthGravity ||
gravity == CenterGravity)
ww->attrib.x -= ww->attrib.width / 2;
if (gravity == EastGravity ||
gravity == WestGravity ||
gravity == CenterGravity)
ww->attrib.y -= ww->attrib.height / 2;
if (gravity != StaticGravity)
ww->gravitate(ApplyGravity);
ww->redrawWindow();
ww->checkMoveMerge(ww->attrib.x, ww->attrib.y);
}
}
else if (e->xclient.message_type == waimea->net->net_wm_moveresize) {
if ((ww = (WaWindow *) waimea->findWin(e->xclient.window,
WindowType))) {
if (e->xclient.data.l[2] == _NET_WM_MOVERESIZE_MOVE ||
e->xclient.data.l[2] == _NET_WM_MOVERESIZE_MOVE_KEYBOARD)
ww->moveOpaque(e);
else if (e->xclient.data.l[2] == _NET_WM_MOVERESIZE_SIZE_TOPLEFT)
ww->resizeOpaque(e, WestResizeTypeMask | NorthResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT)
ww->resizeOpaque(e, WestResizeTypeMask | SouthResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_LEFT)
ww->resizeOpaque(e, WestResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_TOPRIGHT)
ww->resizeOpaque(e, EastResizeTypeMask | NorthResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT)
ww->resizeOpaque(e, EastResizeTypeMask | SouthResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_RIGHT)
ww->resizeOpaque(e, EastResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_TOP)
ww->resizeOpaque(e, NorthResizeTypeMask);
else if (e->xclient.data.l[2] ==
_NET_WM_MOVERESIZE_SIZE_BOTTOM)
ww->resizeOpaque(e, SouthResizeTypeMask);
}
}
else if (e->xclient.message_type == waimea->net->waimea_net_cfg) {
WaScreen *ws = (WaScreen *) waimea->findWin(e->xclient.window,
RootType);
if (ws)
waimea->net->getConfig(ws, e->xclient.data.l[0],
e->xclient.data.l[1], e->xclient.data.l[2]);
}
}
void EventHandler::evAct(XEvent *e, Window win, EventDetail *ed) {
AWindowObject *awo;
map<Window, WindowObject *>::iterator it;
if ((it = waimea->window_table.find(win)) !=
waimea->window_table.end()) {
if (((*it).second)->type & ~ANY_ACTION_WINDOW_TYPE) return;
awo = (AWindowObject *) (*it).second;
if (waimea->eh->move_resize != EndMoveResizeType)
ed->wamod |= MoveResizeMask;
awo->evalState(ed);
if (awo->type == MenuItemType) {
if (ed->type == StateAddNotify) {
((MenuItem *) awo)->mstate = true;
((MenuItem *) awo)->pushRenderEvent();
}
else if (ed->type == StateRemoveNotify) {
((MenuItem *) awo)->mstate = false;
((MenuItem *) awo)->pushRenderEvent();
}
if (((MenuItem *) awo)->mstate)
ed->wamod |= StateTrueMask;
}
WaWindow *wawin = awo->getWindow();
if (wawin) ed->wamod |= wawin->wstate;
awo->ref();
bool status = awo->handleEvent(e, ed);
if (awo->type == WindowType) {
if (! status) {
XAllowEvents(waimea->display, ReplayPointer, CurrentTime);
XAllowEvents(waimea->display, ReplayKeyboard, CurrentTime);
} else {
XAllowEvents(waimea->display, AsyncPointer, CurrentTime);
XAllowEvents(waimea->display, AsyncKeyboard, CurrentTime);
}
}
if (ed->type == WindowStateChangeNotify &&
(awo->type & ANY_DECOR_WINDOW_TYPE)) {
DWindowObject *dwo = (DWindowObject *) awo;
map<int, SubWindowObject *>::iterator it = dwo->subs.begin();
for (; it != dwo->subs.end(); it++)
evAct(NULL, ((*it).second)->id, ed);
}
awo->unref();
}
}
syntax highlighted by Code2HTML, v. 0.9.1