You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2374 lines
54 KiB

/*
* Copyright © 2005 Novell, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Novell, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
* Novell, Inc. makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: David Reveman <davidr@novell.com>
*/
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xfixes.h>
#include <compiz-core.h>
static Window xdndWindow = None;
static Window edgeWindow = None;
static void
handleWindowDamageRect (CompWindow *w,
int x,
int y,
int width,
int height)
{
REGION region;
Bool initial = FALSE;
if (!w->redirected || w->bindFailed)
return;
if (!w->damaged)
{
w->damaged = initial = TRUE;
w->invisible = WINDOW_INVISIBLE (w);
}
region.extents.x1 = x;
region.extents.y1 = y;
region.extents.x2 = region.extents.x1 + width;
region.extents.y2 = region.extents.y1 + height;
if (!(*w->screen->damageWindowRect) (w, initial, &region.extents))
{
region.extents.x1 += w->attrib.x + w->attrib.border_width;
region.extents.y1 += w->attrib.y + w->attrib.border_width;
region.extents.x2 += w->attrib.x + w->attrib.border_width;
region.extents.y2 += w->attrib.y + w->attrib.border_width;
region.rects = &region.extents;
region.numRects = region.size = 1;
damageScreenRegion (w->screen, &region);
}
if (initial)
damageWindowOutputExtents (w);
}
void
handleSyncAlarm (CompWindow *w)
{
if (w->syncWait)
{
if (w->syncWaitHandle)
{
compRemoveTimeout (w->syncWaitHandle);
w->syncWaitHandle = 0;
}
w->syncWait = FALSE;
if (resizeWindow (w,
w->syncX, w->syncY,
w->syncWidth, w->syncHeight,
w->syncBorderWidth))
{
XRectangle *rects;
int nDamage;
nDamage = w->nDamage;
rects = w->damageRects;
while (nDamage--)
{
handleWindowDamageRect (w,
rects[nDamage].x,
rects[nDamage].y,
rects[nDamage].width,
rects[nDamage].height);
}
w->nDamage = 0;
}
else
{
/* resizeWindow failing means that there is another pending
resize and we must send a new sync request to the client */
sendSyncRequest (w);
}
}
}
static void
moveInputFocusToOtherWindow (CompWindow *w)
{
CompDisplay *display = w->screen->display;
if (w->id == display->activeWindow)
{
CompWindow *ancestor;
if (w->transientFor && w->transientFor != w->screen->root)
{
ancestor = findWindowAtDisplay (display, w->transientFor);
if (ancestor && !(ancestor->type & (CompWindowTypeDesktopMask |
CompWindowTypeDockMask)))
{
moveInputFocusToWindow (ancestor);
}
else
focusDefaultWindow (w->screen);
}
else if (w->type & (CompWindowTypeDialogMask |
CompWindowTypeModalDialogMask))
{
CompWindow *a, *focus = NULL;
for (a = w->screen->reverseWindows; a; a = a->prev)
{
if (a->clientLeader == w->clientLeader)
{
if ((*w->screen->focusWindow) (a))
{
if (focus)
{
if (a->type & (CompWindowTypeNormalMask |
CompWindowTypeDialogMask |
CompWindowTypeModalDialogMask))
{
if (compareWindowActiveness (focus, a) < 0)
focus = a;
}
}
else
focus = a;
}
}
}
if (focus && !(focus->type & (CompWindowTypeDesktopMask |
CompWindowTypeDockMask)))
{
moveInputFocusToWindow (focus);
}
else
focusDefaultWindow (w->screen);
}
else
focusDefaultWindow (w->screen);
}
}
static Bool
autoRaiseTimeout (void *closure)
{
CompDisplay *display = closure;
CompWindow *w = findWindowAtDisplay (display, display->activeWindow);
if (display->autoRaiseWindow == display->activeWindow ||
(w && (display->autoRaiseWindow == w->transientFor)))
{
w = findWindowAtDisplay (display, display->autoRaiseWindow);
if (w)
updateWindowAttributes (w, CompStackingUpdateModeNormal);
}
return FALSE;
}
#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
static Bool
isCallBackBinding (CompOption *option,
CompBindingType type,
CompActionState state)
{
if (!isActionOption (option))
return FALSE;
if (!(option->value.action.type & type))
return FALSE;
if (!(option->value.action.state & state))
return FALSE;
return TRUE;
}
static Bool
isInitiateBinding (CompOption *option,
CompBindingType type,
CompActionState state,
CompAction **action)
{
if (!isCallBackBinding (option, type, state))
return FALSE;
if (!option->value.action.initiate)
return FALSE;
*action = &option->value.action;
return TRUE;
}
static Bool
isTerminateBinding (CompOption *option,
CompBindingType type,
CompActionState state,
CompAction **action)
{
if (!isCallBackBinding (option, type, state))
return FALSE;
if (!option->value.action.terminate)
return FALSE;
*action = &option->value.action;
return TRUE;
}
static Bool
triggerButtonPressBindings (CompDisplay *d,
CompOption *option,
int nOption,
XButtonEvent *event,
CompOption *argument,
int nArgument)
{
CompActionState state = CompActionStateInitButton;
CompAction *action;
unsigned int modMask = REAL_MOD_MASK & ~d->ignoredModMask;
unsigned int bindMods;
unsigned int edge = 0;
if (edgeWindow)
{
CompScreen *s;
unsigned int i;
s = findScreenAtDisplay (d, event->root);
if (!s)
return FALSE;
if (event->window != edgeWindow)
{
if (!s->maxGrab || event->window != s->root)
return FALSE;
}
for (i = 0; i < SCREEN_EDGE_NUM; i++)
{
if (edgeWindow == s->screenEdge[i].id)
{
edge = 1 << i;
argument[1].value.i = d->activeWindow;
break;
}
}
}
while (nOption--)
{
if (isInitiateBinding (option, CompBindingTypeButton, state, &action))
{
if (action->button.button == event->button)
{
bindMods = virtualToRealModMask (d, action->button.modifiers);
if ((bindMods & modMask) == (event->state & modMask))
if ((*action->initiate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
if (edge)
{
if (isInitiateBinding (option, CompBindingTypeEdgeButton,
state | CompActionStateInitEdge, &action))
{
if ((action->button.button == event->button) &&
(action->edgeMask & edge))
{
bindMods = virtualToRealModMask (d,
action->button.modifiers);
if ((bindMods & modMask) == (event->state & modMask))
if ((*action->initiate) (d, action, state |
CompActionStateInitEdge,
argument, nArgument))
return TRUE;
}
}
}
option++;
}
return FALSE;
}
static Bool
triggerButtonReleaseBindings (CompDisplay *d,
CompOption *option,
int nOption,
XButtonEvent *event,
CompOption *argument,
int nArgument)
{
CompActionState state = CompActionStateTermButton;
CompBindingType type = CompBindingTypeButton | CompBindingTypeEdgeButton;
CompAction *action;
while (nOption--)
{
if (isTerminateBinding (option, type, state, &action))
{
if (action->button.button == event->button)
{
if ((*action->terminate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
option++;
}
return FALSE;
}
static Bool
triggerKeyPressBindings (CompDisplay *d,
CompOption *option,
int nOption,
XKeyEvent *event,
CompOption *argument,
int nArgument)
{
CompActionState state = 0;
CompAction *action;
unsigned int modMask = REAL_MOD_MASK & ~d->ignoredModMask;
unsigned int bindMods;
if (event->keycode == d->escapeKeyCode)
state = CompActionStateCancel;
else if (event->keycode == d->returnKeyCode)
state = CompActionStateCommit;
if (state)
{
CompOption *o = option;
int n = nOption;
while (n--)
{
if (isActionOption (o))
{
if (o->value.action.terminate)
(*o->value.action.terminate) (d, &o->value.action,
state, NULL, 0);
}
o++;
}
if (state == CompActionStateCancel)
return FALSE;
}
state = CompActionStateInitKey;
while (nOption--)
{
if (isInitiateBinding (option, CompBindingTypeKey, state, &action))
{
bindMods = virtualToRealModMask (d, action->key.modifiers);
if (action->key.keycode == event->keycode)
{
if ((bindMods & modMask) == (event->state & modMask))
if ((*action->initiate) (d, action, state,
argument, nArgument))
return TRUE;
}
else if (!d->xkbEvent && action->key.keycode == 0)
{
if (bindMods == (event->state & modMask))
if ((*action->initiate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
option++;
}
return FALSE;
}
static Bool
triggerKeyReleaseBindings (CompDisplay *d,
CompOption *option,
int nOption,
XKeyEvent *event,
CompOption *argument,
int nArgument)
{
CompActionState state = CompActionStateTermKey;
CompAction *action;
unsigned int modMask = REAL_MOD_MASK & ~d->ignoredModMask;
unsigned int bindMods;
unsigned int mods;
mods = keycodeToModifiers (d, event->keycode);
if (!d->xkbEvent && !mods)
return FALSE;
while (nOption--)
{
if (isTerminateBinding (option, CompBindingTypeKey, state, &action))
{
bindMods = virtualToRealModMask (d, action->key.modifiers);
if ((bindMods & modMask) == 0)
{
if (action->key.keycode == event->keycode)
{
if ((*action->terminate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
else if (!d->xkbEvent && ((mods & modMask & bindMods) != bindMods))
{
if ((*action->terminate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
option++;
}
return FALSE;
}
static Bool
triggerStateNotifyBindings (CompDisplay *d,
CompOption *option,
int nOption,
XkbStateNotifyEvent *event,
CompOption *argument,
int nArgument)
{
CompActionState state;
CompAction *action;
unsigned int modMask = REAL_MOD_MASK & ~d->ignoredModMask;
unsigned int bindMods;
if (event->event_type == KeyPress)
{
state = CompActionStateInitKey;
while (nOption--)
{
if (isInitiateBinding (option, CompBindingTypeKey, state, &action))
{
if (action->key.keycode == 0)
{
bindMods = virtualToRealModMask (d, action->key.modifiers);
if ((event->mods & modMask & bindMods) == bindMods)
{
if ((*action->initiate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
}
option++;
}
}
else
{
state = CompActionStateTermKey;
while (nOption--)
{
if (isTerminateBinding (option, CompBindingTypeKey, state, &action))
{
bindMods = virtualToRealModMask (d, action->key.modifiers);
if ((event->mods & modMask & bindMods) != bindMods)
{
if ((*action->terminate) (d, action, state,
argument, nArgument))
return TRUE;
}
}
option++;
}
}
return FALSE;
}
static Bool
isBellAction (CompOption *option,
CompActionState state,
CompAction **action)
{
if (option->type != CompOptionTypeAction &&
option->type != CompOptionTypeBell)
return FALSE;
if (!option->value.action.bell)
return FALSE;
if (!(option->value.action.state & state))
return FALSE;
if (!option->value.action.initiate)
return FALSE;
*action = &option->value.action;
return TRUE;
}
static Bool
triggerBellNotifyBindings (CompDisplay *d,
CompOption *option,
int nOption,
CompOption *argument,
int nArgument)
{
CompActionState state = CompActionStateInitBell;
CompAction *action;
while (nOption--)
{
if (isBellAction (option, state, &action))
{
if ((*action->initiate) (d, action, state, argument, nArgument))
return TRUE;
}
option++;
}
return FALSE;
}
static Bool
isEdgeAction (CompOption *option,
CompActionState state,
unsigned int edge)
{
if (option->type != CompOptionTypeAction &&
option->type != CompOptionTypeButton &&
option->type != CompOptionTypeEdge)
return FALSE;
if (!(option->value.action.edgeMask & edge))
return FALSE;
if (!(option->value.action.state & state))
return FALSE;
return TRUE;
}
static Bool
isEdgeEnterAction (CompOption *option,
CompActionState state,
CompActionState delayState,
unsigned int edge,
CompAction **action)
{
if (!isEdgeAction (option, state, edge))
return FALSE;
if (option->value.action.type & CompBindingTypeEdgeButton)
return FALSE;
if (!option->value.action.initiate)
return FALSE;
if (delayState)
{
if ((option->value.action.state & CompActionStateNoEdgeDelay) !=
(delayState & CompActionStateNoEdgeDelay))
{
/* ignore edge actions which shouldn't be delayed when invoking
undelayed edges (or vice versa) */
return FALSE;
}
}
*action = &option->value.action;
return TRUE;
}
static Bool
isEdgeLeaveAction (CompOption *option,
CompActionState state,
unsigned int edge,
CompAction **action)
{
if (!isEdgeAction (option, state, edge))
return FALSE;
if (!option->value.action.terminate)
return FALSE;
*action = &option->value.action;
return TRUE;
}
static Bool
triggerEdgeEnterBindings (CompDisplay *d,
CompOption *option,
int nOption,
CompActionState state,
CompActionState delayState,
unsigned int edge,
CompOption *argument,
int nArgument)
{
CompAction *action;
while (nOption--)
{
if (isEdgeEnterAction (option, state, delayState, edge, &action))
{
if ((*action->initiate) (d, action, state, argument, nArgument))
return TRUE;
}
option++;
}
return FALSE;
}
static Bool
triggerEdgeLeaveBindings (CompDisplay *d,
CompOption *option,
int nOption,
CompActionState state,
unsigned int edge,
CompOption *argument,
int nArgument)
{
CompAction *action;
while (nOption--)
{
if (isEdgeLeaveAction (option, state, edge, &action))
{
if ((*action->terminate) (d, action, state, argument, nArgument))
return TRUE;
}
option++;
}
return FALSE;
}
static Bool
triggerAllEdgeEnterBindings (CompDisplay *d,
CompActionState state,
CompActionState delayState,
unsigned int edge,
CompOption *argument,
int nArgument)
{
CompOption *option;
int nOption;
CompPlugin *p;
for (p = getPlugins (); p; p = p->next)
{
if (p->vTable->getObjectOptions)
{
option = (*p->vTable->getObjectOptions) (p, &d->base, &nOption);
if (triggerEdgeEnterBindings (d,
option, nOption,
state, delayState, edge,
argument, nArgument))
{
return TRUE;
}
}
}
return FALSE;
}
static Bool
delayedEdgeTimeout (void *closure)
{
CompDelayedEdgeSettings *settings = (CompDelayedEdgeSettings *) closure;
triggerAllEdgeEnterBindings (settings->d,
settings->state,
~CompActionStateNoEdgeDelay,
settings->edge,
settings->option,
settings->nOption);
free (settings);
return FALSE;
}
static Bool
triggerEdgeEnter (CompDisplay *d,
unsigned int edge,
CompActionState state,
CompOption *argument,
unsigned int nArgument)
{
int delay;
CompDelayedEdgeSettings *delayedSettings = NULL;
delay = d->opt[COMP_DISPLAY_OPTION_EDGE_DELAY].value.i;
if (nArgument > 7)
nArgument = 7;
if (delay > 0)
{
delayedSettings = malloc (sizeof (CompDelayedEdgeSettings));
if (delayedSettings)
{
delayedSettings->d = d;
delayedSettings->edge = edge;
delayedSettings->state = state;
delayedSettings->nOption = nArgument;
}
}
if (delayedSettings)
{
CompActionState delayState;
int i;
for (i = 0; i < nArgument; i++)
delayedSettings->option[i] = argument[i];
d->edgeDelayHandle = compAddTimeout (delay, (float) delay * 1.2,
delayedEdgeTimeout,
delayedSettings);
delayState = CompActionStateNoEdgeDelay;
if (triggerAllEdgeEnterBindings (d, state, delayState,
edge, argument, nArgument))
return TRUE;
}
else
{
if (triggerAllEdgeEnterBindings (d, state, 0, edge,
argument, nArgument))
return TRUE;
}
return FALSE;
}
static Bool
handleActionEvent (CompDisplay *d,
XEvent *event)
{
CompObject *obj = &d->base;
CompOption *option;
int nOption;
CompPlugin *p;
CompOption o[8];
o[0].type = CompOptionTypeInt;
o[0].name = "event_window";
o[1].type = CompOptionTypeInt;
o[1].name = "window";
o[2].type = CompOptionTypeInt;
o[2].name = "modifiers";
o[3].type = CompOptionTypeInt;
o[3].name = "x";
o[4].type = CompOptionTypeInt;
o[4].name = "y";
o[5].type = CompOptionTypeInt;
o[5].name = "root";
switch (event->type) {
case ButtonPress:
o[0].value.i = event->xbutton.window;
o[1].value.i = event->xbutton.window;
o[2].value.i = event->xbutton.state;
o[3].value.i = event->xbutton.x_root;
o[4].value.i = event->xbutton.y_root;
o[5].value.i = event->xbutton.root;
o[6].type = CompOptionTypeInt;
o[6].name = "button";
o[6].value.i = event->xbutton.button;
o[7].type = CompOptionTypeInt;
o[7].name = "time";
o[7].value.i = event->xbutton.time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerButtonPressBindings (d, option, nOption,
&event->xbutton, o, 8))
return TRUE;
}
break;
case ButtonRelease:
o[0].value.i = event->xbutton.window;
o[1].value.i = event->xbutton.window;
o[2].value.i = event->xbutton.state;
o[3].value.i = event->xbutton.x_root;
o[4].value.i = event->xbutton.y_root;
o[5].value.i = event->xbutton.root;
o[6].type = CompOptionTypeInt;
o[6].name = "button";
o[6].value.i = event->xbutton.button;
o[7].type = CompOptionTypeInt;
o[7].name = "time";
o[7].value.i = event->xbutton.time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerButtonReleaseBindings (d, option, nOption,
&event->xbutton, o, 8))
return TRUE;
}
break;
case KeyPress:
o[0].value.i = event->xkey.window;
o[1].value.i = d->activeWindow;
o[2].value.i = event->xkey.state;
o[3].value.i = event->xkey.x_root;
o[4].value.i = event->xkey.y_root;
o[5].value.i = event->xkey.root;
o[6].type = CompOptionTypeInt;
o[6].name = "keycode";
o[6].value.i = event->xkey.keycode;
o[7].type = CompOptionTypeInt;
o[7].name = "time";
o[7].value.i = event->xkey.time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerKeyPressBindings (d, option, nOption,
&event->xkey, o, 8))
return TRUE;
}
break;
case KeyRelease:
o[0].value.i = event->xkey.window;
o[1].value.i = d->activeWindow;
o[2].value.i = event->xkey.state;
o[3].value.i = event->xkey.x_root;
o[4].value.i = event->xkey.y_root;
o[5].value.i = event->xkey.root;
o[6].type = CompOptionTypeInt;
o[6].name = "keycode";
o[6].value.i = event->xkey.keycode;
o[7].type = CompOptionTypeInt;
o[7].name = "time";
o[7].value.i = event->xkey.time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerKeyReleaseBindings (d, option, nOption,
&event->xkey, o, 8))
return TRUE;
}
break;
case EnterNotify:
if (event->xcrossing.mode != NotifyGrab &&
event->xcrossing.mode != NotifyUngrab &&
event->xcrossing.detail != NotifyInferior)
{
CompScreen *s;
unsigned int edge, i;
CompActionState state;
s = findScreenAtDisplay (d, event->xcrossing.root);
if (!s)
return FALSE;
if (d->edgeDelayHandle)
{
void *closure;
closure = compRemoveTimeout (d->edgeDelayHandle);
if (closure)
free (closure);
d->edgeDelayHandle = 0;
}
if (edgeWindow && edgeWindow != event->xcrossing.window)
{
state = CompActionStateTermEdge;
edge = 0;
for (i = 0; i < SCREEN_EDGE_NUM; i++)
{
if (edgeWindow == s->screenEdge[i].id)
{
edge = 1 << i;
break;
}
}
edgeWindow = None;
o[0].value.i = event->xcrossing.window;
o[1].value.i = d->activeWindow;
o[2].value.i = event->xcrossing.state;
o[3].value.i = event->xcrossing.x_root;
o[4].value.i = event->xcrossing.y_root;
o[5].value.i = event->xcrossing.root;
o[6].type = CompOptionTypeInt;
o[6].name = "time";
o[6].value.i = event->xcrossing.time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerEdgeLeaveBindings (d, option, nOption, state,
edge, o, 7))
return TRUE;
}
}
edge = 0;
for (i = 0; i < SCREEN_EDGE_NUM; i++)
{
if (event->xcrossing.window == s->screenEdge[i].id)
{
edge = 1 << i;
break;
}
}
if (edge)
{
state = CompActionStateInitEdge;
edgeWindow = event->xcrossing.window;
o[0].value.i = event->xcrossing.window;
o[1].value.i = d->activeWindow;
o[2].value.i = event->xcrossing.state;
o[3].value.i = event->xcrossing.x_root;
o[4].value.i = event->xcrossing.y_root;
o[5].value.i = event->xcrossing.root;
o[6].type = CompOptionTypeInt;
o[6].name = "time";
o[6].value.i = event->xcrossing.time;
if (triggerEdgeEnter (d, edge, state, o, 7))
return TRUE;
}
}
break;
case ClientMessage:
if (event->xclient.message_type == d->xdndEnterAtom)
{
xdndWindow = event->xclient.window;
}
else if (event->xclient.message_type == d->xdndLeaveAtom)
{
unsigned int edge = 0;
CompActionState state;
Window root = None;
if (!xdndWindow)
{
CompWindow *w;
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
CompScreen *s = w->screen;
unsigned int i;
for (i = 0; i < SCREEN_EDGE_NUM; i++)
{
if (event->xclient.window == s->screenEdge[i].id)
{
edge = 1 << i;
root = s->root;
break;
}
}
}
}
if (edge)
{
state = CompActionStateTermEdgeDnd;
o[0].value.i = event->xclient.window;
o[1].value.i = d->activeWindow;
o[2].value.i = 0; /* fixme */
o[3].value.i = 0; /* fixme */
o[4].value.i = 0; /* fixme */
o[5].value.i = root;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerEdgeLeaveBindings (d, option, nOption, state,
edge, o, 6))
return TRUE;
}
}
}
else if (event->xclient.message_type == d->xdndPositionAtom)
{
unsigned int edge = 0;
CompActionState state;
Window root = None;
if (xdndWindow == event->xclient.window)
{
CompWindow *w;
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
CompScreen *s = w->screen;
unsigned int i;
for (i = 0; i < SCREEN_EDGE_NUM; i++)
{
if (xdndWindow == s->screenEdge[i].id)
{
edge = 1 << i;
root = s->root;
break;
}
}
}
}
if (edge)
{
state = CompActionStateInitEdgeDnd;
o[0].value.i = event->xclient.window;
o[1].value.i = d->activeWindow;
o[2].value.i = 0; /* fixme */
o[3].value.i = event->xclient.data.l[2] >> 16;
o[4].value.i = event->xclient.data.l[2] & 0xffff;
o[5].value.i = root;
if (triggerEdgeEnter (d, edge, state, o, 6))
return TRUE;
}
xdndWindow = None;
}
break;
default:
if (event->type == d->fixesEvent + XFixesCursorNotify)
{
/*
XFixesCursorNotifyEvent *ce = (XFixesCursorNotifyEvent *) event;
CompCursor *cursor;
cursor = findCursorAtDisplay (d);
if (cursor)
updateCursor (cursor, ce->x, ce->y, ce->cursor_serial);
*/
}
else if (event->type == d->xkbEvent)
{
XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
if (xkbEvent->xkb_type == XkbStateNotify)
{
XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
o[0].value.i = d->activeWindow;
o[1].value.i = d->activeWindow;
o[2].value.i = stateEvent->mods;
o[3].type = CompOptionTypeInt;
o[3].name = "time";
o[3].value.i = xkbEvent->time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerStateNotifyBindings (d, option, nOption,
stateEvent, o, 4))
return TRUE;
}
}
else if (xkbEvent->xkb_type == XkbBellNotify)
{
o[0].value.i = d->activeWindow;
o[1].value.i = d->activeWindow;
o[2].type = CompOptionTypeInt;
o[2].name = "time";
o[2].value.i = xkbEvent->time;
for (p = getPlugins (); p; p = p->next)
{
if (!p->vTable->getObjectOptions)
continue;
option = (*p->vTable->getObjectOptions) (p, obj, &nOption);
if (triggerBellNotifyBindings (d, option, nOption, o, 3))
return TRUE;
}
}
}
break;
}
return FALSE;
}
void
handleCompizEvent (CompDisplay *d,
const char *pluginName,
const char *eventName,
CompOption *option,
int nOption)
{
}
void
handleEvent (CompDisplay *d,
XEvent *event)
{
CompScreen *s;
CompWindow *w;
switch (event->type) {
case ButtonPress:
s = findScreenAtDisplay (d, event->xbutton.root);
if (s)
setCurrentOutput (s, outputDeviceForPoint (s,
event->xbutton.x_root,
event->xbutton.y_root));
break;
case MotionNotify:
s = findScreenAtDisplay (d, event->xmotion.root);
if (s)
setCurrentOutput (s, outputDeviceForPoint (s,
event->xmotion.x_root,
event->xmotion.y_root));
break;
case KeyPress:
w = findWindowAtDisplay (d, d->activeWindow);
if (w)
setCurrentOutput (w->screen, outputDeviceForWindow (w));
default:
break;
}
if (handleActionEvent (d, event))
{
if (!d->screens->maxGrab)
XAllowEvents (d->display, AsyncPointer, event->xbutton.time);
return;
}
switch (event->type) {
case Expose:
for (s = d->screens; s; s = s->next)
if (s->output == event->xexpose.window)
break;
if (s)
{
int more = event->xexpose.count + 1;
if (s->nExpose == s->sizeExpose)
{
s->exposeRects = realloc (s->exposeRects,
(s->sizeExpose + more) *
sizeof (XRectangle));
s->sizeExpose += more;
}
s->exposeRects[s->nExpose].x = event->xexpose.x;
s->exposeRects[s->nExpose].y = event->xexpose.y;
s->exposeRects[s->nExpose].width = event->xexpose.width;
s->exposeRects[s->nExpose].height = event->xexpose.height;
s->nExpose++;
if (event->xexpose.count == 0)
{
REGION rect;
rect.rects = &rect.extents;
rect.numRects = rect.size = 1;
while (s->nExpose--)
{
rect.extents.x1 = s->exposeRects[s->nExpose].x;
rect.extents.y1 = s->exposeRects[s->nExpose].y;
rect.extents.x2 = rect.extents.x1 +
s->exposeRects[s->nExpose].width;
rect.extents.y2 = rect.extents.y1 +
s->exposeRects[s->nExpose].height;
damageScreenRegion (s, &rect);
}
s->nExpose = 0;
}
}
break;
case SelectionRequest:
handleSelectionRequest (d, event);
break;
case SelectionClear:
handleSelectionClear (d, event);
break;
case ConfigureNotify:
w = findWindowAtDisplay (d, event->xconfigure.window);
if (w)
{
configureWindow (w, &event->xconfigure);
}
else
{
s = findScreenAtDisplay (d, event->xconfigure.window);
if (s)
configureScreen (s, &event->xconfigure);
}
break;
case CreateNotify:
s = findScreenAtDisplay (d, event->xcreatewindow.parent);
if (s)
{
/* The first time some client asks for the composite
* overlay window, the X server creates it, which causes
* an errorneous CreateNotify event. We catch it and
* ignore it. */
if (s->overlay != event->xcreatewindow.window)
addWindow (s, event->xcreatewindow.window, getTopWindow (s));
}
break;
case DestroyNotify:
w = findWindowAtDisplay (d, event->xdestroywindow.window);
if (w)
{
moveInputFocusToOtherWindow (w);
destroyWindow (w);
}
break;
case MapNotify:
w = findWindowAtDisplay (d, event->xmap.window);
if (w)
{
if (w->pendingMaps)
w->managed = TRUE;
/* been shaded */
if (w->height == 0)
{
if (w->id == d->activeWindow)
moveInputFocusToWindow (w);
}
mapWindow (w);
}
break;
case UnmapNotify:
w = findWindowAtDisplay (d, event->xunmap.window);
if (w)
{
/* Normal -> Iconic */
if (w->pendingUnmaps)
{
setWmState (d, IconicState, w->id);
w->pendingUnmaps--;
}
else /* X -> Withdrawn */
{
/* Iconic -> Withdrawn */
if (w->state & CompWindowStateHiddenMask)
{
w->minimized = FALSE;
changeWindowState (w,
w->state & ~CompWindowStateHiddenMask);
updateClientListForScreen (w->screen);
}
if (!w->attrib.override_redirect)
setWmState (d, WithdrawnState, w->id);
w->placed = FALSE;
}
unmapWindow (w);
if (!w->shaded)
moveInputFocusToOtherWindow (w);
}
break;
case ReparentNotify:
w = findWindowAtDisplay (d, event->xreparent.window);
s = findScreenAtDisplay (d, event->xreparent.parent);
if (s && !w)
{
addWindow (s, event->xreparent.window, getTopWindow (s));
}
else if (w)
{
/* This is the only case where a window is removed but not
destroyed. We must remove our event mask and all passive
grabs. */
XSelectInput (d->display, w->id, NoEventMask);
XShapeSelectInput (d->display, w->id, NoEventMask);
XUngrabButton (d->display, AnyButton, AnyModifier, w->id);
moveInputFocusToOtherWindow (w);
destroyWindow (w);
}
break;
case CirculateNotify:
w = findWindowAtDisplay (d, event->xcirculate.window);
if (w)
circulateWindow (w, &event->xcirculate);
break;
case ButtonPress:
s = findScreenAtDisplay (d, event->xbutton.root);
if (s)
{
if (event->xbutton.button == Button1 ||
event->xbutton.button == Button2 ||
event->xbutton.button == Button3)
{
w = findTopLevelWindowAtScreen (s, event->xbutton.window);
if (w)
{
if (d->opt[COMP_DISPLAY_OPTION_RAISE_ON_CLICK].value.b)
updateWindowAttributes (w,
CompStackingUpdateModeAboveFullscreen);
if (w->id != d->activeWindow)
if (!(w->type & CompWindowTypeDockMask))
if ((*s->focusWindow) (w))
moveInputFocusToWindow (w);
}
}
if (!s->maxGrab)
XAllowEvents (d->display, ReplayPointer, event->xbutton.time);
}
break;
case PropertyNotify:
if (event->xproperty.atom == d->winTypeAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
unsigned int type;
type = getWindowType (d, w->id);
if (type != w->wmType)
{
if (w->attrib.map_state == IsViewable)
{
if (w->type == CompWindowTypeDesktopMask)
w->screen->desktopWindowCount--;
else if (type == CompWindowTypeDesktopMask)
w->screen->desktopWindowCount++;
}
w->wmType = type;
recalcWindowType (w);
recalcWindowActions (w);
if (w->type & CompWindowTypeDesktopMask)
w->paint.opacity = OPAQUE;
if (type & (CompWindowTypeDockMask |
CompWindowTypeDesktopMask))
setDesktopForWindow (w, 0xffffffff);
updateClientListForScreen (w->screen);
(*d->matchPropertyChanged) (d, w);
}
}
}
else if (event->xproperty.atom == d->winStateAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w && !w->managed)
{
unsigned int state;
state = getWindowState (d, w->id);
state = constrainWindowState (state, w->actions);
/* EWMH suggests that we ignore changes
to _NET_WM_STATE_HIDDEN */
if (w->state & CompWindowStateHiddenMask)
state |= CompWindowStateHiddenMask;
else
state &= ~CompWindowStateHiddenMask;
if (state != w->state)
{
if (w->type & CompWindowTypeDesktopMask)
w->paint.opacity = OPAQUE;
changeWindowState (w, state);
}
}
}
else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
updateNormalHints (w);
recalcWindowActions (w);
}
}
else if (event->xproperty.atom == XA_WM_HINTS)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
updateWmHints (w);
}
else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
updateTransientHint (w);
recalcWindowActions (w);
}
}
else if (event->xproperty.atom == d->wmClientLeaderAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
w->clientLeader = getClientLeader (w);
}
else if (event->xproperty.atom == d->wmIconGeometryAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
updateIconGeometry (w);
}
else if (event->xproperty.atom == d->winOpacityAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w && !(w->type & CompWindowTypeDesktopMask))
{
int opacity;
opacity = getWindowProp32 (d, w->id, d->winOpacityAtom, OPAQUE);
if (opacity != w->paint.opacity)
{
w->paint.opacity = opacity;
addWindowDamage (w);
}
}
}
else if (event->xproperty.atom == d->winBrightnessAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
int brightness;
brightness = getWindowProp32 (d, w->id,
d->winBrightnessAtom, BRIGHT);
if (brightness != w->paint.brightness)
{
w->paint.brightness = brightness;
addWindowDamage (w);
}
}
}
else if (event->xproperty.atom == d->winSaturationAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w && w->screen->canDoSaturated)
{
int saturation;
saturation = getWindowProp32 (d, w->id,
d->winSaturationAtom, COLOR);
if (saturation != w->paint.saturation)
{
w->paint.saturation = saturation;
addWindowDamage (w);
}
}
}
else if (event->xproperty.atom == d->xBackgroundAtom[0] ||
event->xproperty.atom == d->xBackgroundAtom[1])
{
s = findScreenAtDisplay (d, event->xproperty.window);
if (s)
{
finiTexture (s, &s->backgroundTexture);
initTexture (s, &s->backgroundTexture);
if (s->backgroundLoaded)
{
s->backgroundLoaded = FALSE;
damageScreen (s);
}
}
}
else if (event->xproperty.atom == d->wmStrutAtom ||
event->xproperty.atom == d->wmStrutPartialAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
if (updateWindowStruts (w))
updateWorkareaForScreen (w->screen);
}
}
else if (event->xproperty.atom == d->mwmHintsAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
getMwmHints (d, w->id, &w->mwmFunc, &w->mwmDecor);
recalcWindowActions (w);
}
}
else if (event->xproperty.atom == d->wmProtocolsAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
w->protocols = getProtocols (d, w->id);
}
else if (event->xproperty.atom == d->wmIconAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
freeWindowIcons (w);
}
else if (event->xproperty.atom == d->startupIdAtom)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
{
if (w->startupId)
free (w->startupId);
w->startupId = getStartupId (w);
if (w->managed && w->startupId)
{
Time timestamp = 0;
int vx, vy, x, y;
CompScreen *s = w->screen;
CompFocusResult focus;
w->initialTimestampSet = FALSE;
applyStartupProperties (w->screen, w);
if (w->initialTimestampSet)
timestamp = w->initialTimestamp;
/* as the viewport can't be transmitted via startup
notification, assume the client changing the ID
wanted to activate the window on the current viewport */
defaultViewportForWindow (w, &vx, &vy);
x = w->attrib.x + (s->x - vx) * s->width;
y = w->attrib.y + (s->y - vy) * s->height;
moveWindowToViewportPosition (w, x, y, TRUE);
focus = allowWindowFocus (w, 0,
w->initialViewportX,
w->initialViewportY,
timestamp);
if (focus == CompFocusAllowed)
(*w->screen->activateWindow) (w);
}
}
}
else if (event->xproperty.atom == XA_WM_CLASS)
{
w = findWindowAtDisplay (d, event->xproperty.window);
if (w)
updateWindowClassHints (w);
}
break;
case MotionNotify:
break;
case ClientMessage:
if (event->xclient.message_type == d->winActiveAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
CompFocusResult focus = CompFocusAllowed;
/* use focus stealing prevention if request came
from an application */
if (event->xclient.data.l[0] == ClientTypeApplication)
focus = allowWindowFocus (w, 0,
w->screen->x,
w->screen->y,
event->xclient.data.l[1]);
if (focus == CompFocusAllowed)
(*w->screen->activateWindow) (w);
}
}
else if (event->xclient.message_type == d->winOpacityAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w && !(w->type & CompWindowTypeDesktopMask))
{
GLushort opacity = event->xclient.data.l[0] >> 16;
setWindowProp32 (d, w->id, d->winOpacityAtom, opacity);
}
}
else if (event->xclient.message_type == d->winBrightnessAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
GLushort brightness = event->xclient.data.l[0] >> 16;
setWindowProp32 (d, w->id, d->winBrightnessAtom, brightness);
}
}
else if (event->xclient.message_type == d->winSaturationAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w && w->screen->canDoSaturated)
{
GLushort saturation = event->xclient.data.l[0] >> 16;
setWindowProp32 (d, w->id, d->winSaturationAtom, saturation);
}
}
else if (event->xclient.message_type == d->winStateAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
unsigned long wState, state;
int i;
wState = w->state;
for (i = 1; i < 3; i++)
{
state = windowStateMask (d, event->xclient.data.l[i]);
if (state & ~CompWindowStateHiddenMask)
{
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
switch (event->xclient.data.l[0]) {
case _NET_WM_STATE_REMOVE:
wState &= ~state;
break;
case _NET_WM_STATE_ADD:
wState |= state;
break;
case _NET_WM_STATE_TOGGLE:
wState ^= state;
break;
}
}
}
wState = constrainWindowState (wState, w->actions);
if (w->id == d->activeWindow)
wState &= ~CompWindowStateDemandsAttentionMask;
if (wState != w->state)
{
CompStackingUpdateMode stackingUpdateMode;
unsigned long dState = wState ^ w->state;
stackingUpdateMode = CompStackingUpdateModeNone;
/* raise the window whenever its fullscreen state,
above/below state or maximization state changed */
if (dState & CompWindowStateFullscreenMask)
stackingUpdateMode = CompStackingUpdateModeAboveFullscreen;
else if (dState & (CompWindowStateAboveMask |
CompWindowStateBelowMask |
CompWindowStateMaximizedHorzMask |
CompWindowStateMaximizedVertMask))
stackingUpdateMode = CompStackingUpdateModeNormal;
changeWindowState (w, wState);
updateWindowAttributes (w, stackingUpdateMode);
}
}
}
else if (event->xclient.message_type == d->wmProtocolsAtom)
{
if (event->xclient.data.l[0] == d->wmPingAtom)
{
w = findWindowAtDisplay (d, event->xclient.data.l[2]);
if (w)
{
if (!w->alive)
{
w->alive = TRUE;
if (w->lastCloseRequestTime)
{
toolkitAction (w->screen,
d->toolkitActionForceQuitDialogAtom,
w->lastCloseRequestTime,
w->id,
FALSE,
0,
0);
w->lastCloseRequestTime = 0;
}
}
w->lastPong = d->lastPing;
}
}
}
else if (event->xclient.message_type == d->closeWindowAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
closeWindow (w, event->xclient.data.l[0]);
}
else if (event->xclient.message_type == d->desktopGeometryAtom)
{
s = findScreenAtDisplay (d, event->xclient.window);
if (s)
{
CompOptionValue value;
value.i = event->xclient.data.l[0] / s->width;
(*core.setOptionForPlugin) (&s->base, "core", "hsize", &value);
value.i = event->xclient.data.l[1] / s->height;
(*core.setOptionForPlugin) (&s->base, "core", "vsize", &value);
}
}
else if (event->xclient.message_type == d->moveResizeWindowAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
unsigned int xwcm = 0;
XWindowChanges xwc;
int gravity;
unsigned int source;
memset (&xwc, 0, sizeof (xwc));
if (event->xclient.data.l[0] & (1 << 8))
{
xwcm |= CWX;
xwc.x = event->xclient.data.l[1];
}
if (event->xclient.data.l[0] & (1 << 9))
{
xwcm |= CWY;
xwc.y = event->xclient.data.l[2];
}
if (event->xclient.data.l[0] & (1 << 10))
{
xwcm |= CWWidth;
xwc.width = event->xclient.data.l[3];
}
if (event->xclient.data.l[0] & (1 << 11))
{
xwcm |= CWHeight;
xwc.height = event->xclient.data.l[4];
}
gravity = event->xclient.data.l[0] & 0xFF;
source = (event->xclient.data.l[0] >> 12) & 0xF;
moveResizeWindow (w, &xwc, xwcm, gravity, source);
}
}
else if (event->xclient.message_type == d->restackWindowAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
/* TODO: other stack modes than Above and Below */
if (event->xclient.data.l[1])
{
CompWindow *sibling;
sibling = findWindowAtDisplay (d, event->xclient.data.l[1]);
if (sibling)
{
if (event->xclient.data.l[2] == Above)
restackWindowAbove (w, sibling);
else if (event->xclient.data.l[2] == Below)
restackWindowBelow (w, sibling);
}
}
else
{
if (event->xclient.data.l[2] == Above)
raiseWindow (w);
else if (event->xclient.data.l[2] == Below)
lowerWindow (w);
}
}
}
else if (event->xclient.message_type == d->wmChangeStateAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
if (event->xclient.data.l[0] == IconicState)
{
if (w->actions & CompWindowActionMinimizeMask)
minimizeWindow (w);
}
else if (event->xclient.data.l[0] == NormalState)
unminimizeWindow (w);
}
}
else if (event->xclient.message_type == d->showingDesktopAtom)
{
for (s = d->screens; s; s = s->next)
{
if (event->xclient.window == s->root ||
event->xclient.window == None)
{
if (event->xclient.data.l[0])
(*s->enterShowDesktopMode) (s);
else
(*s->leaveShowDesktopMode) (s, NULL);
}
}
}
else if (event->xclient.message_type == d->numberOfDesktopsAtom)
{
s = findScreenAtDisplay (d, event->xclient.window);
if (s)
{
CompOptionValue value;
value.i = event->xclient.data.l[0];
(*core.setOptionForPlugin) (&s->base,
"core", "number_of_desktops",
&value);
}
}
else if (event->xclient.message_type == d->currentDesktopAtom)
{
s = findScreenAtDisplay (d, event->xclient.window);
if (s)
setCurrentDesktop (s, event->xclient.data.l[0]);
}
else if (event->xclient.message_type == d->winDesktopAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
setDesktopForWindow (w, event->xclient.data.l[0]);
}
else if (event->xclient.message_type == d->wmFullscreenMonitorsAtom)
{
w = findWindowAtDisplay (d, event->xclient.window);
if (w)
{
CompFullscreenMonitorSet monitors;
monitors.top = event->xclient.data.l[0];
monitors.bottom = event->xclient.data.l[1];
monitors.left = event->xclient.data.l[2];
monitors.right = event->xclient.data.l[3];
setWindowFullscreenMonitors (w, &monitors);
}
}
break;
case MappingNotify:
updateModifierMappings (d);
break;
case MapRequest:
w = findWindowAtDisplay (d, event->xmaprequest.window);
if (w)
{
XWindowAttributes attr;
Bool doMapProcessing = TRUE;
/* We should check the override_redirect flag here, because the
client might have changed it while being unmapped. */
if (XGetWindowAttributes (d->display, w->id, &attr))
{
if (w->attrib.override_redirect != attr.override_redirect)
{
w->attrib.override_redirect = attr.override_redirect;
recalcWindowType (w);
recalcWindowActions (w);
(*d->matchPropertyChanged) (d, w);
}
}
if (w->state & CompWindowStateHiddenMask)
if (!w->minimized && !w->inShowDesktopMode)
doMapProcessing = FALSE;
if (doMapProcessing)
{
w->initialViewportX = w->screen->x;
w->initialViewportY = w->screen->y;
w->initialTimestampSet = FALSE;
applyStartupProperties (w->screen, w);
}
w->managed = TRUE;
if (doMapProcessing)
{
CompFocusResult focus;
CompStackingUpdateMode stackingMode;
if (!w->placed)
{
int newX, newY;
int gravity = w->sizeHints.win_gravity;
XWindowChanges xwc;
unsigned int xwcm, source;
/* adjust for gravity */
xwc.x = w->serverX;
xwc.y = w->serverY;
xwc.width = w->serverWidth;
xwc.height = w->serverHeight;
xwcm = adjustConfigureRequestForGravity (w, &xwc,
CWX | CWY,
gravity, 1);
source = ClientTypeApplication;
(*w->screen->validateWindowResizeRequest) (w, &xwcm, &xwc,
source);
if (xwcm)
configureXWindow (w, xwcm, &xwc);
if ((*w->screen->placeWindow) (w, xwc.x, xwc.y,
&newX, &newY))
{
xwc.x = newX;
xwc.y = newY;
configureXWindow (w, CWX | CWY, &xwc);
}
w->placed = TRUE;
}
focus = allowWindowFocus (w, NO_FOCUS_MASK,
w->screen->x, w->screen->y, 0);
if (focus == CompFocusDenied)
stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
else
stackingMode = CompStackingUpdateModeInitialMap;
updateWindowAttributes (w, stackingMode);
if (w->minimized)
unminimizeWindow (w);
(*w->screen->leaveShowDesktopMode) (w->screen, w);
if (focus == CompFocusAllowed && !onCurrentDesktop (w))
setCurrentDesktop (w->screen, w->desktop);
if (!(w->state & CompWindowStateHiddenMask))
showWindow (w);
if (focus == CompFocusAllowed)
moveInputFocusToWindow (w);
}
setWindowProp (d, w->id, d->winDesktopAtom, w->desktop);
}
else
{
XMapWindow (d->display, event->xmaprequest.window);
}
break;
case ConfigureRequest:
w = findWindowAtDisplay (d, event->xconfigurerequest.window);
if (w && w->managed)
{
XWindowChanges xwc;
memset (&xwc, 0, sizeof (xwc));
xwc.x = event->xconfigurerequest.x;
xwc.y = event->xconfigurerequest.y;
xwc.width = event->xconfigurerequest.width;
xwc.height = event->xconfigurerequest.height;
xwc.border_width = event->xconfigurerequest.border_width;
moveResizeWindow (w, &xwc, event->xconfigurerequest.value_mask,
0, ClientTypeUnknown);
if (event->xconfigurerequest.value_mask & CWStackMode)
{
Window above = None;
CompWindow *sibling = NULL;
CompFocusResult focus;
if (event->xconfigurerequest.value_mask & CWSibling)
{
above = event->xconfigurerequest.above;
sibling = findTopLevelWindowAtDisplay (d, above);
}
switch (event->xconfigurerequest.detail) {
case Above:
focus = allowWindowFocus (w, NO_FOCUS_MASK,
w->screen->x, w->screen->y, 0);
if (focus == CompFocusAllowed)
{
if (above)
{
if (sibling)
restackWindowAbove (w, sibling);
}
else
raiseWindow (w);
}
break;
case Below:
if (above)
{
if (sibling)
restackWindowBelow (w, sibling);
}
else
lowerWindow (w);
break;
default:
/* no handling of the TopIf, BottomIf, Opposite cases -
there will hardly be any client using that */
break;
}
}
}
else
{
XWindowChanges xwc;
unsigned int xwcm;
xwcm = event->xconfigurerequest.value_mask &
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
xwc.x = event->xconfigurerequest.x;
xwc.y = event->xconfigurerequest.y;
xwc.width = event->xconfigurerequest.width;
xwc.height = event->xconfigurerequest.height;
xwc.border_width = event->xconfigurerequest.border_width;
if (w)
configureXWindow (w, xwcm, &xwc);
else
XConfigureWindow (d->display, event->xconfigurerequest.window,
xwcm, &xwc);
}
break;
case CirculateRequest:
break;
case FocusIn:
if (event->xfocus.mode != NotifyGrab)
{
w = findTopLevelWindowAtDisplay (d, event->xfocus.window);
if (w && w->managed)
{
unsigned int state = w->state;
if (w->id != d->activeWindow)
{
d->activeWindow = w->id;
w->activeNum = w->screen->activeNum++;
addToCurrentActiveWindowHistory (w->screen, w->id);
XChangeProperty (d->display, w->screen->root,
d->winActiveAtom,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &w->id, 1);
}
state &= ~CompWindowStateDemandsAttentionMask;
changeWindowState (w, state);
}
}
break;
case EnterNotify:
s = findScreenAtDisplay (d, event->xcrossing.root);
if (s)
w = findTopLevelWindowAtScreen (s, event->xcrossing.window);
else
w = NULL;
if (w && w->id != d->below)
{
d->below = w->id;
if (!d->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS].value.b &&
!s->maxGrab &&
event->xcrossing.mode != NotifyGrab &&
event->xcrossing.detail != NotifyInferior)
{
Bool raise, focus;
int delay;
raise = d->opt[COMP_DISPLAY_OPTION_AUTORAISE].value.b;
delay = d->opt[COMP_DISPLAY_OPTION_AUTORAISE_DELAY].value.i;
if (d->autoRaiseHandle && d->autoRaiseWindow != w->id)
{
compRemoveTimeout (d->autoRaiseHandle);
d->autoRaiseHandle = 0;
}
if (w->type & NO_FOCUS_MASK)
focus = FALSE;
else
focus = (*w->screen->focusWindow) (w);
if (focus)
{
moveInputFocusToWindow (w);
if (raise)
{
if (delay > 0)
{
d->autoRaiseWindow = w->id;
d->autoRaiseHandle =
compAddTimeout (delay, (float) delay * 1.2,
autoRaiseTimeout, d);
}
else
{
CompStackingUpdateMode mode =
CompStackingUpdateModeNormal;
updateWindowAttributes (w, mode);
}
}
}
}
}
break;
case LeaveNotify:
if (event->xcrossing.detail != NotifyInferior)
{
if (event->xcrossing.window == d->below)
d->below = None;
}
break;
default:
if (event->type == d->damageEvent + XDamageNotify)
{
XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
if (lastDamagedWindow && de->drawable == lastDamagedWindow->id)
{
w = lastDamagedWindow;
}
else
{
w = findWindowAtDisplay (d, de->drawable);
if (w)
lastDamagedWindow = w;
}
if (w)
{
w->texture->oldMipmaps = TRUE;
if (w->syncWait)
{
if (w->nDamage == w->sizeDamage)
{
w->damageRects = realloc (w->damageRects,
(w->sizeDamage + 1) *
sizeof (XRectangle));
w->sizeDamage += 1;
}
w->damageRects[w->nDamage].x = de->area.x;
w->damageRects[w->nDamage].y = de->area.y;
w->damageRects[w->nDamage].width = de->area.width;
w->damageRects[w->nDamage].height = de->area.height;
w->nDamage++;
}
else
{
handleWindowDamageRect (w,
de->area.x,
de->area.y,
de->area.width,
de->area.height);
}
}
}
else if (d->shapeExtension &&
event->type == d->shapeEvent + ShapeNotify)
{
w = findWindowAtDisplay (d, ((XShapeEvent *) event)->window);
if (w)
{
if (w->mapNum)
{
addWindowDamage (w);
updateWindowRegion (w);
addWindowDamage (w);
}
}
}
else if (d->randrExtension &&
event->type == d->randrEvent + RRScreenChangeNotify)
{
XRRScreenChangeNotifyEvent *rre;
rre = (XRRScreenChangeNotifyEvent *) event;
s = findScreenAtDisplay (d, rre->root);
if (s)
detectRefreshRateOfScreen (s);
}
else if (event->type == d->syncEvent + XSyncAlarmNotify)
{
XSyncAlarmNotifyEvent *sa;
sa = (XSyncAlarmNotifyEvent *) event;
for (s = d->screens; s; s = s->next)
{
for (w = s->windows; w; w = w->next)
{
if (w->syncAlarm == sa->alarm)
break;
}
if (w)
{
handleSyncAlarm (w);
/* it makes no sense to search for the already
found window on other screens, so leave screen loop */
break;
}
}
}
break;
}
}