/**
* @file Event.cc
* @author David Reveman <david@waimea.org>
* @date 11-May-2001 11:48:03
*
* @brief Implementation of EventHandler class
*
* Eventloop function and functions for handling XEvents.
*
* Copyright (C) David Reveman. All rights reserved.
*
*/
#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>
#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
}
#include "Event.hh"
/**
* @fn EventHandler(Waimea *wa)
* @brief Constructor for EventHandler class
*
* Sets waimea and rh pointers. Creates menu move return mask, window
* move/resize return mask and empty return mask sets.
*
* @param wa Pointer to waimea object
*/
EventHandler::EventHandler(Waimea *wa) {
waimea = wa;
rh = waimea->rh;
focused = last_click_win = (Window) 0;
move_resize = EndMoveResizeType;
last_button = 0;
empty_return_mask = new set<int>;
moveresize_return_mask = new set<int>;
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 = new set<int>;
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);
}
/**
* @fn ~EventHandler(void)
* @brief Destructor for EventHandler class
*
* Deletes return mask lists
*/
EventHandler::~EventHandler(void) {
MAPPTRCLEAR(empty_return_mask);
MAPPTRCLEAR(moveresize_return_mask);
MAPPTRCLEAR(menu_viewport_move_return_mask);
}
/**
* @fn EventLoop(set<int> *return_mask, XEvent *event)
* @brief Eventloop
*
* Infinite loop waiting for an event to occur. This function can be called
* from move and resize functions the return_mask set is then used for
* deciding if an event should be processed as normal or returned to the
* function caller.
*
* @param return_mask set to use as return_mask
* @param event Pointer to allocated event structure
*/
void EventHandler::EventLoop(set<int> *return_mask, XEvent *event) {
for (;;) {
XNextEvent(waimea->display, event);
if (return_mask->find(event->type) != return_mask->end()) return;
HandleEvent(event);
}
}
/**
* @fn HandleEvent(XEvent *event);
* @brief Eventloop
*
* Executes a matching function for an event. If what to do for an
* event is controlled by an action list we set etype, edetail and emod
* variables and call the EvAct() function.
*
* @param event Pointer to allocated event structure
*/
void EventHandler::HandleEvent(XEvent *event) {
Window w;
int i, rx, ry;
struct timeval click_time;
EventDetail *ed = new EventDetail;
switch (event->type) {
case ConfigureRequest:
EvConfigureRequest(&event->xconfigurerequest); break;
case Expose:
if (event->xexpose.count == 0) {
while (XCheckTypedWindowEvent(waimea->display,
event->xexpose.window,
Expose, event));
EvExpose(&event->xexpose);
}
break;
case PropertyNotify:
EvProperty(&event->xproperty); break;
case UnmapNotify:
if(event->xunmap.event != event->xunmap.window) return;
case DestroyNotify:
case ReparentNotify:
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->mod = event->xcrossing.state;
ed->detail = 0;
EvAct(event, event->xcrossing.window, ed);
break;
case KeyPress:
case KeyRelease:
ed->type = event->type;
ed->mod = event->xkey.state;
ed->detail = event->xkey.keycode;
EvAct(event, event->xkey.window, ed);
break;
case ButtonPress:
ed->type = ButtonPress;
if (last_button == event->xbutton.button &&
last_click_win == event->xbutton.window) {
gettimeofday(&click_time, NULL);
if (click_time.tv_sec <= last_click.tv_sec + 1) {
if (click_time.tv_sec == last_click.tv_sec &&
(unsigned long)
(click_time.tv_usec - last_click.tv_usec) <
waimea->double_click * 1000) {
ed->type = DoubleClick;
last_click_win = (Window) 0;
}
else if ((1000000 - last_click.tv_usec) +
(unsigned long) click_time.tv_usec <
waimea->double_click * 1000) {
ed->type = DoubleClick;
last_click_win = (Window) 0;
}
else {
last_click_win = event->xbutton.window;
last_click.tv_sec = click_time.tv_sec;
last_click.tv_usec = click_time.tv_usec;
}
}
else {
last_click_win = event->xbutton.window;
last_click.tv_sec = click_time.tv_sec;
last_click.tv_usec = click_time.tv_usec;
}
}
else {
last_click_win = event->xbutton.window;
gettimeofday(&last_click, NULL);
}
last_button = event->xbutton.button;
case ButtonRelease:
if (event->type == ButtonRelease) ed->type = ButtonRelease;
ed->mod = event->xbutton.state;
ed->detail = event->xbutton.button;
EvAct(event, event->xbutton.window, ed);
break;
case ColormapNotify:
EvColormap(&event->xcolormap); break;
case MapRequest:
EvMapRequest(&event->xmaprequest);
ed->type = event->type;
XQueryPointer(waimea->display, event->xmaprequest.parent,
&w, &w, &rx, &ry, &i, &i, &(ed->mod));
ed->detail = 0;
event->xbutton.x_root = rx;
event->xbutton.y_root = ry;
EvAct(event, event->xmaprequest.window, ed);
break;
case ClientMessage:
EvClientMessage(event, ed);
break;
default:
#ifdef SHAPE
if (event->type == waimea->shape_event) {
XShapeEvent *e = (XShapeEvent *) event;
WaWindow *ww = (WaWindow *)
waimea->FindWin(e->window, WindowType);
if (ww && waimea->shape)
ww->Shape();
}
#endif // SHAPE
#ifdef RANDR
if (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
}
delete ed;
}
/**
* @fn EvProperty(XPropertyEvent *e)
* @brief PropertyEvent handler
*
* We receive a property event when a window want us to update some window
* info. Unless the state of the property event is PropertyDelete, we try
* to find the WaWindow managing the the window who sent the event. If a
* WaWindow was found, we update the stuff indicated by the event. If the
* name should be updated we also redraw the label foreground for the
* WaWindow. If atom is _NET_WM_STRUT we update the strut list and workarea.
*
* @param e The PropertyEvent
*/
void EventHandler::EvProperty(XPropertyEvent *e) {
WaWindow *ww;
if (e->state == PropertyDelete) {
if (e->atom == waimea->net->net_wm_strut) {
if ((ww = (WaWindow *) waimea->FindWin(e->window, WindowType))) {
list<WMstrut *>::iterator s_it =
ww->wascreen->strut_list.begin();
for (; s_it != ww->wascreen->strut_list.end(); ++s_it) {
if ((*s_it)->window == e->window) {
ww->wascreen->strut_list.remove(*s_it);
free(*s_it);
ww->wascreen->UpdateWorkarea();
}
}
}
}
} 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 == XA_WM_NAME) {
if ((ww = (WaWindow *) waimea->FindWin(e->window, WindowType))) {
waimea->net->GetXaName(ww);
if (ww->wascreen->config.db) {
ww->title->Render();
ww->label->Render();
} else
ww->label->Draw();
}
}
#ifdef RENDER
else if (e->atom == waimea->net->xrootpmap_id) {
if (WaScreen *ws = (WaScreen *) waimea->FindWin(e->window, RootType)) {
waimea->net->GetXRootPMapId(ws);
ws->ic->setXRootPMapId((ws->xrootpmap_id)? true: false);
list<DockappHandler *>::iterator dock_it = ws->docks.begin();
for (; dock_it != ws->docks.end(); ++dock_it)
if ((*dock_it)->dockapp_list->size()) (*dock_it)->Render();
list<WaWindow *>::iterator win_it = ws->wawindow_list.begin();
for (; win_it != ws->wawindow_list.end(); ++win_it) {
if ((*win_it)->title_w) (*win_it)->DrawTitlebar();
if ((*win_it)->handle_w) (*win_it)->DrawHandlebar();
}
list<WaMenu *>::iterator menu_it = ws->wamenu_list.begin();
for (; menu_it != ws->wamenu_list.end(); ++menu_it) {
if ((*menu_it)->mapped) (*menu_it)->Render();
}
}
}
#endif // RENDER
}
/**
* @fn EvExpose(XExposeEvent *e)
* @brief ExposeEvent handler
*
* We receive an expose event when a windows foreground has been exposed
* for some change. If the event is from one of our windows with
* foreground, we redraw the foreground for this window.
*
* @param e The ExposeEvent
*/
void EventHandler::EvExpose(XExposeEvent *e) {
if (WindowObject *wo = waimea->FindWin(e->window, LabelType | ButtonType |
MenuTitleType | MenuItemType |
MenuSubType | MenuCBItemType))
switch (wo->type) {
case LabelType:
if (! ((WaChildWindow *) wo)->wa->wascreen->config.db)
((WaChildWindow *) wo)->Draw();
break;
case ButtonType:
((WaChildWindow *) wo)->Draw(); break;
case MenuTitleType:
case MenuItemType:
case MenuSubType:
case MenuCBItemType:
if (! ((WaMenuItem *) wo)->db)
((WaMenuItem *) wo)->Draw();
}
}
/**
* @fn EvFocus(XFocusChangeEvent *e)
* @brief FocusChangeEvent handler
*
* We receive a focus change event when a window gets the keyboard focus.
* If a WaWindow is managing the window pointed to by the event then we change
* the WaWindows decorations to represent a focused window, and we change the
* before focused WaWindows decorations to represent an unfocused window.
*
* @param e The FocusChangeEvent
*/
void EventHandler::EvFocus(XFocusChangeEvent *e) {
WaWindow *ww = NULL, *ww2;
if (e->type == FocusIn && e->window != focused) {
ww = (WaWindow *) waimea->FindWin(e->window, WindowType);
if ((ww2 = (WaWindow *) waimea->FindWin(focused, WindowType))) {
ww2->actionlist =
ww2->GetActionList(&ww2->wascreen->config.ext_pwinacts);
if (! ww2->actionlist)
ww2->actionlist = &ww2->wascreen->config.pwinacts;
ww2->UpdateGrabs();
ww2->UnFocusWin();
}
if (ww) {
ww->actionlist =
ww->GetActionList(&ww->wascreen->config.ext_awinacts);
if (! ww->actionlist)
ww->actionlist = &ww->wascreen->config.awinacts;
ww->UpdateGrabs();
ww->FocusWin();
ww->net->SetActiveWindow(ww->wascreen, ww);
}
focused = e->window;
}
if (WaScreen *ws = (WaScreen *) waimea->FindWin(e->window, RootType))
waimea->net->SetActiveWindow(ws, NULL);
}
/**
* @fn EvConfigureRequest(XConfigureRequestEvent *e)
* @brief ConfigureRequestEvent handler
*
* When we receive this event a window wants to be reconfigured (raised,
* lowered, moved, resized). We try find a matching WaWindow managing the
* window, if found we update that WaWindow with the values from the configure
* request event. If we don't found a WaWindow managing the window who wants
* to be reconfigured, we just update that window with the values from the
* configure request event.
*
* @param e The ConfigureRequestEvent
*/
void EventHandler::EvConfigureRequest(XConfigureRequestEvent *e) {
WindowObject *wo;
WaWindow *ww;
Dockapp *da;
XWindowChanges wc;
int mask;
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;
waimea->net->GetWMNormalHints(ww);
if (ww->ign_config_req) return;
ww->Gravitate(RemoveGravity);
if (e->value_mask & CWX) ww->attrib.x = e->x;
if (e->value_mask & CWY) ww->attrib.y = e->y;
if (e->value_mask & CWWidth) ww->attrib.width = e->width;
if (e->value_mask & CWHeight) ww->attrib.height = e->height;
ww->Gravitate(ApplyGravity);
ww->RedrawWindow();
wc.sibling = e->above;
wc.stack_mode = e->detail;
wc.border_width = 0;
mask = (e->value_mask & CWSibling)? CWSibling: 0;
mask |= (e->value_mask & CWStackMode)? CWStackMode: 0;
XConfigureWindow(ww->display, ww->frame->id, mask, &wc);
if (e->value_mask & CWStackMode) {
ww->wascreen->WaRaiseWindow((Window) 0);
}
ww->net->SetVirtualPos(ww);
return;
}
else if (wo->type == DockAppType) {
da = (Dockapp *) wo;
XGrabServer(e->display);
if (e->value_mask & CWWidth) da->width = e->width;
if (e->value_mask & CWHeight) da->height = e->height;
if (validatedrawable(da->id))
XConfigureWindow(e->display, da->id, e->value_mask, &wc);
XUngrabServer(e->display);
da->dh->Update();
}
}
XGrabServer(e->display);
if (validatedrawable(e->window))
XConfigureWindow(e->display, e->window, e->value_mask, &wc);
XUngrabServer(e->display);
}
/**
* @fn EvColormap(XColormapEvent *e)
* @brief ColormapEvent handler
*
* A window wants to install a new colormap, so we do it.
*
* @param e The ColormapEvent
*/
void EventHandler::EvColormap(XColormapEvent *e) {
XInstallColormap(e->display, e->colormap);
}
/**
* @fn EvMapRequest(XMapRequestEvent *e)
* @brief MapRequestEvent handler
*
* We receive this event then a window wants to be mapped. If the window
* isn't in our window hash_map already it's a new window and we create
* a WaWindow for it. If the window already is managed we just set its
* state to NormalState.
*
* @param e The MapRequestEvent
*/
void EventHandler::EvMapRequest(XMapRequestEvent *e) {
XWindowAttributes attr;
XWMHints *wm_hints;
if (WaWindow *ww = (WaWindow *) waimea->FindWin(e->window, WindowType)) {
ww->net->SetState(ww, NormalState);
}
else if (WaScreen *ws =
(WaScreen *) waimea->FindWin(e->parent, RootType)) {
if (ws->net->IsSystrayWindow(e->window)) {
if (! waimea->FindWin(e->window, SystrayType)) {
XGrabServer(ws->display);
if (validatedrawable(e->window)) {
XSelectInput(ws->display, e->window, StructureNotifyMask);
}
XUngrabServer(ws->display);
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 {
wm_hints = XAllocWMHints();
XGetWindowAttributes(e->display, e->window, &attr);
if (! attr.override_redirect) {
if ((wm_hints = XGetWMHints(e->display, e->window)) &&
(wm_hints->flags & StateHint) &&
(wm_hints->initial_state == WithdrawnState)) {
ws->AddDockapp(e->window);
} else {
new WaWindow(e->window, ws);
ws->net->SetClientList(ws);
ws->net->SetClientListStacking(ws);
}
}
XFree(wm_hints);
}
}
}
/**
* @fn EvUnmapDestroy(XEvent *e)
* @brief UnmapEvent, DestroyEvent and ReparentEvent handler
*
* We receive this event then a window has been unmapped, destroyed or
* reparented. If we can find a WaWindow for this window then the delete that
* WaWindow. If we couldn't find a WaWindow we check if the windows is a
* dockapp window and if it is, we update the dockapp handler holding the
* dockapp.
*
* @param e The XEvent
*/
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 == DestroyNotify)
((WaWindow *) wo)->deleted = true;
delete ((WaWindow *) wo);
}
else if (wo->type == DockAppType) {
if (e->type == DestroyNotify)
((Dockapp *) wo)->deleted = true;
dh = ((Dockapp *) wo)->dh;
delete ((Dockapp *) wo);
dh->Update();
}
else if (wo->type == SystrayType && (e->type == DestroyNotify)) {
SystrayWindow *stw = (SystrayWindow *) wo;
waimea->window_table.erase(stw->id);
XGrabServer(stw->ws->display);
if (validatedrawable(stw->id)) {
XSelectInput(stw->ws->display, stw->id, NoEventMask);
}
XUngrabServer(stw->ws->display);
stw->ws->systray_window_list.remove(stw->id);
stw->ws->net->SetSystrayWindows(stw->ws);
delete stw;
}
}
}
/**
* @fn EvClientMessage(XEvent *e, EventDetail *ed)
* @brief ClientMessageEvent handler
*
* This function handles all client message events received.
*
* @param e The XEvent
* @param ed Structure containing event details
*/
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->Focus(true);
ww->Raise(NULL, NULL);
}
}
else if (e->xclient.message_type == waimea->net->net_wm_name) {
if ((ww = (WaWindow *) waimea->FindWin(e->xclient.window,
WindowType))) {
waimea->net->GetNetName(ww);
if (ww->wascreen->config.db) {
ww->title->Render();
ww->label->Render();
} else
ww->label->Draw();
}
}
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->wascreen->config.desktops) {
ww->desktop_mask =
(1L << (unsigned int) e->xclient.data.l[0]);
if (ww->desktop_mask &
(1L << ww->wascreen->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_desktop_mask) {
if ((ww = (WaWindow *) waimea->FindWin(e->xclient.window,
WindowType))) {
if (e->xclient.data.l[0] <
((1L << ww->wascreen->config.desktops) - 1) &&
e->xclient.data.l[0] >= 0) {
ww->desktop_mask = e->xclient.data.l[0];
if (ww->desktop_mask &
(1L << ww->wascreen->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_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_state_sticky) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->UnSticky(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->Sticky(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->ToggleSticky(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_shaded) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->UnShade(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->Shade(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->ToggleShade(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_maximized_vert ||
(unsigned long) e->xclient.data.l[i] ==
waimea->net->net_maximized_horz) {
if (max_done) break;
max_done = true;
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->UnMaximize(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->Maximize(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->ToggleMaximize(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_aot) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->AlwaysontopOff(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->AlwaysontopOn(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->AlwaysontopToggle(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_aab) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->AlwaysatbottomOff(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->AlwaysatbottomOn(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->AlwaysatbottomToggle(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_decor) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->DecorAllOff(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->DecorAllOn(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
if (ww->flags.all) ww->DecorAllOff(NULL, NULL);
else ww->DecorAllOn(NULL, NULL);
break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_decortitle) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->DecorTitleOff(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->DecorTitleOn(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->DecorTitleToggle(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_decorhandle) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->DecorHandleOff(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->DecorHandleOn(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->DecorHandleToggle(NULL, NULL); break;
}
} else if ((unsigned long) e->xclient.data.l[i] ==
waimea->net->net_state_decorborder) {
switch (e->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
ww->DecorBorderOff(NULL, NULL); break;
case _NET_WM_STATE_ADD:
ww->DecorBorderOn(NULL, NULL); break;
case _NET_WM_STATE_TOGGLE:
ww->DecorBorderToggle(NULL, NULL); break;
}
}
}
}
}
else if (e->xclient.message_type == waimea->net->xa_xdndenter ||
e->xclient.message_type == waimea->net->xa_xdndleave) {
if (e->xclient.message_type == waimea->net->xa_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->mod));
} 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(NULL, NULL);
}
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_restart) {
restart(NULL);
}
else if (e->xclient.message_type == waimea->net->net_shutdown) {
quit(EXIT_SUCCESS);
}
}
/**
* @fn EvAct(XEvent *e, Window win)
* @brief Event action handler
*
* The eventloop will call this function whenever a event that could
* be controlled by the action lists occur. This function finds the
* WindowObject for the window, gets the action list for that type of
* WindowObject and calls the WindowObjects EvAct function.
*
* @param e The Event
* @param win The window we should use in the WindowObject search
* @param ed Structure containing event details
*/
void EventHandler::EvAct(XEvent *e, Window win, EventDetail *ed) {
WindowObject *wo;
WaWindow *wa;
map<Window, WindowObject *>::iterator it;
if ((it = waimea->window_table.find(win)) !=
waimea->window_table.end()) {
wo = (*it).second;
waimea->timer->ValidateInterrupts(e);
switch (wo->type) {
case WindowType:
wa = (WaWindow *) wo;
wa->EvAct(e, ed, wo->actionlist, wo->type);
break;
case FrameType:
case TitleType:
case LabelType:
case HandleType:
case LGripType:
case RGripType:
wa = ((WaChildWindow *) wo)->wa;
wa->EvAct(e, ed, wo->actionlist, wo->type);
break;
case ButtonType: {
wa = ((WaChildWindow *) wo)->wa;
wa->EvAct(e, ed, wo->actionlist, wo->type);
if (ed->type == ButtonPress)
wa->ButtonPressed((WaChildWindow *) wo);
} break;
case MenuTitleType:
case MenuItemType:
case MenuCBItemType:
case MenuSubType:
((WaMenuItem *) wo)->EvAct(e, ed, wo->actionlist);
break;
case WEdgeType:
case EEdgeType:
case NEdgeType:
case SEdgeType:
(((ScreenEdge *) wo)->wa)->EvAct(e, ed, wo->actionlist);
break;
case RootType:
((WaScreen *) wo)->EvAct(e, ed, wo->actionlist);
break;
}
}
}
/**
* @fn eventmatch(WaAction *act, EventDetail *ed)
* @brief Event to action matcher
*
* Checks if action type, detail and modifiers are correct.
*
* @param act Action to use for matching
* @param ed Structure containing event details
*
* @return True if match, otherwise false
*/
Bool eventmatch(WaAction *act, EventDetail *ed) {
int i;
if (ed->type != act->type) return false;
if ((act->detail && ed->detail) ? (act->detail == ed->detail): true) {
for (i = 0; i <= 12; i++)
if (act->mod & (1 << i))
if (! (ed->mod & (1 << i)))
return false;
if (act->mod & MoveResizeMask)
if (! (ed->mod & MoveResizeMask))
return false;
for (i = 0; i <= 12; i++)
if (act->nmod & (1 << i))
if (ed->mod & (1 << i))
return false;
if (act->nmod & MoveResizeMask)
if (ed->mod & MoveResizeMask)
return false;
return true;
}
return false;
}
syntax highlighted by Code2HTML, v. 0.9.1