From b0be6a88c8fecdf15176f642c0799bff99930e0d Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 21 Jan 2011 08:10:52 +0000 Subject: xserver mesa xkbcomp libxcb git update 21 jan 2011 --- xorg-server/Xi/exevents.c | 4353 ++++----- xorg-server/Xi/extinit.c | 2617 ++--- xorg-server/Xi/xiwarppointer.c | 2 + xorg-server/configure.ac | 4 +- xorg-server/dix/events.c | 11632 +++++++++++------------ xorg-server/dix/inpututils.c | 1108 +-- xorg-server/dix/resource.c | 1938 ++-- xorg-server/hw/dmx/config/xdmxconfig.c | 2 +- xorg-server/hw/dmx/dmxextension.c | 3238 +++---- xorg-server/hw/dmx/dmxgc.c | 837 +- xorg-server/hw/dmx/input/dmxinputinit.c | 2580 +++-- xorg-server/hw/xfree86/doc/man/Makefile.am | 2 +- xorg-server/hw/xfree86/doc/man/xorg.conf.d.man | 1 + xorg-server/hw/xwin/InitOutput.c | 2219 ++--- xorg-server/hw/xwin/Makefile.am | 1 + xorg-server/hw/xwin/man/XWin.man | 85 +- xorg-server/hw/xwin/win.h | 2950 +++--- xorg-server/hw/xwin/wincreatewnd.c | 48 +- xorg-server/hw/xwin/windialogs.c | 1547 ++- xorg-server/hw/xwin/winmonitors.c | 92 + xorg-server/hw/xwin/winmonitors.h | 14 + xorg-server/hw/xwin/winnativegdi.c | 1073 ++- xorg-server/hw/xwin/winpfbdd.c | 1354 +-- xorg-server/hw/xwin/winprocarg.c | 2473 +++-- xorg-server/hw/xwin/winrandr.c | 302 +- xorg-server/hw/xwin/winscrinit.c | 1536 +-- xorg-server/hw/xwin/winshaddd.c | 2766 +++--- xorg-server/hw/xwin/winshadddnl.c | 2808 +++--- xorg-server/hw/xwin/winshadgdi.c | 2526 +++-- xorg-server/hw/xwin/winvalargs.c | 360 +- xorg-server/hw/xwin/winwindow.c | 1273 +-- xorg-server/hw/xwin/winwndproc.c | 2575 ++--- xorg-server/include/dix.h | 1211 +-- xorg-server/include/input.h | 1174 +-- xorg-server/include/inputstr.h | 1230 +-- xorg-server/mi/miinitext.c | 2 - xorg-server/os/WaitFor.c | 1368 +-- xorg-server/test/input.c | 2172 +++-- xorg-server/test/xi2/protocol-eventconvert.c | 1824 ++-- xorg-server/test/xi2/protocol-xiselectevents.c | 18 +- xorg-server/xkb/XKBMisc.c | 1679 ++-- xorg-server/xkb/xkbUtils.c | 4247 ++++----- 42 files changed, 34777 insertions(+), 34464 deletions(-) create mode 100644 xorg-server/hw/xfree86/doc/man/xorg.conf.d.man create mode 100644 xorg-server/hw/xwin/winmonitors.c create mode 100644 xorg-server/hw/xwin/winmonitors.h (limited to 'xorg-server') diff --git a/xorg-server/Xi/exevents.c b/xorg-server/Xi/exevents.c index 40e03337d..327873e29 100644 --- a/xorg-server/Xi/exevents.c +++ b/xorg-server/Xi/exevents.c @@ -1,2176 +1,2177 @@ -/************************************************************ - -Copyright 1989, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-PACKARD 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. - -********************************************************/ - -/******************************************************************** - * - * Routines to register and initialize extension input devices. - * This also contains ProcessOtherEvent, the routine called from DDX - * to route extension events. - * - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" -#include -#include -#include -#include -#include -#include -#include "windowstr.h" -#include "miscstruct.h" -#include "region.h" -#include "exevents.h" -#include "extnsionst.h" -#include "exglobals.h" -#include "dixevents.h" /* DeliverFocusedEvent */ -#include "dixgrabs.h" /* CreateGrab() */ -#include "scrnintstr.h" -#include "listdev.h" /* for CopySwapXXXClass */ -#include "xace.h" -#include "xiquerydevice.h" /* For List*Info */ -#include "eventconvert.h" -#include "eventstr.h" - -#include -#include "xkbsrv.h" - -#define WID(w) ((w) ? ((w)->drawable.id) : 0) -#define AllModifiersMask ( \ - ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ - Mod3Mask | Mod4Mask | Mod5Mask ) -#define AllButtonsMask ( \ - Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) - -Bool ShouldFreeInputMasks(WindowPtr /* pWin */ , - Bool /* ignoreSelectedEvents */ - ); -static Bool MakeInputMasks(WindowPtr /* pWin */ - ); - -/* - * Only let the given client know of core events which will affect its - * interpretation of input events, if the client's ClientPointer (or the - * paired keyboard) is the current device. - */ -int -XIShouldNotify(ClientPtr client, DeviceIntPtr dev) -{ - DeviceIntPtr current_ptr = PickPointer(client); - DeviceIntPtr current_kbd = GetPairedDevice(current_ptr); - - if (dev == current_kbd || dev == current_ptr) - return 1; - - return 0; -} - -Bool -IsPointerEvent(InternalEvent* event) -{ - switch(event->any.type) - { - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_Motion: - /* XXX: enter/leave ?? */ - return TRUE; - default: - break; - } - return FALSE; -} - -/** - * @return the device matching the deviceid of the device set in the event, or - * NULL if the event is not an XInput event. - */ -DeviceIntPtr -XIGetDevice(xEvent* xE) -{ - DeviceIntPtr pDev = NULL; - - if (xE->u.u.type == DeviceButtonPress || - xE->u.u.type == DeviceButtonRelease || - xE->u.u.type == DeviceMotionNotify || - xE->u.u.type == ProximityIn || - xE->u.u.type == ProximityOut || - xE->u.u.type == DevicePropertyNotify) - { - int rc; - int id; - - id = ((deviceKeyButtonPointer*)xE)->deviceid & ~MORE_EVENTS; - - rc = dixLookupDevice(&pDev, id, serverClient, DixUnknownAccess); - if (rc != Success) - ErrorF("[dix] XIGetDevice failed on XACE restrictions (%d)\n", rc); - } - return pDev; -} - - -/** - * Copy the device->key into master->key and send a mapping notify to the - * clients if appropriate. - * master->key needs to be allocated by the caller. - * - * Device is the slave device. If it is attached to a master device, we may - * need to send a mapping notify to the client because it causes the MD - * to change state. - * - * Mapping notify needs to be sent in the following cases: - * - different slave device on same master - * - different master - * - * XXX: They way how the code is we also send a map notify if the slave device - * stays the same, but the master changes. This isn't really necessary though. - * - * XXX: this gives you funny behaviour with the ClientPointer. When a - * MappingNotify is sent to the client, the client usually responds with a - * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard - * mapping, regardless of which keyboard sent the last mapping notify request. - * So depending on the CP setting, your keyboard may change layout in each - * app... - * - * This code is basically the old SwitchCoreKeyboard. - */ - -void -CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master) -{ - KeyClassPtr mk = master->key; - - if (device == master) - return; - - mk->sourceid = device->id; - - - if (!XkbCopyDeviceKeymap(master, device)) - FatalError("Couldn't pivot keymap from device to core!\n"); -} - -/** - * Copies the feedback classes from device "from" into device "to". Classes - * are duplicated (not just flipping the pointers). All feedback classes are - * linked lists, the full list is duplicated. - */ -static void -DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to) -{ - ClassesPtr classes; - - - if (from->intfeed) - { - IntegerFeedbackPtr *i, it; - - if (!to->intfeed) - { - classes = to->unused_classes; - to->intfeed = classes->intfeed; - classes->intfeed = NULL; - } - - i = &to->intfeed; - for (it = from->intfeed; it; it = it->next) - { - if (!(*i)) - { - *i = calloc(1, sizeof(IntegerFeedbackClassRec)); - if (!(*i)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*i)->CtrlProc = it->CtrlProc; - (*i)->ctrl = it->ctrl; - - i = &(*i)->next; - } - } else if (to->intfeed && !from->intfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->intfeed = to->intfeed; - to->intfeed = NULL; - } - - if (from->stringfeed) - { - StringFeedbackPtr *s, it; - - if (!to->stringfeed) - { - classes = to->unused_classes; - to->stringfeed = classes->stringfeed; - classes->stringfeed = NULL; - } - - s = &to->stringfeed; - for (it = from->stringfeed; it; it = it->next) - { - if (!(*s)) - { - *s = calloc(1, sizeof(StringFeedbackClassRec)); - if (!(*s)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*s)->CtrlProc = it->CtrlProc; - (*s)->ctrl = it->ctrl; - - s = &(*s)->next; - } - } else if (to->stringfeed && !from->stringfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->stringfeed = to->stringfeed; - to->stringfeed = NULL; - } - - if (from->bell) - { - BellFeedbackPtr *b, it; - - if (!to->bell) - { - classes = to->unused_classes; - to->bell = classes->bell; - classes->bell = NULL; - } - - b = &to->bell; - for (it = from->bell; it; it = it->next) - { - if (!(*b)) - { - *b = calloc(1, sizeof(BellFeedbackClassRec)); - if (!(*b)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*b)->BellProc = it->BellProc; - (*b)->CtrlProc = it->CtrlProc; - (*b)->ctrl = it->ctrl; - - b = &(*b)->next; - } - } else if (to->bell && !from->bell) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->bell = to->bell; - to->bell = NULL; - } - - if (from->leds) - { - LedFeedbackPtr *l, it; - - if (!to->leds) - { - classes = to->unused_classes; - to->leds = classes->leds; - classes->leds = NULL; - } - - l = &to->leds; - for (it = from->leds; it; it = it->next) - { - if (!(*l)) - { - *l = calloc(1, sizeof(LedFeedbackClassRec)); - if (!(*l)) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*l)->CtrlProc = it->CtrlProc; - (*l)->ctrl = it->ctrl; - if ((*l)->xkb_sli) - XkbFreeSrvLedInfo((*l)->xkb_sli); - (*l)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, NULL, *l); - - l = &(*l)->next; - } - } else if (to->leds && !from->leds) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->leds = to->leds; - to->leds = NULL; - } -} - -static void -DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to) -{ - ClassesPtr classes; - - /* XkbInitDevice (->XkbInitIndicatorMap->XkbFindSrvLedInfo) relies on the - * kbdfeed to be set up properly, so let's do the feedback classes first. - */ - if (from->kbdfeed) - { - KbdFeedbackPtr *k, it; - - if (!to->kbdfeed) - { - classes = to->unused_classes; - - to->kbdfeed = classes->kbdfeed; - if (!to->kbdfeed) - InitKeyboardDeviceStruct(to, NULL, NULL, NULL); - classes->kbdfeed = NULL; - } - - k = &to->kbdfeed; - for(it = from->kbdfeed; it; it = it->next) - { - if (!(*k)) - { - *k = calloc(1, sizeof(KbdFeedbackClassRec)); - if (!*k) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*k)->BellProc = it->BellProc; - (*k)->CtrlProc = it->CtrlProc; - (*k)->ctrl = it->ctrl; - if ((*k)->xkb_sli) - XkbFreeSrvLedInfo((*k)->xkb_sli); - (*k)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, *k, NULL); - - k = &(*k)->next; - } - } else if (to->kbdfeed && !from->kbdfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->kbdfeed = to->kbdfeed; - to->kbdfeed = NULL; - } - - if (from->key) - { - if (!to->key) - { - classes = to->unused_classes; - to->key = classes->key; - if (!to->key) - InitKeyboardDeviceStruct(to, NULL, NULL, NULL); - else - classes->key = NULL; - } - - CopyKeyClass(from, to); - } else if (to->key && !from->key) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->key = to->key; - to->key = NULL; - } - - /* If a SrvLedInfoPtr's flags are XkbSLI_IsDefault, the names and maps - * pointer point into the xkbInfo->desc struct. XkbCopySrvLedInfo - * didn't update the pointers so we need to do it manually here. - */ - if (to->kbdfeed) - { - KbdFeedbackPtr k; - - for (k = to->kbdfeed; k; k = k->next) - { - if (!k->xkb_sli) - continue; - if (k->xkb_sli->flags & XkbSLI_IsDefault) - { - k->xkb_sli->names = to->key->xkbInfo->desc->names->indicators; - k->xkb_sli->maps = to->key->xkbInfo->desc->indicators->maps; - } - } - } - - /* We can't just copy over the focus class. When an app sets the focus, - * it'll do so on the master device. Copying the SDs focus means losing - * the focus. - * So we only copy the focus class if the device didn't have one, - * otherwise we leave it as it is. - */ - if (from->focus) - { - if (!to->focus) - { - WindowPtr *oldTrace; - - classes = to->unused_classes; - to->focus = classes->focus; - if (!to->focus) - { - to->focus = calloc(1, sizeof(FocusClassRec)); - if (!to->focus) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->focus = NULL; - - oldTrace = to->focus->trace; - memcpy(to->focus, from->focus, sizeof(FocusClassRec)); - to->focus->trace = realloc(oldTrace, - to->focus->traceSize * sizeof(WindowPtr)); - if (!to->focus->trace && to->focus->traceSize) - FatalError("[Xi] no memory for trace.\n"); - memcpy(to->focus->trace, from->focus->trace, - from->focus->traceSize * sizeof(WindowPtr)); - to->focus->sourceid = from->id; - } - } else if (to->focus) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->focus = to->focus; - to->focus = NULL; - } - -} - -static void -DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) -{ - ClassesPtr classes; - - /* Feedback classes must be copied first */ - if (from->ptrfeed) - { - PtrFeedbackPtr *p, it; - if (!to->ptrfeed) - { - classes = to->unused_classes; - to->ptrfeed = classes->ptrfeed; - classes->ptrfeed = NULL; - } - - p = &to->ptrfeed; - for (it = from->ptrfeed; it; it = it->next) - { - if (!(*p)) - { - *p = calloc(1, sizeof(PtrFeedbackClassRec)); - if (!*p) - { - ErrorF("[Xi] Cannot alloc memory for class copy."); - return; - } - } - (*p)->CtrlProc = it->CtrlProc; - (*p)->ctrl = it->ctrl; - - p = &(*p)->next; - } - } else if (to->ptrfeed && !from->ptrfeed) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->ptrfeed = to->ptrfeed; - to->ptrfeed = NULL; - } - - if (from->valuator) - { - ValuatorClassPtr v; - if (!to->valuator) - { - classes = to->unused_classes; - to->valuator = classes->valuator; - if (to->valuator) - classes->valuator = NULL; - } - - to->valuator = realloc(to->valuator, sizeof(ValuatorClassRec) + - from->valuator->numAxes * sizeof(AxisInfo) + - from->valuator->numAxes * sizeof(double)); - v = to->valuator; - if (!v) - FatalError("[Xi] no memory for class shift.\n"); - - v->numAxes = from->valuator->numAxes; - v->axes = (AxisInfoPtr)&v[1]; - memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo)); - - v->axisVal = (double*)(v->axes + from->valuator->numAxes); - v->sourceid = from->id; - } else if (to->valuator && !from->valuator) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->valuator = to->valuator; - to->valuator = NULL; - } - - if (from->button) - { - if (!to->button) - { - classes = to->unused_classes; - to->button = classes->button; - if (!to->button) - { - to->button = calloc(1, sizeof(ButtonClassRec)); - if (!to->button) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->button = NULL; - } - - if (from->button->xkb_acts) - { - if (!to->button->xkb_acts) - { - to->button->xkb_acts = calloc(1, sizeof(XkbAction)); - if (!to->button->xkb_acts) - FatalError("[Xi] not enough memory for xkb_acts.\n"); - } - memcpy(to->button->xkb_acts, from->button->xkb_acts, - sizeof(XkbAction)); - } else - free(to->button->xkb_acts); - - memcpy(to->button->labels, from->button->labels, - from->button->numButtons * sizeof(Atom)); - to->button->sourceid = from->id; - } else if (to->button && !from->button) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->button = to->button; - to->button = NULL; - } - - if (from->proximity) - { - if (!to->proximity) - { - classes = to->unused_classes; - to->proximity = classes->proximity; - if (!to->proximity) - { - to->proximity = calloc(1, sizeof(ProximityClassRec)); - if (!to->proximity) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->proximity = NULL; - } - memcpy(to->proximity, from->proximity, sizeof(ProximityClassRec)); - to->proximity->sourceid = from->id; - } else if (to->proximity) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->proximity = to->proximity; - to->proximity = NULL; - } - - if (from->absolute) - { - if (!to->absolute) - { - classes = to->unused_classes; - to->absolute = classes->absolute; - if (!to->absolute) - { - to->absolute = calloc(1, sizeof(AbsoluteClassRec)); - if (!to->absolute) - FatalError("[Xi] no memory for class shift.\n"); - } else - classes->absolute = NULL; - } - memcpy(to->absolute, from->absolute, sizeof(AbsoluteClassRec)); - to->absolute->sourceid = from->id; - } else if (to->absolute) - { - ClassesPtr classes; - classes = to->unused_classes; - classes->absolute = to->absolute; - to->absolute = NULL; - } -} - -/** - * Copies the CONTENT of the classes of device from into the classes in device - * to. From and to are identical after finishing. - * - * If to does not have classes from currenly has, the classes are stored in - * to's devPrivates system. Later, we recover it again from there if needed. - * Saves a few memory allocations. - */ -void -DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to, DeviceChangedEvent *dce) -{ - /* generic feedback classes, not tied to pointer and/or keyboard */ - DeepCopyFeedbackClasses(from, to); - - if ((dce->flags & DEVCHANGE_KEYBOARD_EVENT)) - DeepCopyKeyboardClasses(from, to); - if ((dce->flags & DEVCHANGE_POINTER_EVENT)) - DeepCopyPointerClasses(from, to); -} - - -/** - * Send an XI2 DeviceChangedEvent to all interested clients. - */ -void -XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChangedEvent *dce) -{ - xXIDeviceChangedEvent *dcce; - int rc; - - rc = EventToXI2((InternalEvent*)dce, (xEvent**)&dcce); - if (rc != Success) - { - ErrorF("[Xi] event conversion from DCE failed with code %d\n", rc); - return; - } - - /* we don't actually swap if there's a NullClient, swapping is done - * later when event is delivered. */ - SendEventToAllWindows(master, XI_DeviceChangedMask, (xEvent*)dcce, 1); - free(dcce); -} - -static void -ChangeMasterDeviceClasses(DeviceIntPtr device, DeviceChangedEvent *dce) -{ - DeviceIntPtr slave; - int rc; - - /* For now, we don't have devices that change physically. */ - if (!IsMaster(device)) - return; - - rc = dixLookupDevice(&slave, dce->sourceid, serverClient, DixReadAccess); - - if (rc != Success) - return; /* Device has disappeared */ - - if (!slave->u.master) - return; /* set floating since the event */ - - if (slave->u.master->id != dce->masterid) - return; /* not our slave anymore, don't care */ - - /* FIXME: we probably need to send a DCE for the new slave now */ - - device->public.devicePrivate = slave->public.devicePrivate; - - /* FIXME: the classes may have changed since we generated the event. */ - DeepCopyDeviceClasses(slave, device, dce); - XISendDeviceChangedEvent(slave, device, dce); -} - -/** - * Update the device state according to the data in the event. - * - * return values are - * DEFAULT ... process as normal - * DONT_PROCESS ... return immediately from caller - */ -#define DEFAULT 0 -#define DONT_PROCESS 1 -int -UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) -{ - int i; - int key = 0, - bit = 0, - last_valuator; - - KeyClassPtr k = NULL; - ButtonClassPtr b = NULL; - ValuatorClassPtr v = NULL; - - /* This event is always the first we get, before the actual events with - * the data. However, the way how the DDX is set up, "device" will - * actually be the slave device that caused the event. - */ - switch(event->type) - { - case ET_DeviceChanged: - ChangeMasterDeviceClasses(device, (DeviceChangedEvent*)event); - return DONT_PROCESS; /* event has been sent already */ - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - break; - default: - /* other events don't update the device */ - return DEFAULT; - } - - k = device->key; - v = device->valuator; - b = device->button; - - key = event->detail.key; - bit = 1 << (key & 7); - - /* Update device axis */ - /* Check valuators first */ - last_valuator = -1; - for (i = 0; i < MAX_VALUATORS; i++) - { - if (BitIsOn(&event->valuators.mask, i)) - { - if (!v) - { - ErrorF("[Xi] Valuators reported for non-valuator device '%s'. " - "Ignoring event.\n", device->name); - return DONT_PROCESS; - } else if (v->numAxes < i) - { - ErrorF("[Xi] Too many valuators reported for device '%s'. " - "Ignoring event.\n", device->name); - return DONT_PROCESS; - } - last_valuator = i; - } - } - - for (i = 0; i <= last_valuator && i < v->numAxes; i++) - { - if (BitIsOn(&event->valuators.mask, i)) - { - /* XXX: Relative/Absolute mode */ - v->axisVal[i] = event->valuators.data[i]; - v->axisVal[i] += (event->valuators.data_frac[i] * 1.0f / (1 << 16) / (1 << 16)); - } - } - - if (event->type == ET_KeyPress) { - if (!k) - return DONT_PROCESS; - - /* don't allow ddx to generate multiple downs, but repeats are okay */ - if (key_is_down(device, key, KEY_PROCESSED) && !event->key_repeat) - return DONT_PROCESS; - - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - set_key_down(device, key, KEY_PROCESSED); - } else if (event->type == ET_KeyRelease) { - if (!k) - return DONT_PROCESS; - - if (!key_is_down(device, key, KEY_PROCESSED)) /* guard against duplicates */ - return DONT_PROCESS; - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - set_key_up(device, key, KEY_PROCESSED); - } else if (event->type == ET_ButtonPress) { - Mask mask; - if (!b) - return DONT_PROCESS; - - if (button_is_down(device, key, BUTTON_PROCESSED)) - return DONT_PROCESS; - - set_button_down(device, key, BUTTON_PROCESSED); - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - if (!b->map[key]) - return DONT_PROCESS; - b->buttonsDown++; - b->motionMask = DeviceButtonMotionMask; - if (b->map[key] <= 5) - b->state |= (Button1Mask >> 1) << b->map[key]; - - /* Add state and motionMask to the filter for this event */ - mask = DevicePointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, DeviceMotionNotify); - mask = PointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, MotionNotify); - } else if (event->type == ET_ButtonRelease) { - Mask mask; - if (!b) - return DONT_PROCESS; - - if (!button_is_down(device, key, BUTTON_PROCESSED)) - return DONT_PROCESS; - if (IsMaster(device)) { - DeviceIntPtr sd; - - /* - * Leave the button down if any slave has the - * button still down. Note that this depends on the - * event being delivered through the slave first - */ - for (sd = inputInfo.devices; sd; sd = sd->next) { - if (IsMaster(sd) || sd->u.master != device) - continue; - if (!sd->button) - continue; - for (i = 1; i <= sd->button->numButtons; i++) - if (sd->button->map[i] == key && - button_is_down(sd, i, BUTTON_PROCESSED)) - return DONT_PROCESS; - } - } - set_button_up(device, key, BUTTON_PROCESSED); - if (device->valuator) - device->valuator->motionHintWindow = NullWindow; - if (!b->map[key]) - return DONT_PROCESS; - if (b->buttonsDown >= 1 && !--b->buttonsDown) - b->motionMask = 0; - if (b->map[key] <= 5) - b->state &= ~((Button1Mask >> 1) << b->map[key]); - - /* Add state and motionMask to the filter for this event */ - mask = DevicePointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, DeviceMotionNotify); - mask = PointerMotionMask | b->state | b->motionMask; - SetMaskForEvent(device->id, mask, MotionNotify); - } else if (event->type == ET_ProximityIn) - device->proximity->in_proximity = TRUE; - else if (event->type == ET_ProximityOut) - device->proximity->in_proximity = FALSE; - - return DEFAULT; -} - -static void -ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) -{ - GrabPtr grab = device->deviceGrab.grab; - - if (grab) - DeliverGrabbedEvent((InternalEvent*)ev, device, FALSE); - else { /* deliver to all root windows */ - xEvent *xi; - int i; - - i = EventToXI2((InternalEvent*)ev, (xEvent**)&xi); - if (i != Success) - { - ErrorF("[Xi] %s: XI2 conversion failed in ProcessRawEvent (%d)\n", - device->name, i); - return; - } - - for (i = 0; i < screenInfo.numScreens; i++) - DeliverEventsToWindow(device, screenInfo.screens[i]->root, xi, 1, - GetEventFilter(device, xi), NULL); - free(xi); - } -} - -/** - * Main device event processing function. - * Called from when processing the events from the event queue. - * - */ -void -ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) -{ - GrabPtr grab; - Bool deactivateDeviceGrab = FALSE; - int key = 0, rootX, rootY; - ButtonClassPtr b; - KeyClassPtr k; - ValuatorClassPtr v; - int ret = 0; - int state, i; - DeviceIntPtr mouse = NULL, kbd = NULL; - DeviceEvent *event = &ev->device_event; - - CHECKEVENT(ev); - - if (ev->any.type == ET_RawKeyPress || - ev->any.type == ET_RawKeyRelease || - ev->any.type == ET_RawButtonPress || - ev->any.type == ET_RawButtonRelease || - ev->any.type == ET_RawMotion) - { - ProcessRawEvent(&ev->raw_event, device); - return; - } - - if (IsPointerDevice(device)) - { - kbd = GetPairedDevice(device); - mouse = device; - if (!kbd->key) /* can happen with floating SDs */ - kbd = NULL; - } else - { - mouse = GetPairedDevice(device); - kbd = device; - if (!mouse->valuator || !mouse->button) /* may be float. SDs */ - mouse = NULL; - } - - /* State needs to be assembled BEFORE the device is updated. */ - state = (kbd && kbd->key) ? XkbStateFieldFromRec(&kbd->key->xkbInfo->state) : 0; - state |= (mouse && mouse->button) ? (mouse->button->state) : 0; - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(event->buttons, i); - - if (kbd && kbd->key) - { - XkbStatePtr state; - /* we need the state before the event happens */ - if (event->type == ET_KeyPress || event->type == ET_KeyRelease) - state = &kbd->key->xkbInfo->prev_state; - else - state = &kbd->key->xkbInfo->state; - - event->mods.base = state->base_mods; - event->mods.latched = state->latched_mods; - event->mods.locked = state->locked_mods; - event->mods.effective = state->mods; - - event->group.base = state->base_group; - event->group.latched = state->latched_group; - event->group.locked = state->locked_group; - event->group.effective = state->group; - } - - ret = UpdateDeviceState(device, event); - if (ret == DONT_PROCESS) - return; - - v = device->valuator; - b = device->button; - k = device->key; - - if (IsMaster(device) || !device->u.master) - CheckMotion(event, device); - - switch (event->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - GetSpritePosition(device, &rootX, &rootY); - event->root_x = rootX; - event->root_y = rootY; - NoticeEventTime((InternalEvent*)event); - event->corestate = state; - key = event->detail.key; - break; - default: - break; - } - - if (DeviceEventCallback && !syncEvents.playingEvents) { - DeviceEventInfoRec eventinfo; - SpritePtr pSprite = device->spriteInfo->sprite; - - /* see comment in EnqueueEvents regarding the next three lines */ - if (ev->any.type == ET_Motion) - ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id; - - eventinfo.device = device; - eventinfo.event = ev; - CallCallbacks(&DeviceEventCallback, (pointer) & eventinfo); - } - - grab = device->deviceGrab.grab; - - switch(event->type) - { - case ET_KeyPress: - if (!grab && CheckDeviceGrabs(device, event, 0)) { - device->deviceGrab.activatingKey = key; - return; - } - break; - case ET_KeyRelease: - if (grab && device->deviceGrab.fromPassiveGrab && - (key == device->deviceGrab.activatingKey) && - (device->deviceGrab.grab->type == KeyPress || - device->deviceGrab.grab->type == DeviceKeyPress || - device->deviceGrab.grab->type == XI_KeyPress)) - deactivateDeviceGrab = TRUE; - break; - case ET_ButtonPress: - event->detail.button = b->map[key]; - if (!event->detail.button) { /* there's no button 0 */ - event->detail.button = key; - return; - } - if (!grab && CheckDeviceGrabs(device, event, 0)) - { - /* if a passive grab was activated, the event has been sent - * already */ - return; - } - break; - case ET_ButtonRelease: - event->detail.button = b->map[key]; - if (!event->detail.button) { /* there's no button 0 */ - event->detail.button = key; - return; - } - if (grab && !b->buttonsDown && - device->deviceGrab.fromPassiveGrab && - (device->deviceGrab.grab->type == ButtonPress || - device->deviceGrab.grab->type == DeviceButtonPress || - device->deviceGrab.grab->type == XI_ButtonPress)) - deactivateDeviceGrab = TRUE; - default: - break; - } - - - if (grab) - DeliverGrabbedEvent((InternalEvent*)event, device, deactivateDeviceGrab); - else if (device->focus && !IsPointerEvent((InternalEvent*)ev)) - DeliverFocusedEvent(device, (InternalEvent*)event, - GetSpriteWindow(device)); - else - DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent*)event, - NullGrab, NullWindow, device); - - if (deactivateDeviceGrab == TRUE) - (*device->deviceGrab.DeactivateGrab) (device); - event->detail.key = key; -} - -int -InitProximityClassDeviceStruct(DeviceIntPtr dev) -{ - ProximityClassPtr proxc; - - proxc = (ProximityClassPtr) malloc(sizeof(ProximityClassRec)); - if (!proxc) - return FALSE; - proxc->sourceid = dev->id; - proxc->in_proximity = TRUE; - dev->proximity = proxc; - return TRUE; -} - -/** - * Initialise the device's valuators. The memory must already be allocated, - * this function merely inits the matching axis (specified through axnum) to - * sane values. - * - * It is a condition that (minval < maxval). - * - * @see InitValuatorClassDeviceStruct - */ -void -InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval, - int resolution, int min_res, int max_res, int mode) -{ - AxisInfoPtr ax; - - if (!dev || !dev->valuator || minval > maxval) - return; - if (axnum >= dev->valuator->numAxes) - return; - - ax = dev->valuator->axes + axnum; - - ax->min_value = minval; - ax->max_value = maxval; - ax->resolution = resolution; - ax->min_resolution = min_res; - ax->max_resolution = max_res; - ax->label = label; - ax->mode = mode; - - if (mode & OutOfProximity) - dev->proximity->in_proximity = FALSE; -} - -static void -FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, - ButtonClassPtr b, ValuatorClassPtr v, int first) -{ - ev->type = DeviceStateNotify; - ev->deviceid = dev->id; - ev->time = currentTime.milliseconds; - ev->classes_reported = 0; - ev->num_keys = 0; - ev->num_buttons = 0; - ev->num_valuators = 0; - - if (b) { - ev->classes_reported |= (1 << ButtonClass); - ev->num_buttons = b->numButtons; - memcpy((char*)ev->buttons, (char*)b->down, 4); - } else if (k) { - ev->classes_reported |= (1 << KeyClass); - ev->num_keys = k->xkbInfo->desc->max_key_code - - k->xkbInfo->desc->min_key_code; - memmove((char *)&ev->keys[0], (char *)k->down, 4); - } - if (v) { - int nval = v->numAxes - first; - - ev->classes_reported |= (1 << ValuatorClass); - ev->classes_reported |= valuator_get_mode(dev, 0) << ModeBitsShift; - ev->num_valuators = nval < 3 ? nval : 3; - switch (ev->num_valuators) { - case 3: - ev->valuator2 = v->axisVal[first + 2]; - case 2: - ev->valuator1 = v->axisVal[first + 1]; - case 1: - ev->valuator0 = v->axisVal[first]; - break; - } - } -} - -static void -FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, - int first) -{ - int nval = v->numAxes - first; - - ev->type = DeviceValuator; - ev->deviceid = dev->id; - ev->num_valuators = nval < 3 ? nval : 3; - ev->first_valuator = first; - switch (ev->num_valuators) { - case 3: - ev->valuator2 = v->axisVal[first + 2]; - case 2: - ev->valuator1 = v->axisVal[first + 1]; - case 1: - ev->valuator0 = v->axisVal[first]; - break; - } - first += ev->num_valuators; -} - -void -DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, - WindowPtr pWin) -{ - deviceFocus event; - xXIFocusInEvent *xi2event; - DeviceIntPtr mouse; - int btlen, len, i; - - mouse = (IsMaster(dev) || dev->u.master) ? GetMaster(dev, MASTER_POINTER) : dev; - - /* XI 2 event */ - btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; - btlen = bytes_to_int32(btlen); - len = sizeof(xXIFocusInEvent) + btlen * 4; - - xi2event = calloc(1, len); - xi2event->type = GenericEvent; - xi2event->extension = IReqCode; - xi2event->evtype = type; - xi2event->length = bytes_to_int32(len - sizeof(xEvent)); - xi2event->buttons_len = btlen; - xi2event->detail = detail; - xi2event->time = currentTime.milliseconds; - xi2event->deviceid = dev->id; - xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */ - xi2event->mode = mode; - xi2event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); - xi2event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(&xi2event[1], i); - - if (dev->key) - { - xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods; - xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods; - xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods; - xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods; - - xi2event->group.base_group = dev->key->xkbInfo->state.base_group; - xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group; - xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group; - xi2event->group.effective_group = dev->key->xkbInfo->state.group; - } - - FixUpEventFromWindow(dev, (xEvent*)xi2event, pWin, None, FALSE); - - DeliverEventsToWindow(dev, pWin, (xEvent*)xi2event, 1, - GetEventFilter(dev, (xEvent*)xi2event), NullGrab); - - free(xi2event); - - /* XI 1.x event */ - event.deviceid = dev->id; - event.mode = mode; - event.type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut; - event.detail = detail; - event.window = pWin->drawable.id; - event.time = currentTime.milliseconds; - - DeliverEventsToWindow(dev, pWin, (xEvent *) & event, 1, - DeviceFocusChangeMask, NullGrab); - - if ((type == DeviceFocusIn) && - (wOtherInputMasks(pWin)) && - (wOtherInputMasks(pWin)->inputEvents[dev->id] & DeviceStateNotifyMask)) - { - int evcount = 1; - deviceStateNotify *ev, *sev; - deviceKeyStateNotify *kev; - deviceButtonStateNotify *bev; - - KeyClassPtr k; - ButtonClassPtr b; - ValuatorClassPtr v; - int nval = 0, nkeys = 0, nbuttons = 0, first = 0; - - if ((b = dev->button) != NULL) { - nbuttons = b->numButtons; - if (nbuttons > 32) - evcount++; - } - if ((k = dev->key) != NULL) { - nkeys = k->xkbInfo->desc->max_key_code - - k->xkbInfo->desc->min_key_code; - if (nkeys > 32) - evcount++; - if (nbuttons > 0) { - evcount++; - } - } - if ((v = dev->valuator) != NULL) { - nval = v->numAxes; - - if (nval > 3) - evcount++; - if (nval > 6) { - if (!(k && b)) - evcount++; - if (nval > 9) - evcount += ((nval - 7) / 3); - } - } - - sev = ev = (deviceStateNotify *) malloc(evcount * sizeof(xEvent)); - FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); - - if (b != NULL) { - FixDeviceStateNotify(dev, ev++, NULL, b, v, first); - first += 3; - nval -= 3; - if (nbuttons > 32) { - (ev - 1)->deviceid |= MORE_EVENTS; - bev = (deviceButtonStateNotify *) ev++; - bev->type = DeviceButtonStateNotify; - bev->deviceid = dev->id; - memcpy((char*)&bev->buttons[4], (char*)&b->down[4], DOWN_LENGTH - 4); - } - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } - } - - if (k != NULL) { - FixDeviceStateNotify(dev, ev++, k, NULL, v, first); - first += 3; - nval -= 3; - if (nkeys > 32) { - (ev - 1)->deviceid |= MORE_EVENTS; - kev = (deviceKeyStateNotify *) ev++; - kev->type = DeviceKeyStateNotify; - kev->deviceid = dev->id; - memmove((char *)&kev->keys[0], (char *)&k->down[4], 28); - } - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } - } - - while (nval > 0) { - FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); - first += 3; - nval -= 3; - if (nval > 0) { - (ev - 1)->deviceid |= MORE_EVENTS; - FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); - first += 3; - nval -= 3; - } - } - - DeliverEventsToWindow(dev, pWin, (xEvent *) sev, evcount, - DeviceStateNotifyMask, NullGrab); - free(sev); - } -} - -int -CheckGrabValues(ClientPtr client, GrabParameters* param) -{ - if (param->grabtype != GRABTYPE_CORE && - param->grabtype != GRABTYPE_XI && - param->grabtype != GRABTYPE_XI2) - { - ErrorF("[Xi] grabtype is invalid. This is a bug.\n"); - return BadImplementation; - } - - if ((param->this_device_mode != GrabModeSync) && - (param->this_device_mode != GrabModeAsync)) { - client->errorValue = param->this_device_mode; - return BadValue; - } - if ((param->other_devices_mode != GrabModeSync) && - (param->other_devices_mode != GrabModeAsync)) { - client->errorValue = param->other_devices_mode; - return BadValue; - } - - if (param->grabtype != GRABTYPE_XI2 && (param->modifiers != AnyModifier) && - (param->modifiers & ~AllModifiersMask)) { - client->errorValue = param->modifiers; - return BadValue; - } - - if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) { - client->errorValue = param->ownerEvents; - return BadValue; - } - return Success; -} - -int -GrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, - int button, GrabParameters *param, GrabType grabtype, - GrabMask *mask) -{ - WindowPtr pWin, confineTo; - CursorPtr cursor; - GrabPtr grab; - int rc, type = -1; - Mask access_mode = DixGrabAccess; - - rc = CheckGrabValues(client, param); - if (rc != Success) - return rc; - if (param->confineTo == None) - confineTo = NullWindow; - else { - rc = dixLookupWindow(&confineTo, param->confineTo, client, DixSetAttrAccess); - if (rc != Success) - return rc; - } - if (param->cursor == None) - cursor = NullCursor; - else { - rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = param->cursor; - return rc; - } - access_mode |= DixForceAccess; - } - if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - if (grabtype == GRABTYPE_XI) - type = DeviceButtonPress; - else if (grabtype == GRABTYPE_XI2) - type = XI_ButtonPress; - - grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, - mask, param, type, button, confineTo, cursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/** - * Grab the given key. If grabtype is GRABTYPE_XI, the key is a keycode. If - * grabtype is GRABTYPE_XI2, the key is a keysym. - */ -int -GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, - int key, GrabParameters *param, GrabType grabtype, GrabMask *mask) -{ - WindowPtr pWin; - GrabPtr grab; - KeyClassPtr k = dev->key; - Mask access_mode = DixGrabAccess; - int rc, type = -1; - - rc = CheckGrabValues(client, param); - if (rc != Success) - return rc; - if (k == NULL) - return BadMatch; - if (grabtype == GRABTYPE_XI) - { - if ((key > k->xkbInfo->desc->max_key_code || - key < k->xkbInfo->desc->min_key_code) - && (key != AnyKey)) { - client->errorValue = key; - return BadValue; - } - type = DeviceKeyPress; - } else if (grabtype == GRABTYPE_XI2) - type = XI_KeyPress; - - rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, - mask, param, type, key, NULL, NULL); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/* Enter/FocusIn grab */ -int -GrabWindow(ClientPtr client, DeviceIntPtr dev, int type, - GrabParameters *param, GrabMask *mask) -{ - WindowPtr pWin; - CursorPtr cursor; - GrabPtr grab; - Mask access_mode = DixGrabAccess; - int rc; - - rc = CheckGrabValues(client, param); - if (rc != Success) - return rc; - - rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (param->cursor == None) - cursor = NullCursor; - else { - rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = param->cursor; - return rc; - } - access_mode |= DixForceAccess; - } - if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - grab = CreateGrab(client->index, dev, dev, pWin, GRABTYPE_XI2, - mask, param, (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, - 0, NULL, cursor); - - if (!grab) - return BadAlloc; - - return AddPassiveGrabToList(client, grab); -} - -int -SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client, - Mask mask, Mask exclusivemasks) -{ - int mskidx = dev->id; - int i, ret; - Mask check; - InputClientsPtr others; - - check = (mask & exclusivemasks); - if (wOtherInputMasks(pWin)) { - if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) { /* It is illegal for two different - * clients to select on any of the - * events for maskcheck. However, - * it is OK, for some client to - * continue selecting on one of those - * events. */ - for (others = wOtherInputMasks(pWin)->inputClients; others; - others = others->next) { - if (!SameClient(others, client) && (check & - others->mask[mskidx])) - return BadAccess; - } - } - for (others = wOtherInputMasks(pWin)->inputClients; others; - others = others->next) { - if (SameClient(others, client)) { - check = others->mask[mskidx]; - others->mask[mskidx] = mask; - if (mask == 0) { - for (i = 0; i < EMASKSIZE; i++) - if (i != mskidx && others->mask[i] != 0) - break; - if (i == EMASKSIZE) { - RecalculateDeviceDeliverableEvents(pWin); - if (ShouldFreeInputMasks(pWin, FALSE)) - FreeResource(others->resource, RT_NONE); - return Success; - } - } - goto maskSet; - } - } - } - check = 0; - if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success) - return ret; - maskSet: - if (dev->valuator) - if ((dev->valuator->motionHintWindow == pWin) && - (mask & DevicePointerMotionHintMask) && - !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab) - dev->valuator->motionHintWindow = NullWindow; - RecalculateDeviceDeliverableEvents(pWin); - return Success; -} - -int -AddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx) -{ - InputClientsPtr others; - - if (!pWin->optional && !MakeWindowOptional(pWin)) - return BadAlloc; - others = calloc(1, sizeof(InputClients)); - if (!others) - return BadAlloc; - if (!pWin->optional->inputMasks && !MakeInputMasks(pWin)) - return BadAlloc; - others->mask[mskidx] = mask; - others->resource = FakeClientID(client->index); - others->next = pWin->optional->inputMasks->inputClients; - pWin->optional->inputMasks->inputClients = others; - if (!AddResource(others->resource, RT_INPUTCLIENT, (pointer) pWin)) - return BadAlloc; - return Success; -} - -static Bool -MakeInputMasks(WindowPtr pWin) -{ - struct _OtherInputMasks *imasks; - - imasks = calloc(1, sizeof(struct _OtherInputMasks)); - if (!imasks) - return FALSE; - pWin->optional->inputMasks = imasks; - return TRUE; -} - -void -RecalculateDeviceDeliverableEvents(WindowPtr pWin) -{ - InputClientsPtr others; - struct _OtherInputMasks *inputMasks; /* default: NULL */ - WindowPtr pChild, tmp; - int i, j; - - pChild = pWin; - while (1) { - if ((inputMasks = wOtherInputMasks(pChild)) != 0) { - for (i = 0; i < EMASKSIZE; i++) - memset(inputMasks->xi2mask[i], 0, sizeof(inputMasks->xi2mask[i])); - for (others = inputMasks->inputClients; others; - others = others->next) { - for (i = 0; i < EMASKSIZE; i++) - inputMasks->inputEvents[i] |= others->mask[i]; - for (i = 0; i < EMASKSIZE; i++) - for (j = 0; j < XI2MASKSIZE; j++) - inputMasks->xi2mask[i][j] |= others->xi2mask[i][j]; - } - for (i = 0; i < EMASKSIZE; i++) - inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i]; - for (tmp = pChild->parent; tmp; tmp = tmp->parent) - if (wOtherInputMasks(tmp)) - for (i = 0; i < EMASKSIZE; i++) - inputMasks->deliverableEvents[i] |= - (wOtherInputMasks(tmp)->deliverableEvents[i] - & ~inputMasks-> - dontPropagateMask[i] & PropagateMask[i]); - } - if (pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } -} - -int -InputClientGone(WindowPtr pWin, XID id) -{ - InputClientsPtr other, prev; - - if (!wOtherInputMasks(pWin)) - return Success; - prev = 0; - for (other = wOtherInputMasks(pWin)->inputClients; other; - other = other->next) { - if (other->resource == id) { - if (prev) { - prev->next = other->next; - free(other); - } else if (!(other->next)) { - if (ShouldFreeInputMasks(pWin, TRUE)) { - wOtherInputMasks(pWin)->inputClients = other->next; - free(wOtherInputMasks(pWin)); - pWin->optional->inputMasks = (OtherInputMasks *) NULL; - CheckWindowOptionalNeed(pWin); - free(other); - } else { - other->resource = FakeClientID(0); - if (!AddResource(other->resource, RT_INPUTCLIENT, - (pointer) pWin)) - return BadAlloc; - } - } else { - wOtherInputMasks(pWin)->inputClients = other->next; - free(other); - } - RecalculateDeviceDeliverableEvents(pWin); - return Success; - } - prev = other; - } - FatalError("client not on device event list"); -} - -int -SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, - xEvent * ev, Mask mask, int count) -{ - WindowPtr pWin; - WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ - WindowPtr spriteWin = GetSpriteWindow(d); - - if (dest == PointerWindow) - pWin = spriteWin; - else if (dest == InputFocus) { - WindowPtr inputFocus; - - if (!d->focus) - inputFocus = spriteWin; - else - inputFocus = d->focus->win; - - if (inputFocus == FollowKeyboardWin) - inputFocus = inputInfo.keyboard->focus->win; - - if (inputFocus == NoneWin) - return Success; - - /* If the input focus is PointerRootWin, send the event to where - * the pointer is if possible, then perhaps propogate up to root. */ - if (inputFocus == PointerRootWin) - inputFocus = GetCurrentRootWindow(d); - - if (IsParent(inputFocus, spriteWin)) { - effectiveFocus = inputFocus; - pWin = spriteWin; - } else - effectiveFocus = pWin = inputFocus; - } else - dixLookupWindow(&pWin, dest, client, DixSendAccess); - if (!pWin) - return BadWindow; - if ((propagate != xFalse) && (propagate != xTrue)) { - client->errorValue = propagate; - return BadValue; - } - ev->u.u.type |= 0x80; - if (propagate) { - for (; pWin; pWin = pWin->parent) { - if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab)) - return Success; - if (pWin == effectiveFocus) - return Success; - if (wOtherInputMasks(pWin)) - mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id]; - if (!mask) - break; - } - } else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count)) - DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab); - return Success; -} - -int -SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map) -{ - int i; - ButtonClassPtr b = dev->button; - - if (b == NULL) - return BadMatch; - - if (nElts != b->numButtons) { - client->errorValue = nElts; - return BadValue; - } - if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue)) - return BadValue; - for (i = 0; i < nElts; i++) - if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1)) - return MappingBusy; - for (i = 0; i < nElts; i++) - b->map[i + 1] = map[i]; - return Success; -} - -int -ChangeKeyMapping(ClientPtr client, - DeviceIntPtr dev, - unsigned len, - int type, - KeyCode firstKeyCode, - CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map) -{ - KeySymsRec keysyms; - KeyClassPtr k = dev->key; - - if (k == NULL) - return BadMatch; - - if (len != (keyCodes * keySymsPerKeyCode)) - return BadLength; - - if ((firstKeyCode < k->xkbInfo->desc->min_key_code) || - (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) { - client->errorValue = firstKeyCode; - return BadValue; - } - if (keySymsPerKeyCode == 0) { - client->errorValue = 0; - return BadValue; - } - keysyms.minKeyCode = firstKeyCode; - keysyms.maxKeyCode = firstKeyCode + keyCodes - 1; - keysyms.mapWidth = keySymsPerKeyCode; - keysyms.map = map; - - XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL, - serverClient); - - return Success; -} - -static void -DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev) -{ - WindowPtr parent; - - /* Deactivate any grabs performed on this window, before making - * any input focus changes. - * Deactivating a device grab should cause focus events. */ - - if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin)) - (*dev->deviceGrab.DeactivateGrab) (dev); - - /* If the focus window is a root window (ie. has no parent) - * then don't delete the focus from it. */ - - if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) { - int focusEventMode = NotifyNormal; - - /* If a grab is in progress, then alter the mode of focus events. */ - - if (dev->deviceGrab.grab) - focusEventMode = NotifyWhileGrabbed; - - switch (dev->focus->revert) { - case RevertToNone: - if (!ActivateFocusInGrab(dev, pWin, NoneWin)) - DoFocusEvents(dev, pWin, NoneWin, focusEventMode); - dev->focus->win = NoneWin; - dev->focus->traceGood = 0; - break; - case RevertToParent: - parent = pWin; - do { - parent = parent->parent; - dev->focus->traceGood--; - } - while (!parent->realized); - if (!ActivateFocusInGrab(dev, pWin, parent)) - DoFocusEvents(dev, pWin, parent, focusEventMode); - dev->focus->win = parent; - dev->focus->revert = RevertToNone; - break; - case RevertToPointerRoot: - if (!ActivateFocusInGrab(dev, pWin, PointerRootWin)) - DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode); - dev->focus->win = PointerRootWin; - dev->focus->traceGood = 0; - break; - case RevertToFollowKeyboard: - { - DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD); - if (!kbd || (kbd == dev && kbd != inputInfo.keyboard)) - kbd = inputInfo.keyboard; - if (kbd->focus->win) { - if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win)) - DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode); - dev->focus->win = FollowKeyboardWin; - dev->focus->traceGood = 0; - } else { - if (!ActivateFocusInGrab(dev, pWin, NoneWin)) - DoFocusEvents(dev, pWin, NoneWin, focusEventMode); - dev->focus->win = NoneWin; - dev->focus->traceGood = 0; - } - } - break; - } - } - - if (dev->valuator) - if (dev->valuator->motionHintWindow == pWin) - dev->valuator->motionHintWindow = NullWindow; -} - -void -DeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources) -{ - int i; - DeviceIntPtr dev; - InputClientsPtr ic; - struct _OtherInputMasks *inputMasks; - - for (dev = inputInfo.devices; dev; dev = dev->next) { - DeleteDeviceFromAnyExtEvents(pWin, dev); - } - - for (dev = inputInfo.off_devices; dev; dev = dev->next) - DeleteDeviceFromAnyExtEvents(pWin, dev); - - if (freeResources) - while ((inputMasks = wOtherInputMasks(pWin)) != 0) { - ic = inputMasks->inputClients; - for (i = 0; i < EMASKSIZE; i++) - inputMasks->dontPropagateMask[i] = 0; - FreeResource(ic->resource, RT_NONE); - } -} - -int -MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer * pEvents, Mask mask) -{ - DeviceIntPtr dev; - - dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient, - DixReadAccess); - if (!dev) - return 0; - - if (pEvents->type == DeviceMotionNotify) { - if (mask & DevicePointerMotionHintMask) { - if (WID(dev->valuator->motionHintWindow) == pEvents->event) { - return 1; /* don't send, but pretend we did */ - } - pEvents->detail = NotifyHint; - } else { - pEvents->detail = NotifyNormal; - } - } - return 0; -} - -void -CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type, - deviceKeyButtonPointer * xE, GrabPtr grab, - ClientPtr client, Mask deliveryMask) -{ - DeviceIntPtr dev; - - dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient, - DixGrabAccess); - if (!dev) - return; - - if (type == DeviceMotionNotify) - dev->valuator->motionHintWindow = pWin; - else if ((type == DeviceButtonPress) && (!grab) && - (deliveryMask & DeviceButtonGrabMask)) { - GrabRec tempGrab; - - tempGrab.device = dev; - tempGrab.resource = client->clientAsMask; - tempGrab.window = pWin; - tempGrab.ownerEvents = - (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE; - tempGrab.eventMask = deliveryMask; - tempGrab.keyboardMode = GrabModeAsync; - tempGrab.pointerMode = GrabModeAsync; - tempGrab.confineTo = NullWindow; - tempGrab.cursor = NullCursor; - tempGrab.next = NULL; - (*dev->deviceGrab.ActivateGrab) (dev, &tempGrab, currentTime, TRUE); - } -} - -static Mask -DeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client) -{ - InputClientsPtr other; - - if (!wOtherInputMasks(pWin)) - return 0; - for (other = wOtherInputMasks(pWin)->inputClients; other; - other = other->next) { - if (SameClient(other, client)) - return other->mask[dev->id]; - } - return 0; -} - -void -MaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client) -{ - WindowPtr pWin; - GrabPtr grab = dev->deviceGrab.grab; - - pWin = dev->valuator->motionHintWindow; - - if ((grab && SameClient(grab, client) && - ((grab->eventMask & DevicePointerMotionHintMask) || - (grab->ownerEvents && - (DeviceEventMaskForClient(dev, pWin, client) & - DevicePointerMotionHintMask)))) || - (!grab && - (DeviceEventMaskForClient(dev, pWin, client) & - DevicePointerMotionHintMask))) - dev->valuator->motionHintWindow = NullWindow; -} - -int -DeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask, - int maskndx) -{ - struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - - if (mask & ~PropagateMask[maskndx]) { - client->errorValue = mask; - return BadValue; - } - - if (mask == 0) { - if (inputMasks) - inputMasks->dontPropagateMask[maskndx] = mask; - } else { - if (!inputMasks) - AddExtensionClient(pWin, client, 0, 0); - inputMasks = wOtherInputMasks(pWin); - inputMasks->dontPropagateMask[maskndx] = mask; - } - RecalculateDeviceDeliverableEvents(pWin); - if (ShouldFreeInputMasks(pWin, FALSE)) - FreeResource(inputMasks->inputClients->resource, RT_NONE); - return Success; -} - -Bool -ShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents) -{ - int i; - Mask allInputEventMasks = 0; - struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - - for (i = 0; i < EMASKSIZE; i++) - allInputEventMasks |= inputMasks->dontPropagateMask[i]; - if (!ignoreSelectedEvents) - for (i = 0; i < EMASKSIZE; i++) - allInputEventMasks |= inputMasks->inputEvents[i]; - if (allInputEventMasks == 0) - return TRUE; - else - return FALSE; -} - -/*********************************************************************** - * - * Walk through the window tree, finding all clients that want to know - * about the Event. - * - */ - -static void -FindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask, - xEvent * ev, int count) -{ - WindowPtr p2; - - while (p1) { - p2 = p1->firstChild; - DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab); - FindInterestedChildren(dev, p2, mask, ev, count); - p1 = p1->nextSib; - } -} - -/*********************************************************************** - * - * Send an event to interested clients in all windows on all screens. - * - */ - -void -SendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent * ev, int count) -{ - int i; - WindowPtr pWin, p1; - - for (i = 0; i < screenInfo.numScreens; i++) { - pWin = screenInfo.screens[i]->root; - if (!pWin) - continue; - DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab); - p1 = pWin->firstChild; - FindInterestedChildren(dev, p1, mask, ev, count); - } -} - -/** - * Set the XI2 mask for the given client on the given window. - * @param dev The device to set the mask for. - * @param win The window to set the mask on. - * @param client The client setting the mask. - * @param len Number of bytes in mask. - * @param mask Event mask in the form of (1 << eventtype) - */ -int -XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client, - unsigned int len, unsigned char* mask) -{ - OtherInputMasks *masks; - InputClientsPtr others = NULL; - - masks = wOtherInputMasks(win); - if (masks) - { - for (others = wOtherInputMasks(win)->inputClients; others; - others = others->next) { - if (SameClient(others, client)) { - memset(others->xi2mask[dev->id], 0, - sizeof(others->xi2mask[dev->id])); - break; - } - } - } - - len = min(len, sizeof(others->xi2mask[dev->id])); - - if (len && !others) - { - if (AddExtensionClient(win, client, 0, 0) != Success) - return BadAlloc; - others= wOtherInputMasks(win)->inputClients; - } - - if (others) - memset(others->xi2mask[dev->id], 0, sizeof(others->xi2mask[dev->id])); - - if (len) - memcpy(others->xi2mask[dev->id], mask, len); - - RecalculateDeviceDeliverableEvents(win); - - return Success; -} +/************************************************************ + +Copyright 1989, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-PACKARD 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. + +********************************************************/ + +/******************************************************************** + * + * Routines to register and initialize extension input devices. + * This also contains ProcessOtherEvent, the routine called from DDX + * to route extension events. + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" +#include +#include +#include +#include +#include +#include +#include "windowstr.h" +#include "miscstruct.h" +#include "region.h" +#include "exevents.h" +#include "extnsionst.h" +#include "exglobals.h" +#include "dixevents.h" /* DeliverFocusedEvent */ +#include "dixgrabs.h" /* CreateGrab() */ +#include "scrnintstr.h" +#include "listdev.h" /* for CopySwapXXXClass */ +#include "xace.h" +#include "xiquerydevice.h" /* For List*Info */ +#include "eventconvert.h" +#include "eventstr.h" + +#include +#include "xkbsrv.h" + +#define WID(w) ((w) ? ((w)->drawable.id) : 0) +#define AllModifiersMask ( \ + ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask ) +#define AllButtonsMask ( \ + Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) + +Bool ShouldFreeInputMasks(WindowPtr /* pWin */ , + Bool /* ignoreSelectedEvents */ + ); +static Bool MakeInputMasks(WindowPtr /* pWin */ + ); + +/* + * Only let the given client know of core events which will affect its + * interpretation of input events, if the client's ClientPointer (or the + * paired keyboard) is the current device. + */ +int +XIShouldNotify(ClientPtr client, DeviceIntPtr dev) +{ + DeviceIntPtr current_ptr = PickPointer(client); + DeviceIntPtr current_kbd = GetPairedDevice(current_ptr); + + if (dev == current_kbd || dev == current_ptr) + return 1; + + return 0; +} + +Bool +IsPointerEvent(InternalEvent* event) +{ + switch(event->any.type) + { + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: + /* XXX: enter/leave ?? */ + return TRUE; + default: + break; + } + return FALSE; +} + +/** + * @return the device matching the deviceid of the device set in the event, or + * NULL if the event is not an XInput event. + */ +DeviceIntPtr +XIGetDevice(xEvent* xE) +{ + DeviceIntPtr pDev = NULL; + + if (xE->u.u.type == DeviceButtonPress || + xE->u.u.type == DeviceButtonRelease || + xE->u.u.type == DeviceMotionNotify || + xE->u.u.type == ProximityIn || + xE->u.u.type == ProximityOut || + xE->u.u.type == DevicePropertyNotify) + { + int rc; + int id; + + id = ((deviceKeyButtonPointer*)xE)->deviceid & ~MORE_EVENTS; + + rc = dixLookupDevice(&pDev, id, serverClient, DixUnknownAccess); + if (rc != Success) + ErrorF("[dix] XIGetDevice failed on XACE restrictions (%d)\n", rc); + } + return pDev; +} + + +/** + * Copy the device->key into master->key and send a mapping notify to the + * clients if appropriate. + * master->key needs to be allocated by the caller. + * + * Device is the slave device. If it is attached to a master device, we may + * need to send a mapping notify to the client because it causes the MD + * to change state. + * + * Mapping notify needs to be sent in the following cases: + * - different slave device on same master + * - different master + * + * XXX: They way how the code is we also send a map notify if the slave device + * stays the same, but the master changes. This isn't really necessary though. + * + * XXX: this gives you funny behaviour with the ClientPointer. When a + * MappingNotify is sent to the client, the client usually responds with a + * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard + * mapping, regardless of which keyboard sent the last mapping notify request. + * So depending on the CP setting, your keyboard may change layout in each + * app... + * + * This code is basically the old SwitchCoreKeyboard. + */ + +void +CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master) +{ + KeyClassPtr mk = master->key; + + if (device == master) + return; + + mk->sourceid = device->id; + + + if (!XkbCopyDeviceKeymap(master, device)) + FatalError("Couldn't pivot keymap from device to core!\n"); +} + +/** + * Copies the feedback classes from device "from" into device "to". Classes + * are duplicated (not just flipping the pointers). All feedback classes are + * linked lists, the full list is duplicated. + */ +static void +DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to) +{ + ClassesPtr classes; + + + if (from->intfeed) + { + IntegerFeedbackPtr *i, it; + + if (!to->intfeed) + { + classes = to->unused_classes; + to->intfeed = classes->intfeed; + classes->intfeed = NULL; + } + + i = &to->intfeed; + for (it = from->intfeed; it; it = it->next) + { + if (!(*i)) + { + *i = calloc(1, sizeof(IntegerFeedbackClassRec)); + if (!(*i)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*i)->CtrlProc = it->CtrlProc; + (*i)->ctrl = it->ctrl; + + i = &(*i)->next; + } + } else if (to->intfeed && !from->intfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->intfeed = to->intfeed; + to->intfeed = NULL; + } + + if (from->stringfeed) + { + StringFeedbackPtr *s, it; + + if (!to->stringfeed) + { + classes = to->unused_classes; + to->stringfeed = classes->stringfeed; + classes->stringfeed = NULL; + } + + s = &to->stringfeed; + for (it = from->stringfeed; it; it = it->next) + { + if (!(*s)) + { + *s = calloc(1, sizeof(StringFeedbackClassRec)); + if (!(*s)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*s)->CtrlProc = it->CtrlProc; + (*s)->ctrl = it->ctrl; + + s = &(*s)->next; + } + } else if (to->stringfeed && !from->stringfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->stringfeed = to->stringfeed; + to->stringfeed = NULL; + } + + if (from->bell) + { + BellFeedbackPtr *b, it; + + if (!to->bell) + { + classes = to->unused_classes; + to->bell = classes->bell; + classes->bell = NULL; + } + + b = &to->bell; + for (it = from->bell; it; it = it->next) + { + if (!(*b)) + { + *b = calloc(1, sizeof(BellFeedbackClassRec)); + if (!(*b)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*b)->BellProc = it->BellProc; + (*b)->CtrlProc = it->CtrlProc; + (*b)->ctrl = it->ctrl; + + b = &(*b)->next; + } + } else if (to->bell && !from->bell) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->bell = to->bell; + to->bell = NULL; + } + + if (from->leds) + { + LedFeedbackPtr *l, it; + + if (!to->leds) + { + classes = to->unused_classes; + to->leds = classes->leds; + classes->leds = NULL; + } + + l = &to->leds; + for (it = from->leds; it; it = it->next) + { + if (!(*l)) + { + *l = calloc(1, sizeof(LedFeedbackClassRec)); + if (!(*l)) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*l)->CtrlProc = it->CtrlProc; + (*l)->ctrl = it->ctrl; + if ((*l)->xkb_sli) + XkbFreeSrvLedInfo((*l)->xkb_sli); + (*l)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, NULL, *l); + + l = &(*l)->next; + } + } else if (to->leds && !from->leds) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->leds = to->leds; + to->leds = NULL; + } +} + +static void +DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to) +{ + ClassesPtr classes; + + /* XkbInitDevice (->XkbInitIndicatorMap->XkbFindSrvLedInfo) relies on the + * kbdfeed to be set up properly, so let's do the feedback classes first. + */ + if (from->kbdfeed) + { + KbdFeedbackPtr *k, it; + + if (!to->kbdfeed) + { + classes = to->unused_classes; + + to->kbdfeed = classes->kbdfeed; + if (!to->kbdfeed) + InitKeyboardDeviceStruct(to, NULL, NULL, NULL); + classes->kbdfeed = NULL; + } + + k = &to->kbdfeed; + for(it = from->kbdfeed; it; it = it->next) + { + if (!(*k)) + { + *k = calloc(1, sizeof(KbdFeedbackClassRec)); + if (!*k) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*k)->BellProc = it->BellProc; + (*k)->CtrlProc = it->CtrlProc; + (*k)->ctrl = it->ctrl; + if ((*k)->xkb_sli) + XkbFreeSrvLedInfo((*k)->xkb_sli); + (*k)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, *k, NULL); + + k = &(*k)->next; + } + } else if (to->kbdfeed && !from->kbdfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->kbdfeed = to->kbdfeed; + to->kbdfeed = NULL; + } + + if (from->key) + { + if (!to->key) + { + classes = to->unused_classes; + to->key = classes->key; + if (!to->key) + InitKeyboardDeviceStruct(to, NULL, NULL, NULL); + else + classes->key = NULL; + } + + CopyKeyClass(from, to); + } else if (to->key && !from->key) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->key = to->key; + to->key = NULL; + } + + /* If a SrvLedInfoPtr's flags are XkbSLI_IsDefault, the names and maps + * pointer point into the xkbInfo->desc struct. XkbCopySrvLedInfo + * didn't update the pointers so we need to do it manually here. + */ + if (to->kbdfeed) + { + KbdFeedbackPtr k; + + for (k = to->kbdfeed; k; k = k->next) + { + if (!k->xkb_sli) + continue; + if (k->xkb_sli->flags & XkbSLI_IsDefault) + { + k->xkb_sli->names = to->key->xkbInfo->desc->names->indicators; + k->xkb_sli->maps = to->key->xkbInfo->desc->indicators->maps; + } + } + } + + /* We can't just copy over the focus class. When an app sets the focus, + * it'll do so on the master device. Copying the SDs focus means losing + * the focus. + * So we only copy the focus class if the device didn't have one, + * otherwise we leave it as it is. + */ + if (from->focus) + { + if (!to->focus) + { + WindowPtr *oldTrace; + + classes = to->unused_classes; + to->focus = classes->focus; + if (!to->focus) + { + to->focus = calloc(1, sizeof(FocusClassRec)); + if (!to->focus) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->focus = NULL; + + oldTrace = to->focus->trace; + memcpy(to->focus, from->focus, sizeof(FocusClassRec)); + to->focus->trace = realloc(oldTrace, + to->focus->traceSize * sizeof(WindowPtr)); + if (!to->focus->trace && to->focus->traceSize) + FatalError("[Xi] no memory for trace.\n"); + memcpy(to->focus->trace, from->focus->trace, + from->focus->traceSize * sizeof(WindowPtr)); + to->focus->sourceid = from->id; + } + } else if (to->focus) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->focus = to->focus; + to->focus = NULL; + } + +} + +static void +DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) +{ + ClassesPtr classes; + + /* Feedback classes must be copied first */ + if (from->ptrfeed) + { + PtrFeedbackPtr *p, it; + if (!to->ptrfeed) + { + classes = to->unused_classes; + to->ptrfeed = classes->ptrfeed; + classes->ptrfeed = NULL; + } + + p = &to->ptrfeed; + for (it = from->ptrfeed; it; it = it->next) + { + if (!(*p)) + { + *p = calloc(1, sizeof(PtrFeedbackClassRec)); + if (!*p) + { + ErrorF("[Xi] Cannot alloc memory for class copy."); + return; + } + } + (*p)->CtrlProc = it->CtrlProc; + (*p)->ctrl = it->ctrl; + + p = &(*p)->next; + } + } else if (to->ptrfeed && !from->ptrfeed) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->ptrfeed = to->ptrfeed; + to->ptrfeed = NULL; + } + + if (from->valuator) + { + ValuatorClassPtr v; + if (!to->valuator) + { + classes = to->unused_classes; + to->valuator = classes->valuator; + if (to->valuator) + classes->valuator = NULL; + } + + to->valuator = realloc(to->valuator, sizeof(ValuatorClassRec) + + from->valuator->numAxes * sizeof(AxisInfo) + + from->valuator->numAxes * sizeof(double)); + v = to->valuator; + if (!v) + FatalError("[Xi] no memory for class shift.\n"); + + v->numAxes = from->valuator->numAxes; + v->axes = (AxisInfoPtr)&v[1]; + memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo)); + + v->axisVal = (double*)(v->axes + from->valuator->numAxes); + v->sourceid = from->id; + } else if (to->valuator && !from->valuator) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->valuator = to->valuator; + to->valuator = NULL; + } + + if (from->button) + { + if (!to->button) + { + classes = to->unused_classes; + to->button = classes->button; + if (!to->button) + { + to->button = calloc(1, sizeof(ButtonClassRec)); + if (!to->button) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->button = NULL; + } + + if (from->button->xkb_acts) + { + if (!to->button->xkb_acts) + { + to->button->xkb_acts = calloc(1, sizeof(XkbAction)); + if (!to->button->xkb_acts) + FatalError("[Xi] not enough memory for xkb_acts.\n"); + } + memcpy(to->button->xkb_acts, from->button->xkb_acts, + sizeof(XkbAction)); + } else + free(to->button->xkb_acts); + + memcpy(to->button->labels, from->button->labels, + from->button->numButtons * sizeof(Atom)); + to->button->sourceid = from->id; + } else if (to->button && !from->button) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->button = to->button; + to->button = NULL; + } + + if (from->proximity) + { + if (!to->proximity) + { + classes = to->unused_classes; + to->proximity = classes->proximity; + if (!to->proximity) + { + to->proximity = calloc(1, sizeof(ProximityClassRec)); + if (!to->proximity) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->proximity = NULL; + } + memcpy(to->proximity, from->proximity, sizeof(ProximityClassRec)); + to->proximity->sourceid = from->id; + } else if (to->proximity) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->proximity = to->proximity; + to->proximity = NULL; + } + + if (from->absolute) + { + if (!to->absolute) + { + classes = to->unused_classes; + to->absolute = classes->absolute; + if (!to->absolute) + { + to->absolute = calloc(1, sizeof(AbsoluteClassRec)); + if (!to->absolute) + FatalError("[Xi] no memory for class shift.\n"); + } else + classes->absolute = NULL; + } + memcpy(to->absolute, from->absolute, sizeof(AbsoluteClassRec)); + to->absolute->sourceid = from->id; + } else if (to->absolute) + { + ClassesPtr classes; + classes = to->unused_classes; + classes->absolute = to->absolute; + to->absolute = NULL; + } +} + +/** + * Copies the CONTENT of the classes of device from into the classes in device + * to. From and to are identical after finishing. + * + * If to does not have classes from currenly has, the classes are stored in + * to's devPrivates system. Later, we recover it again from there if needed. + * Saves a few memory allocations. + */ +void +DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to, DeviceChangedEvent *dce) +{ + /* generic feedback classes, not tied to pointer and/or keyboard */ + DeepCopyFeedbackClasses(from, to); + + if ((dce->flags & DEVCHANGE_KEYBOARD_EVENT)) + DeepCopyKeyboardClasses(from, to); + if ((dce->flags & DEVCHANGE_POINTER_EVENT)) + DeepCopyPointerClasses(from, to); +} + + +/** + * Send an XI2 DeviceChangedEvent to all interested clients. + */ +void +XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChangedEvent *dce) +{ + xXIDeviceChangedEvent *dcce; + int rc; + + rc = EventToXI2((InternalEvent*)dce, (xEvent**)&dcce); + if (rc != Success) + { + ErrorF("[Xi] event conversion from DCE failed with code %d\n", rc); + return; + } + + /* we don't actually swap if there's a NullClient, swapping is done + * later when event is delivered. */ + SendEventToAllWindows(master, XI_DeviceChangedMask, (xEvent*)dcce, 1); + free(dcce); +} + +static void +ChangeMasterDeviceClasses(DeviceIntPtr device, DeviceChangedEvent *dce) +{ + DeviceIntPtr slave; + int rc; + + /* For now, we don't have devices that change physically. */ + if (!IsMaster(device)) + return; + + rc = dixLookupDevice(&slave, dce->sourceid, serverClient, DixReadAccess); + + if (rc != Success) + return; /* Device has disappeared */ + + if (!slave->u.master) + return; /* set floating since the event */ + + if (slave->u.master->id != dce->masterid) + return; /* not our slave anymore, don't care */ + + /* FIXME: we probably need to send a DCE for the new slave now */ + + device->public.devicePrivate = slave->public.devicePrivate; + + /* FIXME: the classes may have changed since we generated the event. */ + DeepCopyDeviceClasses(slave, device, dce); + XISendDeviceChangedEvent(slave, device, dce); +} + +/** + * Update the device state according to the data in the event. + * + * return values are + * DEFAULT ... process as normal + * DONT_PROCESS ... return immediately from caller + */ +#define DEFAULT 0 +#define DONT_PROCESS 1 +int +UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) +{ + int i; + int key = 0, + bit = 0, + last_valuator; + + KeyClassPtr k = NULL; + ButtonClassPtr b = NULL; + ValuatorClassPtr v = NULL; + + /* This event is always the first we get, before the actual events with + * the data. However, the way how the DDX is set up, "device" will + * actually be the slave device that caused the event. + */ + switch(event->type) + { + case ET_DeviceChanged: + ChangeMasterDeviceClasses(device, (DeviceChangedEvent*)event); + return DONT_PROCESS; /* event has been sent already */ + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + break; + default: + /* other events don't update the device */ + return DEFAULT; + } + + k = device->key; + v = device->valuator; + b = device->button; + + key = event->detail.key; + bit = 1 << (key & 7); + + /* Update device axis */ + /* Check valuators first */ + last_valuator = -1; + for (i = 0; i < MAX_VALUATORS; i++) + { + if (BitIsOn(&event->valuators.mask, i)) + { + if (!v) + { + ErrorF("[Xi] Valuators reported for non-valuator device '%s'. " + "Ignoring event.\n", device->name); + return DONT_PROCESS; + } else if (v->numAxes < i) + { + ErrorF("[Xi] Too many valuators reported for device '%s'. " + "Ignoring event.\n", device->name); + return DONT_PROCESS; + } + last_valuator = i; + } + } + + for (i = 0; i <= last_valuator && i < v->numAxes; i++) + { + if (BitIsOn(&event->valuators.mask, i)) + { + /* XXX: Relative/Absolute mode */ + v->axisVal[i] = event->valuators.data[i]; + v->axisVal[i] += (event->valuators.data_frac[i] * 1.0f / (1 << 16) / (1 << 16)); + } + } + + if (event->type == ET_KeyPress) { + if (!k) + return DONT_PROCESS; + + /* don't allow ddx to generate multiple downs, but repeats are okay */ + if (key_is_down(device, key, KEY_PROCESSED) && !event->key_repeat) + return DONT_PROCESS; + + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + set_key_down(device, key, KEY_PROCESSED); + } else if (event->type == ET_KeyRelease) { + if (!k) + return DONT_PROCESS; + + if (!key_is_down(device, key, KEY_PROCESSED)) /* guard against duplicates */ + return DONT_PROCESS; + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + set_key_up(device, key, KEY_PROCESSED); + } else if (event->type == ET_ButtonPress) { + Mask mask; + if (!b) + return DONT_PROCESS; + + if (button_is_down(device, key, BUTTON_PROCESSED)) + return DONT_PROCESS; + + set_button_down(device, key, BUTTON_PROCESSED); + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + if (!b->map[key]) + return DONT_PROCESS; + b->buttonsDown++; + b->motionMask = DeviceButtonMotionMask; + if (b->map[key] <= 5) + b->state |= (Button1Mask >> 1) << b->map[key]; + + /* Add state and motionMask to the filter for this event */ + mask = DevicePointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, DeviceMotionNotify); + mask = PointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, MotionNotify); + } else if (event->type == ET_ButtonRelease) { + Mask mask; + if (!b) + return DONT_PROCESS; + + if (!button_is_down(device, key, BUTTON_PROCESSED)) + return DONT_PROCESS; + if (IsMaster(device)) { + DeviceIntPtr sd; + + /* + * Leave the button down if any slave has the + * button still down. Note that this depends on the + * event being delivered through the slave first + */ + for (sd = inputInfo.devices; sd; sd = sd->next) { + if (IsMaster(sd) || sd->u.master != device) + continue; + if (!sd->button) + continue; + for (i = 1; i <= sd->button->numButtons; i++) + if (sd->button->map[i] == key && + button_is_down(sd, i, BUTTON_PROCESSED)) + return DONT_PROCESS; + } + } + set_button_up(device, key, BUTTON_PROCESSED); + if (device->valuator) + device->valuator->motionHintWindow = NullWindow; + if (!b->map[key]) + return DONT_PROCESS; + if (b->buttonsDown >= 1 && !--b->buttonsDown) + b->motionMask = 0; + if (b->map[key] <= 5) + b->state &= ~((Button1Mask >> 1) << b->map[key]); + + /* Add state and motionMask to the filter for this event */ + mask = DevicePointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, DeviceMotionNotify); + mask = PointerMotionMask | b->state | b->motionMask; + SetMaskForEvent(device->id, mask, MotionNotify); + } else if (event->type == ET_ProximityIn) + device->proximity->in_proximity = TRUE; + else if (event->type == ET_ProximityOut) + device->proximity->in_proximity = FALSE; + + return DEFAULT; +} + +static void +ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) +{ + GrabPtr grab = device->deviceGrab.grab; + + if (grab) + DeliverGrabbedEvent((InternalEvent*)ev, device, FALSE); + else { /* deliver to all root windows */ + xEvent *xi; + int i; + + i = EventToXI2((InternalEvent*)ev, (xEvent**)&xi); + if (i != Success) + { + ErrorF("[Xi] %s: XI2 conversion failed in ProcessRawEvent (%d)\n", + device->name, i); + return; + } + + for (i = 0; i < screenInfo.numScreens; i++) + DeliverEventsToWindow(device, screenInfo.screens[i]->root, xi, 1, + GetEventFilter(device, xi), NULL); + free(xi); + } +} + +/** + * Main device event processing function. + * Called from when processing the events from the event queue. + * + */ +void +ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) +{ + GrabPtr grab; + Bool deactivateDeviceGrab = FALSE; + int key = 0, rootX, rootY; + ButtonClassPtr b; + KeyClassPtr k; + ValuatorClassPtr v; + int ret = 0; + int state, i; + DeviceIntPtr mouse = NULL, kbd = NULL; + DeviceEvent *event = &ev->device_event; + + CHECKEVENT(ev); + + if (ev->any.type == ET_RawKeyPress || + ev->any.type == ET_RawKeyRelease || + ev->any.type == ET_RawButtonPress || + ev->any.type == ET_RawButtonRelease || + ev->any.type == ET_RawMotion) + { + ProcessRawEvent(&ev->raw_event, device); + return; + } + + if (IsPointerDevice(device)) + { + kbd = GetPairedDevice(device); + mouse = device; + if (!kbd->key) /* can happen with floating SDs */ + kbd = NULL; + } else + { + mouse = GetPairedDevice(device); + kbd = device; + if (!mouse->valuator || !mouse->button) /* may be float. SDs */ + mouse = NULL; + } + + /* State needs to be assembled BEFORE the device is updated. */ + state = (kbd && kbd->key) ? XkbStateFieldFromRec(&kbd->key->xkbInfo->state) : 0; + state |= (mouse && mouse->button) ? (mouse->button->state) : 0; + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(event->buttons, i); + + if (kbd && kbd->key) + { + XkbStatePtr state; + /* we need the state before the event happens */ + if (event->type == ET_KeyPress || event->type == ET_KeyRelease) + state = &kbd->key->xkbInfo->prev_state; + else + state = &kbd->key->xkbInfo->state; + + event->mods.base = state->base_mods; + event->mods.latched = state->latched_mods; + event->mods.locked = state->locked_mods; + event->mods.effective = state->mods; + + event->group.base = state->base_group; + event->group.latched = state->latched_group; + event->group.locked = state->locked_group; + event->group.effective = state->group; + } + + ret = UpdateDeviceState(device, event); + if (ret == DONT_PROCESS) + return; + + v = device->valuator; + b = device->button; + k = device->key; + + if (IsMaster(device) || !device->u.master) + CheckMotion(event, device); + + switch (event->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + GetSpritePosition(device, &rootX, &rootY); + event->root_x = rootX; + event->root_y = rootY; + NoticeEventTime((InternalEvent*)event); + event->corestate = state; + key = event->detail.key; + break; + default: + break; + } + + if (DeviceEventCallback && !syncEvents.playingEvents) { + DeviceEventInfoRec eventinfo; + SpritePtr pSprite = device->spriteInfo->sprite; + + /* see comment in EnqueueEvents regarding the next three lines */ + if (ev->any.type == ET_Motion) + ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id; + + eventinfo.device = device; + eventinfo.event = ev; + CallCallbacks(&DeviceEventCallback, (pointer) & eventinfo); + } + + grab = device->deviceGrab.grab; + + switch(event->type) + { + case ET_KeyPress: + if (!grab && CheckDeviceGrabs(device, event, 0)) { + device->deviceGrab.activatingKey = key; + return; + } + break; + case ET_KeyRelease: + if (grab && device->deviceGrab.fromPassiveGrab && + (key == device->deviceGrab.activatingKey) && + (device->deviceGrab.grab->type == KeyPress || + device->deviceGrab.grab->type == DeviceKeyPress || + device->deviceGrab.grab->type == XI_KeyPress)) + deactivateDeviceGrab = TRUE; + break; + case ET_ButtonPress: + event->detail.button = b->map[key]; + if (!event->detail.button) { /* there's no button 0 */ + event->detail.button = key; + return; + } + if (!grab && CheckDeviceGrabs(device, event, 0)) + { + /* if a passive grab was activated, the event has been sent + * already */ + return; + } + break; + case ET_ButtonRelease: + event->detail.button = b->map[key]; + if (!event->detail.button) { /* there's no button 0 */ + event->detail.button = key; + return; + } + if (grab && !b->buttonsDown && + device->deviceGrab.fromPassiveGrab && + (device->deviceGrab.grab->type == ButtonPress || + device->deviceGrab.grab->type == DeviceButtonPress || + device->deviceGrab.grab->type == XI_ButtonPress)) + deactivateDeviceGrab = TRUE; + default: + break; + } + + + if (grab) + DeliverGrabbedEvent((InternalEvent*)event, device, deactivateDeviceGrab); + else if (device->focus && !IsPointerEvent((InternalEvent*)ev)) + DeliverFocusedEvent(device, (InternalEvent*)event, + GetSpriteWindow(device)); + else + DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent*)event, + NullGrab, NullWindow, device); + + if (deactivateDeviceGrab == TRUE) + (*device->deviceGrab.DeactivateGrab) (device); + event->detail.key = key; +} + +int +InitProximityClassDeviceStruct(DeviceIntPtr dev) +{ + ProximityClassPtr proxc; + + proxc = (ProximityClassPtr) malloc(sizeof(ProximityClassRec)); + if (!proxc) + return FALSE; + proxc->sourceid = dev->id; + proxc->in_proximity = TRUE; + dev->proximity = proxc; + return TRUE; +} + +/** + * Initialise the device's valuators. The memory must already be allocated, + * this function merely inits the matching axis (specified through axnum) to + * sane values. + * + * It is a condition that (minval < maxval). + * + * @see InitValuatorClassDeviceStruct + */ +void +InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval, + int resolution, int min_res, int max_res, int mode) +{ + AxisInfoPtr ax; + + if (!dev || !dev->valuator || minval > maxval) + return; + if (axnum >= dev->valuator->numAxes) + return; + + ax = dev->valuator->axes + axnum; + + ax->min_value = minval; + ax->max_value = maxval; + ax->resolution = resolution; + ax->min_resolution = min_res; + ax->max_resolution = max_res; + ax->label = label; + ax->mode = mode; + + if (mode & OutOfProximity) + dev->proximity->in_proximity = FALSE; +} + +static void +FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, + ButtonClassPtr b, ValuatorClassPtr v, int first) +{ + ev->type = DeviceStateNotify; + ev->deviceid = dev->id; + ev->time = currentTime.milliseconds; + ev->classes_reported = 0; + ev->num_keys = 0; + ev->num_buttons = 0; + ev->num_valuators = 0; + + if (b) { + ev->classes_reported |= (1 << ButtonClass); + ev->num_buttons = b->numButtons; + memcpy((char*)ev->buttons, (char*)b->down, 4); + } else if (k) { + ev->classes_reported |= (1 << KeyClass); + ev->num_keys = k->xkbInfo->desc->max_key_code - + k->xkbInfo->desc->min_key_code; + memmove((char *)&ev->keys[0], (char *)k->down, 4); + } + if (v) { + int nval = v->numAxes - first; + + ev->classes_reported |= (1 << ValuatorClass); + ev->classes_reported |= valuator_get_mode(dev, 0) << ModeBitsShift; + ev->num_valuators = nval < 3 ? nval : 3; + switch (ev->num_valuators) { + case 3: + ev->valuator2 = v->axisVal[first + 2]; + case 2: + ev->valuator1 = v->axisVal[first + 1]; + case 1: + ev->valuator0 = v->axisVal[first]; + break; + } + } +} + +static void +FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v, + int first) +{ + int nval = v->numAxes - first; + + ev->type = DeviceValuator; + ev->deviceid = dev->id; + ev->num_valuators = nval < 3 ? nval : 3; + ev->first_valuator = first; + switch (ev->num_valuators) { + case 3: + ev->valuator2 = v->axisVal[first + 2]; + case 2: + ev->valuator1 = v->axisVal[first + 1]; + case 1: + ev->valuator0 = v->axisVal[first]; + break; + } + first += ev->num_valuators; +} + +void +DeviceFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, + WindowPtr pWin) +{ + deviceFocus event; + xXIFocusInEvent *xi2event; + DeviceIntPtr mouse; + int btlen, len, i; + + mouse = (IsMaster(dev) || dev->u.master) ? GetMaster(dev, MASTER_POINTER) : dev; + + /* XI 2 event */ + btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIFocusInEvent) + btlen * 4; + + xi2event = calloc(1, len); + xi2event->type = GenericEvent; + xi2event->extension = IReqCode; + xi2event->evtype = type; + xi2event->length = bytes_to_int32(len - sizeof(xEvent)); + xi2event->buttons_len = btlen; + xi2event->detail = detail; + xi2event->time = currentTime.milliseconds; + xi2event->deviceid = dev->id; + xi2event->sourceid = dev->id; /* a device doesn't change focus by itself */ + xi2event->mode = mode; + xi2event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); + xi2event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(&xi2event[1], i); + + if (dev->key) + { + xi2event->mods.base_mods = dev->key->xkbInfo->state.base_mods; + xi2event->mods.latched_mods = dev->key->xkbInfo->state.latched_mods; + xi2event->mods.locked_mods = dev->key->xkbInfo->state.locked_mods; + xi2event->mods.effective_mods = dev->key->xkbInfo->state.mods; + + xi2event->group.base_group = dev->key->xkbInfo->state.base_group; + xi2event->group.latched_group = dev->key->xkbInfo->state.latched_group; + xi2event->group.locked_group = dev->key->xkbInfo->state.locked_group; + xi2event->group.effective_group = dev->key->xkbInfo->state.group; + } + + FixUpEventFromWindow(dev->spriteInfo->sprite, (xEvent*)xi2event, pWin, + None, FALSE); + + DeliverEventsToWindow(dev, pWin, (xEvent*)xi2event, 1, + GetEventFilter(dev, (xEvent*)xi2event), NullGrab); + + free(xi2event); + + /* XI 1.x event */ + event.deviceid = dev->id; + event.mode = mode; + event.type = (type == XI_FocusIn) ? DeviceFocusIn : DeviceFocusOut; + event.detail = detail; + event.window = pWin->drawable.id; + event.time = currentTime.milliseconds; + + DeliverEventsToWindow(dev, pWin, (xEvent *) & event, 1, + DeviceFocusChangeMask, NullGrab); + + if ((type == DeviceFocusIn) && + (wOtherInputMasks(pWin)) && + (wOtherInputMasks(pWin)->inputEvents[dev->id] & DeviceStateNotifyMask)) + { + int evcount = 1; + deviceStateNotify *ev, *sev; + deviceKeyStateNotify *kev; + deviceButtonStateNotify *bev; + + KeyClassPtr k; + ButtonClassPtr b; + ValuatorClassPtr v; + int nval = 0, nkeys = 0, nbuttons = 0, first = 0; + + if ((b = dev->button) != NULL) { + nbuttons = b->numButtons; + if (nbuttons > 32) + evcount++; + } + if ((k = dev->key) != NULL) { + nkeys = k->xkbInfo->desc->max_key_code - + k->xkbInfo->desc->min_key_code; + if (nkeys > 32) + evcount++; + if (nbuttons > 0) { + evcount++; + } + } + if ((v = dev->valuator) != NULL) { + nval = v->numAxes; + + if (nval > 3) + evcount++; + if (nval > 6) { + if (!(k && b)) + evcount++; + if (nval > 9) + evcount += ((nval - 7) / 3); + } + } + + sev = ev = (deviceStateNotify *) malloc(evcount * sizeof(xEvent)); + FixDeviceStateNotify(dev, ev, NULL, NULL, NULL, first); + + if (b != NULL) { + FixDeviceStateNotify(dev, ev++, NULL, b, v, first); + first += 3; + nval -= 3; + if (nbuttons > 32) { + (ev - 1)->deviceid |= MORE_EVENTS; + bev = (deviceButtonStateNotify *) ev++; + bev->type = DeviceButtonStateNotify; + bev->deviceid = dev->id; + memcpy((char*)&bev->buttons[4], (char*)&b->down[4], DOWN_LENGTH - 4); + } + if (nval > 0) { + (ev - 1)->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); + first += 3; + nval -= 3; + } + } + + if (k != NULL) { + FixDeviceStateNotify(dev, ev++, k, NULL, v, first); + first += 3; + nval -= 3; + if (nkeys > 32) { + (ev - 1)->deviceid |= MORE_EVENTS; + kev = (deviceKeyStateNotify *) ev++; + kev->type = DeviceKeyStateNotify; + kev->deviceid = dev->id; + memmove((char *)&kev->keys[0], (char *)&k->down[4], 28); + } + if (nval > 0) { + (ev - 1)->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); + first += 3; + nval -= 3; + } + } + + while (nval > 0) { + FixDeviceStateNotify(dev, ev++, NULL, NULL, v, first); + first += 3; + nval -= 3; + if (nval > 0) { + (ev - 1)->deviceid |= MORE_EVENTS; + FixDeviceValuator(dev, (deviceValuator *) ev++, v, first); + first += 3; + nval -= 3; + } + } + + DeliverEventsToWindow(dev, pWin, (xEvent *) sev, evcount, + DeviceStateNotifyMask, NullGrab); + free(sev); + } +} + +int +CheckGrabValues(ClientPtr client, GrabParameters* param) +{ + if (param->grabtype != GRABTYPE_CORE && + param->grabtype != GRABTYPE_XI && + param->grabtype != GRABTYPE_XI2) + { + ErrorF("[Xi] grabtype is invalid. This is a bug.\n"); + return BadImplementation; + } + + if ((param->this_device_mode != GrabModeSync) && + (param->this_device_mode != GrabModeAsync)) { + client->errorValue = param->this_device_mode; + return BadValue; + } + if ((param->other_devices_mode != GrabModeSync) && + (param->other_devices_mode != GrabModeAsync)) { + client->errorValue = param->other_devices_mode; + return BadValue; + } + + if (param->grabtype != GRABTYPE_XI2 && (param->modifiers != AnyModifier) && + (param->modifiers & ~AllModifiersMask)) { + client->errorValue = param->modifiers; + return BadValue; + } + + if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) { + client->errorValue = param->ownerEvents; + return BadValue; + } + return Success; +} + +int +GrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, + int button, GrabParameters *param, GrabType grabtype, + GrabMask *mask) +{ + WindowPtr pWin, confineTo; + CursorPtr cursor; + GrabPtr grab; + int rc, type = -1; + Mask access_mode = DixGrabAccess; + + rc = CheckGrabValues(client, param); + if (rc != Success) + return rc; + if (param->confineTo == None) + confineTo = NullWindow; + else { + rc = dixLookupWindow(&confineTo, param->confineTo, client, DixSetAttrAccess); + if (rc != Success) + return rc; + } + if (param->cursor == None) + cursor = NullCursor; + else { + rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = param->cursor; + return rc; + } + access_mode |= DixForceAccess; + } + if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (grabtype == GRABTYPE_XI) + type = DeviceButtonPress; + else if (grabtype == GRABTYPE_XI2) + type = XI_ButtonPress; + + grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, + mask, param, type, button, confineTo, cursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/** + * Grab the given key. If grabtype is GRABTYPE_XI, the key is a keycode. If + * grabtype is GRABTYPE_XI2, the key is a keysym. + */ +int +GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device, + int key, GrabParameters *param, GrabType grabtype, GrabMask *mask) +{ + WindowPtr pWin; + GrabPtr grab; + KeyClassPtr k = dev->key; + Mask access_mode = DixGrabAccess; + int rc, type = -1; + + rc = CheckGrabValues(client, param); + if (rc != Success) + return rc; + if (k == NULL) + return BadMatch; + if (grabtype == GRABTYPE_XI) + { + if ((key > k->xkbInfo->desc->max_key_code || + key < k->xkbInfo->desc->min_key_code) + && (key != AnyKey)) { + client->errorValue = key; + return BadValue; + } + type = DeviceKeyPress; + } else if (grabtype == GRABTYPE_XI2) + type = XI_KeyPress; + + rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype, + mask, param, type, key, NULL, NULL); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/* Enter/FocusIn grab */ +int +GrabWindow(ClientPtr client, DeviceIntPtr dev, int type, + GrabParameters *param, GrabMask *mask) +{ + WindowPtr pWin; + CursorPtr cursor; + GrabPtr grab; + Mask access_mode = DixGrabAccess; + int rc; + + rc = CheckGrabValues(client, param); + if (rc != Success) + return rc; + + rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (param->cursor == None) + cursor = NullCursor; + else { + rc = dixLookupResourceByType((pointer *)&cursor, param->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = param->cursor; + return rc; + } + access_mode |= DixForceAccess; + } + if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + grab = CreateGrab(client->index, dev, dev, pWin, GRABTYPE_XI2, + mask, param, (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, + 0, NULL, cursor); + + if (!grab) + return BadAlloc; + + return AddPassiveGrabToList(client, grab); +} + +int +SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client, + Mask mask, Mask exclusivemasks) +{ + int mskidx = dev->id; + int i, ret; + Mask check; + InputClientsPtr others; + + check = (mask & exclusivemasks); + if (wOtherInputMasks(pWin)) { + if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) { /* It is illegal for two different + * clients to select on any of the + * events for maskcheck. However, + * it is OK, for some client to + * continue selecting on one of those + * events. */ + for (others = wOtherInputMasks(pWin)->inputClients; others; + others = others->next) { + if (!SameClient(others, client) && (check & + others->mask[mskidx])) + return BadAccess; + } + } + for (others = wOtherInputMasks(pWin)->inputClients; others; + others = others->next) { + if (SameClient(others, client)) { + check = others->mask[mskidx]; + others->mask[mskidx] = mask; + if (mask == 0) { + for (i = 0; i < EMASKSIZE; i++) + if (i != mskidx && others->mask[i] != 0) + break; + if (i == EMASKSIZE) { + RecalculateDeviceDeliverableEvents(pWin); + if (ShouldFreeInputMasks(pWin, FALSE)) + FreeResource(others->resource, RT_NONE); + return Success; + } + } + goto maskSet; + } + } + } + check = 0; + if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success) + return ret; + maskSet: + if (dev->valuator) + if ((dev->valuator->motionHintWindow == pWin) && + (mask & DevicePointerMotionHintMask) && + !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab) + dev->valuator->motionHintWindow = NullWindow; + RecalculateDeviceDeliverableEvents(pWin); + return Success; +} + +int +AddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx) +{ + InputClientsPtr others; + + if (!pWin->optional && !MakeWindowOptional(pWin)) + return BadAlloc; + others = calloc(1, sizeof(InputClients)); + if (!others) + return BadAlloc; + if (!pWin->optional->inputMasks && !MakeInputMasks(pWin)) + return BadAlloc; + others->mask[mskidx] = mask; + others->resource = FakeClientID(client->index); + others->next = pWin->optional->inputMasks->inputClients; + pWin->optional->inputMasks->inputClients = others; + if (!AddResource(others->resource, RT_INPUTCLIENT, (pointer) pWin)) + return BadAlloc; + return Success; +} + +static Bool +MakeInputMasks(WindowPtr pWin) +{ + struct _OtherInputMasks *imasks; + + imasks = calloc(1, sizeof(struct _OtherInputMasks)); + if (!imasks) + return FALSE; + pWin->optional->inputMasks = imasks; + return TRUE; +} + +void +RecalculateDeviceDeliverableEvents(WindowPtr pWin) +{ + InputClientsPtr others; + struct _OtherInputMasks *inputMasks; /* default: NULL */ + WindowPtr pChild, tmp; + int i, j; + + pChild = pWin; + while (1) { + if ((inputMasks = wOtherInputMasks(pChild)) != 0) { + for (i = 0; i < EMASKSIZE; i++) + memset(inputMasks->xi2mask[i], 0, sizeof(inputMasks->xi2mask[i])); + for (others = inputMasks->inputClients; others; + others = others->next) { + for (i = 0; i < EMASKSIZE; i++) + inputMasks->inputEvents[i] |= others->mask[i]; + for (i = 0; i < EMASKSIZE; i++) + for (j = 0; j < XI2MASKSIZE; j++) + inputMasks->xi2mask[i][j] |= others->xi2mask[i][j]; + } + for (i = 0; i < EMASKSIZE; i++) + inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i]; + for (tmp = pChild->parent; tmp; tmp = tmp->parent) + if (wOtherInputMasks(tmp)) + for (i = 0; i < EMASKSIZE; i++) + inputMasks->deliverableEvents[i] |= + (wOtherInputMasks(tmp)->deliverableEvents[i] + & ~inputMasks-> + dontPropagateMask[i] & PropagateMask[i]); + } + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +int +InputClientGone(WindowPtr pWin, XID id) +{ + InputClientsPtr other, prev; + + if (!wOtherInputMasks(pWin)) + return Success; + prev = 0; + for (other = wOtherInputMasks(pWin)->inputClients; other; + other = other->next) { + if (other->resource == id) { + if (prev) { + prev->next = other->next; + free(other); + } else if (!(other->next)) { + if (ShouldFreeInputMasks(pWin, TRUE)) { + wOtherInputMasks(pWin)->inputClients = other->next; + free(wOtherInputMasks(pWin)); + pWin->optional->inputMasks = (OtherInputMasks *) NULL; + CheckWindowOptionalNeed(pWin); + free(other); + } else { + other->resource = FakeClientID(0); + if (!AddResource(other->resource, RT_INPUTCLIENT, + (pointer) pWin)) + return BadAlloc; + } + } else { + wOtherInputMasks(pWin)->inputClients = other->next; + free(other); + } + RecalculateDeviceDeliverableEvents(pWin); + return Success; + } + prev = other; + } + FatalError("client not on device event list"); +} + +int +SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, + xEvent * ev, Mask mask, int count) +{ + WindowPtr pWin; + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + WindowPtr spriteWin = GetSpriteWindow(d); + + if (dest == PointerWindow) + pWin = spriteWin; + else if (dest == InputFocus) { + WindowPtr inputFocus; + + if (!d->focus) + inputFocus = spriteWin; + else + inputFocus = d->focus->win; + + if (inputFocus == FollowKeyboardWin) + inputFocus = inputInfo.keyboard->focus->win; + + if (inputFocus == NoneWin) + return Success; + + /* If the input focus is PointerRootWin, send the event to where + * the pointer is if possible, then perhaps propogate up to root. */ + if (inputFocus == PointerRootWin) + inputFocus = GetCurrentRootWindow(d); + + if (IsParent(inputFocus, spriteWin)) { + effectiveFocus = inputFocus; + pWin = spriteWin; + } else + effectiveFocus = pWin = inputFocus; + } else + dixLookupWindow(&pWin, dest, client, DixSendAccess); + if (!pWin) + return BadWindow; + if ((propagate != xFalse) && (propagate != xTrue)) { + client->errorValue = propagate; + return BadValue; + } + ev->u.u.type |= 0x80; + if (propagate) { + for (; pWin; pWin = pWin->parent) { + if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab)) + return Success; + if (pWin == effectiveFocus) + return Success; + if (wOtherInputMasks(pWin)) + mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id]; + if (!mask) + break; + } + } else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count)) + DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab); + return Success; +} + +int +SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map) +{ + int i; + ButtonClassPtr b = dev->button; + + if (b == NULL) + return BadMatch; + + if (nElts != b->numButtons) { + client->errorValue = nElts; + return BadValue; + } + if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue)) + return BadValue; + for (i = 0; i < nElts; i++) + if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1)) + return MappingBusy; + for (i = 0; i < nElts; i++) + b->map[i + 1] = map[i]; + return Success; +} + +int +ChangeKeyMapping(ClientPtr client, + DeviceIntPtr dev, + unsigned len, + int type, + KeyCode firstKeyCode, + CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map) +{ + KeySymsRec keysyms; + KeyClassPtr k = dev->key; + + if (k == NULL) + return BadMatch; + + if (len != (keyCodes * keySymsPerKeyCode)) + return BadLength; + + if ((firstKeyCode < k->xkbInfo->desc->min_key_code) || + (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) { + client->errorValue = firstKeyCode; + return BadValue; + } + if (keySymsPerKeyCode == 0) { + client->errorValue = 0; + return BadValue; + } + keysyms.minKeyCode = firstKeyCode; + keysyms.maxKeyCode = firstKeyCode + keyCodes - 1; + keysyms.mapWidth = keySymsPerKeyCode; + keysyms.map = map; + + XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL, + serverClient); + + return Success; +} + +static void +DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev) +{ + WindowPtr parent; + + /* Deactivate any grabs performed on this window, before making + * any input focus changes. + * Deactivating a device grab should cause focus events. */ + + if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin)) + (*dev->deviceGrab.DeactivateGrab) (dev); + + /* If the focus window is a root window (ie. has no parent) + * then don't delete the focus from it. */ + + if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) { + int focusEventMode = NotifyNormal; + + /* If a grab is in progress, then alter the mode of focus events. */ + + if (dev->deviceGrab.grab) + focusEventMode = NotifyWhileGrabbed; + + switch (dev->focus->revert) { + case RevertToNone: + if (!ActivateFocusInGrab(dev, pWin, NoneWin)) + DoFocusEvents(dev, pWin, NoneWin, focusEventMode); + dev->focus->win = NoneWin; + dev->focus->traceGood = 0; + break; + case RevertToParent: + parent = pWin; + do { + parent = parent->parent; + dev->focus->traceGood--; + } + while (!parent->realized); + if (!ActivateFocusInGrab(dev, pWin, parent)) + DoFocusEvents(dev, pWin, parent, focusEventMode); + dev->focus->win = parent; + dev->focus->revert = RevertToNone; + break; + case RevertToPointerRoot: + if (!ActivateFocusInGrab(dev, pWin, PointerRootWin)) + DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode); + dev->focus->win = PointerRootWin; + dev->focus->traceGood = 0; + break; + case RevertToFollowKeyboard: + { + DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD); + if (!kbd || (kbd == dev && kbd != inputInfo.keyboard)) + kbd = inputInfo.keyboard; + if (kbd->focus->win) { + if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win)) + DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode); + dev->focus->win = FollowKeyboardWin; + dev->focus->traceGood = 0; + } else { + if (!ActivateFocusInGrab(dev, pWin, NoneWin)) + DoFocusEvents(dev, pWin, NoneWin, focusEventMode); + dev->focus->win = NoneWin; + dev->focus->traceGood = 0; + } + } + break; + } + } + + if (dev->valuator) + if (dev->valuator->motionHintWindow == pWin) + dev->valuator->motionHintWindow = NullWindow; +} + +void +DeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources) +{ + int i; + DeviceIntPtr dev; + InputClientsPtr ic; + struct _OtherInputMasks *inputMasks; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + DeleteDeviceFromAnyExtEvents(pWin, dev); + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + DeleteDeviceFromAnyExtEvents(pWin, dev); + + if (freeResources) + while ((inputMasks = wOtherInputMasks(pWin)) != 0) { + ic = inputMasks->inputClients; + for (i = 0; i < EMASKSIZE; i++) + inputMasks->dontPropagateMask[i] = 0; + FreeResource(ic->resource, RT_NONE); + } +} + +int +MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer * pEvents, Mask mask) +{ + DeviceIntPtr dev; + + dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient, + DixReadAccess); + if (!dev) + return 0; + + if (pEvents->type == DeviceMotionNotify) { + if (mask & DevicePointerMotionHintMask) { + if (WID(dev->valuator->motionHintWindow) == pEvents->event) { + return 1; /* don't send, but pretend we did */ + } + pEvents->detail = NotifyHint; + } else { + pEvents->detail = NotifyNormal; + } + } + return 0; +} + +void +CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type, + deviceKeyButtonPointer * xE, GrabPtr grab, + ClientPtr client, Mask deliveryMask) +{ + DeviceIntPtr dev; + + dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient, + DixGrabAccess); + if (!dev) + return; + + if (type == DeviceMotionNotify) + dev->valuator->motionHintWindow = pWin; + else if ((type == DeviceButtonPress) && (!grab) && + (deliveryMask & DeviceButtonGrabMask)) { + GrabRec tempGrab; + + tempGrab.device = dev; + tempGrab.resource = client->clientAsMask; + tempGrab.window = pWin; + tempGrab.ownerEvents = + (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE; + tempGrab.eventMask = deliveryMask; + tempGrab.keyboardMode = GrabModeAsync; + tempGrab.pointerMode = GrabModeAsync; + tempGrab.confineTo = NullWindow; + tempGrab.cursor = NullCursor; + tempGrab.next = NULL; + (*dev->deviceGrab.ActivateGrab) (dev, &tempGrab, currentTime, TRUE); + } +} + +static Mask +DeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client) +{ + InputClientsPtr other; + + if (!wOtherInputMasks(pWin)) + return 0; + for (other = wOtherInputMasks(pWin)->inputClients; other; + other = other->next) { + if (SameClient(other, client)) + return other->mask[dev->id]; + } + return 0; +} + +void +MaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client) +{ + WindowPtr pWin; + GrabPtr grab = dev->deviceGrab.grab; + + pWin = dev->valuator->motionHintWindow; + + if ((grab && SameClient(grab, client) && + ((grab->eventMask & DevicePointerMotionHintMask) || + (grab->ownerEvents && + (DeviceEventMaskForClient(dev, pWin, client) & + DevicePointerMotionHintMask)))) || + (!grab && + (DeviceEventMaskForClient(dev, pWin, client) & + DevicePointerMotionHintMask))) + dev->valuator->motionHintWindow = NullWindow; +} + +int +DeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask, + int maskndx) +{ + struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + + if (mask & ~PropagateMask[maskndx]) { + client->errorValue = mask; + return BadValue; + } + + if (mask == 0) { + if (inputMasks) + inputMasks->dontPropagateMask[maskndx] = mask; + } else { + if (!inputMasks) + AddExtensionClient(pWin, client, 0, 0); + inputMasks = wOtherInputMasks(pWin); + inputMasks->dontPropagateMask[maskndx] = mask; + } + RecalculateDeviceDeliverableEvents(pWin); + if (ShouldFreeInputMasks(pWin, FALSE)) + FreeResource(inputMasks->inputClients->resource, RT_NONE); + return Success; +} + +Bool +ShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents) +{ + int i; + Mask allInputEventMasks = 0; + struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + + for (i = 0; i < EMASKSIZE; i++) + allInputEventMasks |= inputMasks->dontPropagateMask[i]; + if (!ignoreSelectedEvents) + for (i = 0; i < EMASKSIZE; i++) + allInputEventMasks |= inputMasks->inputEvents[i]; + if (allInputEventMasks == 0) + return TRUE; + else + return FALSE; +} + +/*********************************************************************** + * + * Walk through the window tree, finding all clients that want to know + * about the Event. + * + */ + +static void +FindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask, + xEvent * ev, int count) +{ + WindowPtr p2; + + while (p1) { + p2 = p1->firstChild; + DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab); + FindInterestedChildren(dev, p2, mask, ev, count); + p1 = p1->nextSib; + } +} + +/*********************************************************************** + * + * Send an event to interested clients in all windows on all screens. + * + */ + +void +SendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent * ev, int count) +{ + int i; + WindowPtr pWin, p1; + + for (i = 0; i < screenInfo.numScreens; i++) { + pWin = screenInfo.screens[i]->root; + if (!pWin) + continue; + DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab); + p1 = pWin->firstChild; + FindInterestedChildren(dev, p1, mask, ev, count); + } +} + +/** + * Set the XI2 mask for the given client on the given window. + * @param dev The device to set the mask for. + * @param win The window to set the mask on. + * @param client The client setting the mask. + * @param len Number of bytes in mask. + * @param mask Event mask in the form of (1 << eventtype) + */ +int +XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client, + unsigned int len, unsigned char* mask) +{ + OtherInputMasks *masks; + InputClientsPtr others = NULL; + + masks = wOtherInputMasks(win); + if (masks) + { + for (others = wOtherInputMasks(win)->inputClients; others; + others = others->next) { + if (SameClient(others, client)) { + memset(others->xi2mask[dev->id], 0, + sizeof(others->xi2mask[dev->id])); + break; + } + } + } + + len = min(len, sizeof(others->xi2mask[dev->id])); + + if (len && !others) + { + if (AddExtensionClient(win, client, 0, 0) != Success) + return BadAlloc; + others= wOtherInputMasks(win)->inputClients; + } + + if (others) + memset(others->xi2mask[dev->id], 0, sizeof(others->xi2mask[dev->id])); + + if (len) + memcpy(others->xi2mask[dev->id], mask, len); + + RecalculateDeviceDeliverableEvents(win); + + return Success; +} diff --git a/xorg-server/Xi/extinit.c b/xorg-server/Xi/extinit.c index a6408fbb3..82df7eb02 100644 --- a/xorg-server/Xi/extinit.c +++ b/xorg-server/Xi/extinit.c @@ -1,1308 +1,1309 @@ -/************************************************************ - -Copyright 1989, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - -Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Hewlett-Packard not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -HEWLETT-PACKARD 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. - -********************************************************/ - -/******************************************************************** - * - * Dispatch routines and initialization routines for the X input extension. - * - */ - -#define NUMTYPES 15 - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "inputstr.h" -#include "gcstruct.h" /* pointer for extnsionst.h */ -#include "extnsionst.h" /* extension entry */ -#include -#include -#include -#include -#include "geext.h" /* extension interfaces for ge */ - -#include "dixevents.h" -#include "exevents.h" -#include "extinit.h" -#include "exglobals.h" -#include "swaprep.h" -#include "privates.h" -#include "protocol-versions.h" - -/* modules local to Xi */ -#include "allowev.h" -#include "chgdctl.h" -#include "chgfctl.h" -#include "chgkbd.h" -#include "chgprop.h" -#include "chgptr.h" -#include "closedev.h" -#include "devbell.h" -#include "getbmap.h" -#include "getbmap.h" -#include "getdctl.h" -#include "getfctl.h" -#include "getfocus.h" -#include "getkmap.h" -#include "getmmap.h" -#include "getprop.h" -#include "getselev.h" -#include "getvers.h" -#include "getvers.h" -#include "grabdev.h" -#include "grabdevb.h" -#include "grabdevk.h" -#include "gtmotion.h" -#include "listdev.h" -#include "opendev.h" -#include "queryst.h" -#include "selectev.h" -#include "sendexev.h" -#include "chgkmap.h" -#include "setbmap.h" -#include "setdval.h" -#include "setfocus.h" -#include "setmmap.h" -#include "setmode.h" -#include "ungrdev.h" -#include "ungrdevb.h" -#include "ungrdevk.h" -#include "xiallowev.h" -#include "xiselectev.h" -#include "xigrabdev.h" -#include "xipassivegrab.h" -#include "xisetdevfocus.h" -#include "xiproperty.h" -#include "xichangecursor.h" -#include "xichangehierarchy.h" -#include "xigetclientpointer.h" -#include "xiquerydevice.h" -#include "xiquerypointer.h" -#include "xiqueryversion.h" -#include "xisetclientpointer.h" -#include "xiwarppointer.h" - - -/* Masks for XI events have to be aligned with core event (partially anyway). - * If DeviceButtonMotionMask is != ButtonMotionMask, event delivery - * breaks down. The device needs the dev->button->motionMask. If DBMM is - * the same as BMM, we can ensure that both core and device events can be - * delivered, without the need for extra structures in the DeviceIntRec. */ -const Mask DeviceKeyPressMask = KeyPressMask; -const Mask DeviceKeyReleaseMask = KeyReleaseMask; -const Mask DeviceButtonPressMask = ButtonPressMask; -const Mask DeviceButtonReleaseMask = ButtonReleaseMask; -const Mask DeviceProximityMask = (1L << 4); -const Mask DeviceStateNotifyMask = (1L << 5); -const Mask DevicePointerMotionMask = PointerMotionMask; -const Mask DevicePointerMotionHintMask = PointerMotionHintMask; -const Mask DeviceButton1MotionMask = Button1MotionMask; -const Mask DeviceButton2MotionMask = Button2MotionMask; -const Mask DeviceButton3MotionMask = Button3MotionMask; -const Mask DeviceButton4MotionMask = Button4MotionMask; -const Mask DeviceButton5MotionMask = Button5MotionMask; -const Mask DeviceButtonMotionMask = ButtonMotionMask; -const Mask DeviceFocusChangeMask = (1L << 14); -const Mask DeviceMappingNotifyMask = (1L << 15); -const Mask ChangeDeviceNotifyMask = (1L << 16); -const Mask DeviceButtonGrabMask = (1L << 17); -const Mask DeviceOwnerGrabButtonMask = (1L << 17); -const Mask DevicePresenceNotifyMask = (1L << 18); -const Mask DeviceEnterWindowMask = (1L << 18); -const Mask DeviceLeaveWindowMask = (1L << 19); -const Mask DevicePropertyNotifyMask = (1L << 20); -const Mask XIAllMasks = (1L << 21) - 1; - -int ExtEventIndex; -Mask ExtExclusiveMasks[EMASKSIZE]; - -static struct dev_type -{ - Atom type; - char *name; -} dev_type[] = { - { - 0, XI_KEYBOARD}, { - 0, XI_MOUSE}, { - 0, XI_TABLET}, { - 0, XI_TOUCHSCREEN}, { - 0, XI_TOUCHPAD}, { - 0, XI_BARCODE}, { - 0, XI_BUTTONBOX}, { - 0, XI_KNOB_BOX}, { - 0, XI_ONE_KNOB}, { - 0, XI_NINE_KNOB}, { - 0, XI_TRACKBALL}, { - 0, XI_QUADRATURE}, { - 0, XI_ID_MODULE}, { - 0, XI_SPACEBALL}, { - 0, XI_DATAGLOVE}, { - 0, XI_EYETRACKER}, { - 0, XI_CURSORKEYS}, { -0, XI_FOOTMOUSE}}; - -CARD8 event_base[numInputClasses]; -XExtEventInfo EventInfo[32]; - -static DeviceIntRec xi_all_devices; -static DeviceIntRec xi_all_master_devices; - -/** - * Dispatch vector. Functions defined in here will be called when the matching - * request arrives. - */ -static int (*ProcIVector[])(ClientPtr) = { - NULL, /* 0 */ - ProcXGetExtensionVersion, /* 1 */ - ProcXListInputDevices, /* 2 */ - ProcXOpenDevice, /* 3 */ - ProcXCloseDevice, /* 4 */ - ProcXSetDeviceMode, /* 5 */ - ProcXSelectExtensionEvent, /* 6 */ - ProcXGetSelectedExtensionEvents, /* 7 */ - ProcXChangeDeviceDontPropagateList, /* 8 */ - ProcXGetDeviceDontPropagateList, /* 9 */ - ProcXGetDeviceMotionEvents, /* 10 */ - ProcXChangeKeyboardDevice, /* 11 */ - ProcXChangePointerDevice, /* 12 */ - ProcXGrabDevice, /* 13 */ - ProcXUngrabDevice, /* 14 */ - ProcXGrabDeviceKey, /* 15 */ - ProcXUngrabDeviceKey, /* 16 */ - ProcXGrabDeviceButton, /* 17 */ - ProcXUngrabDeviceButton, /* 18 */ - ProcXAllowDeviceEvents, /* 19 */ - ProcXGetDeviceFocus, /* 20 */ - ProcXSetDeviceFocus, /* 21 */ - ProcXGetFeedbackControl, /* 22 */ - ProcXChangeFeedbackControl, /* 23 */ - ProcXGetDeviceKeyMapping, /* 24 */ - ProcXChangeDeviceKeyMapping, /* 25 */ - ProcXGetDeviceModifierMapping, /* 26 */ - ProcXSetDeviceModifierMapping, /* 27 */ - ProcXGetDeviceButtonMapping, /* 28 */ - ProcXSetDeviceButtonMapping, /* 29 */ - ProcXQueryDeviceState, /* 30 */ - ProcXSendExtensionEvent, /* 31 */ - ProcXDeviceBell, /* 32 */ - ProcXSetDeviceValuators, /* 33 */ - ProcXGetDeviceControl, /* 34 */ - ProcXChangeDeviceControl, /* 35 */ - /* XI 1.5 */ - ProcXListDeviceProperties, /* 36 */ - ProcXChangeDeviceProperty, /* 37 */ - ProcXDeleteDeviceProperty, /* 38 */ - ProcXGetDeviceProperty, /* 39 */ - /* XI 2 */ - ProcXIQueryPointer, /* 40 */ - ProcXIWarpPointer, /* 41 */ - ProcXIChangeCursor, /* 42 */ - ProcXIChangeHierarchy, /* 43 */ - ProcXISetClientPointer, /* 44 */ - ProcXIGetClientPointer, /* 45 */ - ProcXISelectEvents, /* 46 */ - ProcXIQueryVersion, /* 47 */ - ProcXIQueryDevice, /* 48 */ - ProcXISetFocus, /* 49 */ - ProcXIGetFocus, /* 50 */ - ProcXIGrabDevice, /* 51 */ - ProcXIUngrabDevice, /* 52 */ - ProcXIAllowEvents, /* 53 */ - ProcXIPassiveGrabDevice, /* 54 */ - ProcXIPassiveUngrabDevice, /* 55 */ - ProcXIListProperties, /* 56 */ - ProcXIChangeProperty, /* 57 */ - ProcXIDeleteProperty, /* 58 */ - ProcXIGetProperty, /* 59 */ - ProcXIGetSelectedEvents /* 60 */ -}; - -/* For swapped clients */ -static int (*SProcIVector[])(ClientPtr) = { - NULL, /* 0 */ - SProcXGetExtensionVersion, /* 1 */ - SProcXListInputDevices, /* 2 */ - SProcXOpenDevice, /* 3 */ - SProcXCloseDevice, /* 4 */ - SProcXSetDeviceMode, /* 5 */ - SProcXSelectExtensionEvent, /* 6 */ - SProcXGetSelectedExtensionEvents, /* 7 */ - SProcXChangeDeviceDontPropagateList, /* 8 */ - SProcXGetDeviceDontPropagateList, /* 9 */ - SProcXGetDeviceMotionEvents, /* 10 */ - SProcXChangeKeyboardDevice, /* 11 */ - SProcXChangePointerDevice, /* 12 */ - SProcXGrabDevice, /* 13 */ - SProcXUngrabDevice, /* 14 */ - SProcXGrabDeviceKey, /* 15 */ - SProcXUngrabDeviceKey, /* 16 */ - SProcXGrabDeviceButton, /* 17 */ - SProcXUngrabDeviceButton, /* 18 */ - SProcXAllowDeviceEvents, /* 19 */ - SProcXGetDeviceFocus, /* 20 */ - SProcXSetDeviceFocus, /* 21 */ - SProcXGetFeedbackControl, /* 22 */ - SProcXChangeFeedbackControl, /* 23 */ - SProcXGetDeviceKeyMapping, /* 24 */ - SProcXChangeDeviceKeyMapping, /* 25 */ - SProcXGetDeviceModifierMapping, /* 26 */ - SProcXSetDeviceModifierMapping, /* 27 */ - SProcXGetDeviceButtonMapping, /* 28 */ - SProcXSetDeviceButtonMapping, /* 29 */ - SProcXQueryDeviceState, /* 30 */ - SProcXSendExtensionEvent, /* 31 */ - SProcXDeviceBell, /* 32 */ - SProcXSetDeviceValuators, /* 33 */ - SProcXGetDeviceControl, /* 34 */ - SProcXChangeDeviceControl, /* 35 */ - SProcXListDeviceProperties, /* 36 */ - SProcXChangeDeviceProperty, /* 37 */ - SProcXDeleteDeviceProperty, /* 38 */ - SProcXGetDeviceProperty, /* 39 */ - SProcXIQueryPointer, /* 40 */ - SProcXIWarpPointer, /* 41 */ - SProcXIChangeCursor, /* 42 */ - SProcXIChangeHierarchy, /* 43 */ - SProcXISetClientPointer, /* 44 */ - SProcXIGetClientPointer, /* 45 */ - SProcXISelectEvents, /* 46 */ - SProcXIQueryVersion, /* 47 */ - SProcXIQueryDevice, /* 48 */ - SProcXISetFocus, /* 49 */ - SProcXIGetFocus, /* 50 */ - SProcXIGrabDevice, /* 51 */ - SProcXIUngrabDevice, /* 52 */ - SProcXIAllowEvents, /* 53 */ - SProcXIPassiveGrabDevice, /* 54 */ - SProcXIPassiveUngrabDevice, /* 55 */ - SProcXIListProperties, /* 56 */ - SProcXIChangeProperty, /* 57 */ - SProcXIDeleteProperty, /* 58 */ - SProcXIGetProperty, /* 59 */ - SProcXIGetSelectedEvents /* 60 */ -}; - -/***************************************************************** - * - * Globals referenced elsewhere in the server. - * - */ - -int IReqCode = 0; -int IEventBase = 0; -int BadDevice = 0; -static int BadEvent = 1; -int BadMode = 2; -int DeviceBusy = 3; -int BadClass = 4; - -int DeviceValuator; -int DeviceKeyPress; -int DeviceKeyRelease; -int DeviceButtonPress; -int DeviceButtonRelease; -int DeviceMotionNotify; -int DeviceFocusIn; -int DeviceFocusOut; -int ProximityIn; -int ProximityOut; -int DeviceStateNotify; -int DeviceKeyStateNotify; -int DeviceButtonStateNotify; -int DeviceMappingNotify; -int ChangeDeviceNotify; -int DevicePresenceNotify; -int DevicePropertyNotify; - -int RT_INPUTCLIENT; - -/***************************************************************** - * - * Externs defined elsewhere in the X server. - * - */ - -extern XExtensionVersion XIVersion; - - -Mask PropagateMask[MAXDEVICES]; - -/***************************************************************** - * - * Versioning support - * - */ - -DevPrivateKeyRec XIClientPrivateKeyRec; - -/***************************************************************** - * - * Declarations of local routines. - * - */ - -static void -XIClientCallback(CallbackListPtr *list, - pointer closure, - pointer data) -{ - NewClientInfoRec *clientinfo = (NewClientInfoRec*)data; - ClientPtr pClient = clientinfo->client; - XIClientPtr pXIClient; - - pXIClient = dixLookupPrivate(&pClient->devPrivates, XIClientPrivateKey); - pXIClient->major_version = 0; - pXIClient->minor_version = 0; -} - -/************************************************************************* - * - * ProcIDispatch - main dispatch routine for requests to this extension. - * This routine is used if server and client have the same byte ordering. - * - */ - -static int -ProcIDispatch(ClientPtr client) -{ - REQUEST(xReq); - if (stuff->data > (IREQUESTS + XI2REQUESTS) || !ProcIVector[stuff->data]) - return BadRequest; - - return (*ProcIVector[stuff->data])(client); -} - -/******************************************************************************* - * - * SProcXDispatch - * - * Main swapped dispatch routine for requests to this extension. - * This routine is used if server and client do not have the same byte ordering. - * - */ - -static int -SProcIDispatch(ClientPtr client) -{ - REQUEST(xReq); - if (stuff->data > IREQUESTS || !SProcIVector[stuff->data]) - return BadRequest; - - return (*SProcIVector[stuff->data])(client); -} - -/********************************************************************** - * - * SReplyIDispatch - * Swap any replies defined in this extension. - * - */ - -static void -SReplyIDispatch(ClientPtr client, int len, xGrabDeviceReply * rep) - /* All we look at is the type field */ -{ /* This is common to all replies */ - if (rep->RepType == X_GetExtensionVersion) - SRepXGetExtensionVersion(client, len, - (xGetExtensionVersionReply *) rep); - else if (rep->RepType == X_ListInputDevices) - SRepXListInputDevices(client, len, (xListInputDevicesReply *) rep); - else if (rep->RepType == X_OpenDevice) - SRepXOpenDevice(client, len, (xOpenDeviceReply *) rep); - else if (rep->RepType == X_SetDeviceMode) - SRepXSetDeviceMode(client, len, (xSetDeviceModeReply *) rep); - else if (rep->RepType == X_GetSelectedExtensionEvents) - SRepXGetSelectedExtensionEvents(client, len, - (xGetSelectedExtensionEventsReply *) - rep); - else if (rep->RepType == X_GetDeviceDontPropagateList) - SRepXGetDeviceDontPropagateList(client, len, - (xGetDeviceDontPropagateListReply *) - rep); - else if (rep->RepType == X_GetDeviceMotionEvents) - SRepXGetDeviceMotionEvents(client, len, - (xGetDeviceMotionEventsReply *) rep); - else if (rep->RepType == X_GrabDevice) - SRepXGrabDevice(client, len, (xGrabDeviceReply *) rep); - else if (rep->RepType == X_GetDeviceFocus) - SRepXGetDeviceFocus(client, len, (xGetDeviceFocusReply *) rep); - else if (rep->RepType == X_GetFeedbackControl) - SRepXGetFeedbackControl(client, len, (xGetFeedbackControlReply *) rep); - else if (rep->RepType == X_GetDeviceKeyMapping) - SRepXGetDeviceKeyMapping(client, len, - (xGetDeviceKeyMappingReply *) rep); - else if (rep->RepType == X_GetDeviceModifierMapping) - SRepXGetDeviceModifierMapping(client, len, - (xGetDeviceModifierMappingReply *) rep); - else if (rep->RepType == X_SetDeviceModifierMapping) - SRepXSetDeviceModifierMapping(client, len, - (xSetDeviceModifierMappingReply *) rep); - else if (rep->RepType == X_GetDeviceButtonMapping) - SRepXGetDeviceButtonMapping(client, len, - (xGetDeviceButtonMappingReply *) rep); - else if (rep->RepType == X_SetDeviceButtonMapping) - SRepXSetDeviceButtonMapping(client, len, - (xSetDeviceButtonMappingReply *) rep); - else if (rep->RepType == X_QueryDeviceState) - SRepXQueryDeviceState(client, len, (xQueryDeviceStateReply *) rep); - else if (rep->RepType == X_SetDeviceValuators) - SRepXSetDeviceValuators(client, len, (xSetDeviceValuatorsReply *) rep); - else if (rep->RepType == X_GetDeviceControl) - SRepXGetDeviceControl(client, len, (xGetDeviceControlReply *) rep); - else if (rep->RepType == X_ChangeDeviceControl) - SRepXChangeDeviceControl(client, len, - (xChangeDeviceControlReply *) rep); - else if (rep->RepType == X_ListDeviceProperties) - SRepXListDeviceProperties(client, len, (xListDevicePropertiesReply*)rep); - else if (rep->RepType == X_GetDeviceProperty) - SRepXGetDeviceProperty(client, len, (xGetDevicePropertyReply *) rep); - else if (rep->RepType == X_XIQueryPointer) - SRepXIQueryPointer(client, len, (xXIQueryPointerReply *) rep); - else if (rep->RepType == X_XIGetClientPointer) - SRepXIGetClientPointer(client, len, (xXIGetClientPointerReply*) rep); - else if (rep->RepType == X_XIQueryVersion) - SRepXIQueryVersion(client, len, (xXIQueryVersionReply*)rep); - else if (rep->RepType == X_XIQueryDevice) - SRepXIQueryDevice(client, len, (xXIQueryDeviceReply*)rep); - else if (rep->RepType == X_XIGrabDevice) - SRepXIGrabDevice(client, len, (xXIGrabDeviceReply *) rep); - else if (rep->RepType == X_XIGrabDevice) - SRepXIPassiveGrabDevice(client, len, (xXIPassiveGrabDeviceReply *) rep); - else if (rep->RepType == X_XIListProperties) - SRepXIListProperties(client, len, (xXIListPropertiesReply *) rep); - else if (rep->RepType == X_XIGetProperty) - SRepXIGetProperty(client, len, (xXIGetPropertyReply *) rep); - else if (rep->RepType == X_XIGetSelectedEvents) - SRepXIGetSelectedEvents(client, len, (xXIGetSelectedEventsReply *) rep); - else if (rep->RepType == X_XIGetFocus) - SRepXIGetFocus(client, len, (xXIGetFocusReply *) rep); - else { - FatalError("XINPUT confused sending swapped reply"); - } -} - -/************************************************************************ - * - * This function swaps the DeviceValuator event. - * - */ - -static void -SEventDeviceValuator(deviceValuator * from, deviceValuator * to) -{ - char n; - int i; - INT32 *ip B32; - - *to = *from; - swaps(&to->sequenceNumber, n); - swaps(&to->device_state, n); - ip = &to->valuator0; - for (i = 0; i < 6; i++) { - swapl((ip + i), n); /* macro - braces are required */ - } -} - -static void -SEventFocus(deviceFocus * from, deviceFocus * to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber, n); - swapl(&to->time, n); - swapl(&to->window, n); -} - -static void -SDeviceStateNotifyEvent(deviceStateNotify * from, deviceStateNotify * to) -{ - int i; - char n; - INT32 *ip B32; - - *to = *from; - swaps(&to->sequenceNumber, n); - swapl(&to->time, n); - ip = &to->valuator0; - for (i = 0; i < 3; i++) { - swapl((ip + i), n); /* macro - braces are required */ - } -} - -static void -SDeviceKeyStateNotifyEvent(deviceKeyStateNotify * from, - deviceKeyStateNotify * to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber, n); -} - -static void -SDeviceButtonStateNotifyEvent(deviceButtonStateNotify * from, - deviceButtonStateNotify * to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber, n); -} - -static void -SChangeDeviceNotifyEvent(changeDeviceNotify * from, changeDeviceNotify * to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber, n); - swapl(&to->time, n); -} - -static void -SDeviceMappingNotifyEvent(deviceMappingNotify * from, deviceMappingNotify * to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber, n); - swapl(&to->time, n); -} - -static void -SDevicePresenceNotifyEvent (devicePresenceNotify *from, devicePresenceNotify *to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber,n); - swapl(&to->time, n); - swaps(&to->control, n); -} - -static void -SDevicePropertyNotifyEvent (devicePropertyNotify *from, devicePropertyNotify *to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber,n); - swapl(&to->time, n); - swapl(&to->atom, n); -} - -static void -SDeviceLeaveNotifyEvent (xXILeaveEvent *from, xXILeaveEvent *to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber,n); - swapl(&to->length, n); - swaps(&to->evtype, n); - swaps(&to->deviceid, n); - swapl(&to->time, n); - swapl(&to->root, n); - swapl(&to->event, n); - swapl(&to->child, n); - swapl(&to->root_x, n); - swapl(&to->root_y, n); - swapl(&to->event_x, n); - swapl(&to->event_y, n); - swaps(&to->sourceid, n); - swaps(&to->buttons_len, n); - swapl(&to->mods.base_mods, n); - swapl(&to->mods.latched_mods, n); - swapl(&to->mods.locked_mods, n); -} - -static void -SDeviceChangedEvent(xXIDeviceChangedEvent* from, xXIDeviceChangedEvent* to) -{ - char n; - int i, j; - xXIAnyInfo *any; - - *to = *from; - memcpy(&to[1], &from[1], from->length * 4); - - any = (xXIAnyInfo*)&to[1]; - for (i = 0; i < to->num_classes; i++) - { - int length = any->length; - - switch(any->type) - { - case KeyClass: - { - xXIKeyInfo *ki = (xXIKeyInfo*)any; - uint32_t *key = (uint32_t*)&ki[1]; - for (j = 0; j < ki->num_keycodes; j++, key++) - swapl(key, n); - swaps(&ki->num_keycodes, n); - } - break; - case ButtonClass: - { - xXIButtonInfo *bi = (xXIButtonInfo*)any; - Atom *labels = (Atom*)((char*)bi + sizeof(xXIButtonInfo) + - pad_to_int32(bits_to_bytes(bi->num_buttons))); - for (j = 0; j < bi->num_buttons; j++) - swapl(&labels[j], n); - swaps(&bi->num_buttons, n); - } - break; - case ValuatorClass: - { - xXIValuatorInfo* ai = (xXIValuatorInfo*)any; - swapl(&ai->label, n); - swapl(&ai->min.integral, n); - swapl(&ai->min.frac, n); - swapl(&ai->max.integral, n); - swapl(&ai->max.frac, n); - swapl(&ai->resolution, n); - swaps(&ai->number, n); - } - break; - } - - swaps(&any->type, n); - swaps(&any->length, n); - swaps(&any->sourceid, n); - - any = (xXIAnyInfo*)((char*)any + length * 4); - } - - swaps(&to->sequenceNumber, n); - swapl(&to->length, n); - swaps(&to->evtype, n); - swaps(&to->deviceid, n); - swapl(&to->time, n); - swaps(&to->num_classes, n); - swaps(&to->sourceid, n); - -} - -static void SDeviceEvent(xXIDeviceEvent *from, xXIDeviceEvent *to) -{ - int i; - char n; - char *ptr; - char *vmask; - - memcpy(to, from, sizeof(xEvent) + from->length * 4); - - swaps(&to->sequenceNumber, n); - swapl(&to->length, n); - swaps(&to->evtype, n); - swaps(&to->deviceid, n); - swapl(&to->time, n); - swapl(&to->detail, n); - swapl(&to->root, n); - swapl(&to->event, n); - swapl(&to->child, n); - swapl(&to->root_x, n); - swapl(&to->root_y, n); - swapl(&to->event_x, n); - swapl(&to->event_y, n); - swaps(&to->buttons_len, n); - swaps(&to->valuators_len, n); - swaps(&to->sourceid, n); - swapl(&to->mods.base_mods, n); - swapl(&to->mods.latched_mods, n); - swapl(&to->mods.locked_mods, n); - swapl(&to->mods.effective_mods, n); - - ptr = (char*)(&to[1]); - ptr += from->buttons_len * 4; - vmask = ptr; /* valuator mask */ - ptr += from->valuators_len * 4; - for (i = 0; i < from->valuators_len * 32; i++) - { - if (BitIsOn(vmask, i)) - { - swapl(((uint32_t*)ptr), n); - ptr += 4; - swapl(((uint32_t*)ptr), n); - ptr += 4; - } - } -} - -static void SDeviceHierarchyEvent(xXIHierarchyEvent *from, - xXIHierarchyEvent *to) -{ - int i; - char n; - xXIHierarchyInfo *info; - - *to = *from; - memcpy(&to[1], &from[1], from->length * 4); - swaps(&to->sequenceNumber, n); - swapl(&to->length, n); - swaps(&to->evtype, n); - swaps(&to->deviceid, n); - swapl(&to->time, n); - swapl(&to->flags, n); - swaps(&to->num_info, n); - - info = (xXIHierarchyInfo*)&to[1]; - for (i = 0; i< from->num_info; i++) - { - swaps(&info->deviceid, n); - swaps(&info->attachment, n); - info++; - } -} - -static void SXIPropertyEvent(xXIPropertyEvent *from, xXIPropertyEvent *to) -{ - char n; - - *to = *from; - swaps(&to->sequenceNumber, n); - swapl(&to->length, n); - swaps(&to->evtype, n); - swaps(&to->deviceid, n); - swapl(&to->property, n); -} - -static void SRawEvent(xXIRawEvent *from, xXIRawEvent *to) -{ - char n; - int i; - FP3232 *values; - unsigned char *mask; - - memcpy(to, from, sizeof(xEvent) + from->length * 4); - - swaps(&to->sequenceNumber, n); - swapl(&to->length, n); - swaps(&to->evtype, n); - swaps(&to->deviceid, n); - swapl(&to->time, n); - swapl(&to->detail, n); - - - mask = (unsigned char*)&to[1]; - values = (FP3232*)(mask + from->valuators_len * 4); - - for (i = 0; i < from->valuators_len * 4 * 8; i++) - { - if (BitIsOn(mask, i)) - { - /* for each bit set there are two FP3232 values on the wire, in - * the order abcABC for data and data_raw. Here we swap as if - * they were in aAbBcC order because it's easier and really - * doesn't matter. - */ - swapl(&values->integral, n); - swapl(&values->frac, n); - values++; - swapl(&values->integral, n); - swapl(&values->frac, n); - values++; - } - } - - swaps(&to->valuators_len, n); -} - - -/** Event swapping function for XI2 events. */ -void -XI2EventSwap(xGenericEvent *from, xGenericEvent *to) -{ - switch(from->evtype) - { - case XI_Enter: - case XI_Leave: - SDeviceLeaveNotifyEvent((xXILeaveEvent*)from, (xXILeaveEvent*)to); - break; - case XI_DeviceChanged: - SDeviceChangedEvent((xXIDeviceChangedEvent*)from, - (xXIDeviceChangedEvent*)to); - break; - case XI_HierarchyChanged: - SDeviceHierarchyEvent((xXIHierarchyEvent*)from, (xXIHierarchyEvent*)to); - break; - case XI_PropertyEvent: - SXIPropertyEvent((xXIPropertyEvent*)from, - (xXIPropertyEvent*)to); - break; - case XI_Motion: - case XI_KeyPress: - case XI_KeyRelease: - case XI_ButtonPress: - case XI_ButtonRelease: - SDeviceEvent((xXIDeviceEvent*)from, (xXIDeviceEvent*)to); - break; - case XI_RawMotion: - case XI_RawKeyPress: - case XI_RawKeyRelease: - case XI_RawButtonPress: - case XI_RawButtonRelease: - SRawEvent((xXIRawEvent*)from, (xXIRawEvent*)to); - break; - default: - ErrorF("[Xi] Unknown event type to swap. This is a bug.\n"); - break; - } -} - -/************************************************************************** - * - * Allow the specified event to have its propagation suppressed. - * The default is to not allow suppression of propagation. - * - */ - -static void -AllowPropagateSuppress(Mask mask) -{ - int i; - - for (i = 0; i < MAXDEVICES; i++) - PropagateMask[i] |= mask; -} - -/************************************************************************** - * - * Record an event mask where there is no unique corresponding event type. - * We can't call SetMaskForEvent, since that would clobber the existing - * mask for that event. MotionHint and ButtonMotion are examples. - * - * Since extension event types will never be less than 64, we can use - * 0-63 in the EventInfo array as the "type" to be used to look up this - * mask. This means that the corresponding macros such as - * DevicePointerMotionHint must have access to the same constants. - * - */ - -static void -SetEventInfo(Mask mask, int constant) -{ - EventInfo[ExtEventIndex].mask = mask; - EventInfo[ExtEventIndex++].type = constant; -} - -/************************************************************************** - * - * Allow the specified event to be restricted to being selected by one - * client at a time. - * The default is to allow more than one client to select the event. - * - */ - -static void -SetExclusiveAccess(Mask mask) -{ - int i; - - for (i = 0; i < MAXDEVICES; i++) - ExtExclusiveMasks[i] |= mask; -} - -/************************************************************************** - * - * Assign the specified mask to the specified event. - * - */ - -static void -SetMaskForExtEvent(Mask mask, int event) -{ - int i; - - EventInfo[ExtEventIndex].mask = mask; - EventInfo[ExtEventIndex++].type = event; - - if ((event < LASTEvent) || (event >= 128)) - FatalError("MaskForExtensionEvent: bogus event number"); - - for (i = 0; i < MAXDEVICES; i++) - SetMaskForEvent(i, mask, event); -} - -/************************************************************************ - * - * This function sets up extension event types and masks. - * - */ - -static void -FixExtensionEvents(ExtensionEntry * extEntry) -{ - DeviceValuator = extEntry->eventBase; - DeviceKeyPress = DeviceValuator + 1; - DeviceKeyRelease = DeviceKeyPress + 1; - DeviceButtonPress = DeviceKeyRelease + 1; - DeviceButtonRelease = DeviceButtonPress + 1; - DeviceMotionNotify = DeviceButtonRelease + 1; - DeviceFocusIn = DeviceMotionNotify + 1; - DeviceFocusOut = DeviceFocusIn + 1; - ProximityIn = DeviceFocusOut + 1; - ProximityOut = ProximityIn + 1; - DeviceStateNotify = ProximityOut + 1; - DeviceMappingNotify = DeviceStateNotify + 1; - ChangeDeviceNotify = DeviceMappingNotify + 1; - DeviceKeyStateNotify = ChangeDeviceNotify + 1; - DeviceButtonStateNotify = DeviceKeyStateNotify + 1; - DevicePresenceNotify = DeviceButtonStateNotify + 1; - DevicePropertyNotify = DevicePresenceNotify + 1; - - event_base[KeyClass] = DeviceKeyPress; - event_base[ButtonClass] = DeviceButtonPress; - event_base[ValuatorClass] = DeviceMotionNotify; - event_base[ProximityClass] = ProximityIn; - event_base[FocusClass] = DeviceFocusIn; - event_base[OtherClass] = DeviceStateNotify; - - BadDevice += extEntry->errorBase; - BadEvent += extEntry->errorBase; - BadMode += extEntry->errorBase; - DeviceBusy += extEntry->errorBase; - BadClass += extEntry->errorBase; - - SetMaskForExtEvent(DeviceKeyPressMask, DeviceKeyPress); - AllowPropagateSuppress(DeviceKeyPressMask); - SetCriticalEvent(DeviceKeyPress); - - SetMaskForExtEvent(DeviceKeyReleaseMask, DeviceKeyRelease); - AllowPropagateSuppress(DeviceKeyReleaseMask); - SetCriticalEvent(DeviceKeyRelease); - - SetMaskForExtEvent(DeviceButtonPressMask, DeviceButtonPress); - AllowPropagateSuppress(DeviceButtonPressMask); - SetCriticalEvent(DeviceButtonPress); - - SetMaskForExtEvent(DeviceButtonReleaseMask, DeviceButtonRelease); - AllowPropagateSuppress(DeviceButtonReleaseMask); - SetCriticalEvent(DeviceButtonRelease); - - SetMaskForExtEvent(DeviceProximityMask, ProximityIn); - SetMaskForExtEvent(DeviceProximityMask, ProximityOut); - - SetMaskForExtEvent(DeviceStateNotifyMask, DeviceStateNotify); - - SetMaskForExtEvent(DevicePointerMotionMask, DeviceMotionNotify); - AllowPropagateSuppress(DevicePointerMotionMask); - SetCriticalEvent(DeviceMotionNotify); - - SetEventInfo(DevicePointerMotionHintMask, _devicePointerMotionHint); - SetEventInfo(DeviceButton1MotionMask, _deviceButton1Motion); - SetEventInfo(DeviceButton2MotionMask, _deviceButton2Motion); - SetEventInfo(DeviceButton3MotionMask, _deviceButton3Motion); - SetEventInfo(DeviceButton4MotionMask, _deviceButton4Motion); - SetEventInfo(DeviceButton5MotionMask, _deviceButton5Motion); - SetEventInfo(DeviceButtonMotionMask, _deviceButtonMotion); - - SetMaskForExtEvent(DeviceFocusChangeMask, DeviceFocusIn); - SetMaskForExtEvent(DeviceFocusChangeMask, DeviceFocusOut); - - SetMaskForExtEvent(DeviceMappingNotifyMask, DeviceMappingNotify); - SetMaskForExtEvent(ChangeDeviceNotifyMask, ChangeDeviceNotify); - - SetEventInfo(DeviceButtonGrabMask, _deviceButtonGrab); - SetExclusiveAccess(DeviceButtonGrabMask); - - SetEventInfo(DeviceOwnerGrabButtonMask, _deviceOwnerGrabButton); - SetEventInfo(DevicePresenceNotifyMask, _devicePresence); - SetMaskForExtEvent(DevicePropertyNotifyMask, DevicePropertyNotify); - - SetEventInfo(0, _noExtensionEvent); -} - -/************************************************************************ - * - * This function restores extension event types and masks to their - * initial state. - * - */ - -static void -RestoreExtensionEvents(void) -{ - int i, j; - - IReqCode = 0; - IEventBase = 0; - - for (i = 0; i < ExtEventIndex - 1; i++) { - if ((EventInfo[i].type >= LASTEvent) && (EventInfo[i].type < 128)) - { - for (j = 0; j < MAXDEVICES; j++) - SetMaskForEvent(j, 0, EventInfo[i].type); - } - EventInfo[i].mask = 0; - EventInfo[i].type = 0; - } - ExtEventIndex = 0; - DeviceValuator = 0; - DeviceKeyPress = 1; - DeviceKeyRelease = 2; - DeviceButtonPress = 3; - DeviceButtonRelease = 4; - DeviceMotionNotify = 5; - DeviceFocusIn = 6; - DeviceFocusOut = 7; - ProximityIn = 8; - ProximityOut = 9; - DeviceStateNotify = 10; - DeviceMappingNotify = 11; - ChangeDeviceNotify = 12; - DeviceKeyStateNotify = 13; - DeviceButtonStateNotify = 13; - DevicePresenceNotify = 14; - DevicePropertyNotify = 15; - - BadDevice = 0; - BadEvent = 1; - BadMode = 2; - DeviceBusy = 3; - BadClass = 4; - -} - -/*********************************************************************** - * - * IResetProc. - * Remove reply-swapping routine. - * Remove event-swapping routine. - * - */ - -static void -IResetProc(ExtensionEntry * unused) -{ - ReplySwapVector[IReqCode] = ReplyNotSwappd; - EventSwapVector[DeviceValuator] = NotImplemented; - EventSwapVector[DeviceKeyPress] = NotImplemented; - EventSwapVector[DeviceKeyRelease] = NotImplemented; - EventSwapVector[DeviceButtonPress] = NotImplemented; - EventSwapVector[DeviceButtonRelease] = NotImplemented; - EventSwapVector[DeviceMotionNotify] = NotImplemented; - EventSwapVector[DeviceFocusIn] = NotImplemented; - EventSwapVector[DeviceFocusOut] = NotImplemented; - EventSwapVector[ProximityIn] = NotImplemented; - EventSwapVector[ProximityOut] = NotImplemented; - EventSwapVector[DeviceStateNotify] = NotImplemented; - EventSwapVector[DeviceKeyStateNotify] = NotImplemented; - EventSwapVector[DeviceButtonStateNotify] = NotImplemented; - EventSwapVector[DeviceMappingNotify] = NotImplemented; - EventSwapVector[ChangeDeviceNotify] = NotImplemented; - EventSwapVector[DevicePresenceNotify] = NotImplemented; - EventSwapVector[DevicePropertyNotify] = NotImplemented; - RestoreExtensionEvents(); -} - - -/*********************************************************************** - * - * Assign an id and type to an input device. - * - */ - -void -AssignTypeAndName(DeviceIntPtr dev, Atom type, char *name) -{ - dev->xinput_type = type; - dev->name = strdup(name); -} - -/*********************************************************************** - * - * Make device type atoms. - * - */ - -static void -MakeDeviceTypeAtoms(void) -{ - int i; - - for (i = 0; i < NUMTYPES; i++) - dev_type[i].type = - MakeAtom(dev_type[i].name, strlen(dev_type[i].name), 1); -} - -/***************************************************************************** - * - * SEventIDispatch - * - * Swap any events defined in this extension. - */ -#define DO_SWAP(func,type) func ((type *)from, (type *)to) - -static void -SEventIDispatch(xEvent * from, xEvent * to) -{ - int type = from->u.u.type & 0177; - - if (type == DeviceValuator) - DO_SWAP(SEventDeviceValuator, deviceValuator); - else if (type == DeviceKeyPress) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == DeviceKeyRelease) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == DeviceButtonPress) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == DeviceButtonRelease) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == DeviceMotionNotify) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == DeviceFocusIn) - DO_SWAP(SEventFocus, deviceFocus); - else if (type == DeviceFocusOut) - DO_SWAP(SEventFocus, deviceFocus); - else if (type == ProximityIn) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == ProximityOut) { - SKeyButtonPtrEvent(from, to); - to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; - } else if (type == DeviceStateNotify) - DO_SWAP(SDeviceStateNotifyEvent, deviceStateNotify); - else if (type == DeviceKeyStateNotify) - DO_SWAP(SDeviceKeyStateNotifyEvent, deviceKeyStateNotify); - else if (type == DeviceButtonStateNotify) - DO_SWAP(SDeviceButtonStateNotifyEvent, deviceButtonStateNotify); - else if (type == DeviceMappingNotify) - DO_SWAP(SDeviceMappingNotifyEvent, deviceMappingNotify); - else if (type == ChangeDeviceNotify) - DO_SWAP(SChangeDeviceNotifyEvent, changeDeviceNotify); - else if (type == DevicePresenceNotify) - DO_SWAP(SDevicePresenceNotifyEvent, devicePresenceNotify); - else if (type == DevicePropertyNotify) - DO_SWAP(SDevicePropertyNotifyEvent, devicePropertyNotify); - else { - FatalError("XInputExtension: Impossible event!\n"); - } -} - -/********************************************************************** - * - * IExtensionInit - initialize the input extension. - * - * Called from InitExtensions in main() or from QueryExtension() if the - * extension is dynamically loaded. - * - * This extension has several events and errors. - * - * XI is mandatory nowadays, so if we fail to init XI, we die. - */ - -void -XInputExtensionInit(void) -{ - ExtensionEntry *extEntry; - XExtensionVersion thisversion = { XI_Present, - SERVER_XI_MAJOR_VERSION, - SERVER_XI_MINOR_VERSION, - }; - - if (!dixRegisterPrivateKey(&XIClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(XIClientRec))) - FatalError("Cannot request private for XI.\n"); - - if (!AddCallback(&ClientStateCallback, XIClientCallback, 0)) - FatalError("Failed to add callback to XI.\n"); - - extEntry = AddExtension(INAME, IEVENTS, IERRORS, ProcIDispatch, - SProcIDispatch, IResetProc, StandardMinorOpcode); - if (extEntry) { - IReqCode = extEntry->base; - IEventBase = extEntry->eventBase; - XIVersion = thisversion; - MakeDeviceTypeAtoms(); - RT_INPUTCLIENT = CreateNewResourceType((DeleteType) InputClientGone, - "INPUTCLIENT"); - if (!RT_INPUTCLIENT) - FatalError("Failed to add resource type for XI.\n"); - FixExtensionEvents(extEntry); - ReplySwapVector[IReqCode] = (ReplySwapPtr) SReplyIDispatch; - EventSwapVector[DeviceValuator] = SEventIDispatch; - EventSwapVector[DeviceKeyPress] = SEventIDispatch; - EventSwapVector[DeviceKeyRelease] = SEventIDispatch; - EventSwapVector[DeviceButtonPress] = SEventIDispatch; - EventSwapVector[DeviceButtonRelease] = SEventIDispatch; - EventSwapVector[DeviceMotionNotify] = SEventIDispatch; - EventSwapVector[DeviceFocusIn] = SEventIDispatch; - EventSwapVector[DeviceFocusOut] = SEventIDispatch; - EventSwapVector[ProximityIn] = SEventIDispatch; - EventSwapVector[ProximityOut] = SEventIDispatch; - EventSwapVector[DeviceStateNotify] = SEventIDispatch; - EventSwapVector[DeviceKeyStateNotify] = SEventIDispatch; - EventSwapVector[DeviceButtonStateNotify] = SEventIDispatch; - EventSwapVector[DeviceMappingNotify] = SEventIDispatch; - EventSwapVector[ChangeDeviceNotify] = SEventIDispatch; - EventSwapVector[DevicePresenceNotify] = SEventIDispatch; - - GERegisterExtension(IReqCode, XI2EventSwap); - - - memset(&xi_all_devices, 0, sizeof(xi_all_devices)); - memset(&xi_all_master_devices, 0, sizeof(xi_all_master_devices)); - xi_all_devices.id = XIAllDevices; - xi_all_devices.name = "XIAllDevices"; - xi_all_master_devices.id = XIAllMasterDevices; - xi_all_master_devices.name = "XIAllMasterDevices"; - - inputInfo.all_devices = &xi_all_devices; - inputInfo.all_master_devices = &xi_all_master_devices; - - XIResetProperties(); - } else { - FatalError("IExtensionInit: AddExtensions failed\n"); - } -} - +/************************************************************ + +Copyright 1989, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-PACKARD 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. + +********************************************************/ + +/******************************************************************** + * + * Dispatch routines and initialization routines for the X input extension. + * + */ + +#define NUMTYPES 15 + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "inputstr.h" +#include "gcstruct.h" /* pointer for extnsionst.h */ +#include "extnsionst.h" /* extension entry */ +#include +#include +#include +#include +#include "geext.h" /* extension interfaces for ge */ + +#include "dixevents.h" +#include "exevents.h" +#include "extinit.h" +#include "exglobals.h" +#include "swaprep.h" +#include "privates.h" +#include "protocol-versions.h" + +/* modules local to Xi */ +#include "allowev.h" +#include "chgdctl.h" +#include "chgfctl.h" +#include "chgkbd.h" +#include "chgprop.h" +#include "chgptr.h" +#include "closedev.h" +#include "devbell.h" +#include "getbmap.h" +#include "getbmap.h" +#include "getdctl.h" +#include "getfctl.h" +#include "getfocus.h" +#include "getkmap.h" +#include "getmmap.h" +#include "getprop.h" +#include "getselev.h" +#include "getvers.h" +#include "getvers.h" +#include "grabdev.h" +#include "grabdevb.h" +#include "grabdevk.h" +#include "gtmotion.h" +#include "listdev.h" +#include "opendev.h" +#include "queryst.h" +#include "selectev.h" +#include "sendexev.h" +#include "chgkmap.h" +#include "setbmap.h" +#include "setdval.h" +#include "setfocus.h" +#include "setmmap.h" +#include "setmode.h" +#include "ungrdev.h" +#include "ungrdevb.h" +#include "ungrdevk.h" +#include "xiallowev.h" +#include "xiselectev.h" +#include "xigrabdev.h" +#include "xipassivegrab.h" +#include "xisetdevfocus.h" +#include "xiproperty.h" +#include "xichangecursor.h" +#include "xichangehierarchy.h" +#include "xigetclientpointer.h" +#include "xiquerydevice.h" +#include "xiquerypointer.h" +#include "xiqueryversion.h" +#include "xisetclientpointer.h" +#include "xiwarppointer.h" + + +/* Masks for XI events have to be aligned with core event (partially anyway). + * If DeviceButtonMotionMask is != ButtonMotionMask, event delivery + * breaks down. The device needs the dev->button->motionMask. If DBMM is + * the same as BMM, we can ensure that both core and device events can be + * delivered, without the need for extra structures in the DeviceIntRec. */ +const Mask DeviceKeyPressMask = KeyPressMask; +const Mask DeviceKeyReleaseMask = KeyReleaseMask; +const Mask DeviceButtonPressMask = ButtonPressMask; +const Mask DeviceButtonReleaseMask = ButtonReleaseMask; +const Mask DeviceProximityMask = (1L << 4); +const Mask DeviceStateNotifyMask = (1L << 5); +const Mask DevicePointerMotionMask = PointerMotionMask; +const Mask DevicePointerMotionHintMask = PointerMotionHintMask; +const Mask DeviceButton1MotionMask = Button1MotionMask; +const Mask DeviceButton2MotionMask = Button2MotionMask; +const Mask DeviceButton3MotionMask = Button3MotionMask; +const Mask DeviceButton4MotionMask = Button4MotionMask; +const Mask DeviceButton5MotionMask = Button5MotionMask; +const Mask DeviceButtonMotionMask = ButtonMotionMask; +const Mask DeviceFocusChangeMask = (1L << 14); +const Mask DeviceMappingNotifyMask = (1L << 15); +const Mask ChangeDeviceNotifyMask = (1L << 16); +const Mask DeviceButtonGrabMask = (1L << 17); +const Mask DeviceOwnerGrabButtonMask = (1L << 17); +const Mask DevicePresenceNotifyMask = (1L << 18); +const Mask DeviceEnterWindowMask = (1L << 18); +const Mask DeviceLeaveWindowMask = (1L << 19); +const Mask DevicePropertyNotifyMask = (1L << 20); +const Mask XIAllMasks = (1L << 21) - 1; + +int ExtEventIndex; +Mask ExtExclusiveMasks[EMASKSIZE]; + +static struct dev_type +{ + Atom type; + char *name; +} dev_type[] = { + { + 0, XI_KEYBOARD}, { + 0, XI_MOUSE}, { + 0, XI_TABLET}, { + 0, XI_TOUCHSCREEN}, { + 0, XI_TOUCHPAD}, { + 0, XI_BARCODE}, { + 0, XI_BUTTONBOX}, { + 0, XI_KNOB_BOX}, { + 0, XI_ONE_KNOB}, { + 0, XI_NINE_KNOB}, { + 0, XI_TRACKBALL}, { + 0, XI_QUADRATURE}, { + 0, XI_ID_MODULE}, { + 0, XI_SPACEBALL}, { + 0, XI_DATAGLOVE}, { + 0, XI_EYETRACKER}, { + 0, XI_CURSORKEYS}, { +0, XI_FOOTMOUSE}}; + +CARD8 event_base[numInputClasses]; +XExtEventInfo EventInfo[32]; + +static DeviceIntRec xi_all_devices; +static DeviceIntRec xi_all_master_devices; + +/** + * Dispatch vector. Functions defined in here will be called when the matching + * request arrives. + */ +static int (*ProcIVector[])(ClientPtr) = { + NULL, /* 0 */ + ProcXGetExtensionVersion, /* 1 */ + ProcXListInputDevices, /* 2 */ + ProcXOpenDevice, /* 3 */ + ProcXCloseDevice, /* 4 */ + ProcXSetDeviceMode, /* 5 */ + ProcXSelectExtensionEvent, /* 6 */ + ProcXGetSelectedExtensionEvents, /* 7 */ + ProcXChangeDeviceDontPropagateList, /* 8 */ + ProcXGetDeviceDontPropagateList, /* 9 */ + ProcXGetDeviceMotionEvents, /* 10 */ + ProcXChangeKeyboardDevice, /* 11 */ + ProcXChangePointerDevice, /* 12 */ + ProcXGrabDevice, /* 13 */ + ProcXUngrabDevice, /* 14 */ + ProcXGrabDeviceKey, /* 15 */ + ProcXUngrabDeviceKey, /* 16 */ + ProcXGrabDeviceButton, /* 17 */ + ProcXUngrabDeviceButton, /* 18 */ + ProcXAllowDeviceEvents, /* 19 */ + ProcXGetDeviceFocus, /* 20 */ + ProcXSetDeviceFocus, /* 21 */ + ProcXGetFeedbackControl, /* 22 */ + ProcXChangeFeedbackControl, /* 23 */ + ProcXGetDeviceKeyMapping, /* 24 */ + ProcXChangeDeviceKeyMapping, /* 25 */ + ProcXGetDeviceModifierMapping, /* 26 */ + ProcXSetDeviceModifierMapping, /* 27 */ + ProcXGetDeviceButtonMapping, /* 28 */ + ProcXSetDeviceButtonMapping, /* 29 */ + ProcXQueryDeviceState, /* 30 */ + ProcXSendExtensionEvent, /* 31 */ + ProcXDeviceBell, /* 32 */ + ProcXSetDeviceValuators, /* 33 */ + ProcXGetDeviceControl, /* 34 */ + ProcXChangeDeviceControl, /* 35 */ + /* XI 1.5 */ + ProcXListDeviceProperties, /* 36 */ + ProcXChangeDeviceProperty, /* 37 */ + ProcXDeleteDeviceProperty, /* 38 */ + ProcXGetDeviceProperty, /* 39 */ + /* XI 2 */ + ProcXIQueryPointer, /* 40 */ + ProcXIWarpPointer, /* 41 */ + ProcXIChangeCursor, /* 42 */ + ProcXIChangeHierarchy, /* 43 */ + ProcXISetClientPointer, /* 44 */ + ProcXIGetClientPointer, /* 45 */ + ProcXISelectEvents, /* 46 */ + ProcXIQueryVersion, /* 47 */ + ProcXIQueryDevice, /* 48 */ + ProcXISetFocus, /* 49 */ + ProcXIGetFocus, /* 50 */ + ProcXIGrabDevice, /* 51 */ + ProcXIUngrabDevice, /* 52 */ + ProcXIAllowEvents, /* 53 */ + ProcXIPassiveGrabDevice, /* 54 */ + ProcXIPassiveUngrabDevice, /* 55 */ + ProcXIListProperties, /* 56 */ + ProcXIChangeProperty, /* 57 */ + ProcXIDeleteProperty, /* 58 */ + ProcXIGetProperty, /* 59 */ + ProcXIGetSelectedEvents /* 60 */ +}; + +/* For swapped clients */ +static int (*SProcIVector[])(ClientPtr) = { + NULL, /* 0 */ + SProcXGetExtensionVersion, /* 1 */ + SProcXListInputDevices, /* 2 */ + SProcXOpenDevice, /* 3 */ + SProcXCloseDevice, /* 4 */ + SProcXSetDeviceMode, /* 5 */ + SProcXSelectExtensionEvent, /* 6 */ + SProcXGetSelectedExtensionEvents, /* 7 */ + SProcXChangeDeviceDontPropagateList, /* 8 */ + SProcXGetDeviceDontPropagateList, /* 9 */ + SProcXGetDeviceMotionEvents, /* 10 */ + SProcXChangeKeyboardDevice, /* 11 */ + SProcXChangePointerDevice, /* 12 */ + SProcXGrabDevice, /* 13 */ + SProcXUngrabDevice, /* 14 */ + SProcXGrabDeviceKey, /* 15 */ + SProcXUngrabDeviceKey, /* 16 */ + SProcXGrabDeviceButton, /* 17 */ + SProcXUngrabDeviceButton, /* 18 */ + SProcXAllowDeviceEvents, /* 19 */ + SProcXGetDeviceFocus, /* 20 */ + SProcXSetDeviceFocus, /* 21 */ + SProcXGetFeedbackControl, /* 22 */ + SProcXChangeFeedbackControl, /* 23 */ + SProcXGetDeviceKeyMapping, /* 24 */ + SProcXChangeDeviceKeyMapping, /* 25 */ + SProcXGetDeviceModifierMapping, /* 26 */ + SProcXSetDeviceModifierMapping, /* 27 */ + SProcXGetDeviceButtonMapping, /* 28 */ + SProcXSetDeviceButtonMapping, /* 29 */ + SProcXQueryDeviceState, /* 30 */ + SProcXSendExtensionEvent, /* 31 */ + SProcXDeviceBell, /* 32 */ + SProcXSetDeviceValuators, /* 33 */ + SProcXGetDeviceControl, /* 34 */ + SProcXChangeDeviceControl, /* 35 */ + SProcXListDeviceProperties, /* 36 */ + SProcXChangeDeviceProperty, /* 37 */ + SProcXDeleteDeviceProperty, /* 38 */ + SProcXGetDeviceProperty, /* 39 */ + SProcXIQueryPointer, /* 40 */ + SProcXIWarpPointer, /* 41 */ + SProcXIChangeCursor, /* 42 */ + SProcXIChangeHierarchy, /* 43 */ + SProcXISetClientPointer, /* 44 */ + SProcXIGetClientPointer, /* 45 */ + SProcXISelectEvents, /* 46 */ + SProcXIQueryVersion, /* 47 */ + SProcXIQueryDevice, /* 48 */ + SProcXISetFocus, /* 49 */ + SProcXIGetFocus, /* 50 */ + SProcXIGrabDevice, /* 51 */ + SProcXIUngrabDevice, /* 52 */ + SProcXIAllowEvents, /* 53 */ + SProcXIPassiveGrabDevice, /* 54 */ + SProcXIPassiveUngrabDevice, /* 55 */ + SProcXIListProperties, /* 56 */ + SProcXIChangeProperty, /* 57 */ + SProcXIDeleteProperty, /* 58 */ + SProcXIGetProperty, /* 59 */ + SProcXIGetSelectedEvents /* 60 */ +}; + +/***************************************************************** + * + * Globals referenced elsewhere in the server. + * + */ + +int IReqCode = 0; +int IEventBase = 0; +int BadDevice = 0; +static int BadEvent = 1; +int BadMode = 2; +int DeviceBusy = 3; +int BadClass = 4; + +int DeviceValuator; +int DeviceKeyPress; +int DeviceKeyRelease; +int DeviceButtonPress; +int DeviceButtonRelease; +int DeviceMotionNotify; +int DeviceFocusIn; +int DeviceFocusOut; +int ProximityIn; +int ProximityOut; +int DeviceStateNotify; +int DeviceKeyStateNotify; +int DeviceButtonStateNotify; +int DeviceMappingNotify; +int ChangeDeviceNotify; +int DevicePresenceNotify; +int DevicePropertyNotify; + +int RT_INPUTCLIENT; + +/***************************************************************** + * + * Externs defined elsewhere in the X server. + * + */ + +extern XExtensionVersion XIVersion; + + +Mask PropagateMask[MAXDEVICES]; + +/***************************************************************** + * + * Versioning support + * + */ + +DevPrivateKeyRec XIClientPrivateKeyRec; + +/***************************************************************** + * + * Declarations of local routines. + * + */ + +static void +XIClientCallback(CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec*)data; + ClientPtr pClient = clientinfo->client; + XIClientPtr pXIClient; + + pXIClient = dixLookupPrivate(&pClient->devPrivates, XIClientPrivateKey); + pXIClient->major_version = 0; + pXIClient->minor_version = 0; +} + +/************************************************************************* + * + * ProcIDispatch - main dispatch routine for requests to this extension. + * This routine is used if server and client have the same byte ordering. + * + */ + +static int +ProcIDispatch(ClientPtr client) +{ + REQUEST(xReq); + if (stuff->data > (IREQUESTS + XI2REQUESTS) || !ProcIVector[stuff->data]) + return BadRequest; + + return (*ProcIVector[stuff->data])(client); +} + +/******************************************************************************* + * + * SProcXDispatch + * + * Main swapped dispatch routine for requests to this extension. + * This routine is used if server and client do not have the same byte ordering. + * + */ + +static int +SProcIDispatch(ClientPtr client) +{ + REQUEST(xReq); + if (stuff->data > IREQUESTS || !SProcIVector[stuff->data]) + return BadRequest; + + return (*SProcIVector[stuff->data])(client); +} + +/********************************************************************** + * + * SReplyIDispatch + * Swap any replies defined in this extension. + * + */ + +static void +SReplyIDispatch(ClientPtr client, int len, xGrabDeviceReply * rep) + /* All we look at is the type field */ +{ /* This is common to all replies */ + if (rep->RepType == X_GetExtensionVersion) + SRepXGetExtensionVersion(client, len, + (xGetExtensionVersionReply *) rep); + else if (rep->RepType == X_ListInputDevices) + SRepXListInputDevices(client, len, (xListInputDevicesReply *) rep); + else if (rep->RepType == X_OpenDevice) + SRepXOpenDevice(client, len, (xOpenDeviceReply *) rep); + else if (rep->RepType == X_SetDeviceMode) + SRepXSetDeviceMode(client, len, (xSetDeviceModeReply *) rep); + else if (rep->RepType == X_GetSelectedExtensionEvents) + SRepXGetSelectedExtensionEvents(client, len, + (xGetSelectedExtensionEventsReply *) + rep); + else if (rep->RepType == X_GetDeviceDontPropagateList) + SRepXGetDeviceDontPropagateList(client, len, + (xGetDeviceDontPropagateListReply *) + rep); + else if (rep->RepType == X_GetDeviceMotionEvents) + SRepXGetDeviceMotionEvents(client, len, + (xGetDeviceMotionEventsReply *) rep); + else if (rep->RepType == X_GrabDevice) + SRepXGrabDevice(client, len, (xGrabDeviceReply *) rep); + else if (rep->RepType == X_GetDeviceFocus) + SRepXGetDeviceFocus(client, len, (xGetDeviceFocusReply *) rep); + else if (rep->RepType == X_GetFeedbackControl) + SRepXGetFeedbackControl(client, len, (xGetFeedbackControlReply *) rep); + else if (rep->RepType == X_GetDeviceKeyMapping) + SRepXGetDeviceKeyMapping(client, len, + (xGetDeviceKeyMappingReply *) rep); + else if (rep->RepType == X_GetDeviceModifierMapping) + SRepXGetDeviceModifierMapping(client, len, + (xGetDeviceModifierMappingReply *) rep); + else if (rep->RepType == X_SetDeviceModifierMapping) + SRepXSetDeviceModifierMapping(client, len, + (xSetDeviceModifierMappingReply *) rep); + else if (rep->RepType == X_GetDeviceButtonMapping) + SRepXGetDeviceButtonMapping(client, len, + (xGetDeviceButtonMappingReply *) rep); + else if (rep->RepType == X_SetDeviceButtonMapping) + SRepXSetDeviceButtonMapping(client, len, + (xSetDeviceButtonMappingReply *) rep); + else if (rep->RepType == X_QueryDeviceState) + SRepXQueryDeviceState(client, len, (xQueryDeviceStateReply *) rep); + else if (rep->RepType == X_SetDeviceValuators) + SRepXSetDeviceValuators(client, len, (xSetDeviceValuatorsReply *) rep); + else if (rep->RepType == X_GetDeviceControl) + SRepXGetDeviceControl(client, len, (xGetDeviceControlReply *) rep); + else if (rep->RepType == X_ChangeDeviceControl) + SRepXChangeDeviceControl(client, len, + (xChangeDeviceControlReply *) rep); + else if (rep->RepType == X_ListDeviceProperties) + SRepXListDeviceProperties(client, len, (xListDevicePropertiesReply*)rep); + else if (rep->RepType == X_GetDeviceProperty) + SRepXGetDeviceProperty(client, len, (xGetDevicePropertyReply *) rep); + else if (rep->RepType == X_XIQueryPointer) + SRepXIQueryPointer(client, len, (xXIQueryPointerReply *) rep); + else if (rep->RepType == X_XIGetClientPointer) + SRepXIGetClientPointer(client, len, (xXIGetClientPointerReply*) rep); + else if (rep->RepType == X_XIQueryVersion) + SRepXIQueryVersion(client, len, (xXIQueryVersionReply*)rep); + else if (rep->RepType == X_XIQueryDevice) + SRepXIQueryDevice(client, len, (xXIQueryDeviceReply*)rep); + else if (rep->RepType == X_XIGrabDevice) + SRepXIGrabDevice(client, len, (xXIGrabDeviceReply *) rep); + else if (rep->RepType == X_XIGrabDevice) + SRepXIPassiveGrabDevice(client, len, (xXIPassiveGrabDeviceReply *) rep); + else if (rep->RepType == X_XIListProperties) + SRepXIListProperties(client, len, (xXIListPropertiesReply *) rep); + else if (rep->RepType == X_XIGetProperty) + SRepXIGetProperty(client, len, (xXIGetPropertyReply *) rep); + else if (rep->RepType == X_XIGetSelectedEvents) + SRepXIGetSelectedEvents(client, len, (xXIGetSelectedEventsReply *) rep); + else if (rep->RepType == X_XIGetFocus) + SRepXIGetFocus(client, len, (xXIGetFocusReply *) rep); + else { + FatalError("XINPUT confused sending swapped reply"); + } +} + +/************************************************************************ + * + * This function swaps the DeviceValuator event. + * + */ + +static void +SEventDeviceValuator(deviceValuator * from, deviceValuator * to) +{ + char n; + int i; + INT32 *ip B32; + + *to = *from; + swaps(&to->sequenceNumber, n); + swaps(&to->device_state, n); + ip = &to->valuator0; + for (i = 0; i < 6; i++) { + swapl((ip + i), n); /* macro - braces are required */ + } +} + +static void +SEventFocus(deviceFocus * from, deviceFocus * to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber, n); + swapl(&to->time, n); + swapl(&to->window, n); +} + +static void +SDeviceStateNotifyEvent(deviceStateNotify * from, deviceStateNotify * to) +{ + int i; + char n; + INT32 *ip B32; + + *to = *from; + swaps(&to->sequenceNumber, n); + swapl(&to->time, n); + ip = &to->valuator0; + for (i = 0; i < 3; i++) { + swapl((ip + i), n); /* macro - braces are required */ + } +} + +static void +SDeviceKeyStateNotifyEvent(deviceKeyStateNotify * from, + deviceKeyStateNotify * to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber, n); +} + +static void +SDeviceButtonStateNotifyEvent(deviceButtonStateNotify * from, + deviceButtonStateNotify * to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber, n); +} + +static void +SChangeDeviceNotifyEvent(changeDeviceNotify * from, changeDeviceNotify * to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber, n); + swapl(&to->time, n); +} + +static void +SDeviceMappingNotifyEvent(deviceMappingNotify * from, deviceMappingNotify * to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber, n); + swapl(&to->time, n); +} + +static void +SDevicePresenceNotifyEvent (devicePresenceNotify *from, devicePresenceNotify *to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber,n); + swapl(&to->time, n); + swaps(&to->control, n); +} + +static void +SDevicePropertyNotifyEvent (devicePropertyNotify *from, devicePropertyNotify *to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber,n); + swapl(&to->time, n); + swapl(&to->atom, n); +} + +static void +SDeviceLeaveNotifyEvent (xXILeaveEvent *from, xXILeaveEvent *to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber,n); + swapl(&to->length, n); + swaps(&to->evtype, n); + swaps(&to->deviceid, n); + swapl(&to->time, n); + swapl(&to->root, n); + swapl(&to->event, n); + swapl(&to->child, n); + swapl(&to->root_x, n); + swapl(&to->root_y, n); + swapl(&to->event_x, n); + swapl(&to->event_y, n); + swaps(&to->sourceid, n); + swaps(&to->buttons_len, n); + swapl(&to->mods.base_mods, n); + swapl(&to->mods.latched_mods, n); + swapl(&to->mods.locked_mods, n); +} + +static void +SDeviceChangedEvent(xXIDeviceChangedEvent* from, xXIDeviceChangedEvent* to) +{ + char n; + int i, j; + xXIAnyInfo *any; + + *to = *from; + memcpy(&to[1], &from[1], from->length * 4); + + any = (xXIAnyInfo*)&to[1]; + for (i = 0; i < to->num_classes; i++) + { + int length = any->length; + + switch(any->type) + { + case KeyClass: + { + xXIKeyInfo *ki = (xXIKeyInfo*)any; + uint32_t *key = (uint32_t*)&ki[1]; + for (j = 0; j < ki->num_keycodes; j++, key++) + swapl(key, n); + swaps(&ki->num_keycodes, n); + } + break; + case ButtonClass: + { + xXIButtonInfo *bi = (xXIButtonInfo*)any; + Atom *labels = (Atom*)((char*)bi + sizeof(xXIButtonInfo) + + pad_to_int32(bits_to_bytes(bi->num_buttons))); + for (j = 0; j < bi->num_buttons; j++) + swapl(&labels[j], n); + swaps(&bi->num_buttons, n); + } + break; + case ValuatorClass: + { + xXIValuatorInfo* ai = (xXIValuatorInfo*)any; + swapl(&ai->label, n); + swapl(&ai->min.integral, n); + swapl(&ai->min.frac, n); + swapl(&ai->max.integral, n); + swapl(&ai->max.frac, n); + swapl(&ai->resolution, n); + swaps(&ai->number, n); + } + break; + } + + swaps(&any->type, n); + swaps(&any->length, n); + swaps(&any->sourceid, n); + + any = (xXIAnyInfo*)((char*)any + length * 4); + } + + swaps(&to->sequenceNumber, n); + swapl(&to->length, n); + swaps(&to->evtype, n); + swaps(&to->deviceid, n); + swapl(&to->time, n); + swaps(&to->num_classes, n); + swaps(&to->sourceid, n); + +} + +static void SDeviceEvent(xXIDeviceEvent *from, xXIDeviceEvent *to) +{ + int i; + char n; + char *ptr; + char *vmask; + + memcpy(to, from, sizeof(xEvent) + from->length * 4); + + swaps(&to->sequenceNumber, n); + swapl(&to->length, n); + swaps(&to->evtype, n); + swaps(&to->deviceid, n); + swapl(&to->time, n); + swapl(&to->detail, n); + swapl(&to->root, n); + swapl(&to->event, n); + swapl(&to->child, n); + swapl(&to->root_x, n); + swapl(&to->root_y, n); + swapl(&to->event_x, n); + swapl(&to->event_y, n); + swaps(&to->buttons_len, n); + swaps(&to->valuators_len, n); + swaps(&to->sourceid, n); + swapl(&to->mods.base_mods, n); + swapl(&to->mods.latched_mods, n); + swapl(&to->mods.locked_mods, n); + swapl(&to->mods.effective_mods, n); + swapl(&to->flags, n); + + ptr = (char*)(&to[1]); + ptr += from->buttons_len * 4; + vmask = ptr; /* valuator mask */ + ptr += from->valuators_len * 4; + for (i = 0; i < from->valuators_len * 32; i++) + { + if (BitIsOn(vmask, i)) + { + swapl(((uint32_t*)ptr), n); + ptr += 4; + swapl(((uint32_t*)ptr), n); + ptr += 4; + } + } +} + +static void SDeviceHierarchyEvent(xXIHierarchyEvent *from, + xXIHierarchyEvent *to) +{ + int i; + char n; + xXIHierarchyInfo *info; + + *to = *from; + memcpy(&to[1], &from[1], from->length * 4); + swaps(&to->sequenceNumber, n); + swapl(&to->length, n); + swaps(&to->evtype, n); + swaps(&to->deviceid, n); + swapl(&to->time, n); + swapl(&to->flags, n); + swaps(&to->num_info, n); + + info = (xXIHierarchyInfo*)&to[1]; + for (i = 0; i< from->num_info; i++) + { + swaps(&info->deviceid, n); + swaps(&info->attachment, n); + info++; + } +} + +static void SXIPropertyEvent(xXIPropertyEvent *from, xXIPropertyEvent *to) +{ + char n; + + *to = *from; + swaps(&to->sequenceNumber, n); + swapl(&to->length, n); + swaps(&to->evtype, n); + swaps(&to->deviceid, n); + swapl(&to->property, n); +} + +static void SRawEvent(xXIRawEvent *from, xXIRawEvent *to) +{ + char n; + int i; + FP3232 *values; + unsigned char *mask; + + memcpy(to, from, sizeof(xEvent) + from->length * 4); + + swaps(&to->sequenceNumber, n); + swapl(&to->length, n); + swaps(&to->evtype, n); + swaps(&to->deviceid, n); + swapl(&to->time, n); + swapl(&to->detail, n); + + + mask = (unsigned char*)&to[1]; + values = (FP3232*)(mask + from->valuators_len * 4); + + for (i = 0; i < from->valuators_len * 4 * 8; i++) + { + if (BitIsOn(mask, i)) + { + /* for each bit set there are two FP3232 values on the wire, in + * the order abcABC for data and data_raw. Here we swap as if + * they were in aAbBcC order because it's easier and really + * doesn't matter. + */ + swapl(&values->integral, n); + swapl(&values->frac, n); + values++; + swapl(&values->integral, n); + swapl(&values->frac, n); + values++; + } + } + + swaps(&to->valuators_len, n); +} + + +/** Event swapping function for XI2 events. */ +void +XI2EventSwap(xGenericEvent *from, xGenericEvent *to) +{ + switch(from->evtype) + { + case XI_Enter: + case XI_Leave: + SDeviceLeaveNotifyEvent((xXILeaveEvent*)from, (xXILeaveEvent*)to); + break; + case XI_DeviceChanged: + SDeviceChangedEvent((xXIDeviceChangedEvent*)from, + (xXIDeviceChangedEvent*)to); + break; + case XI_HierarchyChanged: + SDeviceHierarchyEvent((xXIHierarchyEvent*)from, (xXIHierarchyEvent*)to); + break; + case XI_PropertyEvent: + SXIPropertyEvent((xXIPropertyEvent*)from, + (xXIPropertyEvent*)to); + break; + case XI_Motion: + case XI_KeyPress: + case XI_KeyRelease: + case XI_ButtonPress: + case XI_ButtonRelease: + SDeviceEvent((xXIDeviceEvent*)from, (xXIDeviceEvent*)to); + break; + case XI_RawMotion: + case XI_RawKeyPress: + case XI_RawKeyRelease: + case XI_RawButtonPress: + case XI_RawButtonRelease: + SRawEvent((xXIRawEvent*)from, (xXIRawEvent*)to); + break; + default: + ErrorF("[Xi] Unknown event type to swap. This is a bug.\n"); + break; + } +} + +/************************************************************************** + * + * Allow the specified event to have its propagation suppressed. + * The default is to not allow suppression of propagation. + * + */ + +static void +AllowPropagateSuppress(Mask mask) +{ + int i; + + for (i = 0; i < MAXDEVICES; i++) + PropagateMask[i] |= mask; +} + +/************************************************************************** + * + * Record an event mask where there is no unique corresponding event type. + * We can't call SetMaskForEvent, since that would clobber the existing + * mask for that event. MotionHint and ButtonMotion are examples. + * + * Since extension event types will never be less than 64, we can use + * 0-63 in the EventInfo array as the "type" to be used to look up this + * mask. This means that the corresponding macros such as + * DevicePointerMotionHint must have access to the same constants. + * + */ + +static void +SetEventInfo(Mask mask, int constant) +{ + EventInfo[ExtEventIndex].mask = mask; + EventInfo[ExtEventIndex++].type = constant; +} + +/************************************************************************** + * + * Allow the specified event to be restricted to being selected by one + * client at a time. + * The default is to allow more than one client to select the event. + * + */ + +static void +SetExclusiveAccess(Mask mask) +{ + int i; + + for (i = 0; i < MAXDEVICES; i++) + ExtExclusiveMasks[i] |= mask; +} + +/************************************************************************** + * + * Assign the specified mask to the specified event. + * + */ + +static void +SetMaskForExtEvent(Mask mask, int event) +{ + int i; + + EventInfo[ExtEventIndex].mask = mask; + EventInfo[ExtEventIndex++].type = event; + + if ((event < LASTEvent) || (event >= 128)) + FatalError("MaskForExtensionEvent: bogus event number"); + + for (i = 0; i < MAXDEVICES; i++) + SetMaskForEvent(i, mask, event); +} + +/************************************************************************ + * + * This function sets up extension event types and masks. + * + */ + +static void +FixExtensionEvents(ExtensionEntry * extEntry) +{ + DeviceValuator = extEntry->eventBase; + DeviceKeyPress = DeviceValuator + 1; + DeviceKeyRelease = DeviceKeyPress + 1; + DeviceButtonPress = DeviceKeyRelease + 1; + DeviceButtonRelease = DeviceButtonPress + 1; + DeviceMotionNotify = DeviceButtonRelease + 1; + DeviceFocusIn = DeviceMotionNotify + 1; + DeviceFocusOut = DeviceFocusIn + 1; + ProximityIn = DeviceFocusOut + 1; + ProximityOut = ProximityIn + 1; + DeviceStateNotify = ProximityOut + 1; + DeviceMappingNotify = DeviceStateNotify + 1; + ChangeDeviceNotify = DeviceMappingNotify + 1; + DeviceKeyStateNotify = ChangeDeviceNotify + 1; + DeviceButtonStateNotify = DeviceKeyStateNotify + 1; + DevicePresenceNotify = DeviceButtonStateNotify + 1; + DevicePropertyNotify = DevicePresenceNotify + 1; + + event_base[KeyClass] = DeviceKeyPress; + event_base[ButtonClass] = DeviceButtonPress; + event_base[ValuatorClass] = DeviceMotionNotify; + event_base[ProximityClass] = ProximityIn; + event_base[FocusClass] = DeviceFocusIn; + event_base[OtherClass] = DeviceStateNotify; + + BadDevice += extEntry->errorBase; + BadEvent += extEntry->errorBase; + BadMode += extEntry->errorBase; + DeviceBusy += extEntry->errorBase; + BadClass += extEntry->errorBase; + + SetMaskForExtEvent(DeviceKeyPressMask, DeviceKeyPress); + AllowPropagateSuppress(DeviceKeyPressMask); + SetCriticalEvent(DeviceKeyPress); + + SetMaskForExtEvent(DeviceKeyReleaseMask, DeviceKeyRelease); + AllowPropagateSuppress(DeviceKeyReleaseMask); + SetCriticalEvent(DeviceKeyRelease); + + SetMaskForExtEvent(DeviceButtonPressMask, DeviceButtonPress); + AllowPropagateSuppress(DeviceButtonPressMask); + SetCriticalEvent(DeviceButtonPress); + + SetMaskForExtEvent(DeviceButtonReleaseMask, DeviceButtonRelease); + AllowPropagateSuppress(DeviceButtonReleaseMask); + SetCriticalEvent(DeviceButtonRelease); + + SetMaskForExtEvent(DeviceProximityMask, ProximityIn); + SetMaskForExtEvent(DeviceProximityMask, ProximityOut); + + SetMaskForExtEvent(DeviceStateNotifyMask, DeviceStateNotify); + + SetMaskForExtEvent(DevicePointerMotionMask, DeviceMotionNotify); + AllowPropagateSuppress(DevicePointerMotionMask); + SetCriticalEvent(DeviceMotionNotify); + + SetEventInfo(DevicePointerMotionHintMask, _devicePointerMotionHint); + SetEventInfo(DeviceButton1MotionMask, _deviceButton1Motion); + SetEventInfo(DeviceButton2MotionMask, _deviceButton2Motion); + SetEventInfo(DeviceButton3MotionMask, _deviceButton3Motion); + SetEventInfo(DeviceButton4MotionMask, _deviceButton4Motion); + SetEventInfo(DeviceButton5MotionMask, _deviceButton5Motion); + SetEventInfo(DeviceButtonMotionMask, _deviceButtonMotion); + + SetMaskForExtEvent(DeviceFocusChangeMask, DeviceFocusIn); + SetMaskForExtEvent(DeviceFocusChangeMask, DeviceFocusOut); + + SetMaskForExtEvent(DeviceMappingNotifyMask, DeviceMappingNotify); + SetMaskForExtEvent(ChangeDeviceNotifyMask, ChangeDeviceNotify); + + SetEventInfo(DeviceButtonGrabMask, _deviceButtonGrab); + SetExclusiveAccess(DeviceButtonGrabMask); + + SetEventInfo(DeviceOwnerGrabButtonMask, _deviceOwnerGrabButton); + SetEventInfo(DevicePresenceNotifyMask, _devicePresence); + SetMaskForExtEvent(DevicePropertyNotifyMask, DevicePropertyNotify); + + SetEventInfo(0, _noExtensionEvent); +} + +/************************************************************************ + * + * This function restores extension event types and masks to their + * initial state. + * + */ + +static void +RestoreExtensionEvents(void) +{ + int i, j; + + IReqCode = 0; + IEventBase = 0; + + for (i = 0; i < ExtEventIndex - 1; i++) { + if ((EventInfo[i].type >= LASTEvent) && (EventInfo[i].type < 128)) + { + for (j = 0; j < MAXDEVICES; j++) + SetMaskForEvent(j, 0, EventInfo[i].type); + } + EventInfo[i].mask = 0; + EventInfo[i].type = 0; + } + ExtEventIndex = 0; + DeviceValuator = 0; + DeviceKeyPress = 1; + DeviceKeyRelease = 2; + DeviceButtonPress = 3; + DeviceButtonRelease = 4; + DeviceMotionNotify = 5; + DeviceFocusIn = 6; + DeviceFocusOut = 7; + ProximityIn = 8; + ProximityOut = 9; + DeviceStateNotify = 10; + DeviceMappingNotify = 11; + ChangeDeviceNotify = 12; + DeviceKeyStateNotify = 13; + DeviceButtonStateNotify = 13; + DevicePresenceNotify = 14; + DevicePropertyNotify = 15; + + BadDevice = 0; + BadEvent = 1; + BadMode = 2; + DeviceBusy = 3; + BadClass = 4; + +} + +/*********************************************************************** + * + * IResetProc. + * Remove reply-swapping routine. + * Remove event-swapping routine. + * + */ + +static void +IResetProc(ExtensionEntry * unused) +{ + ReplySwapVector[IReqCode] = ReplyNotSwappd; + EventSwapVector[DeviceValuator] = NotImplemented; + EventSwapVector[DeviceKeyPress] = NotImplemented; + EventSwapVector[DeviceKeyRelease] = NotImplemented; + EventSwapVector[DeviceButtonPress] = NotImplemented; + EventSwapVector[DeviceButtonRelease] = NotImplemented; + EventSwapVector[DeviceMotionNotify] = NotImplemented; + EventSwapVector[DeviceFocusIn] = NotImplemented; + EventSwapVector[DeviceFocusOut] = NotImplemented; + EventSwapVector[ProximityIn] = NotImplemented; + EventSwapVector[ProximityOut] = NotImplemented; + EventSwapVector[DeviceStateNotify] = NotImplemented; + EventSwapVector[DeviceKeyStateNotify] = NotImplemented; + EventSwapVector[DeviceButtonStateNotify] = NotImplemented; + EventSwapVector[DeviceMappingNotify] = NotImplemented; + EventSwapVector[ChangeDeviceNotify] = NotImplemented; + EventSwapVector[DevicePresenceNotify] = NotImplemented; + EventSwapVector[DevicePropertyNotify] = NotImplemented; + RestoreExtensionEvents(); +} + + +/*********************************************************************** + * + * Assign an id and type to an input device. + * + */ + +void +AssignTypeAndName(DeviceIntPtr dev, Atom type, char *name) +{ + dev->xinput_type = type; + dev->name = strdup(name); +} + +/*********************************************************************** + * + * Make device type atoms. + * + */ + +static void +MakeDeviceTypeAtoms(void) +{ + int i; + + for (i = 0; i < NUMTYPES; i++) + dev_type[i].type = + MakeAtom(dev_type[i].name, strlen(dev_type[i].name), 1); +} + +/***************************************************************************** + * + * SEventIDispatch + * + * Swap any events defined in this extension. + */ +#define DO_SWAP(func,type) func ((type *)from, (type *)to) + +static void +SEventIDispatch(xEvent * from, xEvent * to) +{ + int type = from->u.u.type & 0177; + + if (type == DeviceValuator) + DO_SWAP(SEventDeviceValuator, deviceValuator); + else if (type == DeviceKeyPress) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == DeviceKeyRelease) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == DeviceButtonPress) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == DeviceButtonRelease) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == DeviceMotionNotify) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == DeviceFocusIn) + DO_SWAP(SEventFocus, deviceFocus); + else if (type == DeviceFocusOut) + DO_SWAP(SEventFocus, deviceFocus); + else if (type == ProximityIn) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == ProximityOut) { + SKeyButtonPtrEvent(from, to); + to->u.keyButtonPointer.pad1 = from->u.keyButtonPointer.pad1; + } else if (type == DeviceStateNotify) + DO_SWAP(SDeviceStateNotifyEvent, deviceStateNotify); + else if (type == DeviceKeyStateNotify) + DO_SWAP(SDeviceKeyStateNotifyEvent, deviceKeyStateNotify); + else if (type == DeviceButtonStateNotify) + DO_SWAP(SDeviceButtonStateNotifyEvent, deviceButtonStateNotify); + else if (type == DeviceMappingNotify) + DO_SWAP(SDeviceMappingNotifyEvent, deviceMappingNotify); + else if (type == ChangeDeviceNotify) + DO_SWAP(SChangeDeviceNotifyEvent, changeDeviceNotify); + else if (type == DevicePresenceNotify) + DO_SWAP(SDevicePresenceNotifyEvent, devicePresenceNotify); + else if (type == DevicePropertyNotify) + DO_SWAP(SDevicePropertyNotifyEvent, devicePropertyNotify); + else { + FatalError("XInputExtension: Impossible event!\n"); + } +} + +/********************************************************************** + * + * IExtensionInit - initialize the input extension. + * + * Called from InitExtensions in main() or from QueryExtension() if the + * extension is dynamically loaded. + * + * This extension has several events and errors. + * + * XI is mandatory nowadays, so if we fail to init XI, we die. + */ + +void +XInputExtensionInit(void) +{ + ExtensionEntry *extEntry; + XExtensionVersion thisversion = { XI_Present, + SERVER_XI_MAJOR_VERSION, + SERVER_XI_MINOR_VERSION, + }; + + if (!dixRegisterPrivateKey(&XIClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(XIClientRec))) + FatalError("Cannot request private for XI.\n"); + + if (!AddCallback(&ClientStateCallback, XIClientCallback, 0)) + FatalError("Failed to add callback to XI.\n"); + + extEntry = AddExtension(INAME, IEVENTS, IERRORS, ProcIDispatch, + SProcIDispatch, IResetProc, StandardMinorOpcode); + if (extEntry) { + IReqCode = extEntry->base; + IEventBase = extEntry->eventBase; + XIVersion = thisversion; + MakeDeviceTypeAtoms(); + RT_INPUTCLIENT = CreateNewResourceType((DeleteType) InputClientGone, + "INPUTCLIENT"); + if (!RT_INPUTCLIENT) + FatalError("Failed to add resource type for XI.\n"); + FixExtensionEvents(extEntry); + ReplySwapVector[IReqCode] = (ReplySwapPtr) SReplyIDispatch; + EventSwapVector[DeviceValuator] = SEventIDispatch; + EventSwapVector[DeviceKeyPress] = SEventIDispatch; + EventSwapVector[DeviceKeyRelease] = SEventIDispatch; + EventSwapVector[DeviceButtonPress] = SEventIDispatch; + EventSwapVector[DeviceButtonRelease] = SEventIDispatch; + EventSwapVector[DeviceMotionNotify] = SEventIDispatch; + EventSwapVector[DeviceFocusIn] = SEventIDispatch; + EventSwapVector[DeviceFocusOut] = SEventIDispatch; + EventSwapVector[ProximityIn] = SEventIDispatch; + EventSwapVector[ProximityOut] = SEventIDispatch; + EventSwapVector[DeviceStateNotify] = SEventIDispatch; + EventSwapVector[DeviceKeyStateNotify] = SEventIDispatch; + EventSwapVector[DeviceButtonStateNotify] = SEventIDispatch; + EventSwapVector[DeviceMappingNotify] = SEventIDispatch; + EventSwapVector[ChangeDeviceNotify] = SEventIDispatch; + EventSwapVector[DevicePresenceNotify] = SEventIDispatch; + + GERegisterExtension(IReqCode, XI2EventSwap); + + + memset(&xi_all_devices, 0, sizeof(xi_all_devices)); + memset(&xi_all_master_devices, 0, sizeof(xi_all_master_devices)); + xi_all_devices.id = XIAllDevices; + xi_all_devices.name = "XIAllDevices"; + xi_all_master_devices.id = XIAllMasterDevices; + xi_all_master_devices.name = "XIAllMasterDevices"; + + inputInfo.all_devices = &xi_all_devices; + inputInfo.all_master_devices = &xi_all_master_devices; + + XIResetProperties(); + } else { + FatalError("IExtensionInit: AddExtensions failed\n"); + } +} + diff --git a/xorg-server/Xi/xiwarppointer.c b/xorg-server/Xi/xiwarppointer.c index 7276e6faf..c01b115f3 100644 --- a/xorg-server/Xi/xiwarppointer.c +++ b/xorg-server/Xi/xiwarppointer.c @@ -192,6 +192,8 @@ ProcXIWarpPointer(ClientPtr client) /* if we don't update the device, we get a jump next time it moves */ pDev->last.valuators[0] = x; pDev->last.valuators[1] = y; + pDev->last.remainder[0] = 0; + pDev->last.remainder[1] = 0; miPointerUpdateSprite(pDev); /* FIXME: XWarpPointer is supposed to generate an event. It doesn't do it diff --git a/xorg-server/configure.ac b/xorg-server/configure.ac index 45286eaf4..120321e7c 100644 --- a/xorg-server/configure.ac +++ b/xorg-server/configure.ac @@ -1903,8 +1903,8 @@ AM_CONDITIONAL(XWIN_MULTIWINDOW, [test "x$XWIN" = xyes]) AM_CONDITIONAL(XWIN_MULTIWINDOWEXTWM, [test "x$XWIN" = xyes && test "x$WINDOWSWM" = xyes]) AM_CONDITIONAL(XWIN_CLIPBOARD, [test "x$XWIN" = xyes]) AM_CONDITIONAL(XWIN_GLX_WINDOWS, [test "x$XWIN" = xyes && false]) -AM_CONDITIONAL(XWIN_NATIVEGDI, [test "x$XWIN" = xyes && false]) -AM_CONDITIONAL(XWIN_PRIMARYFB, [test "x$XWIN" = xyes && false]) +AM_CONDITIONAL(XWIN_NATIVEGDI, [test "x$XWIN" = xyes]) +AM_CONDITIONAL(XWIN_PRIMARYFB, [test "x$XWIN" = xyes]) AM_CONDITIONAL(XWIN_RANDR, [test "x$XWIN" = xyes]) AM_CONDITIONAL(XWIN_XV, [test "x$XWIN" = xyes && test "x$XV" = xyes]) diff --git a/xorg-server/dix/events.c b/xorg-server/dix/events.c index 361d6102a..07f8b05ea 100644 --- a/xorg-server/dix/events.c +++ b/xorg-server/dix/events.c @@ -1,5819 +1,5813 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL 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. - -********************************************************/ - -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - -/* - * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** @file events.c - * This file handles event delivery and a big part of the server-side protocol - * handling (the parts for input devices). - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "misc.h" -#include "resource.h" -#include -#include "windowstr.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "cursorstr.h" - -#include "dixstruct.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "globals.h" - -#include -#include "xkbsrv.h" -#include "xace.h" - -#ifdef XSERVER_DTRACE -#include -typedef const char *string; -#include "Xserver-dtrace.h" -#endif - -#include -#include -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "exglobals.h" -#include "extnsionst.h" - -#include "dixevents.h" -#include "dixgrabs.h" -#include "dispatch.h" - -#include -#include "geext.h" -#include "geint.h" - -#include "eventstr.h" -#include "enterleave.h" -#include "eventconvert.h" - -/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ -#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ -#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) -#define AllButtonsMask ( \ - Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) -#define MotionMask ( \ - PointerMotionMask | Button1MotionMask | \ - Button2MotionMask | Button3MotionMask | Button4MotionMask | \ - Button5MotionMask | ButtonMotionMask ) -#define PropagateMask ( \ - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ - MotionMask ) -#define PointerGrabMask ( \ - ButtonPressMask | ButtonReleaseMask | \ - EnterWindowMask | LeaveWindowMask | \ - PointerMotionHintMask | KeymapStateMask | \ - MotionMask ) -#define AllModifiersMask ( \ - ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ - Mod3Mask | Mod4Mask | Mod5Mask ) -#define LastEventMask OwnerGrabButtonMask -#define AllEventMasks (LastEventMask|(LastEventMask-1)) - - -#define CORE_EVENT(event) \ - (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \ - (event)->u.u.type != GenericEvent) -#define XI2_EVENT(event) \ - (((event)->u.u.type == GenericEvent) && \ - ((xGenericEvent*)(event))->extension == IReqCode) - -/** - * Used to indicate a implicit passive grab created by a ButtonPress event. - * See DeliverEventsToWindow(). - */ -#define ImplicitGrabMask (1 << 7) - -#define WID(w) ((w) ? ((w)->drawable.id) : 0) - -#define XE_KBPTR (xE->u.keyButtonPointer) - - -CallbackListPtr EventCallback; -CallbackListPtr DeviceEventCallback; - -#define DNPMCOUNT 8 - -Mask DontPropagateMasks[DNPMCOUNT]; -static int DontPropagateRefCnts[DNPMCOUNT]; - -static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); -static void CheckPhysLimits(DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents, - Bool confineToScreen, - ScreenPtr pScreen); -static Bool CheckPassiveGrabsOnWindow(WindowPtr pWin, - DeviceIntPtr device, - DeviceEvent *event, - BOOL checkCore); - -/** Key repeat hack. Do not use but in TryClientEvents */ -extern BOOL EventIsKeyRepeat(xEvent *event); - -/** - * Main input device struct. - * inputInfo.pointer - * is the core pointer. Referred to as "virtual core pointer", "VCP", - * "core pointer" or inputInfo.pointer. The VCP is the first master - * pointer device and cannot be deleted. - * - * inputInfo.keyboard - * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard"). - * See inputInfo.pointer. - * - * inputInfo.devices - * linked list containing all devices including VCP and VCK. - * - * inputInfo.off_devices - * Devices that have not been initialized and are thus turned off. - * - * inputInfo.numDevices - * Total number of devices. - * - * inputInfo.all_devices - * Virtual device used for XIAllDevices passive grabs. This device is - * not part of the inputInfo.devices list and mostly unset except for - * the deviceid. It exists because passivegrabs need a valid device - * reference. - * - * inputInfo.all_master_devices - * Virtual device used for XIAllMasterDevices passive grabs. This device - * is not part of the inputInfo.devices list and mostly unset except for - * the deviceid. It exists because passivegrabs need a valid device - * reference. - */ -InputInfo inputInfo; - -EventSyncInfoRec syncEvents; - -/** - * The root window the given device is currently on. - */ -#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0] - -static xEvent* swapEvent = NULL; -static int swapEventLen = 0; - -void -NotImplemented(xEvent *from, xEvent *to) -{ - FatalError("Not implemented"); -} - -/** - * Convert the given event type from an XI event to a core event. - * @param[in] The XI 1.x event type. - * @return The matching core event type or 0 if there is none. - */ -int -XItoCoreType(int xitype) -{ - int coretype = 0; - if (xitype == DeviceMotionNotify) - coretype = MotionNotify; - else if (xitype == DeviceButtonPress) - coretype = ButtonPress; - else if (xitype == DeviceButtonRelease) - coretype = ButtonRelease; - else if (xitype == DeviceKeyPress) - coretype = KeyPress; - else if (xitype == DeviceKeyRelease) - coretype = KeyRelease; - - return coretype; -} - -/** - * @return true if the device owns a cursor, false if device shares a cursor - * sprite with another device. - */ -Bool -DevHasCursor(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->spriteOwner; -} - -/* - * @return true if a device is a pointer, check is the same as used by XI to - * fill the 'use' field. - */ -Bool -IsPointerDevice(DeviceIntPtr dev) -{ - return (dev->type == MASTER_POINTER) || - (dev->valuator && dev->button) || - (dev->valuator && !dev->key); -} - -/* - * @return true if a device is a keyboard, check is the same as used by XI to - * fill the 'use' field. - * - * Some pointer devices have keys as well (e.g. multimedia keys). Try to not - * count them as keyboard devices. - */ -Bool -IsKeyboardDevice(DeviceIntPtr dev) -{ - return (dev->type == MASTER_KEYBOARD) || - ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); -} - -Bool -IsMaster(DeviceIntPtr dev) -{ - return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD; -} - -static WindowPtr XYToWindow( - DeviceIntPtr pDev, - int x, - int y -); - -/** - * Max event opcode. - */ -extern int lastEvent; - -extern int DeviceMotionNotify; - -#define CantBeFiltered NoEventMask -/** - * Event masks for each event type. - * - * One set of filters for each device, but only the first layer - * is initialized. The rest is memcpy'd in InitEvents. - * - * Filters are used whether a given event may be delivered to a client, - * usually in the form of if (window-event-mask & filter); then deliver event. - * - * One notable filter is for PointerMotion/DevicePointerMotion events. Each - * time a button is pressed, the filter is modified to also contain the - * matching ButtonXMotion mask. - */ -static Mask filters[MAXDEVICES][128] = { -{ - NoSuchEvent, /* 0 */ - NoSuchEvent, /* 1 */ - KeyPressMask, /* KeyPress */ - KeyReleaseMask, /* KeyRelease */ - ButtonPressMask, /* ButtonPress */ - ButtonReleaseMask, /* ButtonRelease */ - PointerMotionMask, /* MotionNotify (initial state) */ - EnterWindowMask, /* EnterNotify */ - LeaveWindowMask, /* LeaveNotify */ - FocusChangeMask, /* FocusIn */ - FocusChangeMask, /* FocusOut */ - KeymapStateMask, /* KeymapNotify */ - ExposureMask, /* Expose */ - CantBeFiltered, /* GraphicsExpose */ - CantBeFiltered, /* NoExpose */ - VisibilityChangeMask, /* VisibilityNotify */ - SubstructureNotifyMask, /* CreateNotify */ - StructureAndSubMask, /* DestroyNotify */ - StructureAndSubMask, /* UnmapNotify */ - StructureAndSubMask, /* MapNotify */ - SubstructureRedirectMask, /* MapRequest */ - StructureAndSubMask, /* ReparentNotify */ - StructureAndSubMask, /* ConfigureNotify */ - SubstructureRedirectMask, /* ConfigureRequest */ - StructureAndSubMask, /* GravityNotify */ - ResizeRedirectMask, /* ResizeRequest */ - StructureAndSubMask, /* CirculateNotify */ - SubstructureRedirectMask, /* CirculateRequest */ - PropertyChangeMask, /* PropertyNotify */ - CantBeFiltered, /* SelectionClear */ - CantBeFiltered, /* SelectionRequest */ - CantBeFiltered, /* SelectionNotify */ - ColormapChangeMask, /* ColormapNotify */ - CantBeFiltered, /* ClientMessage */ - CantBeFiltered /* MappingNotify */ -}}; - -/** - * For the given event, return the matching event filter. This filter may then - * be AND'ed with the selected event mask. - * - * For XI2 events, the returned filter is simply the byte containing the event - * mask we're interested in. E.g. for a mask of (1 << 13), this would be - * byte[1]. - * - * @param[in] dev The device the event belongs to, may be NULL. - * @param[in] event The event to get the filter for. Only the type of the - * event matters, or the extension + evtype for GenericEvents. - * @return The filter mask for the given event. - * - * @see GetEventMask - */ -Mask -GetEventFilter(DeviceIntPtr dev, xEvent *event) -{ - if (event->u.u.type != GenericEvent) - return filters[dev ? dev->id : 0][event->u.u.type]; - else if (XI2_EVENT(event)) - return (1 << (((xXIDeviceEvent*)event)->evtype % 8)); - ErrorF("[dix] Unknown device type %d. No filter\n", event->u.u.type); - return 0; -} - -/** - * Return the windows complete XI2 mask for the given XI2 event type. - */ -Mask -GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) -{ - OtherInputMasks *inputMasks = wOtherInputMasks(win); - int filter; - int evtype; - - if (!inputMasks || !XI2_EVENT(ev)) - return 0; - - evtype = ((xGenericEvent*)ev)->evtype; - filter = GetEventFilter(dev, ev); - - return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || - inputMasks->xi2mask[XIAllDevices][evtype/8] || - (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); -} - -static Mask -GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) -{ - /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ - if (XI2_EVENT(event)) - { - int byte = ((xGenericEvent*)event)->evtype / 8; - return (other->xi2mask[dev->id][byte] | - other->xi2mask[XIAllDevices][byte] | - (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); - } else if (CORE_EVENT(event)) - return other->mask[XIAllDevices]; - else - return other->mask[dev->id]; -} - - -static CARD8 criticalEvents[32] = -{ - 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ -}; - -static void -SyntheticMotion(DeviceIntPtr dev, int x, int y) { - int screenno = 0; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - screenno = dev->spriteInfo->sprite->screen->myNum; -#endif - PostSyntheticMotion(dev, x, y, screenno, - (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); - -} - -#ifdef PANORAMIX -static void PostNewCursor(DeviceIntPtr pDev); - -static Bool -pointOnScreen(ScreenPtr pScreen, int x, int y) -{ - return x >= pScreen->x && x < pScreen->x + pScreen->width && - y >= pScreen->y && y < pScreen->y + pScreen->height; -} - -static Bool -XineramaSetCursorPosition( - DeviceIntPtr pDev, - int x, - int y, - Bool generateEvent -){ - ScreenPtr pScreen; - int i; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - /* x,y are in Screen 0 coordinates. We need to decide what Screen - to send the message too and what the coordinates relative to - that screen are. */ - - pScreen = pSprite->screen; - x += screenInfo.screens[0]->x; - y += screenInfo.screens[0]->y; - - if(!pointOnScreen(pScreen, x, y)) - { - FOR_NSCREENS(i) - { - if(i == pScreen->myNum) - continue; - if(pointOnScreen(screenInfo.screens[i], x, y)) - { - pScreen = screenInfo.screens[i]; - break; - } - } - } - - pSprite->screen = pScreen; - pSprite->hotPhys.x = x - screenInfo.screens[0]->x; - pSprite->hotPhys.y = y - screenInfo.screens[0]->y; - x -= pScreen->x; - y -= pScreen->y; - - return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent); -} - - -static void -XineramaConstrainCursor(DeviceIntPtr pDev) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - ScreenPtr pScreen; - BoxRec newBox; - - pScreen = pSprite->screen; - newBox = pSprite->physLimits; - - /* Translate the constraining box to the screen - the sprite is actually on */ - newBox.x1 += screenInfo.screens[0]->x - pScreen->x; - newBox.x2 += screenInfo.screens[0]->x - pScreen->x; - newBox.y1 += screenInfo.screens[0]->y - pScreen->y; - newBox.y2 += screenInfo.screens[0]->y - pScreen->y; - - (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); -} - - -static Bool -XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if(pWin == screenInfo.screens[0]->root) { - int i; - for (i = 0; i < PanoramiXNumScreens; i++) - pSprite->windows[i] = screenInfo.screens[i]->root; - } else { - PanoramiXRes *win; - int rc, i; - - rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, - XRT_WINDOW, serverClient, DixReadAccess); - if (rc != Success) - return FALSE; - - for(i = 0; i < PanoramiXNumScreens; i++) { - rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, - serverClient, DixReadAccess); - if (rc != Success) /* window is being unmapped */ - return FALSE; - } - } - return TRUE; -} - -static void -XineramaConfineCursorToWindow(DeviceIntPtr pDev, - WindowPtr pWin, - Bool generateEvents) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - RegionCopy(&pSprite->Reg1, - &pSprite->windows[i]->borderSize); - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - - while(i--) { - x = off_x - screenInfo.screens[i]->x; - y = off_y - screenInfo.screens[i]->y; - - if(x || y) - RegionTranslate(&pSprite->Reg1, x, y); - - RegionUnion(&pSprite->Reg1, &pSprite->Reg1, - &pSprite->windows[i]->borderSize); - - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - } - - pSprite->hotLimits = *RegionExtents(&pSprite->Reg1); - - if(RegionNumRects(&pSprite->Reg1) > 1) - pSprite->hotShape = &pSprite->Reg1; - else - pSprite->hotShape = NullRegion; - - pSprite->confined = FALSE; - pSprite->confineWin = (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin; - - CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); -} - -#endif /* PANORAMIX */ - -/** - * Modifies the filter for the given protocol event type to the given masks. - * - * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). - * The latter initialises masks for the matching XI events, it's a once-off - * setting. - * UDS however changes the mask for MotionNotify and DeviceMotionNotify each - * time a button is pressed to include the matching ButtonXMotion mask in the - * filter. - * - * @param[in] deviceid The device to modify the filter for. - * @param[in] mask The new filter mask. - * @param[in] event Protocol event type. - */ -void -SetMaskForEvent(int deviceid, Mask mask, int event) -{ - if (deviceid < 0 || deviceid >= MAXDEVICES) - FatalError("SetMaskForEvent: bogus device id"); - filters[deviceid][event] = mask; -} - -void -SetCriticalEvent(int event) -{ - if (event >= 128) - FatalError("SetCriticalEvent: bogus event number"); - criticalEvents[event >> 3] |= 1 << (event & 7); -} - -void -ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py) -{ - BoxRec box; - int x = *px, y = *py; - int incx = 1, incy = 1; - SpritePtr pSprite; - - pSprite = pDev->spriteInfo->sprite; - if (RegionContainsPoint(shape, x, y, &box)) - return; - box = *RegionExtents(shape); - /* this is rather crude */ - do { - x += incx; - if (x >= box.x2) - { - incx = -1; - x = *px - 1; - } - else if (x < box.x1) - { - incx = 1; - x = *px; - y += incy; - if (y >= box.y2) - { - incy = -1; - y = *py - 1; - } - else if (y < box.y1) - return; /* should never get here! */ - } - } while (!RegionContainsPoint(shape, x, y, &box)); - *px = x; - *py = y; -} - -static void -CheckPhysLimits( - DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents, - Bool confineToScreen, /* unused if PanoramiX on */ - ScreenPtr pScreen) /* unused if PanoramiX on */ -{ - HotSpot new; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (!cursor) - return; - new = pSprite->hotPhys; -#ifdef PANORAMIX - if (!noPanoramiXExtension) - /* I don't care what the DDX has to say about it */ - pSprite->physLimits = pSprite->hotLimits; - else -#endif - { - if (pScreen) - new.pScreen = pScreen; - else - pScreen = new.pScreen; - (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = confineToScreen; - (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); - } - - /* constrain the pointer to those limits */ - if (new.x < pSprite->physLimits.x1) - new.x = pSprite->physLimits.x1; - else - if (new.x >= pSprite->physLimits.x2) - new.x = pSprite->physLimits.x2 - 1; - if (new.y < pSprite->physLimits.y1) - new.y = pSprite->physLimits.y1; - else - if (new.y >= pSprite->physLimits.y2) - new.y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); - if (( -#ifdef PANORAMIX - noPanoramiXExtension && -#endif - (pScreen != pSprite->hotPhys.pScreen)) || - (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) - { -#ifdef PANORAMIX - if (!noPanoramiXExtension) - XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); - else -#endif - { - if (pScreen != pSprite->hotPhys.pScreen) - pSprite->hotPhys = new; - (*pScreen->SetCursorPosition) - (pDev, pScreen, new.x, new.y, generateEvents); - } - if (!generateEvents) - SyntheticMotion(pDev, new.x, new.y); - } - -#ifdef PANORAMIX - /* Tell DDX what the limits are */ - if (!noPanoramiXExtension) - XineramaConstrainCursor(pDev); -#endif -} - -static void -CheckVirtualMotion( - DeviceIntPtr pDev, - QdEventPtr qe, - WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - RegionPtr reg = NULL; - DeviceEvent *ev = NULL; - - if (qe) - { - ev = &qe->event->device_event; - switch(ev->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - pSprite->hot.pScreen = qe->pScreen; - pSprite->hot.x = ev->root_x; - pSprite->hot.y = ev->root_y; - pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; - break; - default: - break; - } - } - if (pWin) - { - BoxRec lims; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - RegionCopy(&pSprite->Reg2, - &pSprite->windows[i]->borderSize); - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - - while(i--) { - x = off_x - screenInfo.screens[i]->x; - y = off_y - screenInfo.screens[i]->y; - - if(x || y) - RegionTranslate(&pSprite->Reg2, x, y); - - RegionUnion(&pSprite->Reg2, &pSprite->Reg2, - &pSprite->windows[i]->borderSize); - - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - } - } else -#endif - { - if (pSprite->hot.pScreen != pWin->drawable.pScreen) - { - pSprite->hot.pScreen = pWin->drawable.pScreen; - pSprite->hot.x = pSprite->hot.y = 0; - } - } - - lims = *RegionExtents(&pWin->borderSize); - if (pSprite->hot.x < lims.x1) - pSprite->hot.x = lims.x1; - else if (pSprite->hot.x >= lims.x2) - pSprite->hot.x = lims.x2 - 1; - if (pSprite->hot.y < lims.y1) - pSprite->hot.y = lims.y1; - else if (pSprite->hot.y >= lims.y2) - pSprite->hot.y = lims.y2 - 1; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - if (RegionNumRects(&pSprite->Reg2) > 1) - reg = &pSprite->Reg2; - - } else -#endif - { - if (wBoundingShape(pWin)) - reg = &pWin->borderSize; - } - - if (reg) - ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); - - if (qe && ev) - { - qe->pScreen = pSprite->hot.pScreen; - ev->root_x = pSprite->hot.x; - ev->root_y = pSprite->hot.y; - } - } -#ifdef PANORAMIX - if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ -#endif - RootWindow(pDev) = pSprite->hot.pScreen->root; -} - -static void -ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (syncEvents.playingEvents) - { - CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); - SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); - } - else - { -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - XineramaConfineCursorToWindow(pDev, pWin, generateEvents); - return; - } -#endif - pSprite->hotLimits = *RegionExtents(&pWin->borderSize); - pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize - : NullRegion; - CheckPhysLimits(pDev, pSprite->current, generateEvents, - confineToScreen, pWin->drawable.pScreen); - } -} - -Bool -PointerConfinedToScreen(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->confined; -} - -/** - * Update the sprite cursor to the given cursor. - * - * ChangeToCursor() will display the new cursor and free the old cursor (if - * applicable). If the provided cursor is already the updated cursor, nothing - * happens. - */ -static void -ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - ScreenPtr pScreen; - - if (cursor != pSprite->current) - { - if ((pSprite->current->bits->xhot != cursor->bits->xhot) || - (pSprite->current->bits->yhot != cursor->bits->yhot)) - CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, - (ScreenPtr)NULL); -#ifdef PANORAMIX - /* XXX: is this really necessary?? (whot) */ - if (!noPanoramiXExtension) - pScreen = pSprite->screen; - else -#endif - pScreen = pSprite->hotPhys.pScreen; - - (*pScreen->DisplayCursor)(pDev, pScreen, cursor); - FreeCursor(pSprite->current, (Cursor)0); - pSprite->current = cursor; - pSprite->current->refcnt++; - } -} - -/** - * @returns true if b is a descendent of a - */ -Bool -IsParent(WindowPtr a, WindowPtr b) -{ - for (b = b->parent; b; b = b->parent) - if (b == a) return TRUE; - return FALSE; -} - -/** - * Update the cursor displayed on the screen. - * - * Called whenever a cursor may have changed shape or position. - */ -static void -PostNewCursor(DeviceIntPtr pDev) -{ - WindowPtr win; - GrabPtr grab = pDev->deviceGrab.grab; - SpritePtr pSprite = pDev->spriteInfo->sprite; - CursorPtr pCursor; - - if (syncEvents.playingEvents) - return; - if (grab) - { - if (grab->cursor) - { - ChangeToCursor(pDev, grab->cursor); - return; - } - if (IsParent(grab->window, pSprite->win)) - win = pSprite->win; - else - win = grab->window; - } - else - win = pSprite->win; - for (; win; win = win->parent) - { - if (win->optional) - { - pCursor = WindowGetDeviceCursor(win, pDev); - if (!pCursor && win->optional->cursor != NullCursor) - pCursor = win->optional->cursor; - if (pCursor) - { - ChangeToCursor(pDev, pCursor); - return; - } - } - } -} - - -/** - * @param dev device which you want to know its current root window - * @return root window where dev's sprite is located - */ -WindowPtr -GetCurrentRootWindow(DeviceIntPtr dev) -{ - return RootWindow(dev); -} - -/** - * @return window underneath the cursor sprite. - */ -WindowPtr -GetSpriteWindow(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->win; -} - -/** - * @return current sprite cursor. - */ -CursorPtr -GetSpriteCursor(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->current; -} - -/** - * Set x/y current sprite position in screen coordinates. - */ -void -GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - *px = pSprite->hotPhys.x; - *py = pSprite->hotPhys.y; -} - -#ifdef PANORAMIX -int -XineramaGetCursorScreen(DeviceIntPtr pDev) -{ - if(!noPanoramiXExtension) { - return pDev->spriteInfo->sprite->screen->myNum; - } else { - return 0; - } -} -#endif /* PANORAMIX */ - -#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ - -static void -MonthChangedOrBadTime(InternalEvent *ev) -{ - /* If the ddx/OS is careless about not processing timestamped events from - * different sources in sorted order, then it's possible for time to go - * backwards when it should not. Here we ensure a decent time. - */ - if ((currentTime.milliseconds - ev->any.time) > TIMESLOP) - currentTime.months++; - else - ev->any.time = currentTime.milliseconds; -} - -static void -NoticeTime(InternalEvent *ev) -{ - if (ev->any.time < currentTime.milliseconds) - MonthChangedOrBadTime(ev); - currentTime.milliseconds = ev->any.time; - lastDeviceEventTime = currentTime; -} - -void -NoticeEventTime(InternalEvent *ev) -{ - if (!syncEvents.playingEvents) - NoticeTime(ev); -} - -/************************************************************************** - * The following procedures deal with synchronous events * - **************************************************************************/ - -/** - * EnqueueEvent is a device's processInputProc if a device is frozen. - * Instead of delivering the events to the client, the event is tacked onto a - * linked list for later delivery. - */ -void -EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) -{ - QdEventPtr tail = *syncEvents.pendtail; - QdEventPtr qe; - SpritePtr pSprite = device->spriteInfo->sprite; - int eventlen; - DeviceEvent *event = &ev->device_event; - - NoticeTime((InternalEvent*)event); - - /* Fix for key repeating bug. */ - if (device->key != NULL && device->key->xkbInfo != NULL && - event->type == ET_KeyRelease) - AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); - - if (DeviceEventCallback) - { - DeviceEventInfoRec eventinfo; - - /* The RECORD spec says that the root window field of motion events - * must be valid. At this point, it hasn't been filled in yet, so - * we do it here. The long expression below is necessary to get - * the current root window; the apparently reasonable alternative - * GetCurrentRootWindow()->drawable.id doesn't give you the right - * answer on the first motion event after a screen change because - * the data that GetCurrentRootWindow relies on hasn't been - * updated yet. - */ - if (ev->any.type == ET_Motion) - ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id; - - eventinfo.event = ev; - eventinfo.device = device; - CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); - } - - if (event->type == ET_Motion) - { -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - event->root_x += pSprite->screen->x - screenInfo.screens[0]->x; - event->root_y += pSprite->screen->y - screenInfo.screens[0]->y; - } -#endif - pSprite->hotPhys.x = event->root_x; - pSprite->hotPhys.y = event->root_y; - /* do motion compression, but not if from different devices */ - if (tail && - (tail->event->any.type == ET_Motion) && - (tail->device == device) && - (tail->pScreen == pSprite->hotPhys.pScreen)) - { - DeviceEvent *tailev = &tail->event->device_event; - tailev->root_x = pSprite->hotPhys.x; - tailev->root_y = pSprite->hotPhys.y; - tailev->time = event->time; - tail->months = currentTime.months; - return; - } - } - - eventlen = event->length; - - qe = malloc(sizeof(QdEventRec) + eventlen); - if (!qe) - return; - qe->next = (QdEventPtr)NULL; - qe->device = device; - qe->pScreen = pSprite->hotPhys.pScreen; - qe->months = currentTime.months; - qe->event = (InternalEvent *)(qe + 1); - memcpy(qe->event, event, eventlen); - if (tail) - syncEvents.pendtail = &tail->next; - *syncEvents.pendtail = qe; -} - -/** - * Run through the list of events queued up in syncEvents. - * For each event do: - * If the device for this event is not frozen anymore, take it and process it - * as usually. - * After that, check if there's any devices in the list that are not frozen. - * If there is none, we're done. If there is at least one device that is not - * frozen, then re-run from the beginning of the event queue. - */ -static void -PlayReleasedEvents(void) -{ - QdEventPtr *prev, qe; - DeviceIntPtr dev; - DeviceIntPtr pDev; - - prev = &syncEvents.pending; - while ( (qe = *prev) ) - { - if (!qe->device->deviceGrab.sync.frozen) - { - *prev = qe->next; - pDev = qe->device; - if (*syncEvents.pendtail == *prev) - syncEvents.pendtail = prev; - if (qe->event->any.type == ET_Motion) - CheckVirtualMotion(pDev, qe, NullWindow); - syncEvents.time.months = qe->months; - syncEvents.time.milliseconds = qe->event->any.time; -#ifdef PANORAMIX - /* Translate back to the sprite screen since processInputProc - will translate from sprite screen to screen 0 upon reentry - to the DIX layer */ - if(!noPanoramiXExtension) { - DeviceEvent *ev = &qe->event->device_event; - switch(ev->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - ev->root_x += screenInfo.screens[0]->x - - pDev->spriteInfo->sprite->screen->x; - ev->root_y += screenInfo.screens[0]->y - - pDev->spriteInfo->sprite->screen->y; - break; - default: - break; - } - - } -#endif - (*qe->device->public.processInputProc)(qe->event, qe->device); - free(qe); - for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) - ; - if (!dev) - break; - /* Playing the event may have unfrozen another device. */ - /* So to play it safe, restart at the head of the queue */ - prev = &syncEvents.pending; - } - else - prev = &qe->next; - } -} - -/** - * Freeze or thaw the given devices. The device's processing proc is - * switched to either the real processing proc (in case of thawing) or an - * enqueuing processing proc (usually EnqueueEvent()). - * - * @param dev The device to freeze/thaw - * @param frozen True to freeze or false to thaw. - */ -static void -FreezeThaw(DeviceIntPtr dev, Bool frozen) -{ - dev->deviceGrab.sync.frozen = frozen; - if (frozen) - dev->public.processInputProc = dev->public.enqueueInputProc; - else - dev->public.processInputProc = dev->public.realInputProc; -} - -/** - * Unfreeze devices and replay all events to the respective clients. - * - * ComputeFreezes takes the first event in the device's frozen event queue. It - * runs up the sprite tree (spriteTrace) and searches for the window to replay - * the events from. If it is found, it checks for passive grabs one down from - * the window or delivers the events. - */ -static void -ComputeFreezes(void) -{ - DeviceIntPtr replayDev = syncEvents.replayDev; - WindowPtr w; - GrabPtr grab; - DeviceIntPtr dev; - - for (dev = inputInfo.devices; dev; dev = dev->next) - FreezeThaw(dev, dev->deviceGrab.sync.other || - (dev->deviceGrab.sync.state >= FROZEN)); - if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) - return; - syncEvents.playingEvents = TRUE; - if (replayDev) - { - DeviceEvent* event = replayDev->deviceGrab.sync.event; - - syncEvents.replayDev = (DeviceIntPtr)NULL; - - w = XYToWindow(replayDev, event->root_x, event->root_y); - if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) - { - if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) - DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); - else - DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, - NullWindow, replayDev); - } - } - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (!dev->deviceGrab.sync.frozen) - { - PlayReleasedEvents(); - break; - } - } - syncEvents.playingEvents = FALSE; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (DevHasCursor(dev)) - { - /* the following may have been skipped during replay, - so do it now */ - if ((grab = dev->deviceGrab.grab) && grab->confineTo) - { - if (grab->confineTo->drawable.pScreen != - dev->spriteInfo->sprite->hotPhys.pScreen) - dev->spriteInfo->sprite->hotPhys.x = - dev->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE); - } - else - ConfineCursorToWindow(dev, - dev->spriteInfo->sprite->hotPhys.pScreen->root, - TRUE, FALSE); - PostNewCursor(dev); - } - } -} - -#ifdef RANDR -void -ScreenRestructured (ScreenPtr pScreen) -{ - GrabPtr grab; - DeviceIntPtr pDev; - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (!DevHasCursor(pDev)) - continue; - - /* GrabDevice doesn't have a confineTo field, so we don't need to - * worry about it. */ - if ((grab = pDev->deviceGrab.grab) && grab->confineTo) - { - if (grab->confineTo->drawable.pScreen - != pDev->spriteInfo->sprite->hotPhys.pScreen) - pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); - } - else - ConfineCursorToWindow(pDev, - pDev->spriteInfo->sprite->hotPhys.pScreen->root, - TRUE, FALSE); - } -} -#endif - -static void -CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) -{ - GrabPtr grab = thisDev->deviceGrab.grab; - DeviceIntPtr dev; - - if (thisMode == GrabModeSync) - thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT; - else - { /* free both if same client owns both */ - thisDev->deviceGrab.sync.state = THAWED; - if (thisDev->deviceGrab.sync.other && - (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) == - CLIENT_BITS(grab->resource))) - thisDev->deviceGrab.sync.other = NullGrab; - } - - if (IsMaster(thisDev)) - { - dev = GetPairedDevice(thisDev); - if (otherMode == GrabModeSync) - dev->deviceGrab.sync.other = grab; - else - { /* free both if same client owns both */ - if (dev->deviceGrab.sync.other && - (CLIENT_BITS(dev->deviceGrab.sync.other->resource) == - CLIENT_BITS(grab->resource))) - dev->deviceGrab.sync.other = NullGrab; - } - } - ComputeFreezes(); -} - -/** - * Save the device's master device id. This needs to be done - * if a client directly grabs a slave device that is attached to a master. For - * the duration of the grab, the device is detached, ungrabbing re-attaches it - * though. - * - * We store the ID of the master device only in case the master disappears - * while the device has a grab. - */ -static void -DetachFromMaster(DeviceIntPtr dev) -{ - if (!dev->u.master) - return; - - dev->saved_master_id = dev->u.master->id; - - AttachDevice(NULL, dev, NULL); -} - -static void -ReattachToOldMaster(DeviceIntPtr dev) -{ - DeviceIntPtr master = NULL; - - if (IsMaster(dev)) - return; - - dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess); - - if (master) - { - AttachDevice(serverClient, dev, master); - dev->saved_master_id = 0; - } -} - -/** - * Activate a pointer grab on the given device. A pointer grab will cause all - * core pointer events of this device to be delivered to the grabbing client only. - * No other device will send core events to the grab client while the grab is - * on, but core events will be sent to other clients. - * Can cause the cursor to change if a grab cursor is set. - * - * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab - * is an implicit grab caused by a ButtonPress event. - * - * @param mouse The device to grab. - * @param grab The grab structure, needs to be setup. - * @param autoGrab True if the grab was caused by a button down event and not - * explicitely by a client. - */ -void -ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, - TimeStamp time, Bool autoGrab) -{ - GrabInfoPtr grabinfo = &mouse->deviceGrab; - WindowPtr oldWin = (grabinfo->grab) ? - grabinfo->grab->window - : mouse->spriteInfo->sprite->win; - Bool isPassive = autoGrab & ~ImplicitGrabMask; - - /* slave devices need to float for the duration of the grab. */ - if (grab->grabtype == GRABTYPE_XI2 && - !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) - DetachFromMaster(mouse); - - if (grab->confineTo) - { - if (grab->confineTo->drawable.pScreen - != mouse->spriteInfo->sprite->hotPhys.pScreen) - mouse->spriteInfo->sprite->hotPhys.x = - mouse->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); - } - DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); - mouse->valuator->motionHintWindow = NullWindow; - if (syncEvents.playingEvents) - grabinfo->grabTime = syncEvents.time; - else - grabinfo->grabTime = time; - if (grab->cursor) - grab->cursor->refcnt++; - grabinfo->activeGrab = *grab; - grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = isPassive; - grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; - PostNewCursor(mouse); - CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); -} - -/** - * Delete grab on given device, update the sprite. - * - * Extension devices are set up for ActivateKeyboardGrab(). - */ -void -DeactivatePointerGrab(DeviceIntPtr mouse) -{ - GrabPtr grab = mouse->deviceGrab.grab; - DeviceIntPtr dev; - Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && - mouse->deviceGrab.implicitGrab); - - mouse->valuator->motionHintWindow = NullWindow; - mouse->deviceGrab.grab = NullGrab; - mouse->deviceGrab.sync.state = NOT_GRABBED; - mouse->deviceGrab.fromPassiveGrab = FALSE; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.sync.other == grab) - dev->deviceGrab.sync.other = NullGrab; - } - DoEnterLeaveEvents(mouse, mouse->id, grab->window, - mouse->spriteInfo->sprite->win, NotifyUngrab); - if (grab->confineTo) - ConfineCursorToWindow(mouse, RootWindow(mouse), FALSE, FALSE); - PostNewCursor(mouse); - if (grab->cursor) - FreeCursor(grab->cursor, (Cursor)0); - - if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) - ReattachToOldMaster(mouse); - - ComputeFreezes(); -} - -/** - * Activate a keyboard grab on the given device. - * - * Extension devices have ActivateKeyboardGrab() set as their grabbing proc. - */ -void -ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) -{ - GrabInfoPtr grabinfo = &keybd->deviceGrab; - WindowPtr oldWin; - - /* slave devices need to float for the duration of the grab. */ - if (grab->grabtype == GRABTYPE_XI2 && - !(passive & ImplicitGrabMask) && - !IsMaster(keybd)) - DetachFromMaster(keybd); - - if (grabinfo->grab) - oldWin = grabinfo->grab->window; - else if (keybd->focus) - oldWin = keybd->focus->win; - else - oldWin = keybd->spriteInfo->sprite->win; - if (oldWin == FollowKeyboardWin) - oldWin = keybd->focus->win; - if (keybd->valuator) - keybd->valuator->motionHintWindow = NullWindow; - DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); - if (syncEvents.playingEvents) - grabinfo->grabTime = syncEvents.time; - else - grabinfo->grabTime = time; - grabinfo->activeGrab = *grab; - grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = passive; - grabinfo->implicitGrab = passive & ImplicitGrabMask; - CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); -} - -/** - * Delete keyboard grab for the given device. - */ -void -DeactivateKeyboardGrab(DeviceIntPtr keybd) -{ - GrabPtr grab = keybd->deviceGrab.grab; - DeviceIntPtr dev; - WindowPtr focusWin = keybd->focus ? keybd->focus->win - : keybd->spriteInfo->sprite->win; - Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && - keybd->deviceGrab.implicitGrab); - - if (focusWin == FollowKeyboardWin) - focusWin = inputInfo.keyboard->focus->win; - if (keybd->valuator) - keybd->valuator->motionHintWindow = NullWindow; - keybd->deviceGrab.grab = NullGrab; - keybd->deviceGrab.sync.state = NOT_GRABBED; - keybd->deviceGrab.fromPassiveGrab = FALSE; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.sync.other == grab) - dev->deviceGrab.sync.other = NullGrab; - } - DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); - - if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) - ReattachToOldMaster(keybd); - - ComputeFreezes(); -} - -void -AllowSome(ClientPtr client, - TimeStamp time, - DeviceIntPtr thisDev, - int newState) -{ - Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; - TimeStamp grabTime; - DeviceIntPtr dev; - GrabInfoPtr devgrabinfo, - grabinfo = &thisDev->deviceGrab; - - thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client); - thisSynced = FALSE; - otherGrabbed = FALSE; - othersFrozen = FALSE; - grabTime = grabinfo->grabTime; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - - if (dev == thisDev) - continue; - if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) - { - if (!(thisGrabbed || otherGrabbed) || - (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER)) - grabTime = devgrabinfo->grabTime; - otherGrabbed = TRUE; - if (grabinfo->sync.other == devgrabinfo->grab) - thisSynced = TRUE; - if (devgrabinfo->sync.state >= FROZEN) - othersFrozen = TRUE; - } - } - if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced)) - return; - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, grabTime) == EARLIER)) - return; - switch (newState) - { - case THAWED: /* Async */ - if (thisGrabbed) - grabinfo->sync.state = THAWED; - if (thisSynced) - grabinfo->sync.other = NullGrab; - ComputeFreezes(); - break; - case FREEZE_NEXT_EVENT: /* Sync */ - if (thisGrabbed) - { - grabinfo->sync.state = FREEZE_NEXT_EVENT; - if (thisSynced) - grabinfo->sync.other = NullGrab; - ComputeFreezes(); - } - break; - case THAWED_BOTH: /* AsyncBoth */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = THAWED; - if (devgrabinfo->sync.other && - SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT; - if (devgrabinfo->sync.other - && SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - case NOT_GRABBED: /* Replay */ - if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) - { - if (thisSynced) - grabinfo->sync.other = NullGrab; - syncEvents.replayDev = thisDev; - syncEvents.replayWin = grabinfo->grab->window; - (*grabinfo->DeactivateGrab)(thisDev); - syncEvents.replayDev = (DeviceIntPtr)NULL; - } - break; - case THAW_OTHERS: /* AsyncOthers */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev == thisDev) - continue; - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = THAWED; - if (devgrabinfo->sync.other - && SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - } -} - -/** - * Server-side protocol handling for AllowEvents request. - * - * Release some events from a frozen device. - */ -int -ProcAllowEvents(ClientPtr client) -{ - TimeStamp time; - DeviceIntPtr mouse = NULL; - DeviceIntPtr keybd = NULL; - REQUEST(xAllowEventsReq); - - REQUEST_SIZE_MATCH(xAllowEventsReq); - time = ClientTimeToServerTime(stuff->time); - - mouse = PickPointer(client); - keybd = PickKeyboard(client); - - switch (stuff->mode) - { - case ReplayPointer: - AllowSome(client, time, mouse, NOT_GRABBED); - break; - case SyncPointer: - AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); - break; - case AsyncPointer: - AllowSome(client, time, mouse, THAWED); - break; - case ReplayKeyboard: - AllowSome(client, time, keybd, NOT_GRABBED); - break; - case SyncKeyboard: - AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); - break; - case AsyncKeyboard: - AllowSome(client, time, keybd, THAWED); - break; - case SyncBoth: - AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); - break; - case AsyncBoth: - AllowSome(client, time, keybd, THAWED_BOTH); - break; - default: - client->errorValue = stuff->mode; - return BadValue; - } - return Success; -} - -/** - * Deactivate grabs from any device that has been grabbed by the client. - */ -void -ReleaseActiveGrabs(ClientPtr client) -{ - DeviceIntPtr dev; - Bool done; - - /* XXX CloseDownClient should remove passive grabs before - * releasing active grabs. - */ - do { - done = TRUE; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - { - (*dev->deviceGrab.DeactivateGrab)(dev); - done = FALSE; - } - } - } while (!done); -} - -/************************************************************************** - * The following procedures deal with delivering events * - **************************************************************************/ - -/** - * Deliver the given events to the given client. - * - * More than one event may be delivered at a time. This is the case with - * DeviceMotionNotifies which may be followed by DeviceValuator events. - * - * TryClientEvents() is the last station before actually writing the events to - * the socket. Anything that is not filtered here, will get delivered to the - * client. - * An event is only delivered if - * - mask and filter match up. - * - no other client has a grab on the device that caused the event. - * - * - * @param client The target client to deliver to. - * @param dev The device the event came from. May be NULL. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param mask Event mask as set by the window. - * @param filter Mask based on event type. - * @param grab Possible grab on the device that caused the event. - * - * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the - * client. - */ -int -TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, - int count, Mask mask, Mask filter, GrabPtr grab) -{ - int type; - -#ifdef DEBUG_EVENTS - ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", - pEvents->u.u.type, pEvents->u.u.detail, mask, - client ? client->index : -1, - (client && client->clientGone) ? " (gone)" : ""); -#endif - - if (!client || client == serverClient || client->clientGone) { -#ifdef DEBUG_EVENTS - ErrorF(" not delivered to fake/dead client\n"); -#endif - return 0; - } - - if (filter != CantBeFiltered && !(mask & filter)) - { - #ifdef DEBUG_EVENTS - ErrorF(" filtered\n"); - #endif - return 0; - } - - if (grab && !SameClient(grab, client)) - { -#ifdef DEBUG_EVENTS - ErrorF(" not delivered due to grab\n"); -#endif - return -1; /* don't send, but notify caller */ - } - - type = pEvents->u.u.type; - if (type == MotionNotify) - { - if (mask & PointerMotionHintMask) - { - if (WID(dev->valuator->motionHintWindow) == - pEvents->u.keyButtonPointer.event) - { -#ifdef DEBUG_EVENTS - ErrorF("[dix] \n"); - ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n"); -#endif - return 1; /* don't send, but pretend we did */ - } - pEvents->u.u.detail = NotifyHint; - } - else - { - pEvents->u.u.detail = NotifyNormal; - } - } - else if (type == DeviceMotionNotify) - { - if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, - mask) != 0) - return 1; - } else if (type == KeyPress) - { - if (EventIsKeyRepeat(pEvents)) - { - if (!_XkbWantsDetectableAutoRepeat(client)) - { - xEvent release = *pEvents; - release.u.u.type = KeyRelease; - WriteEventsToClient(client, 1, &release); -#ifdef DEBUG_EVENTS - ErrorF(" (plus fake core release for repeat)"); -#endif - } else - { -#ifdef DEBUG_EVENTS - ErrorF(" (detectable autorepeat for core)"); -#endif - } - } - - } else if (type == DeviceKeyPress) - { - if (EventIsKeyRepeat(pEvents)) - { - if (!_XkbWantsDetectableAutoRepeat(client)) - { - deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; - release.type = DeviceKeyRelease; -#ifdef DEBUG_EVENTS - ErrorF(" (plus fake xi1 release for repeat)"); -#endif - WriteEventsToClient(client, 1, (xEvent *) &release); - } - else { -#ifdef DEBUG_EVENTS - ErrorF(" (detectable autorepeat for core)"); -#endif - } - } - } - - if (BitIsOn(criticalEvents, type)) - { - if (client->smart_priority < SMART_MAX_PRIORITY) - client->smart_priority++; - SetCriticalOutputPending(); - } - - WriteEventsToClient(client, count, pEvents); -#ifdef DEBUG_EVENTS - ErrorF("[dix] delivered\n"); -#endif - return 1; -} - -/** - * Deliver events to a window. At this point, we do not yet know if the event - * actually needs to be delivered. May activate a grab if the event is a - * button press. - * - * Core events are always delivered to the window owner. If the filter is - * something other than CantBeFiltered, the event is also delivered to other - * clients with the matching mask on the window. - * - * More than one event may be delivered at a time. This is the case with - * DeviceMotionNotifies which may be followed by DeviceValuator events. - * - * @param pWin The window that would get the event. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param filter Mask based on event type. - * @param grab Possible grab on the device that caused the event. - * - * @return Number of events delivered to various clients. - */ -int -DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent - *pEvents, int count, Mask filter, GrabPtr grab) -{ - int deliveries = 0, nondeliveries = 0; - int attempt; - InputClients *other; - ClientPtr client = NullClient; - Mask deliveryMask = 0; /* If a grab occurs due to a button press, then - this mask is the mask of the grab. */ - int type = pEvents->u.u.type; - - - /* Deliver to window owner */ - if ((filter == CantBeFiltered) || CORE_EVENT(pEvents)) - { - /* if nobody ever wants to see this event, skip some work */ - if (filter != CantBeFiltered && - !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) - return 0; - - if (IsInterferingGrab(wClient(pWin), pDev, pEvents)) - return 0; - - if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents, - count, pWin->eventMask, - filter, grab)) ) - { - if (attempt > 0) - { - deliveries++; - client = wClient(pWin); - deliveryMask = pWin->eventMask; - } else - nondeliveries--; - } - } - - /* CantBeFiltered means only window owner gets the event */ - if (filter != CantBeFiltered) - { - if (CORE_EVENT(pEvents)) - other = (InputClients *)wOtherClients(pWin); - else if (XI2_EVENT(pEvents)) - { - OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - /* Has any client selected for the event? */ - if (!GetWindowXI2Mask(pDev, pWin, pEvents)) - return 0; - other = inputMasks->inputClients; - } else { - OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - /* Has any client selected for the event? */ - if (!inputMasks || - !(inputMasks->inputEvents[pDev->id] & filter)) - return 0; - - other = inputMasks->inputClients; - } - - for (; other; other = other->next) - { - Mask mask; - if (IsInterferingGrab(rClient(other), pDev, pEvents)) - continue; - - mask = GetEventMask(pDev, pEvents, other); - - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, - pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(rClient(other), pDev, - pEvents, count, - mask, filter, grab)) ) - { - if (attempt > 0) - { - deliveries++; - client = rClient(other); - deliveryMask = mask; - } else - nondeliveries--; - } - } - } - /* - * Note that since core events are delivered first, an implicit grab may - * be activated on a core grab, stopping the XI events. - */ - if ((type == DeviceButtonPress || type == ButtonPress || - ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress))) - && deliveries - && (!grab)) - { - GrabRec tempGrab; - OtherInputMasks *inputMasks; - - memset(&tempGrab, 0, sizeof(GrabRec)); - tempGrab.next = NULL; - tempGrab.device = pDev; - tempGrab.resource = client->clientAsMask; - tempGrab.window = pWin; - tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; - tempGrab.eventMask = deliveryMask; - tempGrab.keyboardMode = GrabModeAsync; - tempGrab.pointerMode = GrabModeAsync; - tempGrab.confineTo = NullWindow; - tempGrab.cursor = NullCursor; - tempGrab.type = type; - if (type == ButtonPress) - tempGrab.grabtype = GRABTYPE_CORE; - else if (type == DeviceButtonPress) - tempGrab.grabtype = GRABTYPE_XI; - else - { - tempGrab.type = ((xGenericEvent*)pEvents)->evtype; - tempGrab.grabtype = GRABTYPE_XI2; - } - - /* get the XI and XI2 device mask */ - inputMasks = wOtherInputMasks(pWin); - tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0; - - if (inputMasks) - memcpy(tempGrab.xi2mask, inputMasks->xi2mask, - sizeof(tempGrab.xi2mask)); - - (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab, - currentTime, TRUE | ImplicitGrabMask); - } - else if ((type == MotionNotify) && deliveries) - pDev->valuator->motionHintWindow = pWin; - else - { - if ((type == DeviceMotionNotify || type == DeviceButtonPress) && - deliveries) - CheckDeviceGrabAndHintWindow (pWin, type, - (deviceKeyButtonPointer*) pEvents, - grab, client, deliveryMask); - } - if (deliveries) - return deliveries; - return nondeliveries; -} - -/* If the event goes to dontClient, don't send it and return 0. if - send works, return 1 or if send didn't work, return 2. - Only works for core events. -*/ - -#ifdef PANORAMIX -static int -XineramaTryClientEventsResult( - ClientPtr client, - GrabPtr grab, - Mask mask, - Mask filter -){ - if ((client) && (client != serverClient) && (!client->clientGone) && - ((filter == CantBeFiltered) || (mask & filter))) - { - if (grab && !SameClient(grab, client)) return -1; - else return 1; - } - return 0; -} -#endif - -/** - * Try to deliver events to the interested parties. - * - * @param pWin The window that would get the event. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param filter Mask based on event type. - * @param dontClient Don't deliver to the dontClient. - */ -int -MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, - int count, Mask filter, ClientPtr dontClient) -{ - OtherClients *other; - - - if (pWin->eventMask & filter) - { - if (wClient(pWin) == dontClient) - return 0; -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return XineramaTryClientEventsResult( - wClient(pWin), NullGrab, pWin->eventMask, filter); -#endif - if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) - return 1; /* don't send, but pretend we did */ - return TryClientEvents(wClient(pWin), NULL, pEvents, count, - pWin->eventMask, filter, NullGrab); - } - for (other = wOtherClients(pWin); other; other = other->next) - { - if (other->mask & filter) - { - if (SameClient(other, dontClient)) - return 0; -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return XineramaTryClientEventsResult( - rClient(other), NullGrab, other->mask, filter); -#endif - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents, - count)) - return 1; /* don't send, but pretend we did */ - return TryClientEvents(rClient(other), NULL, pEvents, count, - other->mask, filter, NullGrab); - } - } - return 2; -} - -static Window FindChildForEvent(DeviceIntPtr dev, WindowPtr event) -{ - SpritePtr pSprite = dev->spriteInfo->sprite; - WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; - Window child = None; - - /* If the search ends up past the root should the child field be - set to none or should the value in the argument be passed - through. It probably doesn't matter since everyone calls - this function with child == None anyway. */ - while (w) - { - /* If the source window is same as event window, child should be - none. Don't bother going all all the way back to the root. */ - - if (w == event) - { - child = None; - break; - } - - if (w->parent == event) - { - child = w->drawable.id; - break; - } - w = w->parent; - } - return child; -} - -/** - * Adjust event fields to comply with the window properties. - * - * @param xE Event to be modified in place - * @param pWin The window to get the information from. - * @param child Child window setting for event (if applicable) - * @param calcChild If True, calculate the child window. - */ -void -FixUpEventFromWindow( - DeviceIntPtr pDev, - xEvent *xE, - WindowPtr pWin, - Window child, - Bool calcChild) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (calcChild) - child = FindChildForEvent(pDev, pWin); - - if (XI2_EVENT(xE)) - { - xXIDeviceEvent* event = (xXIDeviceEvent*)xE; - - if (event->evtype == XI_RawKeyPress || - event->evtype == XI_RawKeyRelease || - event->evtype == XI_RawButtonPress || - event->evtype == XI_RawButtonRelease || - event->evtype == XI_RawMotion || - event->evtype == XI_DeviceChanged || - event->evtype == XI_HierarchyChanged || - event->evtype == XI_PropertyEvent) - return; - - event->root = RootWindow(pDev)->drawable.id; - event->event = pWin->drawable.id; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); - event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); - event->child = child; - } else - { - event->event_x = 0; - event->event_y = 0; - event->child = None; - } - - if (event->evtype == XI_Enter || event->evtype == XI_Leave || - event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) - ((xXIEnterEvent*)event)->same_screen = - (pSprite->hot.pScreen == pWin->drawable.pScreen); - - } else - { - XE_KBPTR.root = RootWindow(pDev)->drawable.id; - XE_KBPTR.event = pWin->drawable.id; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - XE_KBPTR.sameScreen = xTrue; - XE_KBPTR.child = child; - XE_KBPTR.eventX = - XE_KBPTR.rootX - pWin->drawable.x; - XE_KBPTR.eventY = - XE_KBPTR.rootY - pWin->drawable.y; - } - else - { - XE_KBPTR.sameScreen = xFalse; - XE_KBPTR.child = None; - XE_KBPTR.eventX = 0; - XE_KBPTR.eventY = 0; - } - } -} - -/** - * Check if a given event is deliverable at all on a given window. - * - * This function only checks if any client wants it, not for a specific - * client. - * - * @param[in] dev The device this event is being sent for. - * @param[in] event The event that is to be sent. - * @param[in] win The current event window. - * - * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and - * ::DONT_PROPAGATE_MASK. - */ -int -EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) -{ - int rc = 0; - int filter = 0; - int type; - OtherInputMasks *inputMasks = wOtherInputMasks(win); - xEvent ev; - - /* XXX: this makes me gag */ - type = GetXI2Type(event); - ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ - ((xGenericEvent*)&ev)->extension = IReqCode; - ((xGenericEvent*)&ev)->evtype = type; - filter = GetEventFilter(dev, &ev); - if (type && inputMasks && - ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || - ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || - (inputMasks->xi2mask[dev->id][type/8] & filter))) - rc |= XI2_MASK; - - type = GetXIType(event); - ev.u.u.type = type; - filter = GetEventFilter(dev, &ev); - - /* Check for XI mask */ - if (type && inputMasks && - (inputMasks->deliverableEvents[dev->id] & filter) && - (inputMasks->inputEvents[dev->id] & filter)) - rc |= XI_MASK; - - /* Check for XI DontPropagate mask */ - if (type && inputMasks && - (inputMasks->dontPropagateMask[dev->id] & filter)) - rc |= DONT_PROPAGATE_MASK; - - /* Check for core mask */ - type = GetCoreType(event); - if (type && (win->deliverableEvents & filter) && - ((wOtherEventMasks(win) | win->eventMask) & filter)) - rc |= CORE_MASK; - - /* Check for core DontPropagate mask */ - if (type && (filter & wDontPropagateMask(win))) - rc |= DONT_PROPAGATE_MASK; - - return rc; -} - -/** - * Deliver events caused by input devices. - * - * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is - * called directly from the processInputProc. - * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call - * DeliverDeviceEvents. - * For focused events, DeliverFocusedEvent is called first, and _may_ call - * DeliverDeviceEvents. - * - * @param pWin Window to deliver event to. - * @param event The events to deliver, not yet in wire format. - * @param grab Possible grab on a device. - * @param stopAt Don't recurse up to the root window. - * @param dev The device that is responsible for the event. - * - * @see DeliverGrabbedEvent - * @see DeliverFocusedEvent - */ -int -DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, - WindowPtr stopAt, DeviceIntPtr dev) -{ - Window child = None; - Mask filter; - int deliveries = 0; - xEvent core; - xEvent *xE = NULL; - int rc, mask, count = 0; - - CHECKEVENT(event); - - while (pWin) - { - if ((mask = EventIsDeliverable(dev, event, pWin))) - { - /* XI2 events first */ - if (mask & XI2_MASK) - { - xEvent *xi2 = NULL; - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - /* XXX: XACE */ - filter = GetEventFilter(dev, xi2); - FixUpEventFromWindow(dev, xi2, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, - filter, grab); - free(xi2); - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", - dev->name, rc); - } - - /* XI events */ - if (mask & XI_MASK) - { - rc = EventToXI(event, &xE, &count); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { - filter = GetEventFilter(dev, xE); - FixUpEventFromWindow(dev, xE, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, xE, count, - filter, grab); - if (deliveries > 0) - goto unwind; - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", - dev->name, event->any.type, rc); - } - - /* Core event */ - if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents) - { - rc = EventToCore(event, &core); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) { - filter = GetEventFilter(dev, &core); - FixUpEventFromWindow(dev, &core, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, &core, 1, - filter, grab); - if (deliveries > 0) - goto unwind; - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", - dev->name, event->any.type, rc); - } - - if ((deliveries < 0) || (pWin == stopAt) || - (mask & DONT_PROPAGATE_MASK)) - { - deliveries = 0; - goto unwind; - } - } - - child = pWin->drawable.id; - pWin = pWin->parent; - } - -unwind: - free(xE); - return deliveries; -} - -#undef XI_MASK -#undef CORE_MASK -#undef DONT_PROPAGATE_MASK - -/** - * Deliver event to a window and it's immediate parent. Used for most window - * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that - * propagate up the tree or extension events - * - * In case of a ReparentNotify event, the event will be delivered to the - * otherParent as well. - * - * @param pWin Window to deliver events to. - * @param xE Events to deliver. - * @param count number of events in xE. - * @param otherParent Used for ReparentNotify events. - */ -int -DeliverEvents(WindowPtr pWin, xEvent *xE, int count, - WindowPtr otherParent) -{ - Mask filter; - int deliveries; - DeviceIntRec dummy; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return count; -#endif - - if (!count) - return 0; - - dummy.id = XIAllDevices; - filter = GetEventFilter(&dummy, xE); - if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) - xE->u.destroyNotify.event = pWin->drawable.id; - if (filter != StructureAndSubMask) - return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab); - deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, - StructureNotifyMask, NullGrab); - if (pWin->parent) - { - xE->u.destroyNotify.event = pWin->parent->drawable.id; - deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, - SubstructureNotifyMask, NullGrab); - if (xE->u.u.type == ReparentNotify) - { - xE->u.destroyNotify.event = otherParent->drawable.id; - deliveries += DeliverEventsToWindow(&dummy, - otherParent, xE, count, SubstructureNotifyMask, - NullGrab); - } - } - return deliveries; -} - - -static Bool -PointInBorderSize(WindowPtr pWin, int x, int y) -{ - BoxRec box; - - if(RegionContainsPoint(&pWin->borderSize, x, y, &box)) - return TRUE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && - XineramaSetWindowPntrs(inputInfo.pointer, pWin)) { - SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite; - int i; - - for(i = 1; i < PanoramiXNumScreens; i++) { - if(RegionContainsPoint(&pSprite->windows[i]->borderSize, - x + screenInfo.screens[0]->x - screenInfo.screens[i]->x, - y + screenInfo.screens[0]->y - screenInfo.screens[i]->y, - &box)) - return TRUE; - } - } -#endif - return FALSE; -} - -/** - * Traversed from the root window to the window at the position x/y. While - * traversing, it sets up the traversal history in the spriteTrace array. - * After completing, the spriteTrace history is set in the following way: - * spriteTrace[0] ... root window - * spriteTrace[1] ... top level window that encloses x/y - * ... - * spriteTrace[spriteTraceGood - 1] ... window at x/y - * - * @returns the window at the given coordinates. - */ -static WindowPtr -XYToWindow(DeviceIntPtr pDev, int x, int y) -{ - WindowPtr pWin; - BoxRec box; - SpritePtr pSprite; - - pSprite = pDev->spriteInfo->sprite; - pSprite->spriteTraceGood = 1; /* root window still there */ - pWin = RootWindow(pDev)->firstChild; - while (pWin) - { - if ((pWin->mapped) && - (x >= pWin->drawable.x - wBorderWidth (pWin)) && - (x < pWin->drawable.x + (int)pWin->drawable.width + - wBorderWidth(pWin)) && - (y >= pWin->drawable.y - wBorderWidth (pWin)) && - (y < pWin->drawable.y + (int)pWin->drawable.height + - wBorderWidth (pWin)) - /* When a window is shaped, a further check - * is made to see if the point is inside - * borderSize - */ - && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) - && (!wInputShape(pWin) || - RegionContainsPoint(wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box)) -#ifdef ROOTLESS - /* In rootless mode windows may be offscreen, even when - * they're in X's stack. (E.g. if the native window system - * implements some form of virtual desktop system). - */ - && !pWin->rootlessUnhittable -#endif - ) - { - if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) - { - pSprite->spriteTraceSize += 10; - pSprite->spriteTrace = realloc(pSprite->spriteTrace, - pSprite->spriteTraceSize*sizeof(WindowPtr)); - } - pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; - pWin = pWin->firstChild; - } - else - pWin = pWin->nextSib; - } - return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; -} - -/** - * Ungrab a currently FocusIn grabbed device and grab the device on the - * given window. If the win given is the NoneWin, the device is ungrabbed if - * applicable and FALSE is returned. - * - * @returns TRUE if the device has been grabbed, or FALSE otherwise. - */ -BOOL -ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) -{ - BOOL rc = FALSE; - DeviceEvent event; - - if (dev->deviceGrab.grab) - { - if (!dev->deviceGrab.fromPassiveGrab || - dev->deviceGrab.grab->type != XI_Enter || - dev->deviceGrab.grab->window == win || - IsParent(dev->deviceGrab.grab->window, win)) - return FALSE; - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - (*dev->deviceGrab.DeactivateGrab)(dev); - } - - if (win == NoneWin || win == PointerRootWin) - return FALSE; - - memset(&event, 0, sizeof(DeviceEvent)); - event.header = ET_Internal; - event.type = ET_FocusIn; - event.length = sizeof(DeviceEvent); - event.time = GetTimeInMillis(); - event.deviceid = dev->id; - event.sourceid = dev->id; - event.detail.button = 0; - rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); - if (rc) - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - return rc; -} - -/** - * Ungrab a currently Enter grabbed device and grab the device for the given - * window. - * - * @returns TRUE if the device has been grabbed, or FALSE otherwise. - */ -static BOOL -ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) -{ - BOOL rc = FALSE; - DeviceEvent event; - - if (dev->deviceGrab.grab) - { - if (!dev->deviceGrab.fromPassiveGrab || - dev->deviceGrab.grab->type != XI_Enter || - dev->deviceGrab.grab->window == win || - IsParent(dev->deviceGrab.grab->window, win)) - return FALSE; - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - (*dev->deviceGrab.DeactivateGrab)(dev); - } - - memset(&event, 0, sizeof(DeviceEvent)); - event.header = ET_Internal; - event.type = ET_Enter; - event.length = sizeof(DeviceEvent); - event.time = GetTimeInMillis(); - event.deviceid = dev->id; - event.sourceid = dev->id; - event.detail.button = 0; - rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); - if (rc) - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); - - return rc; -} - -/** - * Update the sprite coordinates based on the event. Update the cursor - * position, then update the event with the new coordinates that may have been - * changed. If the window underneath the sprite has changed, change to new - * cursor and send enter/leave events. - * - * CheckMotion() will not do anything and return FALSE if the event is not a - * pointer event. - * - * @return TRUE if the sprite has moved or FALSE otherwise. - */ -Bool -CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) -{ - WindowPtr prevSpriteWin, newSpriteWin; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - CHECKEVENT(ev); - - prevSpriteWin = pSprite->win; - - if (ev && !syncEvents.playingEvents) - { - /* GetPointerEvents() guarantees that pointer events have the correct - rootX/Y set already. */ - switch (ev->type) - { - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_Motion: - break; - default: - /* all other events return FALSE */ - return FALSE; - } - - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - /* Motion events entering DIX get translated to Screen 0 - coordinates. Replayed events have already been - translated since they've entered DIX before */ - ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x; - ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y; - } else -#endif - { - if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) - { - pSprite->hot.pScreen = pSprite->hotPhys.pScreen; - RootWindow(pDev) = pSprite->hot.pScreen->root; - } - } - - pSprite->hot.x = ev->root_x; - pSprite->hot.y = ev->root_y; - if (pSprite->hot.x < pSprite->physLimits.x1) - pSprite->hot.x = pSprite->physLimits.x1; - else if (pSprite->hot.x >= pSprite->physLimits.x2) - pSprite->hot.x = pSprite->physLimits.x2 - 1; - if (pSprite->hot.y < pSprite->physLimits.y1) - pSprite->hot.y = pSprite->physLimits.y1; - else if (pSprite->hot.y >= pSprite->physLimits.y2) - pSprite->hot.y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); - pSprite->hotPhys = pSprite->hot; - - if ((pSprite->hotPhys.x != ev->root_x) || - (pSprite->hotPhys.y != ev->root_y)) - { -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - XineramaSetCursorPosition( - pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } else -#endif - { - (*pSprite->hotPhys.pScreen->SetCursorPosition)( - pDev, pSprite->hotPhys.pScreen, - pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } - } - - ev->root_x = pSprite->hot.x; - ev->root_y = pSprite->hot.y; - } - - newSpriteWin = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y); - - if (newSpriteWin != prevSpriteWin) - { - int sourceid; - if (!ev) { - UpdateCurrentTimeIf(); - sourceid = pDev->id; /* when from WindowsRestructured */ - } else - sourceid = ev->sourceid; - - if (prevSpriteWin != NullWindow) { - if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) - DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, - newSpriteWin, NotifyNormal); - } - /* set pSprite->win after ActivateEnterGrab, otherwise - sprite window == grab_window and no enter/leave events are - sent. */ - pSprite->win = newSpriteWin; - PostNewCursor(pDev); - return FALSE; - } - return TRUE; -} - -/** - * Windows have restructured, we need to update the sprite position and the - * sprite's cursor. - */ -void -WindowsRestructured(void) -{ - DeviceIntPtr pDev = inputInfo.devices; - while(pDev) - { - if (IsMaster(pDev) || !pDev->u.master) - CheckMotion(NULL, pDev); - pDev = pDev->next; - } -} - -#ifdef PANORAMIX -/* This was added to support reconfiguration under Xdmx. The problem is - * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin - * other than 0,0, the information in the private sprite structure must - * be updated accordingly, or XYToWindow (and other routines) will not - * compute correctly. */ -void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) -{ - GrabPtr grab; - DeviceIntPtr pDev; - SpritePtr pSprite; - - if (noPanoramiXExtension) return; - - pDev = inputInfo.devices; - while(pDev) - { - if (DevHasCursor(pDev)) - { - pSprite = pDev->spriteInfo->sprite; - pSprite->hot.x -= xoff; - pSprite->hot.y -= yoff; - - pSprite->hotPhys.x -= xoff; - pSprite->hotPhys.y -= yoff; - - pSprite->hotLimits.x1 -= xoff; - pSprite->hotLimits.y1 -= yoff; - pSprite->hotLimits.x2 -= xoff; - pSprite->hotLimits.y2 -= yoff; - - if (RegionNotEmpty(&pSprite->Reg1)) - RegionTranslate(&pSprite->Reg1, xoff, yoff); - if (RegionNotEmpty(&pSprite->Reg2)) - RegionTranslate(&pSprite->Reg2, xoff, yoff); - - /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ - if ((grab = pDev->deviceGrab.grab) && grab->confineTo) { - if (grab->confineTo->drawable.pScreen - != pSprite->hotPhys.pScreen) - pSprite->hotPhys.x = pSprite->hotPhys.y = 0; - ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); - } else - ConfineCursorToWindow( - pDev, - pSprite->hotPhys.pScreen->root, - TRUE, FALSE); - - } - pDev = pDev->next; - } -} -#endif - -/** - * Initialize a sprite for the given device and set it to some sane values. If - * the device already has a sprite alloc'd, don't realloc but just reset to - * default values. - * If a window is supplied, the sprite will be initialized with the window's - * cursor and positioned in the center of the window's screen. The root window - * is a good choice to pass in here. - * - * It's a good idea to call it only for pointer devices, unless you have a - * really talented keyboard. - * - * @param pDev The device to initialize. - * @param pWin The window where to generate the sprite in. - * - */ -void -InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) -{ - SpritePtr pSprite; - ScreenPtr pScreen; - CursorPtr pCursor; - - if (!pDev->spriteInfo->sprite) - { - DeviceIntPtr it; - - pDev->spriteInfo->sprite = (SpritePtr)calloc(1, sizeof(SpriteRec)); - if (!pDev->spriteInfo->sprite) - FatalError("InitializeSprite: failed to allocate sprite struct"); - - /* We may have paired another device with this device before our - * device had a actual sprite. We need to check for this and reset the - * sprite field for all paired devices. - * - * The VCK is always paired with the VCP before the VCP has a sprite. - */ - for (it = inputInfo.devices; it; it = it->next) - { - if (it->spriteInfo->paired == pDev) - it->spriteInfo->sprite = pDev->spriteInfo->sprite; - } - if (inputInfo.keyboard->spriteInfo->paired == pDev) - inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite; - } - - pSprite = pDev->spriteInfo->sprite; - pDev->spriteInfo->spriteOwner = TRUE; - - pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL; - pSprite->hot.pScreen = pScreen; - pSprite->hotPhys.pScreen = pScreen; - if (pScreen) - { - pSprite->hotPhys.x = pScreen->width / 2; - pSprite->hotPhys.y = pScreen->height / 2; - pSprite->hotLimits.x2 = pScreen->width; - pSprite->hotLimits.y2 = pScreen->height; - } - - pSprite->hot = pSprite->hotPhys; - pSprite->win = pWin; - - if (pWin) - { - pCursor = wCursor(pWin); - pSprite->spriteTrace = (WindowPtr *)calloc(1, 32*sizeof(WindowPtr)); - if (!pSprite->spriteTrace) - FatalError("Failed to allocate spriteTrace"); - pSprite->spriteTraceSize = 32; - - RootWindow(pDev) = pWin; - pSprite->spriteTraceGood = 1; - - pSprite->pEnqueueScreen = pScreen; - pSprite->pDequeueScreen = pSprite->pEnqueueScreen; - - } else { - pCursor = NullCursor; - pSprite->spriteTrace = NULL; - pSprite->spriteTraceSize = 0; - pSprite->spriteTraceGood = 0; - pSprite->pEnqueueScreen = screenInfo.screens[0]; - pSprite->pDequeueScreen = pSprite->pEnqueueScreen; - } - if (pCursor) - pCursor->refcnt++; - if (pSprite->current) - FreeCursor(pSprite->current, None); - pSprite->current = pCursor; - - if (pScreen) - { - (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current); - (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current, - &pSprite->hotLimits, &pSprite->physLimits); - pSprite->confined = FALSE; - - (*pScreen->ConstrainCursor) (pDev, pScreen, - &pSprite->physLimits); - (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x, - pSprite->hot.y, - FALSE); - (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); - } -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; - pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; - pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; - pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; - pSprite->physLimits = pSprite->hotLimits; - pSprite->confineWin = NullWindow; - pSprite->hotShape = NullRegion; - pSprite->screen = pScreen; - /* gotta UNINIT these someplace */ - RegionNull(&pSprite->Reg1); - RegionNull(&pSprite->Reg2); - } -#endif -} - -/** - * Update the mouse sprite info when the server switches from a pScreen to another. - * Otherwise, the pScreen of the mouse sprite is never updated when we switch - * from a pScreen to another. Never updating the pScreen of the mouse sprite - * implies that windows that are in pScreen whose pScreen->myNum >0 will never - * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen - * always points to the first pScreen it has been set by - * DefineInitialRootWindow(). - * - * Calling this function is useful for use cases where the server - * has more than one pScreen. - * This function is similar to DefineInitialRootWindow() but it does not - * reset the mouse pointer position. - * @param win must be the new pScreen we are switching to. - */ -void -UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - SpritePtr pSprite = NULL; - WindowPtr win = NULL; - CursorPtr pCursor; - if (!pScreen) - return ; - - if (!pDev->spriteInfo->sprite) - return; - - pSprite = pDev->spriteInfo->sprite; - - win = pScreen->root; - - pSprite->hotPhys.pScreen = pScreen; - pSprite->hot = pSprite->hotPhys; - pSprite->hotLimits.x2 = pScreen->width; - pSprite->hotLimits.y2 = pScreen->height; - pSprite->win = win; - pCursor = wCursor(win); - if (pCursor) - pCursor->refcnt++; - if (pSprite->current) - FreeCursor(pSprite->current, 0); - pSprite->current = pCursor; - pSprite->spriteTraceGood = 1; - pSprite->spriteTrace[0] = win; - (*pScreen->CursorLimits) (pDev, - pScreen, - pSprite->current, - &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = FALSE; - (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits); - (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; - pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; - pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; - pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; - pSprite->physLimits = pSprite->hotLimits; - pSprite->screen = pScreen; - } -#endif -} - -/* - * This does not take any shortcuts, and even ignores its argument, since - * it does not happen very often, and one has to walk up the tree since - * this might be a newly instantiated cursor for an intermediate window - * between the one the pointer is in and the one that the last cursor was - * instantiated from. - */ -void -WindowHasNewCursor(WindowPtr pWin) -{ - DeviceIntPtr pDev; - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - if (DevHasCursor(pDev)) - PostNewCursor(pDev); -} - -void -NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - pSprite->hotPhys.x = x; - pSprite->hotPhys.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x; - pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y; - if (newScreen != pSprite->screen) { - pSprite->screen = newScreen; - /* Make sure we tell the DDX to update its copy of the screen */ - if(pSprite->confineWin) - XineramaConfineCursorToWindow(pDev, - pSprite->confineWin, TRUE); - else - XineramaConfineCursorToWindow(pDev, screenInfo.screens[0]->root, TRUE); - /* if the pointer wasn't confined, the DDX won't get - told of the pointer warp so we reposition it here */ - if(!syncEvents.playingEvents) - (*pSprite->screen->SetCursorPosition)( - pDev, - pSprite->screen, - pSprite->hotPhys.x + screenInfo.screens[0]->x - - pSprite->screen->x, - pSprite->hotPhys.y + screenInfo.screens[0]->y - - pSprite->screen->y, FALSE); - } - } else -#endif - if (newScreen != pSprite->hotPhys.pScreen) - ConfineCursorToWindow(pDev, newScreen->root, TRUE, FALSE); -} - -#ifdef PANORAMIX - -static Bool -XineramaPointInWindowIsVisible( - WindowPtr pWin, - int x, - int y -) -{ - BoxRec box; - int i, xoff, yoff; - - if (!pWin->realized) return FALSE; - - if (RegionContainsPoint(&pWin->borderClip, x, y, &box)) - return TRUE; - - if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE; - - xoff = x + screenInfo.screens[0]->x; - yoff = y + screenInfo.screens[0]->y; - - for(i = 1; i < PanoramiXNumScreens; i++) { - pWin = inputInfo.pointer->spriteInfo->sprite->windows[i]; - x = xoff - screenInfo.screens[i]->x; - y = yoff - screenInfo.screens[i]->y; - - if(RegionContainsPoint(&pWin->borderClip, x, y, &box) - && (!wInputShape(pWin) || - RegionContainsPoint(wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box))) - return TRUE; - - } - - return FALSE; -} - -static int -XineramaWarpPointer(ClientPtr client) -{ - WindowPtr dest = NULL; - int x, y, rc; - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; - - REQUEST(xWarpPointerReq); - - - if (stuff->dstWid != None) { - rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess); - if (rc != Success) - return rc; - } - x = pSprite->hotPhys.x; - y = pSprite->hotPhys.y; - - if (stuff->srcWid != None) - { - int winX, winY; - XID winID = stuff->srcWid; - WindowPtr source; - - rc = dixLookupWindow(&source, winID, client, DixReadAccess); - if (rc != Success) - return rc; - - winX = source->drawable.x; - winY = source->drawable.y; - if(source == screenInfo.screens[0]->root) { - winX -= screenInfo.screens[0]->x; - winY -= screenInfo.screens[0]->y; - } - if (x < winX + stuff->srcX || - y < winY + stuff->srcY || - (stuff->srcWidth != 0 && - winX + stuff->srcX + (int)stuff->srcWidth < x) || - (stuff->srcHeight != 0 && - winY + stuff->srcY + (int)stuff->srcHeight < y) || - !XineramaPointInWindowIsVisible(source, x, y)) - return Success; - } - if (dest) { - x = dest->drawable.x; - y = dest->drawable.y; - if(dest == screenInfo.screens[0]->root) { - x -= screenInfo.screens[0]->x; - y -= screenInfo.screens[0]->y; - } - } - - x += stuff->dstX; - y += stuff->dstY; - - if (x < pSprite->physLimits.x1) - x = pSprite->physLimits.x1; - else if (x >= pSprite->physLimits.x2) - x = pSprite->physLimits.x2 - 1; - if (y < pSprite->physLimits.y1) - y = pSprite->physLimits.y1; - else if (y >= pSprite->physLimits.y2) - y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y); - - XineramaSetCursorPosition(PickPointer(client), x, y, TRUE); - - return Success; -} - -#endif - - -/** - * Server-side protocol handling for WarpPointer request. - * Warps the cursor position to the coordinates given in the request. - */ -int -ProcWarpPointer(ClientPtr client) -{ - WindowPtr dest = NULL; - int x, y, rc; - ScreenPtr newScreen; - DeviceIntPtr dev, tmp; - SpritePtr pSprite; - - REQUEST(xWarpPointerReq); - REQUEST_SIZE_MATCH(xWarpPointerReq); - - dev = PickPointer(client); - - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) { - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); - if (rc != Success) - return rc; - } - } - - if (dev->u.lastSlave) - dev = dev->u.lastSlave; - pSprite = dev->spriteInfo->sprite; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) - return XineramaWarpPointer(client); -#endif - - if (stuff->dstWid != None) { - rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - } - x = pSprite->hotPhys.x; - y = pSprite->hotPhys.y; - - if (stuff->srcWid != None) - { - int winX, winY; - XID winID = stuff->srcWid; - WindowPtr source; - - rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - winX = source->drawable.x; - winY = source->drawable.y; - if (source->drawable.pScreen != pSprite->hotPhys.pScreen || - x < winX + stuff->srcX || - y < winY + stuff->srcY || - (stuff->srcWidth != 0 && - winX + stuff->srcX + (int)stuff->srcWidth < x) || - (stuff->srcHeight != 0 && - winY + stuff->srcY + (int)stuff->srcHeight < y) || - !PointInWindowIsVisible(source, x, y)) - return Success; - } - if (dest) - { - x = dest->drawable.x; - y = dest->drawable.y; - newScreen = dest->drawable.pScreen; - } else - newScreen = pSprite->hotPhys.pScreen; - - x += stuff->dstX; - y += stuff->dstY; - - if (x < 0) - x = 0; - else if (x >= newScreen->width) - x = newScreen->width - 1; - if (y < 0) - y = 0; - else if (y >= newScreen->height) - y = newScreen->height - 1; - - if (newScreen == pSprite->hotPhys.pScreen) - { - if (x < pSprite->physLimits.x1) - x = pSprite->physLimits.x1; - else if (x >= pSprite->physLimits.x2) - x = pSprite->physLimits.x2 - 1; - if (y < pSprite->physLimits.y1) - y = pSprite->physLimits.y1; - else if (y >= pSprite->physLimits.y2) - y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(dev, pSprite->hotShape, &x, &y); - (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE); - } - else if (!PointerConfinedToScreen(dev)) - { - NewCurrentScreen(dev, newScreen, x, y); - } - return Success; -} - -static Bool -BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) -{ - if(RegionNotEmpty(&pWin->borderSize)) - return TRUE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) { - int i; - - for(i = 1; i < PanoramiXNumScreens; i++) { - if(RegionNotEmpty(&pDev->spriteInfo->sprite->windows[i]->borderSize)) - return TRUE; - } - } -#endif - return FALSE; -} - -/** - * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a - * passive grab set on the window to be activated. - * If a passive grab is activated, the event will be delivered to the client. - * - * @param pWin The window that may be subject to a passive grab. - * @param device Device that caused the event. - * @param event The current device event. - * @param checkCore Check for core grabs too. - */ - -static Bool -CheckPassiveGrabsOnWindow( - WindowPtr pWin, - DeviceIntPtr device, - DeviceEvent *event, - BOOL checkCore) -{ - GrabPtr grab = wPassiveGrabs(pWin); - GrabRec tempGrab; - GrabInfoPtr grabinfo; -#define CORE_MATCH 0x1 -#define XI_MATCH 0x2 -#define XI2_MATCH 0x4 - int match = 0; - - if (!grab) - return FALSE; - /* Fill out the grab details, but leave the type for later before - * comparing */ - tempGrab.window = pWin; - tempGrab.device = device; - tempGrab.detail.exact = event->detail.key; - tempGrab.detail.pMask = NULL; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.next = NULL; - for (; grab; grab = grab->next) - { - DeviceIntPtr gdev; - XkbSrvInfoPtr xkbi = NULL; - - gdev= grab->modifierDevice; - if (grab->grabtype == GRABTYPE_CORE) - { - if (IsPointerDevice(device)) - gdev = GetPairedDevice(device); - else - gdev = device; - } else if (grab->grabtype == GRABTYPE_XI2) - { - /* if the device is an attached slave device, gdev must be the - * attached master keyboard. Since the slave may have been - * reattached after the grab, the modifier device may not be the - * same. */ - if (!IsMaster(grab->device) && device->u.master) - gdev = GetMaster(device, MASTER_KEYBOARD); - } - - - if (gdev && gdev->key) - xkbi= gdev->key->xkbInfo; - tempGrab.modifierDevice = grab->modifierDevice; - tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; - - /* Check for XI2 and XI grabs first */ - tempGrab.type = GetXI2Type((InternalEvent*)event); - tempGrab.grabtype = GRABTYPE_XI2; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) - match = XI2_MATCH; - - tempGrab.detail.exact = event->detail.key; - if (!match) - { - tempGrab.type = GetXIType((InternalEvent*)event); - tempGrab.grabtype = GRABTYPE_XI; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) - match = XI_MATCH; - } - - /* Check for a core grab (ignore the device when comparing) */ - if (!match && checkCore) - { - tempGrab.grabtype = GRABTYPE_CORE; - if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && - (GrabMatchesSecond(&tempGrab, grab, TRUE))) - match = CORE_MATCH; - } - - if (match && (!grab->confineTo || - (grab->confineTo->realized && - BorderSizeNotEmpty(device, grab->confineTo)))) - { - int rc, count = 0; - xEvent *xE = NULL; - xEvent core; - - event->corestate &= 0x1f00; - event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); - grabinfo = &device->deviceGrab; - /* In some cases a passive core grab may exist, but the client - * already has a core grab on some other device. In this case we - * must not get the grab, otherwise we may never ungrab the - * device. - */ - - if (grab->grabtype == GRABTYPE_CORE) - { - DeviceIntPtr other; - BOOL interfering = FALSE; - - /* A passive grab may have been created for a different device - than it is assigned to at this point in time. - Update the grab's device and modifier device to reflect the - current state. - Since XGrabDeviceButton requires to specify the - modifierDevice explicitly, we don't override this choice. - */ - if (tempGrab.type < GenericEvent) - { - grab->device = device; - grab->modifierDevice = GetPairedDevice(device); - } - - for (other = inputInfo.devices; other; other = other->next) - { - GrabPtr othergrab = other->deviceGrab.grab; - if (othergrab && othergrab->grabtype == GRABTYPE_CORE && - SameClient(grab, rClient(othergrab)) && - ((IsPointerDevice(grab->device) && - IsPointerDevice(othergrab->device)) || - (IsKeyboardDevice(grab->device) && - IsKeyboardDevice(othergrab->device)))) - { - interfering = TRUE; - break; - } - } - if (interfering) - continue; - } - - - if (match & CORE_MATCH) - { - rc = EventToCore((InternalEvent*)event, &core); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - xE = &core; - count = 1; - } else if (match & XI2_MATCH) - { - rc = EventToXI2((InternalEvent*)event, &xE); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - count = 1; - } else - { - rc = EventToXI((InternalEvent*)event, &xE, &count); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - } - - (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); - - if (xE) - { - FixUpEventFromWindow(device, xE, grab->window, None, TRUE); - - TryClientEvents(rClient(grab), device, xE, count, - GetEventFilter(device, xE), - GetEventFilter(device, xE), grab); - } - - if (grabinfo->sync.state == FROZEN_NO_EVENT) - { - if (!grabinfo->sync.event) - grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); - *grabinfo->sync.event = *event; - grabinfo->sync.state = FROZEN_WITH_EVENT; - } - - if (match & (XI_MATCH | XI2_MATCH)) - free(xE); /* on core match xE == &core */ - return TRUE; - } - } - return FALSE; -#undef CORE_MATCH -#undef XI_MATCH -#undef XI2_MATCH -} - -/** - * CheckDeviceGrabs handles both keyboard and pointer events that may cause - * a passive grab to be activated. - * - * If the event is a keyboard event, the ancestors of the focus window are - * traced down and tried to see if they have any passive grabs to be - * activated. If the focus window itself is reached and it's descendants - * contain the pointer, the ancestors of the window that the pointer is in - * are then traced down starting at the focus window, otherwise no grabs are - * activated. - * If the event is a pointer event, the ancestors of the window that the - * pointer is in are traced down starting at the root until CheckPassiveGrabs - * causes a passive grab to activate or all the windows are - * tried. PRH - * - * If a grab is activated, the event has been sent to the client already! - * - * The event we pass in must always be an XI event. From this, we then emulate - * the core event and then check for grabs. - * - * @param device The device that caused the event. - * @param xE The event to handle (Device{Button|Key}Press). - * @param count Number of events in list. - * @return TRUE if a grab has been activated or false otherwise. -*/ - -Bool -CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) -{ - int i; - WindowPtr pWin = NULL; - FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; - BOOL sendCore = (IsMaster(device) && device->coreEvents); - - if (event->type != ET_ButtonPress && - event->type != ET_KeyPress) - return FALSE; - - if (event->type == ET_ButtonPress - && (device->button->buttonsDown != 1)) - return FALSE; - - if (device->deviceGrab.grab) - return FALSE; - - i = 0; - if (ancestor) - { - while (i < device->spriteInfo->sprite->spriteTraceGood) - if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor) - break; - if (i == device->spriteInfo->sprite->spriteTraceGood) - return FALSE; - } - - if (focus) - { - for (; i < focus->traceGood; i++) - { - pWin = focus->trace[i]; - if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore)) - return TRUE; - } - - if ((focus->win == NoneWin) || - (i >= device->spriteInfo->sprite->spriteTraceGood) || - (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i-1])) - return FALSE; - } - - for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) - { - pWin = device->spriteInfo->sprite->spriteTrace[i]; - if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore)) - return TRUE; - } - - return FALSE; -} - -/** - * Called for keyboard events to deliver event to whatever client owns the - * focus. - * - * The event is delivered to the keyboard's focus window, the root window or - * to the window owning the input focus. - * - * @param keybd The keyboard originating the event. - * @param event The event, not yet in wire format. - * @param window Window underneath the sprite. - */ -void -DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) -{ - DeviceIntPtr ptr; - WindowPtr focus = keybd->focus->win; - BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); - xEvent core; - xEvent *xE = NULL, *xi2 = NULL; - int count, rc; - int deliveries = 0; - - if (focus == FollowKeyboardWin) - focus = inputInfo.keyboard->focus->win; - if (!focus) - return; - if (focus == PointerRootWin) - { - DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); - return; - } - if ((focus == window) || IsParent(focus, window)) - { - if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) - return; - } - - /* just deliver it to the focus window */ - ptr = GetPairedDevice(keybd); - - - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - /* XXX: XACE */ - int filter = GetEventFilter(keybd, xi2); - FixUpEventFromWindow(ptr, xi2, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, - filter, NullGrab); - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - - rc = EventToXI(event, &xE, &count); - if (rc == Success && - XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) - { - FixUpEventFromWindow(ptr, xE, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xE, count, - GetEventFilter(keybd, xE), - NullGrab); - - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - - if (sendCore) - { - rc = EventToCore(event, &core); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) { - FixUpEventFromWindow(keybd, &core, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, - GetEventFilter(keybd, &core), - NullGrab); - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - } - -unwind: - free(xE); - free(xi2); - return; -} - -/** - * Deliver an event from a device that is currently grabbed. Uses - * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the - * grab. If not, TryClientEvents() is used. - * - * @param deactivateGrab True if the device's grab should be deactivated. - */ -void -DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, - Bool deactivateGrab) -{ - GrabPtr grab; - GrabInfoPtr grabinfo; - int deliveries = 0; - DeviceIntPtr dev; - SpritePtr pSprite = thisDev->spriteInfo->sprite; - BOOL sendCore = FALSE; - int rc, count = 0; - xEvent *xi = NULL; - xEvent *xi2 = NULL; - - grabinfo = &thisDev->deviceGrab; - grab = grabinfo->grab; - - if (grab->ownerEvents) - { - WindowPtr focus; - - /* Hack: Some pointer device have a focus class. So we need to check - * for the type of event, to see if we really want to deliver it to - * the focus window. For pointer events, the answer is no. - */ - if (IsPointerEvent(event)) - focus = PointerRootWin; - else if (thisDev->focus) - { - focus = thisDev->focus->win; - if (focus == FollowKeyboardWin) - focus = inputInfo.keyboard->focus->win; - } - else - focus = PointerRootWin; - if (focus == PointerRootWin) - deliveries = DeliverDeviceEvents(pSprite->win, event, grab, - NullWindow, thisDev); - else if (focus && (focus == pSprite->win || - IsParent(focus, pSprite->win))) - deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, - thisDev); - else if (focus) - deliveries = DeliverDeviceEvents(focus, event, grab, focus, - thisDev); - } - if (!deliveries) - { - Mask mask; - - /* XXX: In theory, we could pass the internal events through to - * everything and only convert just before hitting the wire. We can't - * do that yet, so DGE is the last stop for internal events. From here - * onwards, we deal with core/XI events. - */ - - mask = grab->eventMask; - - sendCore = (IsMaster(thisDev) && thisDev->coreEvents); - /* try core event */ - if (sendCore && grab->grabtype == GRABTYPE_CORE) - { - xEvent core; - - rc = EventToCore(event, &core); - if (rc == Success) - { - FixUpEventFromWindow(thisDev, &core, grab->window, - None, TRUE); - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, &core, 1) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, &core, 1)) - deliveries = 1; /* don't send, but pretend we did */ - else if (!IsInterferingGrab(rClient(grab), thisDev, &core)) - { - deliveries = TryClientEvents(rClient(grab), thisDev, - &core, 1, mask, - GetEventFilter(thisDev, &core), - grab); - } - } else if (rc != BadMatch) - ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); - } - - if (!deliveries) - { - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - int evtype = ((xGenericEvent*)xi2)->evtype; - mask = grab->xi2mask[XIAllDevices][evtype/8] | - grab->xi2mask[XIAllMasterDevices][evtype/8] | - grab->xi2mask[thisDev->id][evtype/8]; - /* try XI2 event */ - FixUpEventFromWindow(thisDev, xi2, grab->window, None, TRUE); - /* XXX: XACE */ - deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, - GetEventFilter(thisDev, xi2), grab); - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", - thisDev->name, event->any.type, rc); - } - - if (!deliveries) - { - rc = EventToXI(event, &xi, &count); - if (rc == Success) - { - /* try XI event */ - if (grabinfo->fromPassiveGrab && - grabinfo->implicitGrab) - mask = grab->deviceMask; - else - mask = grab->eventMask; - - FixUpEventFromWindow(thisDev, xi, grab->window, - None, TRUE); - - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, xi, count) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, xi, count)) - deliveries = 1; /* don't send, but pretend we did */ - else - { - deliveries = - TryClientEvents(rClient(grab), thisDev, - xi, count, - mask, - GetEventFilter(thisDev, xi), - grab); - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", - thisDev->name, event->any.type, rc); - } - - if (deliveries && (event->any.type == ET_Motion)) - thisDev->valuator->motionHintWindow = grab->window; - } - if (deliveries && !deactivateGrab && event->any.type != ET_Motion) - { - switch (grabinfo->sync.state) - { - case FREEZE_BOTH_NEXT_EVENT: - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev == thisDev) - continue; - FreezeThaw(dev, TRUE); - if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && - (CLIENT_BITS(grab->resource) == - CLIENT_BITS(dev->deviceGrab.grab->resource))) - dev->deviceGrab.sync.state = FROZEN_NO_EVENT; - else - dev->deviceGrab.sync.other = grab; - } - /* fall through */ - case FREEZE_NEXT_EVENT: - grabinfo->sync.state = FROZEN_WITH_EVENT; - FreezeThaw(thisDev, TRUE); - if (!grabinfo->sync.event) - grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); - *grabinfo->sync.event = event->device_event; - break; - } - } - - free(xi); - free(xi2); -} - -/* This function is used to set the key pressed or key released state - - this is only used when the pressing of keys does not cause - the device's processInputProc to be called, as in for example Mouse Keys. -*/ -void -FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) -{ - int key = event->detail.key; - - if (event->type == ET_KeyPress) { - DebugF("FixKeyState: Key %d %s\n",key, - ((event->type == ET_KeyPress) ? "down" : "up")); - } - - if (event->type == ET_KeyPress) - set_key_down(keybd, key, KEY_PROCESSED); - else if (event->type == ET_KeyRelease) - set_key_up(keybd, key, KEY_PROCESSED); - else - FatalError("Impossible keyboard event"); -} - -#define AtMostOneClient \ - (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) -#define ManagerMask \ - (SubstructureRedirectMask | ResizeRedirectMask) - -/** - * Recalculate which events may be deliverable for the given window. - * Recalculated mask is used for quicker determination which events may be - * delivered to a window. - * - * The otherEventMasks on a WindowOptional is the combination of all event - * masks set by all clients on the window. - * deliverableEventMask is the combination of the eventMask and the - * otherEventMask plus the events that may be propagated to the parent. - * - * Traverses to siblings and parents of the window. - */ -void -RecalculateDeliverableEvents(WindowPtr pWin) -{ - OtherClients *others; - WindowPtr pChild; - - pChild = pWin; - while (1) - { - if (pChild->optional) - { - pChild->optional->otherEventMasks = 0; - for (others = wOtherClients(pChild); others; others = others->next) - { - pChild->optional->otherEventMasks |= others->mask; - } - } - pChild->deliverableEvents = pChild->eventMask| - wOtherEventMasks(pChild); - if (pChild->parent) - pChild->deliverableEvents |= - (pChild->parent->deliverableEvents & - ~wDontPropagateMask(pChild) & PropagateMask); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } -} - -/** - * - * \param value must conform to DeleteType - */ -int -OtherClientGone(pointer value, XID id) -{ - OtherClientsPtr other, prev; - WindowPtr pWin = (WindowPtr)value; - - prev = 0; - for (other = wOtherClients(pWin); other; other = other->next) - { - if (other->resource == id) - { - if (prev) - prev->next = other->next; - else - { - if (!(pWin->optional->otherClients = other->next)) - CheckWindowOptionalNeed (pWin); - } - free(other); - RecalculateDeliverableEvents(pWin); - return Success; - } - prev = other; - } - FatalError("client not on event list"); - /*NOTREACHED*/ - return -1; /* make compiler happy */ -} - -int -EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask) -{ - Mask check; - OtherClients * others; - DeviceIntPtr dev; - int rc; - - if (mask & ~AllEventMasks) - { - client->errorValue = mask; - return BadValue; - } - check = (mask & ManagerMask); - if (check) { - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess); - if (rc != Success) - return rc; - } - check = (mask & AtMostOneClient); - if (check & (pWin->eventMask|wOtherEventMasks(pWin))) - { /* It is illegal for two different - clients to select on any of the - events for AtMostOneClient. However, - it is OK, for some client to - continue selecting on one of those - events. */ - if ((wClient(pWin) != client) && (check & pWin->eventMask)) - return BadAccess; - for (others = wOtherClients (pWin); others; others = others->next) - { - if (!SameClient(others, client) && (check & others->mask)) - return BadAccess; - } - } - if (wClient (pWin) == client) - { - check = pWin->eventMask; - pWin->eventMask = mask; - } - else - { - for (others = wOtherClients (pWin); others; others = others->next) - { - if (SameClient(others, client)) - { - check = others->mask; - if (mask == 0) - { - FreeResource(others->resource, RT_NONE); - return Success; - } - else - others->mask = mask; - goto maskSet; - } - } - check = 0; - if (!pWin->optional && !MakeWindowOptional (pWin)) - return BadAlloc; - others = malloc(sizeof(OtherClients)); - if (!others) - return BadAlloc; - others->mask = mask; - others->resource = FakeClientID(client->index); - others->next = pWin->optional->otherClients; - pWin->optional->otherClients = others; - if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin)) - return BadAlloc; - } -maskSet: - if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->valuator && dev->valuator->motionHintWindow == pWin) - dev->valuator->motionHintWindow = NullWindow; - } - } - RecalculateDeliverableEvents(pWin); - return Success; -} - -int -EventSuppressForWindow(WindowPtr pWin, ClientPtr client, - Mask mask, Bool *checkOptional) -{ - int i, free; - - if (mask & ~PropagateMask) - { - client->errorValue = mask; - return BadValue; - } - if (pWin->dontPropagate) - DontPropagateRefCnts[pWin->dontPropagate]--; - if (!mask) - i = 0; - else - { - for (i = DNPMCOUNT, free = 0; --i > 0; ) - { - if (!DontPropagateRefCnts[i]) - free = i; - else if (mask == DontPropagateMasks[i]) - break; - } - if (!i && free) - { - i = free; - DontPropagateMasks[i] = mask; - } - } - if (i || !mask) - { - pWin->dontPropagate = i; - if (i) - DontPropagateRefCnts[i]++; - if (pWin->optional) - { - pWin->optional->dontPropagateMask = mask; - *checkOptional = TRUE; - } - } - else - { - if (!pWin->optional && !MakeWindowOptional (pWin)) - { - if (pWin->dontPropagate) - DontPropagateRefCnts[pWin->dontPropagate]++; - return BadAlloc; - } - pWin->dontPropagate = 0; - pWin->optional->dontPropagateMask = mask; - } - RecalculateDeliverableEvents(pWin); - return Success; -} - -/** - * Assembles an EnterNotify or LeaveNotify and sends it event to the client. - * Uses the paired keyboard to get some additional information. - */ -void -CoreEnterLeaveEvent( - DeviceIntPtr mouse, - int type, - int mode, - int detail, - WindowPtr pWin, - Window child) -{ - xEvent event; - WindowPtr focus; - DeviceIntPtr keybd; - GrabPtr grab = mouse->deviceGrab.grab; - Mask mask; - - keybd = GetPairedDevice(mouse); - - if ((pWin == mouse->valuator->motionHintWindow) && - (detail != NotifyInferior)) - mouse->valuator->motionHintWindow = NullWindow; - if (grab) - { - mask = (pWin == grab->window) ? grab->eventMask : 0; - if (grab->ownerEvents) - mask |= EventMaskForClient(pWin, rClient(grab)); - } - else - { - mask = pWin->eventMask | wOtherEventMasks(pWin); - } - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = type; - event.u.u.detail = detail; - event.u.enterLeave.time = currentTime.milliseconds; - event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x; - event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y; - /* Counts on the same initial structure of crossing & button events! */ - FixUpEventFromWindow(mouse, &event, pWin, None, FALSE); - /* Enter/Leave events always set child */ - event.u.enterLeave.child = child; - event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? - ELFlagSameScreen : 0; - event.u.enterLeave.state = mouse->button ? (mouse->button->state & 0x1f00) : 0; - if (keybd) - event.u.enterLeave.state |= - XkbGrabStateFromRec(&keybd->key->xkbInfo->state); - event.u.enterLeave.mode = mode; - focus = (keybd) ? keybd->focus->win : None; - if ((focus != NoneWin) && - ((pWin == focus) || (focus == PointerRootWin) || - IsParent(focus, pWin))) - event.u.enterLeave.flags |= ELFlagFocus; - - if ((mask & GetEventFilter(mouse, &event))) - { - if (grab) - TryClientEvents(rClient(grab), mouse, &event, 1, mask, - GetEventFilter(mouse, &event), grab); - else - DeliverEventsToWindow(mouse, pWin, &event, 1, - GetEventFilter(mouse, &event), - NullGrab); - } - - if ((type == EnterNotify) && (mask & KeymapStateMask)) - { - xKeymapEvent ke; - ClientPtr client = grab ? rClient(grab) : wClient(pWin); - if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) - memset((char *)&ke.map[0], 0, 31); - else - memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); - - ke.type = KeymapNotify; - if (grab) - TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1, - mask, KeymapStateMask, grab); - else - DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab); - } -} - -void -DeviceEnterLeaveEvent( - DeviceIntPtr mouse, - int sourceid, - int type, - int mode, - int detail, - WindowPtr pWin, - Window child) -{ - GrabPtr grab = mouse->deviceGrab.grab; - xXIEnterEvent *event; - int filter; - int btlen, len, i; - DeviceIntPtr kbd; - - if ((mode == XINotifyPassiveGrab && type == XI_Leave) || - (mode == XINotifyPassiveUngrab && type == XI_Enter)) - return; - - btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; - btlen = bytes_to_int32(btlen); - len = sizeof(xXIEnterEvent) + btlen * 4; - - event = calloc(1, len); - event->type = GenericEvent; - event->extension = IReqCode; - event->evtype = type; - event->length = (len - sizeof(xEvent))/4; - event->buttons_len = btlen; - event->detail = detail; - event->time = currentTime.milliseconds; - event->deviceid = mouse->id; - event->sourceid = sourceid; - event->mode = mode; - event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); - event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(&event[1], i); - - kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL; - if (kbd && kbd->key) - { - event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; - event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; - event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; - - event->group.base_group = kbd->key->xkbInfo->state.base_group; - event->group.latched_group = kbd->key->xkbInfo->state.latched_group; - event->group.locked_group = kbd->key->xkbInfo->state.locked_group; - } - - FixUpEventFromWindow(mouse, (xEvent*)event, pWin, None, FALSE); - - filter = GetEventFilter(mouse, (xEvent*)event); - - if (grab) - { - Mask mask; - mask = grab->xi2mask[XIAllDevices][type/8] | - grab->xi2mask[XIAllMasterDevices][type/8] | - grab->xi2mask[mouse->id][type/8]; - TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, - filter, grab); - } else { - if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) - goto out; - DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, - NullGrab); - } - -out: - free(event); -} - -void -CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) -{ - xEvent event; - - memset(&event, 0, sizeof(xEvent)); - event.u.focus.mode = mode; - event.u.u.type = type; - event.u.u.detail = detail; - event.u.focus.window = pWin->drawable.id; - - DeliverEventsToWindow(dev, pWin, &event, 1, - GetEventFilter(dev, &event), NullGrab); - if ((type == FocusIn) && - ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) - { - xKeymapEvent ke; - ClientPtr client = wClient(pWin); - if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) - memset((char *)&ke.map[0], 0, 31); - else - memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); - - ke.type = KeymapNotify; - DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab); - } -} - -/** - * Set the input focus to the given window. Subsequent keyboard events will be - * delivered to the given window. - * - * Usually called from ProcSetInputFocus as result of a client request. If so, - * the device is the inputInfo.keyboard. - * If called from ProcXSetInputFocus as result of a client xinput request, the - * device is set to the device specified by the client. - * - * @param client Client that requested input focus change. - * @param dev Focus device. - * @param focusID The window to obtain the focus. Can be PointerRoot or None. - * @param revertTo Specifies where the focus reverts to when window becomes - * unviewable. - * @param ctime Specifies the time. - * @param followOK True if pointer is allowed to follow the keyboard. - */ -int -SetInputFocus( - ClientPtr client, - DeviceIntPtr dev, - Window focusID, - CARD8 revertTo, - Time ctime, - Bool followOK) -{ - FocusClassPtr focus; - WindowPtr focusWin; - int mode, rc; - TimeStamp time; - DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */ - - - UpdateCurrentTime(); - if ((revertTo != RevertToParent) && - (revertTo != RevertToPointerRoot) && - (revertTo != RevertToNone) && - ((revertTo != RevertToFollowKeyboard) || !followOK)) - { - client->errorValue = revertTo; - return BadValue; - } - time = ClientTimeToServerTime(ctime); - - if (IsKeyboardDevice(dev)) - keybd = dev; - else - keybd = GetPairedDevice(dev); - - if ((focusID == None) || (focusID == PointerRoot)) - focusWin = (WindowPtr)(long)focusID; - else if ((focusID == FollowKeyboard) && followOK) - { - focusWin = keybd->focus->win; - } - else { - rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess); - if (rc != Success) - return rc; - /* It is a match error to try to set the input focus to an - unviewable window. */ - if(!focusWin->realized) - return BadMatch; - } - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess); - if (rc != Success) - return Success; - - focus = dev->focus; - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, focus->time) == EARLIER)) - return Success; - mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; - if (focus->win == FollowKeyboardWin) - { - if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) - DoFocusEvents(dev, keybd->focus->win, focusWin, mode); - } else - { - if (!ActivateFocusInGrab(dev, focus->win, focusWin)) - DoFocusEvents(dev, focus->win, focusWin, mode); - } - focus->time = time; - focus->revert = revertTo; - if (focusID == FollowKeyboard) - focus->win = FollowKeyboardWin; - else - focus->win = focusWin; - if ((focusWin == NoneWin) || (focusWin == PointerRootWin)) - focus->traceGood = 0; - else - { - int depth = 0; - WindowPtr pWin; - - for (pWin = focusWin; pWin; pWin = pWin->parent) depth++; - if (depth > focus->traceSize) - { - focus->traceSize = depth+1; - focus->trace = realloc(focus->trace, - focus->traceSize * sizeof(WindowPtr)); - } - focus->traceGood = depth; - for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) - focus->trace[depth] = pWin; - } - return Success; -} - -/** - * Server-side protocol handling for SetInputFocus request. - * - * Sets the input focus for the virtual core keyboard. - */ -int -ProcSetInputFocus(ClientPtr client) -{ - DeviceIntPtr kbd = PickKeyboard(client); - REQUEST(xSetInputFocusReq); - - REQUEST_SIZE_MATCH(xSetInputFocusReq); - - return SetInputFocus(client, kbd, stuff->focus, - stuff->revertTo, stuff->time, FALSE); -} - -/** - * Server-side protocol handling for GetInputFocus request. - * - * Sends the current input focus for the client's keyboard back to the - * client. - */ -int -ProcGetInputFocus(ClientPtr client) -{ - DeviceIntPtr kbd = PickKeyboard(client); - xGetInputFocusReply rep; - FocusClassPtr focus = kbd->focus; - int rc; - /* REQUEST(xReq); */ - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess); - if (rc != Success) - return rc; - - memset(&rep, 0, sizeof(xGetInputFocusReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (focus->win == NoneWin) - rep.focus = None; - else if (focus->win == PointerRootWin) - rep.focus = PointerRoot; - else rep.focus = focus->win->drawable.id; - rep.revertTo = focus->revert; - WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for GrabPointer request. - * - * Sets an active grab on the client's ClientPointer and returns success - * status to client. - */ -int -ProcGrabPointer(ClientPtr client) -{ - xGrabPointerReply rep; - DeviceIntPtr device = PickPointer(client); - GrabPtr grab; - GrabMask mask; - WindowPtr confineTo; - CursorPtr oldCursor; - REQUEST(xGrabPointerReq); - TimeStamp time; - int rc; - - REQUEST_SIZE_MATCH(xGrabPointerReq); - UpdateCurrentTime(); - - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - - if (stuff->confineTo == None) - confineTo = NullWindow; - else - { - rc = dixLookupWindow(&confineTo, stuff->confineTo, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - memset(&rep, 0, sizeof(xGrabPointerReply)); - oldCursor = NullCursor; - grab = device->deviceGrab.grab; - - if (grab) - { - if (grab->confineTo && !confineTo) - ConfineCursorToWindow(device, RootWindow(device), FALSE, FALSE); - oldCursor = grab->cursor; - } - - mask.core = stuff->eventMask; - - rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, - stuff->grabWindow, stuff->ownerEvents, stuff->time, - &mask, GRABTYPE_CORE, stuff->cursor, - stuff->confineTo, &rep.status); - if (rc != Success) - return rc; - - if (oldCursor && rep.status == GrabSuccess) - FreeCursor (oldCursor, (Cursor)0); - - time = ClientTimeToServerTime(stuff->time); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for ChangeActivePointerGrab request. - * - * Changes properties of the grab hold by the client. If the client does not - * hold an active grab on the device, nothing happens. - */ -int -ProcChangeActivePointerGrab(ClientPtr client) -{ - DeviceIntPtr device; - GrabPtr grab; - CursorPtr newCursor, oldCursor; - REQUEST(xChangeActivePointerGrabReq); - TimeStamp time; - - REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq); - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - if (stuff->cursor == None) - newCursor = NullCursor; - else - { - int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return rc; - } - } - - device = PickPointer(client); - grab = device->deviceGrab.grab; - - if (!grab) - return Success; - if (!SameClient(grab, client)) - return Success; - time = ClientTimeToServerTime(stuff->time); - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) - return Success; - oldCursor = grab->cursor; - grab->cursor = newCursor; - if (newCursor) - newCursor->refcnt++; - PostNewCursor(device); - if (oldCursor) - FreeCursor(oldCursor, (Cursor)0); - grab->eventMask = stuff->eventMask; - return Success; -} - -/** - * Server-side protocol handling for UngrabPointer request. - * - * Deletes a pointer grab on a device the client has grabbed. - */ -int -ProcUngrabPointer(ClientPtr client) -{ - DeviceIntPtr device = PickPointer(client); - GrabPtr grab; - TimeStamp time; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - UpdateCurrentTime(); - grab = device->deviceGrab.grab; - - time = ClientTimeToServerTime(stuff->id); - if ((CompareTimeStamps(time, currentTime) != LATER) && - (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client)) - (*device->deviceGrab.DeactivateGrab)(device); - return Success; -} - -/** - * Sets a grab on the given device. - * - * Called from ProcGrabKeyboard to work on the client's keyboard. - * Called from ProcXGrabDevice to work on the device specified by the client. - * - * The parameters this_mode and other_mode represent the keyboard_mode and - * pointer_mode parameters of XGrabKeyboard(). - * See man page for details on all the parameters - * - * @param client Client that owns the grab. - * @param dev The device to grab. - * @param this_mode GrabModeSync or GrabModeAsync - * @param other_mode GrabModeSync or GrabModeAsync - * @param status Return code to be returned to the caller. - * - * @returns Success or BadValue. - */ -int -GrabDevice(ClientPtr client, DeviceIntPtr dev, - unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, - unsigned ownerEvents, Time ctime, GrabMask *mask, - int grabtype, Cursor curs, Window confineToWin, CARD8 *status) -{ - WindowPtr pWin, confineTo; - GrabPtr grab; - TimeStamp time; - Mask access_mode = DixGrabAccess; - int rc; - GrabInfoPtr grabInfo = &dev->deviceGrab; - CursorPtr cursor; - - UpdateCurrentTime(); - if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) - { - client->errorValue = keyboard_mode; - return BadValue; - } - if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) - { - client->errorValue = pointer_mode; - return BadValue; - } - if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) - { - client->errorValue = ownerEvents; - return BadValue; - } - - rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - if (confineToWin == None) - confineTo = NullWindow; - else - { - rc = dixLookupWindow(&confineTo, confineToWin, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - if (curs == None) - cursor = NullCursor; - else - { - rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = curs; - return rc; - } - access_mode |= DixForceAccess; - } - - if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - time = ClientTimeToServerTime(ctime); - grab = grabInfo->grab; - if (grab && grab->grabtype != grabtype) - *status = AlreadyGrabbed; - if (grab && !SameClient(grab, client)) - *status = AlreadyGrabbed; - else if ((!pWin->realized) || - (confineTo && - !(confineTo->realized - && BorderSizeNotEmpty(dev, confineTo)))) - *status = GrabNotViewable; - else if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) - *status = GrabInvalidTime; - else if (grabInfo->sync.frozen && - grabInfo->sync.other && !SameClient(grabInfo->sync.other, client)) - *status = GrabFrozen; - else - { - GrabRec tempGrab; - - /* Otherwise segfaults happen on grabbed MPX devices */ - memset(&tempGrab, 0, sizeof(GrabRec)); - - tempGrab.next = NULL; - tempGrab.window = pWin; - tempGrab.resource = client->clientAsMask; - tempGrab.ownerEvents = ownerEvents; - tempGrab.keyboardMode = keyboard_mode; - tempGrab.pointerMode = pointer_mode; - if (grabtype == GRABTYPE_CORE) - tempGrab.eventMask = mask->core; - else if (grabtype == GRABTYPE_XI) - tempGrab.eventMask = mask->xi; - else - memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); - tempGrab.device = dev; - tempGrab.cursor = cursor; - tempGrab.confineTo = confineTo; - tempGrab.grabtype = grabtype; - (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); - *status = GrabSuccess; - } - return Success; -} - -/** - * Server-side protocol handling for GrabKeyboard request. - * - * Grabs the client's keyboard and returns success status to client. - */ -int -ProcGrabKeyboard(ClientPtr client) -{ - xGrabKeyboardReply rep; - REQUEST(xGrabKeyboardReq); - int result; - DeviceIntPtr keyboard = PickKeyboard(client); - GrabMask mask; - - REQUEST_SIZE_MATCH(xGrabKeyboardReq); - - memset(&rep, 0, sizeof(xGrabKeyboardReply)); - mask.core = KeyPressMask | KeyReleaseMask; - - result = GrabDevice(client, keyboard, stuff->pointerMode, - stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, - stuff->time, &mask, GRABTYPE_CORE, None, None, - &rep.status); - - if (result != Success) - return result; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for UngrabKeyboard request. - * - * Deletes a possible grab on the client's keyboard. - */ -int -ProcUngrabKeyboard(ClientPtr client) -{ - DeviceIntPtr device = PickKeyboard(client); - GrabPtr grab; - TimeStamp time; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - UpdateCurrentTime(); - - grab = device->deviceGrab.grab; - - time = ClientTimeToServerTime(stuff->id); - if ((CompareTimeStamps(time, currentTime) != LATER) && - (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) - (*device->deviceGrab.DeactivateGrab)(device); - return Success; -} - -/** - * Server-side protocol handling for QueryPointer request. - * - * Returns the current state and position of the client's ClientPointer to the - * client. - */ -int -ProcQueryPointer(ClientPtr client) -{ - xQueryPointerReply rep; - WindowPtr pWin, t; - DeviceIntPtr mouse = PickPointer(client); - DeviceIntPtr keyboard; - SpritePtr pSprite; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); - if (rc != Success && rc != BadAccess) - return rc; - - keyboard = GetPairedDevice(mouse); - - pSprite = mouse->spriteInfo->sprite; - if (mouse->valuator->motionHintWindow) - MaybeStopHint(mouse, client); - memset(&rep, 0, sizeof(xQueryPointerReply)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.mask = mouse->button ? (mouse->button->state) : 0; - rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); - rep.length = 0; - rep.root = (RootWindow(mouse))->drawable.id; - rep.rootX = pSprite->hot.x; - rep.rootY = pSprite->hot.y; - rep.child = None; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - rep.sameScreen = xTrue; - rep.winX = pSprite->hot.x - pWin->drawable.x; - rep.winY = pSprite->hot.y - pWin->drawable.y; - for (t = pSprite->win; t; t = t->parent) - if (t->parent == pWin) - { - rep.child = t->drawable.id; - break; - } - } - else - { - rep.sameScreen = xFalse; - rep.winX = 0; - rep.winY = 0; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - rep.rootX += screenInfo.screens[0]->x; - rep.rootY += screenInfo.screens[0]->y; - if(stuff->id == rep.root) { - rep.winX += screenInfo.screens[0]->x; - rep.winY += screenInfo.screens[0]->y; - } - } -#endif - - if (rc == BadAccess) { - rep.mask = 0; - rep.child = None; - rep.rootX = 0; - rep.rootY = 0; - rep.winX = 0; - rep.winY = 0; - } - - WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); - - return Success; -} - -/** - * Initializes the device list and the DIX sprite to sane values. Allocates - * trace memory used for quick window traversal. - */ -void -InitEvents(void) -{ - int i; - - inputInfo.numDevices = 0; - inputInfo.devices = (DeviceIntPtr)NULL; - inputInfo.off_devices = (DeviceIntPtr)NULL; - inputInfo.keyboard = (DeviceIntPtr)NULL; - inputInfo.pointer = (DeviceIntPtr)NULL; - /* The mask for pointer motion events may have changed in the last server - * generation. See comment above definition of filters. */ - filters[0][PointerMotionMask] = MotionNotify; - for (i = 1; i < MAXDEVICES; i++) - { - memcpy(&filters[i], filters[0], sizeof(filters[0])); - } - - syncEvents.replayDev = (DeviceIntPtr)NULL; - syncEvents.replayWin = NullWindow; - while (syncEvents.pending) - { - QdEventPtr next = syncEvents.pending->next; - free(syncEvents.pending); - syncEvents.pending = next; - } - syncEvents.pendtail = &syncEvents.pending; - syncEvents.playingEvents = FALSE; - syncEvents.time.months = 0; - syncEvents.time.milliseconds = 0; /* hardly matters */ - currentTime.months = 0; - currentTime.milliseconds = GetTimeInMillis(); - lastDeviceEventTime = currentTime; - for (i = 0; i < DNPMCOUNT; i++) - { - DontPropagateMasks[i] = 0; - DontPropagateRefCnts[i] = 0; - } - - InputEventListLen = GetMaximumEventsNum(); - InputEventList = InitEventList(InputEventListLen); - if (!InputEventList) - FatalError("[dix] Failed to allocate input event list.\n"); -} - -void -CloseDownEvents(void) -{ - FreeEventList(InputEventList, InputEventListLen); - InputEventListLen = 0; - InputEventList = NULL; -} - -/** - * Server-side protocol handling for SendEvent request. - * - * Locates the window to send the event to and forwards the event. - */ -int -ProcSendEvent(ClientPtr client) -{ - WindowPtr pWin; - WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ - DeviceIntPtr dev = PickPointer(client); - DeviceIntPtr keybd = GetPairedDevice(dev); - SpritePtr pSprite = dev->spriteInfo->sprite; - REQUEST(xSendEventReq); - - REQUEST_SIZE_MATCH(xSendEventReq); - - /* The client's event type must be a core event type or one defined by an - extension. */ - - if ( ! ((stuff->event.u.u.type > X_Reply && - stuff->event.u.u.type < LASTEvent) || - (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && - stuff->event.u.u.type < (unsigned)lastEvent))) - { - client->errorValue = stuff->event.u.u.type; - return BadValue; - } - if (stuff->event.u.u.type == ClientMessage && - stuff->event.u.u.detail != 8 && - stuff->event.u.u.detail != 16 && - stuff->event.u.u.detail != 32) - { - client->errorValue = stuff->event.u.u.detail; - return BadValue; - } - if (stuff->eventMask & ~AllEventMasks) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - - if (stuff->destination == PointerWindow) - pWin = pSprite->win; - else if (stuff->destination == InputFocus) - { - WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; - - if (inputFocus == NoneWin) - return Success; - - /* If the input focus is PointerRootWin, send the event to where - the pointer is if possible, then perhaps propogate up to root. */ - if (inputFocus == PointerRootWin) - inputFocus = RootWindow(dev); - - if (IsParent(inputFocus, pSprite->win)) - { - effectiveFocus = inputFocus; - pWin = pSprite->win; - } - else - effectiveFocus = pWin = inputFocus; - } - else - dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess); - - if (!pWin) - return BadWindow; - if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) - { - client->errorValue = stuff->propagate; - return BadValue; - } - stuff->event.u.u.type |= 0x80; - if (stuff->propagate) - { - for (;pWin; pWin = pWin->parent) - { - if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, - &stuff->event, 1)) - return Success; - if (DeliverEventsToWindow(dev, pWin, - &stuff->event, 1, stuff->eventMask, NullGrab)) - return Success; - if (pWin == effectiveFocus) - return Success; - stuff->eventMask &= ~wDontPropagateMask(pWin); - if (!stuff->eventMask) - break; - } - } - else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) - DeliverEventsToWindow(dev, pWin, &stuff->event, - 1, stuff->eventMask, NullGrab); - return Success; -} - -/** - * Server-side protocol handling for UngrabKey request. - * - * Deletes a passive grab for the given key. Works on the - * client's keyboard. - */ -int -ProcUngrabKey(ClientPtr client) -{ - REQUEST(xUngrabKeyReq); - WindowPtr pWin; - GrabRec tempGrab; - DeviceIntPtr keybd = PickKeyboard(client); - int rc; - - REQUEST_SIZE_MATCH(xUngrabKeyReq); - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || - (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) - && (stuff->key != AnyKey)) - { - client->errorValue = stuff->key; - return BadValue; - } - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - tempGrab.resource = client->clientAsMask; - tempGrab.device = keybd; - tempGrab.window = pWin; - tempGrab.modifiersDetail.exact = stuff->modifiers; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = GetPairedDevice(keybd); - tempGrab.type = KeyPress; - tempGrab.grabtype = GRABTYPE_CORE; - tempGrab.detail.exact = stuff->key; - tempGrab.detail.pMask = NULL; - tempGrab.next = NULL; - - if (!DeletePassiveGrabFromList(&tempGrab)) - return BadAlloc; - return Success; -} - -/** - * Server-side protocol handling for GrabKey request. - * - * Creates a grab for the client's keyboard and adds it to the list of passive - * grabs. - */ -int -ProcGrabKey(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xGrabKeyReq); - GrabPtr grab; - DeviceIntPtr keybd = PickKeyboard(client); - int rc; - GrabParameters param; - GrabMask mask; - - REQUEST_SIZE_MATCH(xGrabKeyReq); - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_CORE; - param.ownerEvents = stuff->ownerEvents; - param.this_device_mode = stuff->keyboardMode; - param.other_devices_mode = stuff->pointerMode; - param.modifiers = stuff->modifiers; - - rc = CheckGrabValues(client, ¶m); - if (rc != Success) - return rc; - - if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || - (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) - && (stuff->key != AnyKey)) - { - client->errorValue = stuff->key; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - - mask.core = (KeyPressMask | KeyReleaseMask); - - grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, - ¶m, KeyPress, stuff->key, NullWindow, NullCursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - - -/** - * Server-side protocol handling for GrabButton request. - * - * Creates a grab for the client's ClientPointer and adds it as a passive grab - * to the list. - */ -int -ProcGrabButton(ClientPtr client) -{ - WindowPtr pWin, confineTo; - REQUEST(xGrabButtonReq); - CursorPtr cursor; - GrabPtr grab; - DeviceIntPtr ptr, modifierDevice; - Mask access_mode = DixGrabAccess; - GrabMask mask; - GrabParameters param; - int rc; - - REQUEST_SIZE_MATCH(xGrabButtonReq); - if ((stuff->pointerMode != GrabModeSync) && - (stuff->pointerMode != GrabModeAsync)) - { - client->errorValue = stuff->pointerMode; - return BadValue; - } - if ((stuff->keyboardMode != GrabModeSync) && - (stuff->keyboardMode != GrabModeAsync)) - { - client->errorValue = stuff->keyboardMode; - return BadValue; - } - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) - { - client->errorValue = stuff->ownerEvents; - return BadValue; - } - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (stuff->confineTo == None) - confineTo = NullWindow; - else { - rc = dixLookupWindow(&confineTo, stuff->confineTo, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - if (stuff->cursor == None) - cursor = NullCursor; - else - { - rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return rc; - } - access_mode |= DixForceAccess; - } - - ptr = PickPointer(client); - modifierDevice = GetPairedDevice(ptr); - if (stuff->pointerMode == GrabModeSync || - stuff->keyboardMode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode); - if (rc != Success) - return rc; - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_CORE; - param.ownerEvents = stuff->ownerEvents; - param.this_device_mode = stuff->keyboardMode; - param.other_devices_mode = stuff->pointerMode; - param.modifiers = stuff->modifiers; - - mask.core = stuff->eventMask; - - grab = CreateGrab(client->index, ptr, modifierDevice, pWin, - GRABTYPE_CORE, &mask, ¶m, ButtonPress, - stuff->button, confineTo, cursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/** - * Server-side protocol handling for UngrabButton request. - * - * Deletes a passive grab on the client's ClientPointer from the list. - */ -int -ProcUngrabButton(ClientPtr client) -{ - REQUEST(xUngrabButtonReq); - WindowPtr pWin; - GrabRec tempGrab; - int rc; - DeviceIntPtr ptr; - - REQUEST_SIZE_MATCH(xUngrabButtonReq); - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); - if (rc != Success) - return rc; - - ptr = PickPointer(client); - - tempGrab.resource = client->clientAsMask; - tempGrab.device = ptr; - tempGrab.window = pWin; - tempGrab.modifiersDetail.exact = stuff->modifiers; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = GetPairedDevice(ptr); - tempGrab.type = ButtonPress; - tempGrab.detail.exact = stuff->button; - tempGrab.grabtype = GRABTYPE_CORE; - tempGrab.detail.pMask = NULL; - tempGrab.next = NULL; - - if (!DeletePassiveGrabFromList(&tempGrab)) - return BadAlloc; - return Success; -} - -/** - * Deactivate any grab that may be on the window, remove the focus. - * Delete any XInput extension events from the window too. Does not change the - * window mask. Use just before the window is deleted. - * - * If freeResources is set, passive grabs on the window are deleted. - * - * @param pWin The window to delete events from. - * @param freeResources True if resources associated with the window should be - * deleted. - */ -void -DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) -{ - WindowPtr parent; - DeviceIntPtr mouse = inputInfo.pointer; - DeviceIntPtr keybd = inputInfo.keyboard; - FocusClassPtr focus; - OtherClientsPtr oc; - GrabPtr passive; - GrabPtr grab; - - - /* Deactivate any grabs performed on this window, before making any - input focus changes. */ - grab = mouse->deviceGrab.grab; - if (grab && - ((grab->window == pWin) || (grab->confineTo == pWin))) - (*mouse->deviceGrab.DeactivateGrab)(mouse); - - - /* Deactivating a keyboard grab should cause focus events. */ - grab = keybd->deviceGrab.grab; - if (grab && (grab->window == pWin)) - (*keybd->deviceGrab.DeactivateGrab)(keybd); - - /* And now the real devices */ - for (mouse = inputInfo.devices; mouse; mouse = mouse->next) - { - grab = mouse->deviceGrab.grab; - if (grab && ((grab->window == pWin) || (grab->confineTo == pWin))) - (*mouse->deviceGrab.DeactivateGrab)(mouse); - } - - - for (keybd = inputInfo.devices; keybd; keybd = keybd->next) - { - if (IsKeyboardDevice(keybd)) - { - focus = keybd->focus; - - /* If the focus window is a root window (ie. has no parent) then don't - delete the focus from it. */ - - if ((pWin == focus->win) && (pWin->parent != NullWindow)) - { - int focusEventMode = NotifyNormal; - - /* If a grab is in progress, then alter the mode of focus events. */ - - if (keybd->deviceGrab.grab) - focusEventMode = NotifyWhileGrabbed; - - switch (focus->revert) - { - case RevertToNone: - DoFocusEvents(keybd, pWin, NoneWin, focusEventMode); - focus->win = NoneWin; - focus->traceGood = 0; - break; - case RevertToParent: - parent = pWin; - do - { - parent = parent->parent; - focus->traceGood--; - } while (!parent->realized - /* This would be a good protocol change -- windows being reparented - during SaveSet processing would cause the focus to revert to the - nearest enclosing window which will survive the death of the exiting - client, instead of ending up reverting to a dying window and thence - to None - */ -#ifdef NOTDEF - || wClient(parent)->clientGone -#endif - ); - if (!ActivateFocusInGrab(keybd, pWin, parent)) - DoFocusEvents(keybd, pWin, parent, focusEventMode); - focus->win = parent; - focus->revert = RevertToNone; - break; - case RevertToPointerRoot: - if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) - DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); - focus->win = PointerRootWin; - focus->traceGood = 0; - break; - } - } - } - - if (IsPointerDevice(keybd)) - { - if (keybd->valuator->motionHintWindow == pWin) - keybd->valuator->motionHintWindow = NullWindow; - } - } - - if (freeResources) - { - if (pWin->dontPropagate) - DontPropagateRefCnts[pWin->dontPropagate]--; - while ( (oc = wOtherClients(pWin)) ) - FreeResource(oc->resource, RT_NONE); - while ( (passive = wPassiveGrabs(pWin)) ) - FreeResource(passive->resource, RT_NONE); - } - - DeleteWindowFromAnyExtEvents(pWin, freeResources); -} - -/** - * Call this whenever some window at or below pWin has changed geometry. If - * there is a grab on the window, the cursor will be re-confined into the - * window. - */ -void -CheckCursorConfinement(WindowPtr pWin) -{ - GrabPtr grab; - WindowPtr confineTo; - DeviceIntPtr pDev; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; -#endif - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - grab = pDev->deviceGrab.grab; - if (grab && (confineTo = grab->confineTo)) - { - if (!BorderSizeNotEmpty(pDev, confineTo)) - (*pDev->deviceGrab.DeactivateGrab)(pDev); - else if ((pWin == confineTo) || IsParent(pWin, confineTo)) - ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE); - } - } - } -} - -Mask -EventMaskForClient(WindowPtr pWin, ClientPtr client) -{ - OtherClientsPtr other; - - if (wClient (pWin) == client) - return pWin->eventMask; - for (other = wOtherClients(pWin); other; other = other->next) - { - if (SameClient(other, client)) - return other->mask; - } - return 0; -} - -/** - * Server-side protocol handling for RecolorCursor request. - */ -int -ProcRecolorCursor(ClientPtr client) -{ - CursorPtr pCursor; - int rc, nscr; - ScreenPtr pscr; - Bool displayed; - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; - REQUEST(xRecolorCursorReq); - - REQUEST_SIZE_MATCH(xRecolorCursorReq); - rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, - client, DixWriteAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return rc; - } - - pCursor->foreRed = stuff->foreRed; - pCursor->foreGreen = stuff->foreGreen; - pCursor->foreBlue = stuff->foreBlue; - - pCursor->backRed = stuff->backRed; - pCursor->backGreen = stuff->backGreen; - pCursor->backBlue = stuff->backBlue; - - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) - { - pscr = screenInfo.screens[nscr]; -#ifdef PANORAMIX - if(!noPanoramiXExtension) - displayed = (pscr == pSprite->screen); - else -#endif - displayed = (pscr == pSprite->hotPhys.pScreen); - ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor, - (pCursor == pSprite->current) && displayed); - } - return Success; -} - -/** - * Write the given events to a client, swapping the byte order if necessary. - * To swap the byte ordering, a callback is called that has to be set up for - * the given event type. - * - * In the case of DeviceMotionNotify trailed by DeviceValuators, the events - * can be more than one. Usually it's just one event. - * - * Do not modify the event structure passed in. See comment below. - * - * @param pClient Client to send events to. - * @param count Number of events. - * @param events The event list. - */ -void -WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) -{ -#ifdef PANORAMIX - xEvent eventCopy; -#endif - xEvent *eventTo, *eventFrom; - int i, - eventlength = sizeof(xEvent); - - if (!pClient || pClient == serverClient || pClient->clientGone) - return; - - for (i = 0; i < count; i++) - if ((events[i].u.u.type & 0x7f) != KeymapNotify) - events[i].u.u.sequenceNumber = pClient->sequence; - - /* Let XKB rewrite the state, as it depends on client preferences. */ - XkbFilterEvents(pClient, count, events); - -#ifdef PANORAMIX - if(!noPanoramiXExtension && - (screenInfo.screens[0]->x || screenInfo.screens[0]->y)) - { - switch(events->u.u.type) { - case MotionNotify: - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - case EnterNotify: - case LeaveNotify: - /* - When multiple clients want the same event DeliverEventsToWindow - passes the same event structure multiple times so we can't - modify the one passed to us - */ - count = 1; /* should always be 1 */ - memcpy(&eventCopy, events, sizeof(xEvent)); - eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x; - eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y; - if(eventCopy.u.keyButtonPointer.event == - eventCopy.u.keyButtonPointer.root) - { - eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x; - eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y; - } - events = &eventCopy; - break; - default: break; - } - } -#endif - - if (EventCallback) - { - EventInfoRec eventinfo; - eventinfo.client = pClient; - eventinfo.events = events; - eventinfo.count = count; - CallCallbacks(&EventCallback, (pointer)&eventinfo); - } -#ifdef XSERVER_DTRACE - if (XSERVER_SEND_EVENT_ENABLED()) { - for (i = 0; i < count; i++) - { - XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]); - } - } -#endif - /* Just a safety check to make sure we only have one GenericEvent, it just - * makes things easier for me right now. (whot) */ - for (i = 1; i < count; i++) - { - if (events[i].u.u.type == GenericEvent) - { - ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n"); - return; - } - } - - if (events->u.u.type == GenericEvent) - { - eventlength += ((xGenericEvent*)events)->length * 4; - } - - if(pClient->swapped) - { - if (eventlength > swapEventLen) - { - swapEventLen = eventlength; - swapEvent = realloc(swapEvent, swapEventLen); - if (!swapEvent) - { - FatalError("WriteEventsToClient: Out of memory.\n"); - return; - } - } - - for(i = 0; i < count; i++) - { - eventFrom = &events[i]; - eventTo = swapEvent; - - /* Remember to strip off the leading bit of type in case - this event was sent with "SendEvent." */ - (*EventSwapVector[eventFrom->u.u.type & 0177]) - (eventFrom, eventTo); - - WriteToClient(pClient, eventlength, (char *)eventTo); - } - } - else - { - /* only one GenericEvent, remember? that means either count is 1 and - * eventlength is arbitrary or eventlength is 32 and count doesn't - * matter. And we're all set. Woohoo. */ - WriteToClient(pClient, count * eventlength, (char *) events); - } -} - -/* - * Set the client pointer for the given client. - * - * A client can have exactly one ClientPointer. Each time a - * request/reply/event is processed and the choice of devices is ambiguous - * (e.g. QueryPointer request), the server will pick the ClientPointer (see - * PickPointer()). - * If a keyboard is needed, the first keyboard paired with the CP is used. - */ -int -SetClientPointer(ClientPtr client, DeviceIntPtr device) -{ - int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); - if (rc != Success) - return rc; - - if (!IsMaster(device)) - { - ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); - return BadDevice; - } else if (!device->spriteInfo->spriteOwner) - { - ErrorF("[dix] Device %d does not have a sprite. " - "Cannot be ClientPointer\n", device->id); - return BadDevice; - } - client->clientPtr = device; - return Success; -} - -/* PickPointer will pick an appropriate pointer for the given client. - * - * An "appropriate device" is (in order of priority): - * 1) A device the given client has a core grab on. - * 2) A device set as ClientPointer for the given client. - * 3) The first master device. - */ -DeviceIntPtr -PickPointer(ClientPtr client) -{ - DeviceIntPtr it = inputInfo.devices; - - /* First, check if the client currently has a grab on a device. Even - * keyboards count. */ - for(it = inputInfo.devices; it; it = it->next) - { - GrabPtr grab = it->deviceGrab.grab; - if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) - { - it = GetMaster(it, MASTER_POINTER); - return it; /* Always return a core grabbed device */ - } - } - - if (!client->clientPtr) - { - DeviceIntPtr it = inputInfo.devices; - while (it) - { - if (IsMaster(it) && it->spriteInfo->spriteOwner) - { - client->clientPtr = it; - break; - } - it = it->next; - } - } - return client->clientPtr; -} - -/* PickKeyboard will pick an appropriate keyboard for the given client by - * searching the list of devices for the keyboard device that is paired with - * the client's pointer. - */ -DeviceIntPtr -PickKeyboard(ClientPtr client) -{ - DeviceIntPtr ptr = PickPointer(client); - DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); - - if (!kbd) - { - ErrorF("[dix] ClientPointer not paired with a keyboard. This " - "is a bug.\n"); - } - - return kbd; -} - -/* A client that has one or more core grabs does not get core events from - * devices it does not have a grab on. Legacy applications behave bad - * otherwise because they are not used to it and the events interfere. - * Only applies for core events. - * - * Return true if a core event from the device would interfere and should not - * be delivered. - */ -Bool -IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) -{ - DeviceIntPtr it = inputInfo.devices; - - switch(event->u.u.type) - { - case KeyPress: - case KeyRelease: - case ButtonPress: - case ButtonRelease: - case MotionNotify: - case EnterNotify: - case LeaveNotify: - break; - default: - return FALSE; - } - - if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - return FALSE; - - while(it) - { - if (it != dev) - { - if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client) - && !it->deviceGrab.fromPassiveGrab) - { - if ((IsPointerDevice(it) && IsPointerDevice(dev)) || - (IsKeyboardDevice(it) && IsKeyboardDevice(dev))) - return TRUE; - } - } - it = it->next; - } - - return FALSE; -} - +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/* + * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** @file events.c + * This file handles event delivery and a big part of the server-side protocol + * handling (the parts for input devices). + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "resource.h" +#include +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" + +#include "dixstruct.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "globals.h" + +#include +#include "xkbsrv.h" +#include "xace.h" + +#ifdef XSERVER_DTRACE +#include +typedef const char *string; +#include "Xserver-dtrace.h" +#endif + +#include +#include +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "exglobals.h" +#include "extnsionst.h" + +#include "dixevents.h" +#include "dixgrabs.h" +#include "dispatch.h" + +#include +#include "geext.h" +#include "geint.h" + +#include "eventstr.h" +#include "enterleave.h" +#include "eventconvert.h" + +/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ +#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ +#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) +#define AllButtonsMask ( \ + Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) +#define MotionMask ( \ + PointerMotionMask | Button1MotionMask | \ + Button2MotionMask | Button3MotionMask | Button4MotionMask | \ + Button5MotionMask | ButtonMotionMask ) +#define PropagateMask ( \ + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ + MotionMask ) +#define PointerGrabMask ( \ + ButtonPressMask | ButtonReleaseMask | \ + EnterWindowMask | LeaveWindowMask | \ + PointerMotionHintMask | KeymapStateMask | \ + MotionMask ) +#define AllModifiersMask ( \ + ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask ) +#define LastEventMask OwnerGrabButtonMask +#define AllEventMasks (LastEventMask|(LastEventMask-1)) + + +#define CORE_EVENT(event) \ + (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \ + (event)->u.u.type != GenericEvent) +#define XI2_EVENT(event) \ + (((event)->u.u.type == GenericEvent) && \ + ((xGenericEvent*)(event))->extension == IReqCode) + +/** + * Used to indicate a implicit passive grab created by a ButtonPress event. + * See DeliverEventsToWindow(). + */ +#define ImplicitGrabMask (1 << 7) + +#define WID(w) ((w) ? ((w)->drawable.id) : 0) + +#define XE_KBPTR (xE->u.keyButtonPointer) + + +CallbackListPtr EventCallback; +CallbackListPtr DeviceEventCallback; + +#define DNPMCOUNT 8 + +Mask DontPropagateMasks[DNPMCOUNT]; +static int DontPropagateRefCnts[DNPMCOUNT]; + +static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); +static void CheckPhysLimits(DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, + ScreenPtr pScreen); + +/** Key repeat hack. Do not use but in TryClientEvents */ +extern BOOL EventIsKeyRepeat(xEvent *event); + +/** + * Main input device struct. + * inputInfo.pointer + * is the core pointer. Referred to as "virtual core pointer", "VCP", + * "core pointer" or inputInfo.pointer. The VCP is the first master + * pointer device and cannot be deleted. + * + * inputInfo.keyboard + * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard"). + * See inputInfo.pointer. + * + * inputInfo.devices + * linked list containing all devices including VCP and VCK. + * + * inputInfo.off_devices + * Devices that have not been initialized and are thus turned off. + * + * inputInfo.numDevices + * Total number of devices. + * + * inputInfo.all_devices + * Virtual device used for XIAllDevices passive grabs. This device is + * not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + * + * inputInfo.all_master_devices + * Virtual device used for XIAllMasterDevices passive grabs. This device + * is not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + */ +InputInfo inputInfo; + +EventSyncInfoRec syncEvents; + +/** + * The root window the given device is currently on. + */ +#define RootWindow(sprite) sprite->spriteTrace[0] + +static xEvent* swapEvent = NULL; +static int swapEventLen = 0; + +void +NotImplemented(xEvent *from, xEvent *to) +{ + FatalError("Not implemented"); +} + +/** + * Convert the given event type from an XI event to a core event. + * @param[in] The XI 1.x event type. + * @return The matching core event type or 0 if there is none. + */ +int +XItoCoreType(int xitype) +{ + int coretype = 0; + if (xitype == DeviceMotionNotify) + coretype = MotionNotify; + else if (xitype == DeviceButtonPress) + coretype = ButtonPress; + else if (xitype == DeviceButtonRelease) + coretype = ButtonRelease; + else if (xitype == DeviceKeyPress) + coretype = KeyPress; + else if (xitype == DeviceKeyRelease) + coretype = KeyRelease; + + return coretype; +} + +/** + * @return true if the device owns a cursor, false if device shares a cursor + * sprite with another device. + */ +Bool +DevHasCursor(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->spriteOwner; +} + +/* + * @return true if a device is a pointer, check is the same as used by XI to + * fill the 'use' field. + */ +Bool +IsPointerDevice(DeviceIntPtr dev) +{ + return (dev->type == MASTER_POINTER) || + (dev->valuator && dev->button) || + (dev->valuator && !dev->key); +} + +/* + * @return true if a device is a keyboard, check is the same as used by XI to + * fill the 'use' field. + * + * Some pointer devices have keys as well (e.g. multimedia keys). Try to not + * count them as keyboard devices. + */ +Bool +IsKeyboardDevice(DeviceIntPtr dev) +{ + return (dev->type == MASTER_KEYBOARD) || + ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); +} + +Bool +IsMaster(DeviceIntPtr dev) +{ + return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD; +} + +/** + * Max event opcode. + */ +extern int lastEvent; + +extern int DeviceMotionNotify; + +#define CantBeFiltered NoEventMask +/** + * Event masks for each event type. + * + * One set of filters for each device, but only the first layer + * is initialized. The rest is memcpy'd in InitEvents. + * + * Filters are used whether a given event may be delivered to a client, + * usually in the form of if (window-event-mask & filter); then deliver event. + * + * One notable filter is for PointerMotion/DevicePointerMotion events. Each + * time a button is pressed, the filter is modified to also contain the + * matching ButtonXMotion mask. + */ +static Mask filters[MAXDEVICES][128] = { +{ + NoSuchEvent, /* 0 */ + NoSuchEvent, /* 1 */ + KeyPressMask, /* KeyPress */ + KeyReleaseMask, /* KeyRelease */ + ButtonPressMask, /* ButtonPress */ + ButtonReleaseMask, /* ButtonRelease */ + PointerMotionMask, /* MotionNotify (initial state) */ + EnterWindowMask, /* EnterNotify */ + LeaveWindowMask, /* LeaveNotify */ + FocusChangeMask, /* FocusIn */ + FocusChangeMask, /* FocusOut */ + KeymapStateMask, /* KeymapNotify */ + ExposureMask, /* Expose */ + CantBeFiltered, /* GraphicsExpose */ + CantBeFiltered, /* NoExpose */ + VisibilityChangeMask, /* VisibilityNotify */ + SubstructureNotifyMask, /* CreateNotify */ + StructureAndSubMask, /* DestroyNotify */ + StructureAndSubMask, /* UnmapNotify */ + StructureAndSubMask, /* MapNotify */ + SubstructureRedirectMask, /* MapRequest */ + StructureAndSubMask, /* ReparentNotify */ + StructureAndSubMask, /* ConfigureNotify */ + SubstructureRedirectMask, /* ConfigureRequest */ + StructureAndSubMask, /* GravityNotify */ + ResizeRedirectMask, /* ResizeRequest */ + StructureAndSubMask, /* CirculateNotify */ + SubstructureRedirectMask, /* CirculateRequest */ + PropertyChangeMask, /* PropertyNotify */ + CantBeFiltered, /* SelectionClear */ + CantBeFiltered, /* SelectionRequest */ + CantBeFiltered, /* SelectionNotify */ + ColormapChangeMask, /* ColormapNotify */ + CantBeFiltered, /* ClientMessage */ + CantBeFiltered /* MappingNotify */ +}}; + +/** + * For the given event, return the matching event filter. This filter may then + * be AND'ed with the selected event mask. + * + * For XI2 events, the returned filter is simply the byte containing the event + * mask we're interested in. E.g. for a mask of (1 << 13), this would be + * byte[1]. + * + * @param[in] dev The device the event belongs to, may be NULL. + * @param[in] event The event to get the filter for. Only the type of the + * event matters, or the extension + evtype for GenericEvents. + * @return The filter mask for the given event. + * + * @see GetEventMask + */ +Mask +GetEventFilter(DeviceIntPtr dev, xEvent *event) +{ + if (event->u.u.type != GenericEvent) + return filters[dev ? dev->id : 0][event->u.u.type]; + else if (XI2_EVENT(event)) + return (1 << (((xXIDeviceEvent*)event)->evtype % 8)); + ErrorF("[dix] Unknown device type %d. No filter\n", event->u.u.type); + return 0; +} + +/** + * Return the windows complete XI2 mask for the given XI2 event type. + */ +Mask +GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) +{ + OtherInputMasks *inputMasks = wOtherInputMasks(win); + int filter; + int evtype; + + if (!inputMasks || !XI2_EVENT(ev)) + return 0; + + evtype = ((xGenericEvent*)ev)->evtype; + filter = GetEventFilter(dev, ev); + + return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || + inputMasks->xi2mask[XIAllDevices][evtype/8] || + (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); +} + +Mask +GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) +{ + /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ + if (XI2_EVENT(event)) + { + int byte = ((xGenericEvent*)event)->evtype / 8; + return (other->xi2mask[dev->id][byte] | + other->xi2mask[XIAllDevices][byte] | + (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); + } else if (CORE_EVENT(event)) + return other->mask[XIAllDevices]; + else + return other->mask[dev->id]; +} + + +static CARD8 criticalEvents[32] = +{ + 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ +}; + +static void +SyntheticMotion(DeviceIntPtr dev, int x, int y) { + int screenno = 0; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + screenno = dev->spriteInfo->sprite->screen->myNum; +#endif + PostSyntheticMotion(dev, x, y, screenno, + (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); + +} + +#ifdef PANORAMIX +static void PostNewCursor(DeviceIntPtr pDev); + +static Bool +pointOnScreen(ScreenPtr pScreen, int x, int y) +{ + return x >= pScreen->x && x < pScreen->x + pScreen->width && + y >= pScreen->y && y < pScreen->y + pScreen->height; +} + +static Bool +XineramaSetCursorPosition( + DeviceIntPtr pDev, + int x, + int y, + Bool generateEvent +){ + ScreenPtr pScreen; + int i; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + /* x,y are in Screen 0 coordinates. We need to decide what Screen + to send the message too and what the coordinates relative to + that screen are. */ + + pScreen = pSprite->screen; + x += screenInfo.screens[0]->x; + y += screenInfo.screens[0]->y; + + if(!pointOnScreen(pScreen, x, y)) + { + FOR_NSCREENS(i) + { + if(i == pScreen->myNum) + continue; + if(pointOnScreen(screenInfo.screens[i], x, y)) + { + pScreen = screenInfo.screens[i]; + break; + } + } + } + + pSprite->screen = pScreen; + pSprite->hotPhys.x = x - screenInfo.screens[0]->x; + pSprite->hotPhys.y = y - screenInfo.screens[0]->y; + x -= pScreen->x; + y -= pScreen->y; + + return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent); +} + + +static void +XineramaConstrainCursor(DeviceIntPtr pDev) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + ScreenPtr pScreen; + BoxRec newBox; + + pScreen = pSprite->screen; + newBox = pSprite->physLimits; + + /* Translate the constraining box to the screen + the sprite is actually on */ + newBox.x1 += screenInfo.screens[0]->x - pScreen->x; + newBox.x2 += screenInfo.screens[0]->x - pScreen->x; + newBox.y1 += screenInfo.screens[0]->y - pScreen->y; + newBox.y2 += screenInfo.screens[0]->y - pScreen->y; + + (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); +} + + +static Bool +XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if(pWin == screenInfo.screens[0]->root) { + int i; + for (i = 0; i < PanoramiXNumScreens; i++) + pSprite->windows[i] = screenInfo.screens[i]->root; + } else { + PanoramiXRes *win; + int rc, i; + + rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, + XRT_WINDOW, serverClient, DixReadAccess); + if (rc != Success) + return FALSE; + + for(i = 0; i < PanoramiXNumScreens; i++) { + rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, + serverClient, DixReadAccess); + if (rc != Success) /* window is being unmapped */ + return FALSE; + } + } + return TRUE; +} + +static void +XineramaConfineCursorToWindow(DeviceIntPtr pDev, + WindowPtr pWin, + Bool generateEvents) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + RegionCopy(&pSprite->Reg1, + &pSprite->windows[i]->borderSize); + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + + while(i--) { + x = off_x - screenInfo.screens[i]->x; + y = off_y - screenInfo.screens[i]->y; + + if(x || y) + RegionTranslate(&pSprite->Reg1, x, y); + + RegionUnion(&pSprite->Reg1, &pSprite->Reg1, + &pSprite->windows[i]->borderSize); + + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + } + + pSprite->hotLimits = *RegionExtents(&pSprite->Reg1); + + if(RegionNumRects(&pSprite->Reg1) > 1) + pSprite->hotShape = &pSprite->Reg1; + else + pSprite->hotShape = NullRegion; + + pSprite->confined = FALSE; + pSprite->confineWin = (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin; + + CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); +} + +#endif /* PANORAMIX */ + +/** + * Modifies the filter for the given protocol event type to the given masks. + * + * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). + * The latter initialises masks for the matching XI events, it's a once-off + * setting. + * UDS however changes the mask for MotionNotify and DeviceMotionNotify each + * time a button is pressed to include the matching ButtonXMotion mask in the + * filter. + * + * @param[in] deviceid The device to modify the filter for. + * @param[in] mask The new filter mask. + * @param[in] event Protocol event type. + */ +void +SetMaskForEvent(int deviceid, Mask mask, int event) +{ + if (deviceid < 0 || deviceid >= MAXDEVICES) + FatalError("SetMaskForEvent: bogus device id"); + filters[deviceid][event] = mask; +} + +void +SetCriticalEvent(int event) +{ + if (event >= 128) + FatalError("SetCriticalEvent: bogus event number"); + criticalEvents[event >> 3] |= 1 << (event & 7); +} + +void +ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py) +{ + BoxRec box; + int x = *px, y = *py; + int incx = 1, incy = 1; + SpritePtr pSprite; + + pSprite = pDev->spriteInfo->sprite; + if (RegionContainsPoint(shape, x, y, &box)) + return; + box = *RegionExtents(shape); + /* this is rather crude */ + do { + x += incx; + if (x >= box.x2) + { + incx = -1; + x = *px - 1; + } + else if (x < box.x1) + { + incx = 1; + x = *px; + y += incy; + if (y >= box.y2) + { + incy = -1; + y = *py - 1; + } + else if (y < box.y1) + return; /* should never get here! */ + } + } while (!RegionContainsPoint(shape, x, y, &box)); + *px = x; + *py = y; +} + +static void +CheckPhysLimits( + DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, /* unused if PanoramiX on */ + ScreenPtr pScreen) /* unused if PanoramiX on */ +{ + HotSpot new; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (!cursor) + return; + new = pSprite->hotPhys; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + /* I don't care what the DDX has to say about it */ + pSprite->physLimits = pSprite->hotLimits; + else +#endif + { + if (pScreen) + new.pScreen = pScreen; + else + pScreen = new.pScreen; + (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = confineToScreen; + (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); + } + + /* constrain the pointer to those limits */ + if (new.x < pSprite->physLimits.x1) + new.x = pSprite->physLimits.x1; + else + if (new.x >= pSprite->physLimits.x2) + new.x = pSprite->physLimits.x2 - 1; + if (new.y < pSprite->physLimits.y1) + new.y = pSprite->physLimits.y1; + else + if (new.y >= pSprite->physLimits.y2) + new.y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); + if (( +#ifdef PANORAMIX + noPanoramiXExtension && +#endif + (pScreen != pSprite->hotPhys.pScreen)) || + (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) + { +#ifdef PANORAMIX + if (!noPanoramiXExtension) + XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); + else +#endif + { + if (pScreen != pSprite->hotPhys.pScreen) + pSprite->hotPhys = new; + (*pScreen->SetCursorPosition) + (pDev, pScreen, new.x, new.y, generateEvents); + } + if (!generateEvents) + SyntheticMotion(pDev, new.x, new.y); + } + +#ifdef PANORAMIX + /* Tell DDX what the limits are */ + if (!noPanoramiXExtension) + XineramaConstrainCursor(pDev); +#endif +} + +static void +CheckVirtualMotion( + DeviceIntPtr pDev, + QdEventPtr qe, + WindowPtr pWin) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + RegionPtr reg = NULL; + DeviceEvent *ev = NULL; + + if (qe) + { + ev = &qe->event->device_event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + pSprite->hot.pScreen = qe->pScreen; + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; + break; + default: + break; + } + } + if (pWin) + { + BoxRec lims; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + RegionCopy(&pSprite->Reg2, + &pSprite->windows[i]->borderSize); + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + + while(i--) { + x = off_x - screenInfo.screens[i]->x; + y = off_y - screenInfo.screens[i]->y; + + if(x || y) + RegionTranslate(&pSprite->Reg2, x, y); + + RegionUnion(&pSprite->Reg2, &pSprite->Reg2, + &pSprite->windows[i]->borderSize); + + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + } + } else +#endif + { + if (pSprite->hot.pScreen != pWin->drawable.pScreen) + { + pSprite->hot.pScreen = pWin->drawable.pScreen; + pSprite->hot.x = pSprite->hot.y = 0; + } + } + + lims = *RegionExtents(&pWin->borderSize); + if (pSprite->hot.x < lims.x1) + pSprite->hot.x = lims.x1; + else if (pSprite->hot.x >= lims.x2) + pSprite->hot.x = lims.x2 - 1; + if (pSprite->hot.y < lims.y1) + pSprite->hot.y = lims.y1; + else if (pSprite->hot.y >= lims.y2) + pSprite->hot.y = lims.y2 - 1; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (RegionNumRects(&pSprite->Reg2) > 1) + reg = &pSprite->Reg2; + + } else +#endif + { + if (wBoundingShape(pWin)) + reg = &pWin->borderSize; + } + + if (reg) + ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); + + if (qe && ev) + { + qe->pScreen = pSprite->hot.pScreen; + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; + } + } +#ifdef PANORAMIX + if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ +#endif + RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root; +} + +static void +ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (syncEvents.playingEvents) + { + CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); + SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); + } + else + { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + XineramaConfineCursorToWindow(pDev, pWin, generateEvents); + return; + } +#endif + pSprite->hotLimits = *RegionExtents(&pWin->borderSize); + pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize + : NullRegion; + CheckPhysLimits(pDev, pSprite->current, generateEvents, + confineToScreen, pWin->drawable.pScreen); + } +} + +Bool +PointerConfinedToScreen(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->confined; +} + +/** + * Update the sprite cursor to the given cursor. + * + * ChangeToCursor() will display the new cursor and free the old cursor (if + * applicable). If the provided cursor is already the updated cursor, nothing + * happens. + */ +static void +ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + ScreenPtr pScreen; + + if (cursor != pSprite->current) + { + if ((pSprite->current->bits->xhot != cursor->bits->xhot) || + (pSprite->current->bits->yhot != cursor->bits->yhot)) + CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, + (ScreenPtr)NULL); +#ifdef PANORAMIX + /* XXX: is this really necessary?? (whot) */ + if (!noPanoramiXExtension) + pScreen = pSprite->screen; + else +#endif + pScreen = pSprite->hotPhys.pScreen; + + (*pScreen->DisplayCursor)(pDev, pScreen, cursor); + FreeCursor(pSprite->current, (Cursor)0); + pSprite->current = cursor; + pSprite->current->refcnt++; + } +} + +/** + * @returns true if b is a descendent of a + */ +Bool +IsParent(WindowPtr a, WindowPtr b) +{ + for (b = b->parent; b; b = b->parent) + if (b == a) return TRUE; + return FALSE; +} + +/** + * Update the cursor displayed on the screen. + * + * Called whenever a cursor may have changed shape or position. + */ +static void +PostNewCursor(DeviceIntPtr pDev) +{ + WindowPtr win; + GrabPtr grab = pDev->deviceGrab.grab; + SpritePtr pSprite = pDev->spriteInfo->sprite; + CursorPtr pCursor; + + if (syncEvents.playingEvents) + return; + if (grab) + { + if (grab->cursor) + { + ChangeToCursor(pDev, grab->cursor); + return; + } + if (IsParent(grab->window, pSprite->win)) + win = pSprite->win; + else + win = grab->window; + } + else + win = pSprite->win; + for (; win; win = win->parent) + { + if (win->optional) + { + pCursor = WindowGetDeviceCursor(win, pDev); + if (!pCursor && win->optional->cursor != NullCursor) + pCursor = win->optional->cursor; + if (pCursor) + { + ChangeToCursor(pDev, pCursor); + return; + } + } + } +} + + +/** + * @param dev device which you want to know its current root window + * @return root window where dev's sprite is located + */ +WindowPtr +GetCurrentRootWindow(DeviceIntPtr dev) +{ + return RootWindow(dev->spriteInfo->sprite); +} + +/** + * @return window underneath the cursor sprite. + */ +WindowPtr +GetSpriteWindow(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->win; +} + +/** + * @return current sprite cursor. + */ +CursorPtr +GetSpriteCursor(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->current; +} + +/** + * Set x/y current sprite position in screen coordinates. + */ +void +GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + *px = pSprite->hotPhys.x; + *py = pSprite->hotPhys.y; +} + +#ifdef PANORAMIX +int +XineramaGetCursorScreen(DeviceIntPtr pDev) +{ + if(!noPanoramiXExtension) { + return pDev->spriteInfo->sprite->screen->myNum; + } else { + return 0; + } +} +#endif /* PANORAMIX */ + +#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ + +static void +MonthChangedOrBadTime(InternalEvent *ev) +{ + /* If the ddx/OS is careless about not processing timestamped events from + * different sources in sorted order, then it's possible for time to go + * backwards when it should not. Here we ensure a decent time. + */ + if ((currentTime.milliseconds - ev->any.time) > TIMESLOP) + currentTime.months++; + else + ev->any.time = currentTime.milliseconds; +} + +static void +NoticeTime(InternalEvent *ev) +{ + if (ev->any.time < currentTime.milliseconds) + MonthChangedOrBadTime(ev); + currentTime.milliseconds = ev->any.time; + lastDeviceEventTime = currentTime; +} + +void +NoticeEventTime(InternalEvent *ev) +{ + if (!syncEvents.playingEvents) + NoticeTime(ev); +} + +/************************************************************************** + * The following procedures deal with synchronous events * + **************************************************************************/ + +/** + * EnqueueEvent is a device's processInputProc if a device is frozen. + * Instead of delivering the events to the client, the event is tacked onto a + * linked list for later delivery. + */ +void +EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) +{ + QdEventPtr tail = *syncEvents.pendtail; + QdEventPtr qe; + SpritePtr pSprite = device->spriteInfo->sprite; + int eventlen; + DeviceEvent *event = &ev->device_event; + + NoticeTime((InternalEvent*)event); + + /* Fix for key repeating bug. */ + if (device->key != NULL && device->key->xkbInfo != NULL && + event->type == ET_KeyRelease) + AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); + + if (DeviceEventCallback) + { + DeviceEventInfoRec eventinfo; + + /* The RECORD spec says that the root window field of motion events + * must be valid. At this point, it hasn't been filled in yet, so + * we do it here. The long expression below is necessary to get + * the current root window; the apparently reasonable alternative + * GetCurrentRootWindow()->drawable.id doesn't give you the right + * answer on the first motion event after a screen change because + * the data that GetCurrentRootWindow relies on hasn't been + * updated yet. + */ + if (ev->any.type == ET_Motion) + ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id; + + eventinfo.event = ev; + eventinfo.device = device; + CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); + } + + if (event->type == ET_Motion) + { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + event->root_x += pSprite->screen->x - screenInfo.screens[0]->x; + event->root_y += pSprite->screen->y - screenInfo.screens[0]->y; + } +#endif + pSprite->hotPhys.x = event->root_x; + pSprite->hotPhys.y = event->root_y; + /* do motion compression, but not if from different devices */ + if (tail && + (tail->event->any.type == ET_Motion) && + (tail->device == device) && + (tail->pScreen == pSprite->hotPhys.pScreen)) + { + DeviceEvent *tailev = &tail->event->device_event; + tailev->root_x = pSprite->hotPhys.x; + tailev->root_y = pSprite->hotPhys.y; + tailev->time = event->time; + tail->months = currentTime.months; + return; + } + } + + eventlen = event->length; + + qe = malloc(sizeof(QdEventRec) + eventlen); + if (!qe) + return; + qe->next = (QdEventPtr)NULL; + qe->device = device; + qe->pScreen = pSprite->hotPhys.pScreen; + qe->months = currentTime.months; + qe->event = (InternalEvent *)(qe + 1); + memcpy(qe->event, event, eventlen); + if (tail) + syncEvents.pendtail = &tail->next; + *syncEvents.pendtail = qe; +} + +/** + * Run through the list of events queued up in syncEvents. + * For each event do: + * If the device for this event is not frozen anymore, take it and process it + * as usually. + * After that, check if there's any devices in the list that are not frozen. + * If there is none, we're done. If there is at least one device that is not + * frozen, then re-run from the beginning of the event queue. + */ +static void +PlayReleasedEvents(void) +{ + QdEventPtr *prev, qe; + DeviceIntPtr dev; + DeviceIntPtr pDev; + + prev = &syncEvents.pending; + while ( (qe = *prev) ) + { + if (!qe->device->deviceGrab.sync.frozen) + { + *prev = qe->next; + pDev = qe->device; + if (*syncEvents.pendtail == *prev) + syncEvents.pendtail = prev; + if (qe->event->any.type == ET_Motion) + CheckVirtualMotion(pDev, qe, NullWindow); + syncEvents.time.months = qe->months; + syncEvents.time.milliseconds = qe->event->any.time; +#ifdef PANORAMIX + /* Translate back to the sprite screen since processInputProc + will translate from sprite screen to screen 0 upon reentry + to the DIX layer */ + if(!noPanoramiXExtension) { + DeviceEvent *ev = &qe->event->device_event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + ev->root_x += screenInfo.screens[0]->x - + pDev->spriteInfo->sprite->screen->x; + ev->root_y += screenInfo.screens[0]->y - + pDev->spriteInfo->sprite->screen->y; + break; + default: + break; + } + + } +#endif + (*qe->device->public.processInputProc)(qe->event, qe->device); + free(qe); + for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) + ; + if (!dev) + break; + /* Playing the event may have unfrozen another device. */ + /* So to play it safe, restart at the head of the queue */ + prev = &syncEvents.pending; + } + else + prev = &qe->next; + } +} + +/** + * Freeze or thaw the given devices. The device's processing proc is + * switched to either the real processing proc (in case of thawing) or an + * enqueuing processing proc (usually EnqueueEvent()). + * + * @param dev The device to freeze/thaw + * @param frozen True to freeze or false to thaw. + */ +static void +FreezeThaw(DeviceIntPtr dev, Bool frozen) +{ + dev->deviceGrab.sync.frozen = frozen; + if (frozen) + dev->public.processInputProc = dev->public.enqueueInputProc; + else + dev->public.processInputProc = dev->public.realInputProc; +} + +/** + * Unfreeze devices and replay all events to the respective clients. + * + * ComputeFreezes takes the first event in the device's frozen event queue. It + * runs up the sprite tree (spriteTrace) and searches for the window to replay + * the events from. If it is found, it checks for passive grabs one down from + * the window or delivers the events. + */ +static void +ComputeFreezes(void) +{ + DeviceIntPtr replayDev = syncEvents.replayDev; + WindowPtr w; + GrabPtr grab; + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + FreezeThaw(dev, dev->deviceGrab.sync.other || + (dev->deviceGrab.sync.state >= FROZEN)); + if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) + return; + syncEvents.playingEvents = TRUE; + if (replayDev) + { + DeviceEvent* event = replayDev->deviceGrab.sync.event; + + syncEvents.replayDev = (DeviceIntPtr)NULL; + + w = XYToWindow(replayDev->spriteInfo->sprite, + event->root_x, event->root_y); + if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) + { + if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) + DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); + else + DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, + NullWindow, replayDev); + } + } + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.sync.frozen) + { + PlayReleasedEvents(); + break; + } + } + syncEvents.playingEvents = FALSE; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (DevHasCursor(dev)) + { + /* the following may have been skipped during replay, + so do it now */ + if ((grab = dev->deviceGrab.grab) && grab->confineTo) + { + if (grab->confineTo->drawable.pScreen != + dev->spriteInfo->sprite->hotPhys.pScreen) + dev->spriteInfo->sprite->hotPhys.x = + dev->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(dev, + dev->spriteInfo->sprite->hotPhys.pScreen->root, + TRUE, FALSE); + PostNewCursor(dev); + } + } +} + +#ifdef RANDR +void +ScreenRestructured (ScreenPtr pScreen) +{ + GrabPtr grab; + DeviceIntPtr pDev; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (!DevHasCursor(pDev)) + continue; + + /* GrabDevice doesn't have a confineTo field, so we don't need to + * worry about it. */ + if ((grab = pDev->deviceGrab.grab) && grab->confineTo) + { + if (grab->confineTo->drawable.pScreen + != pDev->spriteInfo->sprite->hotPhys.pScreen) + pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(pDev, + pDev->spriteInfo->sprite->hotPhys.pScreen->root, + TRUE, FALSE); + } +} +#endif + +static void +CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) +{ + GrabPtr grab = thisDev->deviceGrab.grab; + DeviceIntPtr dev; + + if (thisMode == GrabModeSync) + thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT; + else + { /* free both if same client owns both */ + thisDev->deviceGrab.sync.state = THAWED; + if (thisDev->deviceGrab.sync.other && + (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) == + CLIENT_BITS(grab->resource))) + thisDev->deviceGrab.sync.other = NullGrab; + } + + if (IsMaster(thisDev)) + { + dev = GetPairedDevice(thisDev); + if (otherMode == GrabModeSync) + dev->deviceGrab.sync.other = grab; + else + { /* free both if same client owns both */ + if (dev->deviceGrab.sync.other && + (CLIENT_BITS(dev->deviceGrab.sync.other->resource) == + CLIENT_BITS(grab->resource))) + dev->deviceGrab.sync.other = NullGrab; + } + } + ComputeFreezes(); +} + +/** + * Save the device's master device id. This needs to be done + * if a client directly grabs a slave device that is attached to a master. For + * the duration of the grab, the device is detached, ungrabbing re-attaches it + * though. + * + * We store the ID of the master device only in case the master disappears + * while the device has a grab. + */ +static void +DetachFromMaster(DeviceIntPtr dev) +{ + if (!dev->u.master) + return; + + dev->saved_master_id = dev->u.master->id; + + AttachDevice(NULL, dev, NULL); +} + +static void +ReattachToOldMaster(DeviceIntPtr dev) +{ + DeviceIntPtr master = NULL; + + if (IsMaster(dev)) + return; + + dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess); + + if (master) + { + AttachDevice(serverClient, dev, master); + dev->saved_master_id = 0; + } +} + +/** + * Activate a pointer grab on the given device. A pointer grab will cause all + * core pointer events of this device to be delivered to the grabbing client only. + * No other device will send core events to the grab client while the grab is + * on, but core events will be sent to other clients. + * Can cause the cursor to change if a grab cursor is set. + * + * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab + * is an implicit grab caused by a ButtonPress event. + * + * @param mouse The device to grab. + * @param grab The grab structure, needs to be setup. + * @param autoGrab True if the grab was caused by a button down event and not + * explicitely by a client. + */ +void +ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, + TimeStamp time, Bool autoGrab) +{ + GrabInfoPtr grabinfo = &mouse->deviceGrab; + WindowPtr oldWin = (grabinfo->grab) ? + grabinfo->grab->window + : mouse->spriteInfo->sprite->win; + Bool isPassive = autoGrab & ~ImplicitGrabMask; + + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) + DetachFromMaster(mouse); + + if (grab->confineTo) + { + if (grab->confineTo->drawable.pScreen + != mouse->spriteInfo->sprite->hotPhys.pScreen) + mouse->spriteInfo->sprite->hotPhys.x = + mouse->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); + } + DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); + mouse->valuator->motionHintWindow = NullWindow; + if (syncEvents.playingEvents) + grabinfo->grabTime = syncEvents.time; + else + grabinfo->grabTime = time; + if (grab->cursor) + grab->cursor->refcnt++; + grabinfo->activeGrab = *grab; + grabinfo->grab = &grabinfo->activeGrab; + grabinfo->fromPassiveGrab = isPassive; + grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; + PostNewCursor(mouse); + CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); +} + +/** + * Delete grab on given device, update the sprite. + * + * Extension devices are set up for ActivateKeyboardGrab(). + */ +void +DeactivatePointerGrab(DeviceIntPtr mouse) +{ + GrabPtr grab = mouse->deviceGrab.grab; + DeviceIntPtr dev; + Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && + mouse->deviceGrab.implicitGrab); + + mouse->valuator->motionHintWindow = NullWindow; + mouse->deviceGrab.grab = NullGrab; + mouse->deviceGrab.sync.state = NOT_GRABBED; + mouse->deviceGrab.fromPassiveGrab = FALSE; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.sync.other == grab) + dev->deviceGrab.sync.other = NullGrab; + } + DoEnterLeaveEvents(mouse, mouse->id, grab->window, + mouse->spriteInfo->sprite->win, NotifyUngrab); + if (grab->confineTo) + ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE); + PostNewCursor(mouse); + if (grab->cursor) + FreeCursor(grab->cursor, (Cursor)0); + + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(mouse); + + ComputeFreezes(); +} + +/** + * Activate a keyboard grab on the given device. + * + * Extension devices have ActivateKeyboardGrab() set as their grabbing proc. + */ +void +ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) +{ + GrabInfoPtr grabinfo = &keybd->deviceGrab; + WindowPtr oldWin; + + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(passive & ImplicitGrabMask) && + !IsMaster(keybd)) + DetachFromMaster(keybd); + + if (grabinfo->grab) + oldWin = grabinfo->grab->window; + else if (keybd->focus) + oldWin = keybd->focus->win; + else + oldWin = keybd->spriteInfo->sprite->win; + if (oldWin == FollowKeyboardWin) + oldWin = keybd->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); + if (syncEvents.playingEvents) + grabinfo->grabTime = syncEvents.time; + else + grabinfo->grabTime = time; + grabinfo->activeGrab = *grab; + grabinfo->grab = &grabinfo->activeGrab; + grabinfo->fromPassiveGrab = passive; + grabinfo->implicitGrab = passive & ImplicitGrabMask; + CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); +} + +/** + * Delete keyboard grab for the given device. + */ +void +DeactivateKeyboardGrab(DeviceIntPtr keybd) +{ + GrabPtr grab = keybd->deviceGrab.grab; + DeviceIntPtr dev; + WindowPtr focusWin = keybd->focus ? keybd->focus->win + : keybd->spriteInfo->sprite->win; + Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && + keybd->deviceGrab.implicitGrab); + + if (focusWin == FollowKeyboardWin) + focusWin = inputInfo.keyboard->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + keybd->deviceGrab.grab = NullGrab; + keybd->deviceGrab.sync.state = NOT_GRABBED; + keybd->deviceGrab.fromPassiveGrab = FALSE; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.sync.other == grab) + dev->deviceGrab.sync.other = NullGrab; + } + DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); + + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(keybd); + + ComputeFreezes(); +} + +void +AllowSome(ClientPtr client, + TimeStamp time, + DeviceIntPtr thisDev, + int newState) +{ + Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; + TimeStamp grabTime; + DeviceIntPtr dev; + GrabInfoPtr devgrabinfo, + grabinfo = &thisDev->deviceGrab; + + thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client); + thisSynced = FALSE; + otherGrabbed = FALSE; + othersFrozen = FALSE; + grabTime = grabinfo->grabTime; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + + if (dev == thisDev) + continue; + if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) + { + if (!(thisGrabbed || otherGrabbed) || + (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER)) + grabTime = devgrabinfo->grabTime; + otherGrabbed = TRUE; + if (grabinfo->sync.other == devgrabinfo->grab) + thisSynced = TRUE; + if (devgrabinfo->sync.state >= FROZEN) + othersFrozen = TRUE; + } + } + if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced)) + return; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabTime) == EARLIER)) + return; + switch (newState) + { + case THAWED: /* Async */ + if (thisGrabbed) + grabinfo->sync.state = THAWED; + if (thisSynced) + grabinfo->sync.other = NullGrab; + ComputeFreezes(); + break; + case FREEZE_NEXT_EVENT: /* Sync */ + if (thisGrabbed) + { + grabinfo->sync.state = FREEZE_NEXT_EVENT; + if (thisSynced) + grabinfo->sync.other = NullGrab; + ComputeFreezes(); + } + break; + case THAWED_BOTH: /* AsyncBoth */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = THAWED; + if (devgrabinfo->sync.other && + SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT; + if (devgrabinfo->sync.other + && SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case NOT_GRABBED: /* Replay */ + if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) + { + if (thisSynced) + grabinfo->sync.other = NullGrab; + syncEvents.replayDev = thisDev; + syncEvents.replayWin = grabinfo->grab->window; + (*grabinfo->DeactivateGrab)(thisDev); + syncEvents.replayDev = (DeviceIntPtr)NULL; + } + break; + case THAW_OTHERS: /* AsyncOthers */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev == thisDev) + continue; + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = THAWED; + if (devgrabinfo->sync.other + && SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + } +} + +/** + * Server-side protocol handling for AllowEvents request. + * + * Release some events from a frozen device. + */ +int +ProcAllowEvents(ClientPtr client) +{ + TimeStamp time; + DeviceIntPtr mouse = NULL; + DeviceIntPtr keybd = NULL; + REQUEST(xAllowEventsReq); + + REQUEST_SIZE_MATCH(xAllowEventsReq); + time = ClientTimeToServerTime(stuff->time); + + mouse = PickPointer(client); + keybd = PickKeyboard(client); + + switch (stuff->mode) + { + case ReplayPointer: + AllowSome(client, time, mouse, NOT_GRABBED); + break; + case SyncPointer: + AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); + break; + case AsyncPointer: + AllowSome(client, time, mouse, THAWED); + break; + case ReplayKeyboard: + AllowSome(client, time, keybd, NOT_GRABBED); + break; + case SyncKeyboard: + AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); + break; + case AsyncKeyboard: + AllowSome(client, time, keybd, THAWED); + break; + case SyncBoth: + AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); + break; + case AsyncBoth: + AllowSome(client, time, keybd, THAWED_BOTH); + break; + default: + client->errorValue = stuff->mode; + return BadValue; + } + return Success; +} + +/** + * Deactivate grabs from any device that has been grabbed by the client. + */ +void +ReleaseActiveGrabs(ClientPtr client) +{ + DeviceIntPtr dev; + Bool done; + + /* XXX CloseDownClient should remove passive grabs before + * releasing active grabs. + */ + do { + done = TRUE; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + { + (*dev->deviceGrab.DeactivateGrab)(dev); + done = FALSE; + } + } + } while (!done); +} + +/************************************************************************** + * The following procedures deal with delivering events * + **************************************************************************/ + +/** + * Deliver the given events to the given client. + * + * More than one event may be delivered at a time. This is the case with + * DeviceMotionNotifies which may be followed by DeviceValuator events. + * + * TryClientEvents() is the last station before actually writing the events to + * the socket. Anything that is not filtered here, will get delivered to the + * client. + * An event is only delivered if + * - mask and filter match up. + * - no other client has a grab on the device that caused the event. + * + * + * @param client The target client to deliver to. + * @param dev The device the event came from. May be NULL. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param mask Event mask as set by the window. + * @param filter Mask based on event type. + * @param grab Possible grab on the device that caused the event. + * + * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the + * client. + */ +int +TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, + int count, Mask mask, Mask filter, GrabPtr grab) +{ + int type; + +#ifdef DEBUG_EVENTS + ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", + pEvents->u.u.type, pEvents->u.u.detail, mask, + client ? client->index : -1, + (client && client->clientGone) ? " (gone)" : ""); +#endif + + if (!client || client == serverClient || client->clientGone) { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered to fake/dead client\n"); +#endif + return 0; + } + + if (filter != CantBeFiltered && !(mask & filter)) + { + #ifdef DEBUG_EVENTS + ErrorF(" filtered\n"); + #endif + return 0; + } + + if (grab && !SameClient(grab, client)) + { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered due to grab\n"); +#endif + return -1; /* don't send, but notify caller */ + } + + type = pEvents->u.u.type; + if (type == MotionNotify) + { + if (mask & PointerMotionHintMask) + { + if (WID(dev->valuator->motionHintWindow) == + pEvents->u.keyButtonPointer.event) + { +#ifdef DEBUG_EVENTS + ErrorF("[dix] \n"); + ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n"); +#endif + return 1; /* don't send, but pretend we did */ + } + pEvents->u.u.detail = NotifyHint; + } + else + { + pEvents->u.u.detail = NotifyNormal; + } + } + else if (type == DeviceMotionNotify) + { + if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, + mask) != 0) + return 1; + } else if (type == KeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + xEvent release = *pEvents; + release.u.u.type = KeyRelease; + WriteEventsToClient(client, 1, &release); +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake core release for repeat)"); +#endif + } else + { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + + } else if (type == DeviceKeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; + release.type = DeviceKeyRelease; +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake xi1 release for repeat)"); +#endif + WriteEventsToClient(client, 1, (xEvent *) &release); + } + else { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + } + + if (BitIsOn(criticalEvents, type)) + { + if (client->smart_priority < SMART_MAX_PRIORITY) + client->smart_priority++; + SetCriticalOutputPending(); + } + + WriteEventsToClient(client, count, pEvents); +#ifdef DEBUG_EVENTS + ErrorF("[dix] delivered\n"); +#endif + return 1; +} + +/** + * Deliver events to a window. At this point, we do not yet know if the event + * actually needs to be delivered. May activate a grab if the event is a + * button press. + * + * Core events are always delivered to the window owner. If the filter is + * something other than CantBeFiltered, the event is also delivered to other + * clients with the matching mask on the window. + * + * More than one event may be delivered at a time. This is the case with + * DeviceMotionNotifies which may be followed by DeviceValuator events. + * + * @param pWin The window that would get the event. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param filter Mask based on event type. + * @param grab Possible grab on the device that caused the event. + * + * @return Number of events delivered to various clients. + */ +int +DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent + *pEvents, int count, Mask filter, GrabPtr grab) +{ + int deliveries = 0, nondeliveries = 0; + int attempt; + InputClients *other; + ClientPtr client = NullClient; + Mask deliveryMask = 0; /* If a grab occurs due to a button press, then + this mask is the mask of the grab. */ + int type = pEvents->u.u.type; + + + /* Deliver to window owner */ + if ((filter == CantBeFiltered) || CORE_EVENT(pEvents)) + { + /* if nobody ever wants to see this event, skip some work */ + if (filter != CantBeFiltered && + !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) + return 0; + + if (IsInterferingGrab(wClient(pWin), pDev, pEvents)) + return 0; + + if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) + /* do nothing */; + else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents, + count, pWin->eventMask, + filter, grab)) ) + { + if (attempt > 0) + { + deliveries++; + client = wClient(pWin); + deliveryMask = pWin->eventMask; + } else + nondeliveries--; + } + } + + /* CantBeFiltered means only window owner gets the event */ + if (filter != CantBeFiltered) + { + if (CORE_EVENT(pEvents)) + other = (InputClients *)wOtherClients(pWin); + else if (XI2_EVENT(pEvents)) + { + OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + /* Has any client selected for the event? */ + if (!GetWindowXI2Mask(pDev, pWin, pEvents)) + return 0; + other = inputMasks->inputClients; + } else { + OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + /* Has any client selected for the event? */ + if (!inputMasks || + !(inputMasks->inputEvents[pDev->id] & filter)) + return 0; + + other = inputMasks->inputClients; + } + + for (; other; other = other->next) + { + Mask mask; + if (IsInterferingGrab(rClient(other), pDev, pEvents)) + continue; + + mask = GetEventMask(pDev, pEvents, other); + + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, + pEvents, count)) + /* do nothing */; + else if ( (attempt = TryClientEvents(rClient(other), pDev, + pEvents, count, + mask, filter, grab)) ) + { + if (attempt > 0) + { + deliveries++; + client = rClient(other); + deliveryMask = mask; + } else + nondeliveries--; + } + } + } + /* + * Note that since core events are delivered first, an implicit grab may + * be activated on a core grab, stopping the XI events. + */ + if ((type == DeviceButtonPress || type == ButtonPress || + ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress))) + && deliveries + && (!grab)) + { + GrabRec tempGrab; + OtherInputMasks *inputMasks; + + memset(&tempGrab, 0, sizeof(GrabRec)); + tempGrab.next = NULL; + tempGrab.device = pDev; + tempGrab.resource = client->clientAsMask; + tempGrab.window = pWin; + tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; + tempGrab.eventMask = deliveryMask; + tempGrab.keyboardMode = GrabModeAsync; + tempGrab.pointerMode = GrabModeAsync; + tempGrab.confineTo = NullWindow; + tempGrab.cursor = NullCursor; + tempGrab.type = type; + if (type == ButtonPress) + tempGrab.grabtype = GRABTYPE_CORE; + else if (type == DeviceButtonPress) + tempGrab.grabtype = GRABTYPE_XI; + else + { + tempGrab.type = ((xGenericEvent*)pEvents)->evtype; + tempGrab.grabtype = GRABTYPE_XI2; + } + + /* get the XI and XI2 device mask */ + inputMasks = wOtherInputMasks(pWin); + tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0; + + if (inputMasks) + memcpy(tempGrab.xi2mask, inputMasks->xi2mask, + sizeof(tempGrab.xi2mask)); + + (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab, + currentTime, TRUE | ImplicitGrabMask); + } + else if ((type == MotionNotify) && deliveries) + pDev->valuator->motionHintWindow = pWin; + else + { + if ((type == DeviceMotionNotify || type == DeviceButtonPress) && + deliveries) + CheckDeviceGrabAndHintWindow (pWin, type, + (deviceKeyButtonPointer*) pEvents, + grab, client, deliveryMask); + } + if (deliveries) + return deliveries; + return nondeliveries; +} + +/* If the event goes to dontClient, don't send it and return 0. if + send works, return 1 or if send didn't work, return 2. + Only works for core events. +*/ + +#ifdef PANORAMIX +static int +XineramaTryClientEventsResult( + ClientPtr client, + GrabPtr grab, + Mask mask, + Mask filter +){ + if ((client) && (client != serverClient) && (!client->clientGone) && + ((filter == CantBeFiltered) || (mask & filter))) + { + if (grab && !SameClient(grab, client)) return -1; + else return 1; + } + return 0; +} +#endif + +/** + * Try to deliver events to the interested parties. + * + * @param pWin The window that would get the event. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param filter Mask based on event type. + * @param dontClient Don't deliver to the dontClient. + */ +int +MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, + int count, Mask filter, ClientPtr dontClient) +{ + OtherClients *other; + + + if (pWin->eventMask & filter) + { + if (wClient(pWin) == dontClient) + return 0; +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return XineramaTryClientEventsResult( + wClient(pWin), NullGrab, pWin->eventMask, filter); +#endif + if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) + return 1; /* don't send, but pretend we did */ + return TryClientEvents(wClient(pWin), NULL, pEvents, count, + pWin->eventMask, filter, NullGrab); + } + for (other = wOtherClients(pWin); other; other = other->next) + { + if (other->mask & filter) + { + if (SameClient(other, dontClient)) + return 0; +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return XineramaTryClientEventsResult( + rClient(other), NullGrab, other->mask, filter); +#endif + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents, + count)) + return 1; /* don't send, but pretend we did */ + return TryClientEvents(rClient(other), NULL, pEvents, count, + other->mask, filter, NullGrab); + } + } + return 2; +} + +static Window FindChildForEvent(SpritePtr pSprite, WindowPtr event) +{ + WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; + Window child = None; + + /* If the search ends up past the root should the child field be + set to none or should the value in the argument be passed + through. It probably doesn't matter since everyone calls + this function with child == None anyway. */ + while (w) + { + /* If the source window is same as event window, child should be + none. Don't bother going all all the way back to the root. */ + + if (w == event) + { + child = None; + break; + } + + if (w->parent == event) + { + child = w->drawable.id; + break; + } + w = w->parent; + } + return child; +} + +/** + * Adjust event fields to comply with the window properties. + * + * @param xE Event to be modified in place + * @param pWin The window to get the information from. + * @param child Child window setting for event (if applicable) + * @param calcChild If True, calculate the child window. + */ +void +FixUpEventFromWindow( + SpritePtr pSprite, + xEvent *xE, + WindowPtr pWin, + Window child, + Bool calcChild) +{ + if (calcChild) + child = FindChildForEvent(pSprite, pWin); + + if (XI2_EVENT(xE)) + { + xXIDeviceEvent* event = (xXIDeviceEvent*)xE; + + if (event->evtype == XI_RawKeyPress || + event->evtype == XI_RawKeyRelease || + event->evtype == XI_RawButtonPress || + event->evtype == XI_RawButtonRelease || + event->evtype == XI_RawMotion || + event->evtype == XI_DeviceChanged || + event->evtype == XI_HierarchyChanged || + event->evtype == XI_PropertyEvent) + return; + + event->root = RootWindow(pSprite)->drawable.id; + event->event = pWin->drawable.id; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); + event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); + event->child = child; + } else + { + event->event_x = 0; + event->event_y = 0; + event->child = None; + } + + if (event->evtype == XI_Enter || event->evtype == XI_Leave || + event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) + ((xXIEnterEvent*)event)->same_screen = + (pSprite->hot.pScreen == pWin->drawable.pScreen); + + } else + { + XE_KBPTR.root = RootWindow(pSprite)->drawable.id; + XE_KBPTR.event = pWin->drawable.id; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + XE_KBPTR.sameScreen = xTrue; + XE_KBPTR.child = child; + XE_KBPTR.eventX = + XE_KBPTR.rootX - pWin->drawable.x; + XE_KBPTR.eventY = + XE_KBPTR.rootY - pWin->drawable.y; + } + else + { + XE_KBPTR.sameScreen = xFalse; + XE_KBPTR.child = None; + XE_KBPTR.eventX = 0; + XE_KBPTR.eventY = 0; + } + } +} + +/** + * Check if a given event is deliverable at all on a given window. + * + * This function only checks if any client wants it, not for a specific + * client. + * + * @param[in] dev The device this event is being sent for. + * @param[in] event The event that is to be sent. + * @param[in] win The current event window. + * + * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and + * ::DONT_PROPAGATE_MASK. + */ +int +EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) +{ + int rc = 0; + int filter = 0; + int type; + OtherInputMasks *inputMasks = wOtherInputMasks(win); + xEvent ev; + + /* XXX: this makes me gag */ + type = GetXI2Type(event); + ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ + ((xGenericEvent*)&ev)->extension = IReqCode; + ((xGenericEvent*)&ev)->evtype = type; + filter = GetEventFilter(dev, &ev); + if (type && inputMasks && + ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || + ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || + (inputMasks->xi2mask[dev->id][type/8] & filter))) + rc |= XI2_MASK; + + type = GetXIType(event); + ev.u.u.type = type; + filter = GetEventFilter(dev, &ev); + + /* Check for XI mask */ + if (type && inputMasks && + (inputMasks->deliverableEvents[dev->id] & filter) && + (inputMasks->inputEvents[dev->id] & filter)) + rc |= XI_MASK; + + /* Check for XI DontPropagate mask */ + if (type && inputMasks && + (inputMasks->dontPropagateMask[dev->id] & filter)) + rc |= DONT_PROPAGATE_MASK; + + /* Check for core mask */ + type = GetCoreType(event); + if (type && (win->deliverableEvents & filter) && + ((wOtherEventMasks(win) | win->eventMask) & filter)) + rc |= CORE_MASK; + + /* Check for core DontPropagate mask */ + if (type && (filter & wDontPropagateMask(win))) + rc |= DONT_PROPAGATE_MASK; + + return rc; +} + +/** + * Deliver events caused by input devices. + * + * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is + * called directly from the processInputProc. + * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call + * DeliverDeviceEvents. + * For focused events, DeliverFocusedEvent is called first, and _may_ call + * DeliverDeviceEvents. + * + * @param pWin Window to deliver event to. + * @param event The events to deliver, not yet in wire format. + * @param grab Possible grab on a device. + * @param stopAt Don't recurse up to the root window. + * @param dev The device that is responsible for the event. + * + * @see DeliverGrabbedEvent + * @see DeliverFocusedEvent + */ +int +DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, + WindowPtr stopAt, DeviceIntPtr dev) +{ + SpritePtr pSprite = dev->spriteInfo->sprite; + Window child = None; + Mask filter; + int deliveries = 0; + xEvent core; + xEvent *xE = NULL; + int rc, mask, count = 0; + + CHECKEVENT(event); + + while (pWin) + { + if ((mask = EventIsDeliverable(dev, event, pWin))) + { + /* XI2 events first */ + if (mask & XI2_MASK) + { + xEvent *xi2 = NULL; + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + filter = GetEventFilter(dev, xi2); + FixUpEventFromWindow(pSprite, xi2, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, + filter, grab); + free(xi2); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", + dev->name, rc); + } + + /* XI events */ + if (mask & XI_MASK) + { + rc = EventToXI(event, &xE, &count); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { + filter = GetEventFilter(dev, xE); + FixUpEventFromWindow(pSprite, xE, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xE, count, + filter, grab); + if (deliveries > 0) + goto unwind; + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", + dev->name, event->any.type, rc); + } + + /* Core event */ + if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents) + { + rc = EventToCore(event, &core); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) { + filter = GetEventFilter(dev, &core); + FixUpEventFromWindow(pSprite, &core, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, &core, 1, + filter, grab); + if (deliveries > 0) + goto unwind; + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", + dev->name, event->any.type, rc); + } + + if ((deliveries < 0) || (pWin == stopAt) || + (mask & DONT_PROPAGATE_MASK)) + { + deliveries = 0; + goto unwind; + } + } + + child = pWin->drawable.id; + pWin = pWin->parent; + } + +unwind: + free(xE); + return deliveries; +} + +#undef XI_MASK +#undef CORE_MASK +#undef DONT_PROPAGATE_MASK + +/** + * Deliver event to a window and it's immediate parent. Used for most window + * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that + * propagate up the tree or extension events + * + * In case of a ReparentNotify event, the event will be delivered to the + * otherParent as well. + * + * @param pWin Window to deliver events to. + * @param xE Events to deliver. + * @param count number of events in xE. + * @param otherParent Used for ReparentNotify events. + */ +int +DeliverEvents(WindowPtr pWin, xEvent *xE, int count, + WindowPtr otherParent) +{ + Mask filter; + int deliveries; + DeviceIntRec dummy; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return count; +#endif + + if (!count) + return 0; + + dummy.id = XIAllDevices; + filter = GetEventFilter(&dummy, xE); + if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) + xE->u.destroyNotify.event = pWin->drawable.id; + if (filter != StructureAndSubMask) + return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab); + deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, + StructureNotifyMask, NullGrab); + if (pWin->parent) + { + xE->u.destroyNotify.event = pWin->parent->drawable.id; + deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, + SubstructureNotifyMask, NullGrab); + if (xE->u.u.type == ReparentNotify) + { + xE->u.destroyNotify.event = otherParent->drawable.id; + deliveries += DeliverEventsToWindow(&dummy, + otherParent, xE, count, SubstructureNotifyMask, + NullGrab); + } + } + return deliveries; +} + + +static Bool +PointInBorderSize(WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if(RegionContainsPoint(&pWin->borderSize, x, y, &box)) + return TRUE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && + XineramaSetWindowPntrs(inputInfo.pointer, pWin)) { + SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite; + int i; + + for(i = 1; i < PanoramiXNumScreens; i++) { + if(RegionContainsPoint(&pSprite->windows[i]->borderSize, + x + screenInfo.screens[0]->x - screenInfo.screens[i]->x, + y + screenInfo.screens[0]->y - screenInfo.screens[i]->y, + &box)) + return TRUE; + } + } +#endif + return FALSE; +} + +/** + * Traversed from the root window to the window at the position x/y. While + * traversing, it sets up the traversal history in the spriteTrace array. + * After completing, the spriteTrace history is set in the following way: + * spriteTrace[0] ... root window + * spriteTrace[1] ... top level window that encloses x/y + * ... + * spriteTrace[spriteTraceGood - 1] ... window at x/y + * + * @returns the window at the given coordinates. + */ +WindowPtr +XYToWindow(SpritePtr pSprite, int x, int y) +{ + WindowPtr pWin; + BoxRec box; + + pSprite->spriteTraceGood = 1; /* root window still there */ + pWin = RootWindow(pSprite)->firstChild; + while (pWin) + { + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth (pWin)) && + (x < pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth (pWin)) && + (y < pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) +#ifdef ROOTLESS + /* In rootless mode windows may be offscreen, even when + * they're in X's stack. (E.g. if the native window system + * implements some form of virtual desktop system). + */ + && !pWin->rootlessUnhittable +#endif + ) + { + if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) + { + pSprite->spriteTraceSize += 10; + pSprite->spriteTrace = realloc(pSprite->spriteTrace, + pSprite->spriteTraceSize*sizeof(WindowPtr)); + } + pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; +} + +/** + * Ungrab a currently FocusIn grabbed device and grab the device on the + * given window. If the win given is the NoneWin, the device is ungrabbed if + * applicable and FALSE is returned. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +BOOL +ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab) + { + if (!dev->deviceGrab.fromPassiveGrab || + dev->deviceGrab.grab->type != XI_Enter || + dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + if (win == NoneWin || win == PointerRootWin) + return FALSE; + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_FocusIn; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + return rc; +} + +/** + * Ungrab a currently Enter grabbed device and grab the device for the given + * window. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +static BOOL +ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab) + { + if (!dev->deviceGrab.fromPassiveGrab || + dev->deviceGrab.grab->type != XI_Enter || + dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_Enter; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); + return rc; +} + +/** + * Update the sprite coordinates based on the event. Update the cursor + * position, then update the event with the new coordinates that may have been + * changed. If the window underneath the sprite has changed, change to new + * cursor and send enter/leave events. + * + * CheckMotion() will not do anything and return FALSE if the event is not a + * pointer event. + * + * @return TRUE if the sprite has moved or FALSE otherwise. + */ +Bool +CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) +{ + WindowPtr prevSpriteWin, newSpriteWin; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + CHECKEVENT(ev); + + prevSpriteWin = pSprite->win; + + if (ev && !syncEvents.playingEvents) + { + /* GetPointerEvents() guarantees that pointer events have the correct + rootX/Y set already. */ + switch (ev->type) + { + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: + break; + default: + /* all other events return FALSE */ + return FALSE; + } + + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + /* Motion events entering DIX get translated to Screen 0 + coordinates. Replayed events have already been + translated since they've entered DIX before */ + ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x; + ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y; + } else +#endif + { + if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) + { + pSprite->hot.pScreen = pSprite->hotPhys.pScreen; + RootWindow(pDev->spriteInfo->sprite) = + pSprite->hot.pScreen->root; + } + } + + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + if (pSprite->hot.x < pSprite->physLimits.x1) + pSprite->hot.x = pSprite->physLimits.x1; + else if (pSprite->hot.x >= pSprite->physLimits.x2) + pSprite->hot.x = pSprite->physLimits.x2 - 1; + if (pSprite->hot.y < pSprite->physLimits.y1) + pSprite->hot.y = pSprite->physLimits.y1; + else if (pSprite->hot.y >= pSprite->physLimits.y2) + pSprite->hot.y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); + pSprite->hotPhys = pSprite->hot; + + if ((pSprite->hotPhys.x != ev->root_x) || + (pSprite->hotPhys.y != ev->root_y)) + { +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + XineramaSetCursorPosition( + pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } else +#endif + { + (*pSprite->hotPhys.pScreen->SetCursorPosition)( + pDev, pSprite->hotPhys.pScreen, + pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } + } + + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; + } + + newSpriteWin = XYToWindow(pSprite, pSprite->hot.x, pSprite->hot.y); + + if (newSpriteWin != prevSpriteWin) + { + int sourceid; + if (!ev) { + UpdateCurrentTimeIf(); + sourceid = pDev->id; /* when from WindowsRestructured */ + } else + sourceid = ev->sourceid; + + if (prevSpriteWin != NullWindow) { + if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) + DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, + newSpriteWin, NotifyNormal); + } + /* set pSprite->win after ActivateEnterGrab, otherwise + sprite window == grab_window and no enter/leave events are + sent. */ + pSprite->win = newSpriteWin; + PostNewCursor(pDev); + return FALSE; + } + return TRUE; +} + +/** + * Windows have restructured, we need to update the sprite position and the + * sprite's cursor. + */ +void +WindowsRestructured(void) +{ + DeviceIntPtr pDev = inputInfo.devices; + while(pDev) + { + if (IsMaster(pDev) || !pDev->u.master) + CheckMotion(NULL, pDev); + pDev = pDev->next; + } +} + +#ifdef PANORAMIX +/* This was added to support reconfiguration under Xdmx. The problem is + * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin + * other than 0,0, the information in the private sprite structure must + * be updated accordingly, or XYToWindow (and other routines) will not + * compute correctly. */ +void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) +{ + GrabPtr grab; + DeviceIntPtr pDev; + SpritePtr pSprite; + + if (noPanoramiXExtension) return; + + pDev = inputInfo.devices; + while(pDev) + { + if (DevHasCursor(pDev)) + { + pSprite = pDev->spriteInfo->sprite; + pSprite->hot.x -= xoff; + pSprite->hot.y -= yoff; + + pSprite->hotPhys.x -= xoff; + pSprite->hotPhys.y -= yoff; + + pSprite->hotLimits.x1 -= xoff; + pSprite->hotLimits.y1 -= yoff; + pSprite->hotLimits.x2 -= xoff; + pSprite->hotLimits.y2 -= yoff; + + if (RegionNotEmpty(&pSprite->Reg1)) + RegionTranslate(&pSprite->Reg1, xoff, yoff); + if (RegionNotEmpty(&pSprite->Reg2)) + RegionTranslate(&pSprite->Reg2, xoff, yoff); + + /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ + if ((grab = pDev->deviceGrab.grab) && grab->confineTo) { + if (grab->confineTo->drawable.pScreen + != pSprite->hotPhys.pScreen) + pSprite->hotPhys.x = pSprite->hotPhys.y = 0; + ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); + } else + ConfineCursorToWindow( + pDev, + pSprite->hotPhys.pScreen->root, + TRUE, FALSE); + + } + pDev = pDev->next; + } +} +#endif + +/** + * Initialize a sprite for the given device and set it to some sane values. If + * the device already has a sprite alloc'd, don't realloc but just reset to + * default values. + * If a window is supplied, the sprite will be initialized with the window's + * cursor and positioned in the center of the window's screen. The root window + * is a good choice to pass in here. + * + * It's a good idea to call it only for pointer devices, unless you have a + * really talented keyboard. + * + * @param pDev The device to initialize. + * @param pWin The window where to generate the sprite in. + * + */ +void +InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) +{ + SpritePtr pSprite; + ScreenPtr pScreen; + CursorPtr pCursor; + + if (!pDev->spriteInfo->sprite) + { + DeviceIntPtr it; + + pDev->spriteInfo->sprite = (SpritePtr)calloc(1, sizeof(SpriteRec)); + if (!pDev->spriteInfo->sprite) + FatalError("InitializeSprite: failed to allocate sprite struct"); + + /* We may have paired another device with this device before our + * device had a actual sprite. We need to check for this and reset the + * sprite field for all paired devices. + * + * The VCK is always paired with the VCP before the VCP has a sprite. + */ + for (it = inputInfo.devices; it; it = it->next) + { + if (it->spriteInfo->paired == pDev) + it->spriteInfo->sprite = pDev->spriteInfo->sprite; + } + if (inputInfo.keyboard->spriteInfo->paired == pDev) + inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite; + } + + pSprite = pDev->spriteInfo->sprite; + pDev->spriteInfo->spriteOwner = TRUE; + + pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL; + pSprite->hot.pScreen = pScreen; + pSprite->hotPhys.pScreen = pScreen; + if (pScreen) + { + pSprite->hotPhys.x = pScreen->width / 2; + pSprite->hotPhys.y = pScreen->height / 2; + pSprite->hotLimits.x2 = pScreen->width; + pSprite->hotLimits.y2 = pScreen->height; + } + + pSprite->hot = pSprite->hotPhys; + pSprite->win = pWin; + + if (pWin) + { + pCursor = wCursor(pWin); + pSprite->spriteTrace = (WindowPtr *)calloc(1, 32*sizeof(WindowPtr)); + if (!pSprite->spriteTrace) + FatalError("Failed to allocate spriteTrace"); + pSprite->spriteTraceSize = 32; + + RootWindow(pDev->spriteInfo->sprite) = pWin; + pSprite->spriteTraceGood = 1; + + pSprite->pEnqueueScreen = pScreen; + pSprite->pDequeueScreen = pSprite->pEnqueueScreen; + + } else { + pCursor = NullCursor; + pSprite->spriteTrace = NULL; + pSprite->spriteTraceSize = 0; + pSprite->spriteTraceGood = 0; + pSprite->pEnqueueScreen = screenInfo.screens[0]; + pSprite->pDequeueScreen = pSprite->pEnqueueScreen; + } + if (pCursor) + pCursor->refcnt++; + if (pSprite->current) + FreeCursor(pSprite->current, None); + pSprite->current = pCursor; + + if (pScreen) + { + (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current); + (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current, + &pSprite->hotLimits, &pSprite->physLimits); + pSprite->confined = FALSE; + + (*pScreen->ConstrainCursor) (pDev, pScreen, + &pSprite->physLimits); + (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x, + pSprite->hot.y, + FALSE); + (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); + } +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; + pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; + pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; + pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; + pSprite->physLimits = pSprite->hotLimits; + pSprite->confineWin = NullWindow; + pSprite->hotShape = NullRegion; + pSprite->screen = pScreen; + /* gotta UNINIT these someplace */ + RegionNull(&pSprite->Reg1); + RegionNull(&pSprite->Reg2); + } +#endif +} + +/** + * Update the mouse sprite info when the server switches from a pScreen to another. + * Otherwise, the pScreen of the mouse sprite is never updated when we switch + * from a pScreen to another. Never updating the pScreen of the mouse sprite + * implies that windows that are in pScreen whose pScreen->myNum >0 will never + * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen + * always points to the first pScreen it has been set by + * DefineInitialRootWindow(). + * + * Calling this function is useful for use cases where the server + * has more than one pScreen. + * This function is similar to DefineInitialRootWindow() but it does not + * reset the mouse pointer position. + * @param win must be the new pScreen we are switching to. + */ +void +UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SpritePtr pSprite = NULL; + WindowPtr win = NULL; + CursorPtr pCursor; + if (!pScreen) + return ; + + if (!pDev->spriteInfo->sprite) + return; + + pSprite = pDev->spriteInfo->sprite; + + win = pScreen->root; + + pSprite->hotPhys.pScreen = pScreen; + pSprite->hot = pSprite->hotPhys; + pSprite->hotLimits.x2 = pScreen->width; + pSprite->hotLimits.y2 = pScreen->height; + pSprite->win = win; + pCursor = wCursor(win); + if (pCursor) + pCursor->refcnt++; + if (pSprite->current) + FreeCursor(pSprite->current, 0); + pSprite->current = pCursor; + pSprite->spriteTraceGood = 1; + pSprite->spriteTrace[0] = win; + (*pScreen->CursorLimits) (pDev, + pScreen, + pSprite->current, + &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = FALSE; + (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits); + (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; + pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; + pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; + pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; + pSprite->physLimits = pSprite->hotLimits; + pSprite->screen = pScreen; + } +#endif +} + +/* + * This does not take any shortcuts, and even ignores its argument, since + * it does not happen very often, and one has to walk up the tree since + * this might be a newly instantiated cursor for an intermediate window + * between the one the pointer is in and the one that the last cursor was + * instantiated from. + */ +void +WindowHasNewCursor(WindowPtr pWin) +{ + DeviceIntPtr pDev; + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + if (DevHasCursor(pDev)) + PostNewCursor(pDev); +} + +void +NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + pSprite->hotPhys.x = x; + pSprite->hotPhys.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x; + pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y; + if (newScreen != pSprite->screen) { + pSprite->screen = newScreen; + /* Make sure we tell the DDX to update its copy of the screen */ + if(pSprite->confineWin) + XineramaConfineCursorToWindow(pDev, + pSprite->confineWin, TRUE); + else + XineramaConfineCursorToWindow(pDev, screenInfo.screens[0]->root, TRUE); + /* if the pointer wasn't confined, the DDX won't get + told of the pointer warp so we reposition it here */ + if(!syncEvents.playingEvents) + (*pSprite->screen->SetCursorPosition)( + pDev, + pSprite->screen, + pSprite->hotPhys.x + screenInfo.screens[0]->x - + pSprite->screen->x, + pSprite->hotPhys.y + screenInfo.screens[0]->y - + pSprite->screen->y, FALSE); + } + } else +#endif + if (newScreen != pSprite->hotPhys.pScreen) + ConfineCursorToWindow(pDev, newScreen->root, TRUE, FALSE); +} + +#ifdef PANORAMIX + +static Bool +XineramaPointInWindowIsVisible( + WindowPtr pWin, + int x, + int y +) +{ + BoxRec box; + int i, xoff, yoff; + + if (!pWin->realized) return FALSE; + + if (RegionContainsPoint(&pWin->borderClip, x, y, &box)) + return TRUE; + + if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE; + + xoff = x + screenInfo.screens[0]->x; + yoff = y + screenInfo.screens[0]->y; + + for(i = 1; i < PanoramiXNumScreens; i++) { + pWin = inputInfo.pointer->spriteInfo->sprite->windows[i]; + x = xoff - screenInfo.screens[i]->x; + y = yoff - screenInfo.screens[i]->y; + + if(RegionContainsPoint(&pWin->borderClip, x, y, &box) + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + return TRUE; + + } + + return FALSE; +} + +static int +XineramaWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + int x, y, rc; + SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + + REQUEST(xWarpPointerReq); + + + if (stuff->dstWid != None) { + rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess); + if (rc != Success) + return rc; + } + x = pSprite->hotPhys.x; + y = pSprite->hotPhys.y; + + if (stuff->srcWid != None) + { + int winX, winY; + XID winID = stuff->srcWid; + WindowPtr source; + + rc = dixLookupWindow(&source, winID, client, DixReadAccess); + if (rc != Success) + return rc; + + winX = source->drawable.x; + winY = source->drawable.y; + if(source == screenInfo.screens[0]->root) { + winX -= screenInfo.screens[0]->x; + winY -= screenInfo.screens[0]->y; + } + if (x < winX + stuff->srcX || + y < winY + stuff->srcY || + (stuff->srcWidth != 0 && + winX + stuff->srcX + (int)stuff->srcWidth < x) || + (stuff->srcHeight != 0 && + winY + stuff->srcY + (int)stuff->srcHeight < y) || + !XineramaPointInWindowIsVisible(source, x, y)) + return Success; + } + if (dest) { + x = dest->drawable.x; + y = dest->drawable.y; + if(dest == screenInfo.screens[0]->root) { + x -= screenInfo.screens[0]->x; + y -= screenInfo.screens[0]->y; + } + } + + x += stuff->dstX; + y += stuff->dstY; + + if (x < pSprite->physLimits.x1) + x = pSprite->physLimits.x1; + else if (x >= pSprite->physLimits.x2) + x = pSprite->physLimits.x2 - 1; + if (y < pSprite->physLimits.y1) + y = pSprite->physLimits.y1; + else if (y >= pSprite->physLimits.y2) + y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y); + + XineramaSetCursorPosition(PickPointer(client), x, y, TRUE); + + return Success; +} + +#endif + + +/** + * Server-side protocol handling for WarpPointer request. + * Warps the cursor position to the coordinates given in the request. + */ +int +ProcWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + int x, y, rc; + ScreenPtr newScreen; + DeviceIntPtr dev, tmp; + SpritePtr pSprite; + + REQUEST(xWarpPointerReq); + REQUEST_SIZE_MATCH(xWarpPointerReq); + + dev = PickPointer(client); + + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); + if (rc != Success) + return rc; + } + } + + if (dev->u.lastSlave) + dev = dev->u.lastSlave; + pSprite = dev->spriteInfo->sprite; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + return XineramaWarpPointer(client); +#endif + + if (stuff->dstWid != None) { + rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + } + x = pSprite->hotPhys.x; + y = pSprite->hotPhys.y; + + if (stuff->srcWid != None) + { + int winX, winY; + XID winID = stuff->srcWid; + WindowPtr source; + + rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + winX = source->drawable.x; + winY = source->drawable.y; + if (source->drawable.pScreen != pSprite->hotPhys.pScreen || + x < winX + stuff->srcX || + y < winY + stuff->srcY || + (stuff->srcWidth != 0 && + winX + stuff->srcX + (int)stuff->srcWidth < x) || + (stuff->srcHeight != 0 && + winY + stuff->srcY + (int)stuff->srcHeight < y) || + !PointInWindowIsVisible(source, x, y)) + return Success; + } + if (dest) + { + x = dest->drawable.x; + y = dest->drawable.y; + newScreen = dest->drawable.pScreen; + } else + newScreen = pSprite->hotPhys.pScreen; + + x += stuff->dstX; + y += stuff->dstY; + + if (x < 0) + x = 0; + else if (x >= newScreen->width) + x = newScreen->width - 1; + if (y < 0) + y = 0; + else if (y >= newScreen->height) + y = newScreen->height - 1; + + if (newScreen == pSprite->hotPhys.pScreen) + { + if (x < pSprite->physLimits.x1) + x = pSprite->physLimits.x1; + else if (x >= pSprite->physLimits.x2) + x = pSprite->physLimits.x2 - 1; + if (y < pSprite->physLimits.y1) + y = pSprite->physLimits.y1; + else if (y >= pSprite->physLimits.y2) + y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(dev, pSprite->hotShape, &x, &y); + (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE); + } + else if (!PointerConfinedToScreen(dev)) + { + NewCurrentScreen(dev, newScreen, x, y); + } + return Success; +} + +static Bool +BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) +{ + if(RegionNotEmpty(&pWin->borderSize)) + return TRUE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) { + int i; + + for(i = 1; i < PanoramiXNumScreens; i++) { + if(RegionNotEmpty(&pDev->spriteInfo->sprite->windows[i]->borderSize)) + return TRUE; + } + } +#endif + return FALSE; +} + +/** + * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a + * passive grab set on the window to be activated. + * If activate is true and a passive grab is found, it will be activated, + * and the event will be delivered to the client. + * + * @param pWin The window that may be subject to a passive grab. + * @param device Device that caused the event. + * @param event The current device event. + * @param checkCore Check for core grabs too. + * @param activate If a grab is found, activate it and deliver the event. + */ + +GrabPtr +CheckPassiveGrabsOnWindow( + WindowPtr pWin, + DeviceIntPtr device, + DeviceEvent *event, + BOOL checkCore, + BOOL activate) +{ + SpritePtr pSprite = device->spriteInfo->sprite; + GrabPtr grab = wPassiveGrabs(pWin); + GrabRec tempGrab; + GrabInfoPtr grabinfo; +#define CORE_MATCH 0x1 +#define XI_MATCH 0x2 +#define XI2_MATCH 0x4 + int match = 0; + + if (!grab) + return NULL; + /* Fill out the grab details, but leave the type for later before + * comparing */ + tempGrab.window = pWin; + tempGrab.device = device; + tempGrab.detail.exact = event->detail.key; + tempGrab.detail.pMask = NULL; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.next = NULL; + for (; grab; grab = grab->next) + { + DeviceIntPtr gdev; + XkbSrvInfoPtr xkbi = NULL; + + gdev= grab->modifierDevice; + if (grab->grabtype == GRABTYPE_CORE) + { + if (IsPointerDevice(device)) + gdev = GetPairedDevice(device); + else + gdev = device; + } else if (grab->grabtype == GRABTYPE_XI2) + { + /* if the device is an attached slave device, gdev must be the + * attached master keyboard. Since the slave may have been + * reattached after the grab, the modifier device may not be the + * same. */ + if (!IsMaster(grab->device) && device->u.master) + gdev = GetMaster(device, MASTER_KEYBOARD); + } + + + if (gdev && gdev->key) + xkbi= gdev->key->xkbInfo; + tempGrab.modifierDevice = grab->modifierDevice; + tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; + + /* Check for XI2 and XI grabs first */ + tempGrab.type = GetXI2Type((InternalEvent*)event); + tempGrab.grabtype = GRABTYPE_XI2; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI2_MATCH; + + tempGrab.detail.exact = event->detail.key; + if (!match) + { + tempGrab.grabtype = GRABTYPE_XI; + if ((tempGrab.type = GetXIType((InternalEvent*)event)) && + (GrabMatchesSecond(&tempGrab, grab, FALSE))) + match = XI_MATCH; + } + + /* Check for a core grab (ignore the device when comparing) */ + if (!match && checkCore) + { + tempGrab.grabtype = GRABTYPE_CORE; + if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && + (GrabMatchesSecond(&tempGrab, grab, TRUE))) + match = CORE_MATCH; + } + + if (match && (!grab->confineTo || + (grab->confineTo->realized && + BorderSizeNotEmpty(device, grab->confineTo)))) + { + int rc, count = 0; + xEvent *xE = NULL; + xEvent core; + + event->corestate &= 0x1f00; + event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); + grabinfo = &device->deviceGrab; + /* In some cases a passive core grab may exist, but the client + * already has a core grab on some other device. In this case we + * must not get the grab, otherwise we may never ungrab the + * device. + */ + + if (grab->grabtype == GRABTYPE_CORE) + { + DeviceIntPtr other; + BOOL interfering = FALSE; + + /* A passive grab may have been created for a different device + than it is assigned to at this point in time. + Update the grab's device and modifier device to reflect the + current state. + Since XGrabDeviceButton requires to specify the + modifierDevice explicitly, we don't override this choice. + */ + if (tempGrab.type < GenericEvent) + { + grab->device = device; + grab->modifierDevice = GetPairedDevice(device); + } + + for (other = inputInfo.devices; other; other = other->next) + { + GrabPtr othergrab = other->deviceGrab.grab; + if (othergrab && othergrab->grabtype == GRABTYPE_CORE && + SameClient(grab, rClient(othergrab)) && + ((IsPointerDevice(grab->device) && + IsPointerDevice(othergrab->device)) || + (IsKeyboardDevice(grab->device) && + IsKeyboardDevice(othergrab->device)))) + { + interfering = TRUE; + break; + } + } + if (interfering) + continue; + } + + if (!activate) + return grab; + + if (match & CORE_MATCH) + { + rc = EventToCore((InternalEvent*)event, &core); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + xE = &core; + count = 1; + } else if (match & XI2_MATCH) + { + rc = EventToXI2((InternalEvent*)event, &xE); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + count = 1; + } else + { + rc = EventToXI((InternalEvent*)event, &xE, &count); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + } + + (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); + + if (xE) + { + FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); + + TryClientEvents(rClient(grab), device, xE, count, + GetEventFilter(device, xE), + GetEventFilter(device, xE), grab); + } + + if (grabinfo->sync.state == FROZEN_NO_EVENT) + { + if (!grabinfo->sync.event) + grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = *event; + grabinfo->sync.state = FROZEN_WITH_EVENT; + } + + if (match & (XI_MATCH | XI2_MATCH)) + free(xE); /* on core match xE == &core */ + return grab; + } + } + return NULL; +#undef CORE_MATCH +#undef XI_MATCH +#undef XI2_MATCH +} + +/** + * CheckDeviceGrabs handles both keyboard and pointer events that may cause + * a passive grab to be activated. + * + * If the event is a keyboard event, the ancestors of the focus window are + * traced down and tried to see if they have any passive grabs to be + * activated. If the focus window itself is reached and it's descendants + * contain the pointer, the ancestors of the window that the pointer is in + * are then traced down starting at the focus window, otherwise no grabs are + * activated. + * If the event is a pointer event, the ancestors of the window that the + * pointer is in are traced down starting at the root until CheckPassiveGrabs + * causes a passive grab to activate or all the windows are + * tried. PRH + * + * If a grab is activated, the event has been sent to the client already! + * + * The event we pass in must always be an XI event. From this, we then emulate + * the core event and then check for grabs. + * + * @param device The device that caused the event. + * @param xE The event to handle (Device{Button|Key}Press). + * @param count Number of events in list. + * @return TRUE if a grab has been activated or false otherwise. +*/ + +Bool +CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) +{ + int i; + WindowPtr pWin = NULL; + FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; + BOOL sendCore = (IsMaster(device) && device->coreEvents); + + if (event->type != ET_ButtonPress && + event->type != ET_KeyPress) + return FALSE; + + if (event->type == ET_ButtonPress + && (device->button->buttonsDown != 1)) + return FALSE; + + if (device->deviceGrab.grab) + return FALSE; + + i = 0; + if (ancestor) + { + while (i < device->spriteInfo->sprite->spriteTraceGood) + if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor) + break; + if (i == device->spriteInfo->sprite->spriteTraceGood) + return FALSE; + } + + if (focus) + { + for (; i < focus->traceGood; i++) + { + pWin = focus->trace[i]; + if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) + return TRUE; + } + + if ((focus->win == NoneWin) || + (i >= device->spriteInfo->sprite->spriteTraceGood) || + (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i-1])) + return FALSE; + } + + for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) + { + pWin = device->spriteInfo->sprite->spriteTrace[i]; + if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) + return TRUE; + } + + return FALSE; +} + +/** + * Called for keyboard events to deliver event to whatever client owns the + * focus. + * + * The event is delivered to the keyboard's focus window, the root window or + * to the window owning the input focus. + * + * @param keybd The keyboard originating the event. + * @param event The event, not yet in wire format. + * @param window Window underneath the sprite. + */ +void +DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) +{ + DeviceIntPtr ptr; + WindowPtr focus = keybd->focus->win; + BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); + xEvent core; + xEvent *xE = NULL, *xi2 = NULL; + int count, rc; + int deliveries = 0; + + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + if (!focus) + return; + if (focus == PointerRootWin) + { + DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); + return; + } + if ((focus == window) || IsParent(focus, window)) + { + if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) + return; + } + + /* just deliver it to the focus window */ + ptr = GetPairedDevice(keybd); + + + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + int filter = GetEventFilter(keybd, xi2); + FixUpEventFromWindow(ptr->spriteInfo->sprite, xi2, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, + filter, NullGrab); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + rc = EventToXI(event, &xE, &count); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) + { + FixUpEventFromWindow(ptr->spriteInfo->sprite, xE, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xE, count, + GetEventFilter(keybd, xE), + NullGrab); + + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + if (sendCore) + { + rc = EventToCore(event, &core); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) { + FixUpEventFromWindow(keybd->spriteInfo->sprite, &core, focus, + None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, + GetEventFilter(keybd, &core), + NullGrab); + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + } + +unwind: + free(xE); + free(xi2); + return; +} + +/** + * Deliver an event from a device that is currently grabbed. Uses + * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the + * grab. If not, TryClientEvents() is used. + * + * @param deactivateGrab True if the device's grab should be deactivated. + */ +void +DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, + Bool deactivateGrab) +{ + GrabPtr grab; + GrabInfoPtr grabinfo; + int deliveries = 0; + DeviceIntPtr dev; + SpritePtr pSprite = thisDev->spriteInfo->sprite; + BOOL sendCore = FALSE; + int rc, count = 0; + xEvent *xi = NULL; + xEvent *xi2 = NULL; + + grabinfo = &thisDev->deviceGrab; + grab = grabinfo->grab; + + if (grab->ownerEvents) + { + WindowPtr focus; + + /* Hack: Some pointer device have a focus class. So we need to check + * for the type of event, to see if we really want to deliver it to + * the focus window. For pointer events, the answer is no. + */ + if (IsPointerEvent(event)) + focus = PointerRootWin; + else if (thisDev->focus) + { + focus = thisDev->focus->win; + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + } + else + focus = PointerRootWin; + if (focus == PointerRootWin) + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, + NullWindow, thisDev); + else if (focus && (focus == pSprite->win || + IsParent(focus, pSprite->win))) + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, + thisDev); + else if (focus) + deliveries = DeliverDeviceEvents(focus, event, grab, focus, + thisDev); + } + if (!deliveries) + { + Mask mask; + + /* XXX: In theory, we could pass the internal events through to + * everything and only convert just before hitting the wire. We can't + * do that yet, so DGE is the last stop for internal events. From here + * onwards, we deal with core/XI events. + */ + + mask = grab->eventMask; + + sendCore = (IsMaster(thisDev) && thisDev->coreEvents); + /* try core event */ + if (sendCore && grab->grabtype == GRABTYPE_CORE) + { + xEvent core; + + rc = EventToCore(event, &core); + if (rc == Success) + { + FixUpEventFromWindow(pSprite, &core, grab->window, None, TRUE); + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, &core, 1) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, &core, 1)) + deliveries = 1; /* don't send, but pretend we did */ + else if (!IsInterferingGrab(rClient(grab), thisDev, &core)) + { + deliveries = TryClientEvents(rClient(grab), thisDev, + &core, 1, mask, + GetEventFilter(thisDev, &core), + grab); + } + } else if (rc != BadMatch) + ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); + } + + if (!deliveries) + { + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + int evtype = ((xGenericEvent*)xi2)->evtype; + mask = grab->xi2mask[XIAllDevices][evtype/8] | + grab->xi2mask[XIAllMasterDevices][evtype/8] | + grab->xi2mask[thisDev->id][evtype/8]; + /* try XI2 event */ + FixUpEventFromWindow(pSprite, xi2, grab->window, None, TRUE); + /* XXX: XACE */ + deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, + GetEventFilter(thisDev, xi2), grab); + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (!deliveries) + { + rc = EventToXI(event, &xi, &count); + if (rc == Success) + { + /* try XI event */ + if (grabinfo->fromPassiveGrab && + grabinfo->implicitGrab) + mask = grab->deviceMask; + else + mask = grab->eventMask; + + FixUpEventFromWindow(pSprite, xi, grab->window, None, TRUE); + + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, xi, count) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, xi, count)) + deliveries = 1; /* don't send, but pretend we did */ + else + { + deliveries = + TryClientEvents(rClient(grab), thisDev, + xi, count, + mask, + GetEventFilter(thisDev, xi), + grab); + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (deliveries && (event->any.type == ET_Motion)) + thisDev->valuator->motionHintWindow = grab->window; + } + if (deliveries && !deactivateGrab && event->any.type != ET_Motion) + { + switch (grabinfo->sync.state) + { + case FREEZE_BOTH_NEXT_EVENT: + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev == thisDev) + continue; + FreezeThaw(dev, TRUE); + if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && + (CLIENT_BITS(grab->resource) == + CLIENT_BITS(dev->deviceGrab.grab->resource))) + dev->deviceGrab.sync.state = FROZEN_NO_EVENT; + else if (GetPairedDevice(thisDev) == dev) + dev->deviceGrab.sync.other = grab; + } + /* fall through */ + case FREEZE_NEXT_EVENT: + grabinfo->sync.state = FROZEN_WITH_EVENT; + FreezeThaw(thisDev, TRUE); + if (!grabinfo->sync.event) + grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = event->device_event; + break; + } + } + + free(xi); + free(xi2); +} + +/* This function is used to set the key pressed or key released state - + this is only used when the pressing of keys does not cause + the device's processInputProc to be called, as in for example Mouse Keys. +*/ +void +FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) +{ + int key = event->detail.key; + + if (event->type == ET_KeyPress) { + DebugF("FixKeyState: Key %d %s\n",key, + ((event->type == ET_KeyPress) ? "down" : "up")); + } + + if (event->type == ET_KeyPress) + set_key_down(keybd, key, KEY_PROCESSED); + else if (event->type == ET_KeyRelease) + set_key_up(keybd, key, KEY_PROCESSED); + else + FatalError("Impossible keyboard event"); +} + +#define AtMostOneClient \ + (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) +#define ManagerMask \ + (SubstructureRedirectMask | ResizeRedirectMask) + +/** + * Recalculate which events may be deliverable for the given window. + * Recalculated mask is used for quicker determination which events may be + * delivered to a window. + * + * The otherEventMasks on a WindowOptional is the combination of all event + * masks set by all clients on the window. + * deliverableEventMask is the combination of the eventMask and the + * otherEventMask plus the events that may be propagated to the parent. + * + * Traverses to siblings and parents of the window. + */ +void +RecalculateDeliverableEvents(WindowPtr pWin) +{ + OtherClients *others; + WindowPtr pChild; + + pChild = pWin; + while (1) + { + if (pChild->optional) + { + pChild->optional->otherEventMasks = 0; + for (others = wOtherClients(pChild); others; others = others->next) + { + pChild->optional->otherEventMasks |= others->mask; + } + } + pChild->deliverableEvents = pChild->eventMask| + wOtherEventMasks(pChild); + if (pChild->parent) + pChild->deliverableEvents |= + (pChild->parent->deliverableEvents & + ~wDontPropagateMask(pChild) & PropagateMask); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +/** + * + * \param value must conform to DeleteType + */ +int +OtherClientGone(pointer value, XID id) +{ + OtherClientsPtr other, prev; + WindowPtr pWin = (WindowPtr)value; + + prev = 0; + for (other = wOtherClients(pWin); other; other = other->next) + { + if (other->resource == id) + { + if (prev) + prev->next = other->next; + else + { + if (!(pWin->optional->otherClients = other->next)) + CheckWindowOptionalNeed (pWin); + } + free(other); + RecalculateDeliverableEvents(pWin); + return Success; + } + prev = other; + } + FatalError("client not on event list"); + /*NOTREACHED*/ + return -1; /* make compiler happy */ +} + +int +EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask) +{ + Mask check; + OtherClients * others; + DeviceIntPtr dev; + int rc; + + if (mask & ~AllEventMasks) + { + client->errorValue = mask; + return BadValue; + } + check = (mask & ManagerMask); + if (check) { + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess); + if (rc != Success) + return rc; + } + check = (mask & AtMostOneClient); + if (check & (pWin->eventMask|wOtherEventMasks(pWin))) + { /* It is illegal for two different + clients to select on any of the + events for AtMostOneClient. However, + it is OK, for some client to + continue selecting on one of those + events. */ + if ((wClient(pWin) != client) && (check & pWin->eventMask)) + return BadAccess; + for (others = wOtherClients (pWin); others; others = others->next) + { + if (!SameClient(others, client) && (check & others->mask)) + return BadAccess; + } + } + if (wClient (pWin) == client) + { + check = pWin->eventMask; + pWin->eventMask = mask; + } + else + { + for (others = wOtherClients (pWin); others; others = others->next) + { + if (SameClient(others, client)) + { + check = others->mask; + if (mask == 0) + { + FreeResource(others->resource, RT_NONE); + return Success; + } + else + others->mask = mask; + goto maskSet; + } + } + check = 0; + if (!pWin->optional && !MakeWindowOptional (pWin)) + return BadAlloc; + others = malloc(sizeof(OtherClients)); + if (!others) + return BadAlloc; + others->mask = mask; + others->resource = FakeClientID(client->index); + others->next = pWin->optional->otherClients; + pWin->optional->otherClients = others; + if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin)) + return BadAlloc; + } +maskSet: + if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->valuator && dev->valuator->motionHintWindow == pWin) + dev->valuator->motionHintWindow = NullWindow; + } + } + RecalculateDeliverableEvents(pWin); + return Success; +} + +int +EventSuppressForWindow(WindowPtr pWin, ClientPtr client, + Mask mask, Bool *checkOptional) +{ + int i, free; + + if (mask & ~PropagateMask) + { + client->errorValue = mask; + return BadValue; + } + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]--; + if (!mask) + i = 0; + else + { + for (i = DNPMCOUNT, free = 0; --i > 0; ) + { + if (!DontPropagateRefCnts[i]) + free = i; + else if (mask == DontPropagateMasks[i]) + break; + } + if (!i && free) + { + i = free; + DontPropagateMasks[i] = mask; + } + } + if (i || !mask) + { + pWin->dontPropagate = i; + if (i) + DontPropagateRefCnts[i]++; + if (pWin->optional) + { + pWin->optional->dontPropagateMask = mask; + *checkOptional = TRUE; + } + } + else + { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]++; + return BadAlloc; + } + pWin->dontPropagate = 0; + pWin->optional->dontPropagateMask = mask; + } + RecalculateDeliverableEvents(pWin); + return Success; +} + +/** + * Assembles an EnterNotify or LeaveNotify and sends it event to the client. + * Uses the paired keyboard to get some additional information. + */ +void +CoreEnterLeaveEvent( + DeviceIntPtr mouse, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + xEvent event; + WindowPtr focus; + DeviceIntPtr keybd; + GrabPtr grab = mouse->deviceGrab.grab; + Mask mask; + + keybd = GetPairedDevice(mouse); + + if ((pWin == mouse->valuator->motionHintWindow) && + (detail != NotifyInferior)) + mouse->valuator->motionHintWindow = NullWindow; + if (grab) + { + mask = (pWin == grab->window) ? grab->eventMask : 0; + if (grab->ownerEvents) + mask |= EventMaskForClient(pWin, rClient(grab)); + } + else + { + mask = pWin->eventMask | wOtherEventMasks(pWin); + } + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = type; + event.u.u.detail = detail; + event.u.enterLeave.time = currentTime.milliseconds; + event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x; + event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y; + /* Counts on the same initial structure of crossing & button events! */ + FixUpEventFromWindow(mouse->spriteInfo->sprite, &event, pWin, None, FALSE); + /* Enter/Leave events always set child */ + event.u.enterLeave.child = child; + event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? + ELFlagSameScreen : 0; + event.u.enterLeave.state = mouse->button ? (mouse->button->state & 0x1f00) : 0; + if (keybd) + event.u.enterLeave.state |= + XkbGrabStateFromRec(&keybd->key->xkbInfo->state); + event.u.enterLeave.mode = mode; + focus = (keybd) ? keybd->focus->win : None; + if ((focus != NoneWin) && + ((pWin == focus) || (focus == PointerRootWin) || + IsParent(focus, pWin))) + event.u.enterLeave.flags |= ELFlagFocus; + + if ((mask & GetEventFilter(mouse, &event))) + { + if (grab) + TryClientEvents(rClient(grab), mouse, &event, 1, mask, + GetEventFilter(mouse, &event), grab); + else + DeliverEventsToWindow(mouse, pWin, &event, 1, + GetEventFilter(mouse, &event), + NullGrab); + } + + if ((type == EnterNotify) && (mask & KeymapStateMask)) + { + xKeymapEvent ke; + ClientPtr client = grab ? rClient(grab) : wClient(pWin); + if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) + memset((char *)&ke.map[0], 0, 31); + else + memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); + + ke.type = KeymapNotify; + if (grab) + TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1, + mask, KeymapStateMask, grab); + else + DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); + } +} + +void +DeviceEnterLeaveEvent( + DeviceIntPtr mouse, + int sourceid, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + GrabPtr grab = mouse->deviceGrab.grab; + xXIEnterEvent *event; + int filter; + int btlen, len, i; + DeviceIntPtr kbd; + + if ((mode == XINotifyPassiveGrab && type == XI_Leave) || + (mode == XINotifyPassiveUngrab && type == XI_Enter)) + return; + + btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIEnterEvent) + btlen * 4; + + event = calloc(1, len); + event->type = GenericEvent; + event->extension = IReqCode; + event->evtype = type; + event->length = (len - sizeof(xEvent))/4; + event->buttons_len = btlen; + event->detail = detail; + event->time = currentTime.milliseconds; + event->deviceid = mouse->id; + event->sourceid = sourceid; + event->mode = mode; + event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); + event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(&event[1], i); + + kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL; + if (kbd && kbd->key) + { + event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; + event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; + event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; + + event->group.base_group = kbd->key->xkbInfo->state.base_group; + event->group.latched_group = kbd->key->xkbInfo->state.latched_group; + event->group.locked_group = kbd->key->xkbInfo->state.locked_group; + } + + FixUpEventFromWindow(mouse->spriteInfo->sprite, (xEvent*)event, pWin, + None, FALSE); + + filter = GetEventFilter(mouse, (xEvent*)event); + + if (grab) + { + Mask mask; + mask = grab->xi2mask[XIAllDevices][type/8] | + grab->xi2mask[XIAllMasterDevices][type/8] | + grab->xi2mask[mouse->id][type/8]; + TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, + filter, grab); + } else { + if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) + goto out; + DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, + NullGrab); + } + +out: + free(event); +} + +void +CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) +{ + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.focus.mode = mode; + event.u.u.type = type; + event.u.u.detail = detail; + event.u.focus.window = pWin->drawable.id; + + DeliverEventsToWindow(dev, pWin, &event, 1, + GetEventFilter(dev, &event), NullGrab); + if ((type == FocusIn) && + ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) + { + xKeymapEvent ke; + ClientPtr client = wClient(pWin); + if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) + memset((char *)&ke.map[0], 0, 31); + else + memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); + + ke.type = KeymapNotify; + DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); + } +} + +/** + * Set the input focus to the given window. Subsequent keyboard events will be + * delivered to the given window. + * + * Usually called from ProcSetInputFocus as result of a client request. If so, + * the device is the inputInfo.keyboard. + * If called from ProcXSetInputFocus as result of a client xinput request, the + * device is set to the device specified by the client. + * + * @param client Client that requested input focus change. + * @param dev Focus device. + * @param focusID The window to obtain the focus. Can be PointerRoot or None. + * @param revertTo Specifies where the focus reverts to when window becomes + * unviewable. + * @param ctime Specifies the time. + * @param followOK True if pointer is allowed to follow the keyboard. + */ +int +SetInputFocus( + ClientPtr client, + DeviceIntPtr dev, + Window focusID, + CARD8 revertTo, + Time ctime, + Bool followOK) +{ + FocusClassPtr focus; + WindowPtr focusWin; + int mode, rc; + TimeStamp time; + DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */ + + + UpdateCurrentTime(); + if ((revertTo != RevertToParent) && + (revertTo != RevertToPointerRoot) && + (revertTo != RevertToNone) && + ((revertTo != RevertToFollowKeyboard) || !followOK)) + { + client->errorValue = revertTo; + return BadValue; + } + time = ClientTimeToServerTime(ctime); + + if (IsKeyboardDevice(dev)) + keybd = dev; + else + keybd = GetPairedDevice(dev); + + if ((focusID == None) || (focusID == PointerRoot)) + focusWin = (WindowPtr)(long)focusID; + else if ((focusID == FollowKeyboard) && followOK) + { + focusWin = keybd->focus->win; + } + else { + rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess); + if (rc != Success) + return rc; + /* It is a match error to try to set the input focus to an + unviewable window. */ + if(!focusWin->realized) + return BadMatch; + } + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess); + if (rc != Success) + return Success; + + focus = dev->focus; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, focus->time) == EARLIER)) + return Success; + mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; + if (focus->win == FollowKeyboardWin) + { + if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) + DoFocusEvents(dev, keybd->focus->win, focusWin, mode); + } else + { + if (!ActivateFocusInGrab(dev, focus->win, focusWin)) + DoFocusEvents(dev, focus->win, focusWin, mode); + } + focus->time = time; + focus->revert = revertTo; + if (focusID == FollowKeyboard) + focus->win = FollowKeyboardWin; + else + focus->win = focusWin; + if ((focusWin == NoneWin) || (focusWin == PointerRootWin)) + focus->traceGood = 0; + else + { + int depth = 0; + WindowPtr pWin; + + for (pWin = focusWin; pWin; pWin = pWin->parent) depth++; + if (depth > focus->traceSize) + { + focus->traceSize = depth+1; + focus->trace = realloc(focus->trace, + focus->traceSize * sizeof(WindowPtr)); + } + focus->traceGood = depth; + for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) + focus->trace[depth] = pWin; + } + return Success; +} + +/** + * Server-side protocol handling for SetInputFocus request. + * + * Sets the input focus for the virtual core keyboard. + */ +int +ProcSetInputFocus(ClientPtr client) +{ + DeviceIntPtr kbd = PickKeyboard(client); + REQUEST(xSetInputFocusReq); + + REQUEST_SIZE_MATCH(xSetInputFocusReq); + + return SetInputFocus(client, kbd, stuff->focus, + stuff->revertTo, stuff->time, FALSE); +} + +/** + * Server-side protocol handling for GetInputFocus request. + * + * Sends the current input focus for the client's keyboard back to the + * client. + */ +int +ProcGetInputFocus(ClientPtr client) +{ + DeviceIntPtr kbd = PickKeyboard(client); + xGetInputFocusReply rep; + FocusClassPtr focus = kbd->focus; + int rc; + /* REQUEST(xReq); */ + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess); + if (rc != Success) + return rc; + + memset(&rep, 0, sizeof(xGetInputFocusReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (focus->win == NoneWin) + rep.focus = None; + else if (focus->win == PointerRootWin) + rep.focus = PointerRoot; + else rep.focus = focus->win->drawable.id; + rep.revertTo = focus->revert; + WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for GrabPointer request. + * + * Sets an active grab on the client's ClientPointer and returns success + * status to client. + */ +int +ProcGrabPointer(ClientPtr client) +{ + xGrabPointerReply rep; + DeviceIntPtr device = PickPointer(client); + GrabPtr grab; + GrabMask mask; + WindowPtr confineTo; + CursorPtr oldCursor; + REQUEST(xGrabPointerReq); + TimeStamp time; + int rc; + + REQUEST_SIZE_MATCH(xGrabPointerReq); + UpdateCurrentTime(); + + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->confineTo == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, stuff->confineTo, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + memset(&rep, 0, sizeof(xGrabPointerReply)); + oldCursor = NullCursor; + grab = device->deviceGrab.grab; + + if (grab) + { + if (grab->confineTo && !confineTo) + ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, + FALSE); + oldCursor = grab->cursor; + } + + mask.core = stuff->eventMask; + + rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, + stuff->grabWindow, stuff->ownerEvents, stuff->time, + &mask, GRABTYPE_CORE, stuff->cursor, + stuff->confineTo, &rep.status); + if (rc != Success) + return rc; + + if (oldCursor && rep.status == GrabSuccess) + FreeCursor (oldCursor, (Cursor)0); + + time = ClientTimeToServerTime(stuff->time); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for ChangeActivePointerGrab request. + * + * Changes properties of the grab hold by the client. If the client does not + * hold an active grab on the device, nothing happens. + */ +int +ProcChangeActivePointerGrab(ClientPtr client) +{ + DeviceIntPtr device; + GrabPtr grab; + CursorPtr newCursor, oldCursor; + REQUEST(xChangeActivePointerGrabReq); + TimeStamp time; + + REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq); + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + if (stuff->cursor == None) + newCursor = NullCursor; + else + { + int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return rc; + } + } + + device = PickPointer(client); + grab = device->deviceGrab.grab; + + if (!grab) + return Success; + if (!SameClient(grab, client)) + return Success; + time = ClientTimeToServerTime(stuff->time); + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) + return Success; + oldCursor = grab->cursor; + grab->cursor = newCursor; + if (newCursor) + newCursor->refcnt++; + PostNewCursor(device); + if (oldCursor) + FreeCursor(oldCursor, (Cursor)0); + grab->eventMask = stuff->eventMask; + return Success; +} + +/** + * Server-side protocol handling for UngrabPointer request. + * + * Deletes a pointer grab on a device the client has grabbed. + */ +int +ProcUngrabPointer(ClientPtr client) +{ + DeviceIntPtr device = PickPointer(client); + GrabPtr grab; + TimeStamp time; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + grab = device->deviceGrab.grab; + + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && + (grab) && SameClient(grab, client)) + (*device->deviceGrab.DeactivateGrab)(device); + return Success; +} + +/** + * Sets a grab on the given device. + * + * Called from ProcGrabKeyboard to work on the client's keyboard. + * Called from ProcXGrabDevice to work on the device specified by the client. + * + * The parameters this_mode and other_mode represent the keyboard_mode and + * pointer_mode parameters of XGrabKeyboard(). + * See man page for details on all the parameters + * + * @param client Client that owns the grab. + * @param dev The device to grab. + * @param this_mode GrabModeSync or GrabModeAsync + * @param other_mode GrabModeSync or GrabModeAsync + * @param status Return code to be returned to the caller. + * + * @returns Success or BadValue. + */ +int +GrabDevice(ClientPtr client, DeviceIntPtr dev, + unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, + unsigned ownerEvents, Time ctime, GrabMask *mask, + int grabtype, Cursor curs, Window confineToWin, CARD8 *status) +{ + WindowPtr pWin, confineTo; + GrabPtr grab; + TimeStamp time; + Mask access_mode = DixGrabAccess; + int rc; + GrabInfoPtr grabInfo = &dev->deviceGrab; + CursorPtr cursor; + + UpdateCurrentTime(); + if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) + { + client->errorValue = keyboard_mode; + return BadValue; + } + if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) + { + client->errorValue = pointer_mode; + return BadValue; + } + if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) + { + client->errorValue = ownerEvents; + return BadValue; + } + + rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (confineToWin == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, confineToWin, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + if (curs == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = curs; + return rc; + } + access_mode |= DixForceAccess; + } + + if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + time = ClientTimeToServerTime(ctime); + grab = grabInfo->grab; + if (grab && grab->grabtype != grabtype) + *status = AlreadyGrabbed; + if (grab && !SameClient(grab, client)) + *status = AlreadyGrabbed; + else if ((!pWin->realized) || + (confineTo && + !(confineTo->realized + && BorderSizeNotEmpty(dev, confineTo)))) + *status = GrabNotViewable; + else if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) + *status = GrabInvalidTime; + else if (grabInfo->sync.frozen && + grabInfo->sync.other && !SameClient(grabInfo->sync.other, client)) + *status = GrabFrozen; + else + { + GrabRec tempGrab; + + /* Otherwise segfaults happen on grabbed MPX devices */ + memset(&tempGrab, 0, sizeof(GrabRec)); + + tempGrab.next = NULL; + tempGrab.window = pWin; + tempGrab.resource = client->clientAsMask; + tempGrab.ownerEvents = ownerEvents; + tempGrab.keyboardMode = keyboard_mode; + tempGrab.pointerMode = pointer_mode; + if (grabtype == GRABTYPE_CORE) + tempGrab.eventMask = mask->core; + else if (grabtype == GRABTYPE_XI) + tempGrab.eventMask = mask->xi; + else + memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); + tempGrab.device = dev; + tempGrab.cursor = cursor; + tempGrab.confineTo = confineTo; + tempGrab.grabtype = grabtype; + (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); + *status = GrabSuccess; + } + return Success; +} + +/** + * Server-side protocol handling for GrabKeyboard request. + * + * Grabs the client's keyboard and returns success status to client. + */ +int +ProcGrabKeyboard(ClientPtr client) +{ + xGrabKeyboardReply rep; + REQUEST(xGrabKeyboardReq); + int result; + DeviceIntPtr keyboard = PickKeyboard(client); + GrabMask mask; + + REQUEST_SIZE_MATCH(xGrabKeyboardReq); + + memset(&rep, 0, sizeof(xGrabKeyboardReply)); + mask.core = KeyPressMask | KeyReleaseMask; + + result = GrabDevice(client, keyboard, stuff->pointerMode, + stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, + stuff->time, &mask, GRABTYPE_CORE, None, None, + &rep.status); + + if (result != Success) + return result; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for UngrabKeyboard request. + * + * Deletes a possible grab on the client's keyboard. + */ +int +ProcUngrabKeyboard(ClientPtr client) +{ + DeviceIntPtr device = PickKeyboard(client); + GrabPtr grab; + TimeStamp time; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + + grab = device->deviceGrab.grab; + + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && + (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) + (*device->deviceGrab.DeactivateGrab)(device); + return Success; +} + +/** + * Server-side protocol handling for QueryPointer request. + * + * Returns the current state and position of the client's ClientPointer to the + * client. + */ +int +ProcQueryPointer(ClientPtr client) +{ + xQueryPointerReply rep; + WindowPtr pWin, t; + DeviceIntPtr mouse = PickPointer(client); + DeviceIntPtr keyboard; + SpritePtr pSprite; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); + if (rc != Success && rc != BadAccess) + return rc; + + keyboard = GetPairedDevice(mouse); + + pSprite = mouse->spriteInfo->sprite; + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + memset(&rep, 0, sizeof(xQueryPointerReply)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.mask = mouse->button ? (mouse->button->state) : 0; + rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); + rep.length = 0; + rep.root = (GetCurrentRootWindow(mouse))->drawable.id; + rep.rootX = pSprite->hot.x; + rep.rootY = pSprite->hot.y; + rep.child = None; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + rep.sameScreen = xTrue; + rep.winX = pSprite->hot.x - pWin->drawable.x; + rep.winY = pSprite->hot.y - pWin->drawable.y; + for (t = pSprite->win; t; t = t->parent) + if (t->parent == pWin) + { + rep.child = t->drawable.id; + break; + } + } + else + { + rep.sameScreen = xFalse; + rep.winX = 0; + rep.winY = 0; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + rep.rootX += screenInfo.screens[0]->x; + rep.rootY += screenInfo.screens[0]->y; + if(stuff->id == rep.root) { + rep.winX += screenInfo.screens[0]->x; + rep.winY += screenInfo.screens[0]->y; + } + } +#endif + + if (rc == BadAccess) { + rep.mask = 0; + rep.child = None; + rep.rootX = 0; + rep.rootY = 0; + rep.winX = 0; + rep.winY = 0; + } + + WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); + + return Success; +} + +/** + * Initializes the device list and the DIX sprite to sane values. Allocates + * trace memory used for quick window traversal. + */ +void +InitEvents(void) +{ + int i; + + inputInfo.numDevices = 0; + inputInfo.devices = (DeviceIntPtr)NULL; + inputInfo.off_devices = (DeviceIntPtr)NULL; + inputInfo.keyboard = (DeviceIntPtr)NULL; + inputInfo.pointer = (DeviceIntPtr)NULL; + /* The mask for pointer motion events may have changed in the last server + * generation. See comment above definition of filters. */ + filters[0][PointerMotionMask] = MotionNotify; + for (i = 1; i < MAXDEVICES; i++) + { + memcpy(&filters[i], filters[0], sizeof(filters[0])); + } + + syncEvents.replayDev = (DeviceIntPtr)NULL; + syncEvents.replayWin = NullWindow; + while (syncEvents.pending) + { + QdEventPtr next = syncEvents.pending->next; + free(syncEvents.pending); + syncEvents.pending = next; + } + syncEvents.pendtail = &syncEvents.pending; + syncEvents.playingEvents = FALSE; + syncEvents.time.months = 0; + syncEvents.time.milliseconds = 0; /* hardly matters */ + currentTime.months = 0; + currentTime.milliseconds = GetTimeInMillis(); + lastDeviceEventTime = currentTime; + for (i = 0; i < DNPMCOUNT; i++) + { + DontPropagateMasks[i] = 0; + DontPropagateRefCnts[i] = 0; + } + + InputEventListLen = GetMaximumEventsNum(); + InputEventList = InitEventList(InputEventListLen); + if (!InputEventList) + FatalError("[dix] Failed to allocate input event list.\n"); +} + +void +CloseDownEvents(void) +{ + FreeEventList(InputEventList, InputEventListLen); + InputEventListLen = 0; + InputEventList = NULL; +} + +/** + * Server-side protocol handling for SendEvent request. + * + * Locates the window to send the event to and forwards the event. + */ +int +ProcSendEvent(ClientPtr client) +{ + WindowPtr pWin; + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + DeviceIntPtr dev = PickPointer(client); + DeviceIntPtr keybd = GetPairedDevice(dev); + SpritePtr pSprite = dev->spriteInfo->sprite; + REQUEST(xSendEventReq); + + REQUEST_SIZE_MATCH(xSendEventReq); + + /* The client's event type must be a core event type or one defined by an + extension. */ + + if ( ! ((stuff->event.u.u.type > X_Reply && + stuff->event.u.u.type < LASTEvent) || + (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && + stuff->event.u.u.type < (unsigned)lastEvent))) + { + client->errorValue = stuff->event.u.u.type; + return BadValue; + } + if (stuff->event.u.u.type == ClientMessage && + stuff->event.u.u.detail != 8 && + stuff->event.u.u.detail != 16 && + stuff->event.u.u.detail != 32) + { + client->errorValue = stuff->event.u.u.detail; + return BadValue; + } + if (stuff->eventMask & ~AllEventMasks) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->destination == PointerWindow) + pWin = pSprite->win; + else if (stuff->destination == InputFocus) + { + WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; + + if (inputFocus == NoneWin) + return Success; + + /* If the input focus is PointerRootWin, send the event to where + the pointer is if possible, then perhaps propogate up to root. */ + if (inputFocus == PointerRootWin) + inputFocus = GetCurrentRootWindow(dev); + + if (IsParent(inputFocus, pSprite->win)) + { + effectiveFocus = inputFocus; + pWin = pSprite->win; + } + else + effectiveFocus = pWin = inputFocus; + } + else + dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess); + + if (!pWin) + return BadWindow; + if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) + { + client->errorValue = stuff->propagate; + return BadValue; + } + stuff->event.u.u.type |= 0x80; + if (stuff->propagate) + { + for (;pWin; pWin = pWin->parent) + { + if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, + &stuff->event, 1)) + return Success; + if (DeliverEventsToWindow(dev, pWin, + &stuff->event, 1, stuff->eventMask, NullGrab)) + return Success; + if (pWin == effectiveFocus) + return Success; + stuff->eventMask &= ~wDontPropagateMask(pWin); + if (!stuff->eventMask) + break; + } + } + else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) + DeliverEventsToWindow(dev, pWin, &stuff->event, + 1, stuff->eventMask, NullGrab); + return Success; +} + +/** + * Server-side protocol handling for UngrabKey request. + * + * Deletes a passive grab for the given key. Works on the + * client's keyboard. + */ +int +ProcUngrabKey(ClientPtr client) +{ + REQUEST(xUngrabKeyReq); + WindowPtr pWin; + GrabRec tempGrab; + DeviceIntPtr keybd = PickKeyboard(client); + int rc; + + REQUEST_SIZE_MATCH(xUngrabKeyReq); + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) + && (stuff->key != AnyKey)) + { + client->errorValue = stuff->key; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + tempGrab.resource = client->clientAsMask; + tempGrab.device = keybd; + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = GetPairedDevice(keybd); + tempGrab.type = KeyPress; + tempGrab.grabtype = GRABTYPE_CORE; + tempGrab.detail.exact = stuff->key; + tempGrab.detail.pMask = NULL; + tempGrab.next = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return BadAlloc; + return Success; +} + +/** + * Server-side protocol handling for GrabKey request. + * + * Creates a grab for the client's keyboard and adds it to the list of passive + * grabs. + */ +int +ProcGrabKey(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xGrabKeyReq); + GrabPtr grab; + DeviceIntPtr keybd = PickKeyboard(client); + int rc; + GrabParameters param; + GrabMask mask; + + REQUEST_SIZE_MATCH(xGrabKeyReq); + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + rc = CheckGrabValues(client, ¶m); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) + && (stuff->key != AnyKey)) + { + client->errorValue = stuff->key; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + + mask.core = (KeyPressMask | KeyReleaseMask); + + grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, + ¶m, KeyPress, stuff->key, NullWindow, NullCursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + + +/** + * Server-side protocol handling for GrabButton request. + * + * Creates a grab for the client's ClientPointer and adds it as a passive grab + * to the list. + */ +int +ProcGrabButton(ClientPtr client) +{ + WindowPtr pWin, confineTo; + REQUEST(xGrabButtonReq); + CursorPtr cursor; + GrabPtr grab; + DeviceIntPtr ptr, modifierDevice; + Mask access_mode = DixGrabAccess; + GrabMask mask; + GrabParameters param; + int rc; + + REQUEST_SIZE_MATCH(xGrabButtonReq); + if ((stuff->pointerMode != GrabModeSync) && + (stuff->pointerMode != GrabModeAsync)) + { + client->errorValue = stuff->pointerMode; + return BadValue; + } + if ((stuff->keyboardMode != GrabModeSync) && + (stuff->keyboardMode != GrabModeAsync)) + { + client->errorValue = stuff->keyboardMode; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) + { + client->errorValue = stuff->ownerEvents; + return BadValue; + } + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (stuff->confineTo == None) + confineTo = NullWindow; + else { + rc = dixLookupWindow(&confineTo, stuff->confineTo, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + if (stuff->cursor == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return rc; + } + access_mode |= DixForceAccess; + } + + ptr = PickPointer(client); + modifierDevice = GetPairedDevice(ptr); + if (stuff->pointerMode == GrabModeSync || + stuff->keyboardMode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode); + if (rc != Success) + return rc; + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + mask.core = stuff->eventMask; + + grab = CreateGrab(client->index, ptr, modifierDevice, pWin, + GRABTYPE_CORE, &mask, ¶m, ButtonPress, + stuff->button, confineTo, cursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/** + * Server-side protocol handling for UngrabButton request. + * + * Deletes a passive grab on the client's ClientPointer from the list. + */ +int +ProcUngrabButton(ClientPtr client) +{ + REQUEST(xUngrabButtonReq); + WindowPtr pWin; + GrabRec tempGrab; + int rc; + DeviceIntPtr ptr; + + REQUEST_SIZE_MATCH(xUngrabButtonReq); + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); + if (rc != Success) + return rc; + + ptr = PickPointer(client); + + tempGrab.resource = client->clientAsMask; + tempGrab.device = ptr; + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = GetPairedDevice(ptr); + tempGrab.type = ButtonPress; + tempGrab.detail.exact = stuff->button; + tempGrab.grabtype = GRABTYPE_CORE; + tempGrab.detail.pMask = NULL; + tempGrab.next = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return BadAlloc; + return Success; +} + +/** + * Deactivate any grab that may be on the window, remove the focus. + * Delete any XInput extension events from the window too. Does not change the + * window mask. Use just before the window is deleted. + * + * If freeResources is set, passive grabs on the window are deleted. + * + * @param pWin The window to delete events from. + * @param freeResources True if resources associated with the window should be + * deleted. + */ +void +DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) +{ + WindowPtr parent; + DeviceIntPtr mouse = inputInfo.pointer; + DeviceIntPtr keybd = inputInfo.keyboard; + FocusClassPtr focus; + OtherClientsPtr oc; + GrabPtr passive; + GrabPtr grab; + + + /* Deactivate any grabs performed on this window, before making any + input focus changes. */ + grab = mouse->deviceGrab.grab; + if (grab && + ((grab->window == pWin) || (grab->confineTo == pWin))) + (*mouse->deviceGrab.DeactivateGrab)(mouse); + + + /* Deactivating a keyboard grab should cause focus events. */ + grab = keybd->deviceGrab.grab; + if (grab && (grab->window == pWin)) + (*keybd->deviceGrab.DeactivateGrab)(keybd); + + /* And now the real devices */ + for (mouse = inputInfo.devices; mouse; mouse = mouse->next) + { + grab = mouse->deviceGrab.grab; + if (grab && ((grab->window == pWin) || (grab->confineTo == pWin))) + (*mouse->deviceGrab.DeactivateGrab)(mouse); + } + + + for (keybd = inputInfo.devices; keybd; keybd = keybd->next) + { + if (IsKeyboardDevice(keybd)) + { + focus = keybd->focus; + + /* If the focus window is a root window (ie. has no parent) then don't + delete the focus from it. */ + + if ((pWin == focus->win) && (pWin->parent != NullWindow)) + { + int focusEventMode = NotifyNormal; + + /* If a grab is in progress, then alter the mode of focus events. */ + + if (keybd->deviceGrab.grab) + focusEventMode = NotifyWhileGrabbed; + + switch (focus->revert) + { + case RevertToNone: + DoFocusEvents(keybd, pWin, NoneWin, focusEventMode); + focus->win = NoneWin; + focus->traceGood = 0; + break; + case RevertToParent: + parent = pWin; + do + { + parent = parent->parent; + focus->traceGood--; + } while (!parent->realized + /* This would be a good protocol change -- windows being reparented + during SaveSet processing would cause the focus to revert to the + nearest enclosing window which will survive the death of the exiting + client, instead of ending up reverting to a dying window and thence + to None + */ +#ifdef NOTDEF + || wClient(parent)->clientGone +#endif + ); + if (!ActivateFocusInGrab(keybd, pWin, parent)) + DoFocusEvents(keybd, pWin, parent, focusEventMode); + focus->win = parent; + focus->revert = RevertToNone; + break; + case RevertToPointerRoot: + if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) + DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); + focus->win = PointerRootWin; + focus->traceGood = 0; + break; + } + } + } + + if (IsPointerDevice(keybd)) + { + if (keybd->valuator->motionHintWindow == pWin) + keybd->valuator->motionHintWindow = NullWindow; + } + } + + if (freeResources) + { + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]--; + while ( (oc = wOtherClients(pWin)) ) + FreeResource(oc->resource, RT_NONE); + while ( (passive = wPassiveGrabs(pWin)) ) + FreeResource(passive->resource, RT_NONE); + } + + DeleteWindowFromAnyExtEvents(pWin, freeResources); +} + +/** + * Call this whenever some window at or below pWin has changed geometry. If + * there is a grab on the window, the cursor will be re-confined into the + * window. + */ +void +CheckCursorConfinement(WindowPtr pWin) +{ + GrabPtr grab; + WindowPtr confineTo; + DeviceIntPtr pDev; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; +#endif + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + grab = pDev->deviceGrab.grab; + if (grab && (confineTo = grab->confineTo)) + { + if (!BorderSizeNotEmpty(pDev, confineTo)) + (*pDev->deviceGrab.DeactivateGrab)(pDev); + else if ((pWin == confineTo) || IsParent(pWin, confineTo)) + ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE); + } + } + } +} + +Mask +EventMaskForClient(WindowPtr pWin, ClientPtr client) +{ + OtherClientsPtr other; + + if (wClient (pWin) == client) + return pWin->eventMask; + for (other = wOtherClients(pWin); other; other = other->next) + { + if (SameClient(other, client)) + return other->mask; + } + return 0; +} + +/** + * Server-side protocol handling for RecolorCursor request. + */ +int +ProcRecolorCursor(ClientPtr client) +{ + CursorPtr pCursor; + int rc, nscr; + ScreenPtr pscr; + Bool displayed; + SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + REQUEST(xRecolorCursorReq); + + REQUEST_SIZE_MATCH(xRecolorCursorReq); + rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, + client, DixWriteAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return rc; + } + + pCursor->foreRed = stuff->foreRed; + pCursor->foreGreen = stuff->foreGreen; + pCursor->foreBlue = stuff->foreBlue; + + pCursor->backRed = stuff->backRed; + pCursor->backGreen = stuff->backGreen; + pCursor->backBlue = stuff->backBlue; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; +#ifdef PANORAMIX + if(!noPanoramiXExtension) + displayed = (pscr == pSprite->screen); + else +#endif + displayed = (pscr == pSprite->hotPhys.pScreen); + ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor, + (pCursor == pSprite->current) && displayed); + } + return Success; +} + +/** + * Write the given events to a client, swapping the byte order if necessary. + * To swap the byte ordering, a callback is called that has to be set up for + * the given event type. + * + * In the case of DeviceMotionNotify trailed by DeviceValuators, the events + * can be more than one. Usually it's just one event. + * + * Do not modify the event structure passed in. See comment below. + * + * @param pClient Client to send events to. + * @param count Number of events. + * @param events The event list. + */ +void +WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) +{ +#ifdef PANORAMIX + xEvent eventCopy; +#endif + xEvent *eventTo, *eventFrom; + int i, + eventlength = sizeof(xEvent); + + if (!pClient || pClient == serverClient || pClient->clientGone) + return; + + for (i = 0; i < count; i++) + if ((events[i].u.u.type & 0x7f) != KeymapNotify) + events[i].u.u.sequenceNumber = pClient->sequence; + + /* Let XKB rewrite the state, as it depends on client preferences. */ + XkbFilterEvents(pClient, count, events); + +#ifdef PANORAMIX + if(!noPanoramiXExtension && + (screenInfo.screens[0]->x || screenInfo.screens[0]->y)) + { + switch(events->u.u.type) { + case MotionNotify: + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + case EnterNotify: + case LeaveNotify: + /* + When multiple clients want the same event DeliverEventsToWindow + passes the same event structure multiple times so we can't + modify the one passed to us + */ + count = 1; /* should always be 1 */ + memcpy(&eventCopy, events, sizeof(xEvent)); + eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x; + eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y; + if(eventCopy.u.keyButtonPointer.event == + eventCopy.u.keyButtonPointer.root) + { + eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x; + eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y; + } + events = &eventCopy; + break; + default: break; + } + } +#endif + + if (EventCallback) + { + EventInfoRec eventinfo; + eventinfo.client = pClient; + eventinfo.events = events; + eventinfo.count = count; + CallCallbacks(&EventCallback, (pointer)&eventinfo); + } +#ifdef XSERVER_DTRACE + if (XSERVER_SEND_EVENT_ENABLED()) { + for (i = 0; i < count; i++) + { + XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]); + } + } +#endif + /* Just a safety check to make sure we only have one GenericEvent, it just + * makes things easier for me right now. (whot) */ + for (i = 1; i < count; i++) + { + if (events[i].u.u.type == GenericEvent) + { + ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n"); + return; + } + } + + if (events->u.u.type == GenericEvent) + { + eventlength += ((xGenericEvent*)events)->length * 4; + } + + if(pClient->swapped) + { + if (eventlength > swapEventLen) + { + swapEventLen = eventlength; + swapEvent = realloc(swapEvent, swapEventLen); + if (!swapEvent) + { + FatalError("WriteEventsToClient: Out of memory.\n"); + return; + } + } + + for(i = 0; i < count; i++) + { + eventFrom = &events[i]; + eventTo = swapEvent; + + /* Remember to strip off the leading bit of type in case + this event was sent with "SendEvent." */ + (*EventSwapVector[eventFrom->u.u.type & 0177]) + (eventFrom, eventTo); + + WriteToClient(pClient, eventlength, (char *)eventTo); + } + } + else + { + /* only one GenericEvent, remember? that means either count is 1 and + * eventlength is arbitrary or eventlength is 32 and count doesn't + * matter. And we're all set. Woohoo. */ + WriteToClient(pClient, count * eventlength, (char *) events); + } +} + +/* + * Set the client pointer for the given client. + * + * A client can have exactly one ClientPointer. Each time a + * request/reply/event is processed and the choice of devices is ambiguous + * (e.g. QueryPointer request), the server will pick the ClientPointer (see + * PickPointer()). + * If a keyboard is needed, the first keyboard paired with the CP is used. + */ +int +SetClientPointer(ClientPtr client, DeviceIntPtr device) +{ + int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); + if (rc != Success) + return rc; + + if (!IsMaster(device)) + { + ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); + return BadDevice; + } else if (!device->spriteInfo->spriteOwner) + { + ErrorF("[dix] Device %d does not have a sprite. " + "Cannot be ClientPointer\n", device->id); + return BadDevice; + } + client->clientPtr = device; + return Success; +} + +/* PickPointer will pick an appropriate pointer for the given client. + * + * An "appropriate device" is (in order of priority): + * 1) A device the given client has a core grab on. + * 2) A device set as ClientPointer for the given client. + * 3) The first master device. + */ +DeviceIntPtr +PickPointer(ClientPtr client) +{ + DeviceIntPtr it = inputInfo.devices; + + /* First, check if the client currently has a grab on a device. Even + * keyboards count. */ + for(it = inputInfo.devices; it; it = it->next) + { + GrabPtr grab = it->deviceGrab.grab; + if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) + { + it = GetMaster(it, MASTER_POINTER); + return it; /* Always return a core grabbed device */ + } + } + + if (!client->clientPtr) + { + DeviceIntPtr it = inputInfo.devices; + while (it) + { + if (IsMaster(it) && it->spriteInfo->spriteOwner) + { + client->clientPtr = it; + break; + } + it = it->next; + } + } + return client->clientPtr; +} + +/* PickKeyboard will pick an appropriate keyboard for the given client by + * searching the list of devices for the keyboard device that is paired with + * the client's pointer. + */ +DeviceIntPtr +PickKeyboard(ClientPtr client) +{ + DeviceIntPtr ptr = PickPointer(client); + DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); + + if (!kbd) + { + ErrorF("[dix] ClientPointer not paired with a keyboard. This " + "is a bug.\n"); + } + + return kbd; +} + +/* A client that has one or more core grabs does not get core events from + * devices it does not have a grab on. Legacy applications behave bad + * otherwise because they are not used to it and the events interfere. + * Only applies for core events. + * + * Return true if a core event from the device would interfere and should not + * be delivered. + */ +Bool +IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) +{ + DeviceIntPtr it = inputInfo.devices; + + switch(event->u.u.type) + { + case KeyPress: + case KeyRelease: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case EnterNotify: + case LeaveNotify: + break; + default: + return FALSE; + } + + if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + return FALSE; + + while(it) + { + if (it != dev) + { + if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client) + && !it->deviceGrab.fromPassiveGrab) + { + if ((IsPointerDevice(it) && IsPointerDevice(dev)) || + (IsKeyboardDevice(it) && IsKeyboardDevice(dev))) + return TRUE; + } + } + it = it->next; + } + + return FALSE; +} + diff --git a/xorg-server/dix/inpututils.c b/xorg-server/dix/inpututils.c index 80275bd40..ef3142c84 100644 --- a/xorg-server/dix/inpututils.c +++ b/xorg-server/dix/inpututils.c @@ -1,550 +1,558 @@ -/* - * Copyright © 2008 Daniel Stone - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Daniel Stone - */ - -#ifdef HAVE_DIX_CONFIG_H -#include "dix-config.h" -#endif - -#include "exevents.h" -#include "exglobals.h" -#include "misc.h" -#include "input.h" -#include "inputstr.h" -#include "xace.h" -#include "xkbsrv.h" -#include "xkbstr.h" -#include "inpututils.h" - -/* Check if a button map change is okay with the device. - * Returns -1 for BadValue, as it collides with MappingBusy. */ -static int -check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out, - ClientPtr client) -{ - int i, ret; - - if (!dev || !dev->button) - { - client->errorValue = (dev) ? dev->id : 0; - return BadDevice; - } - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (ret != Success) - { - client->errorValue = dev->id; - return ret; - } - - for (i = 0; i < len; i++) { - if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1]) - return MappingBusy; - } - - return Success; -} - -static void -do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) -{ - int i; - xEvent core_mn; - deviceMappingNotify xi_mn; - - /* The map in ButtonClassRec refers to button numbers, whereas the - * protocol is zero-indexed. Sigh. */ - memcpy(&(dev->button->map[1]), map, len); - - core_mn.u.u.type = MappingNotify; - core_mn.u.mappingNotify.request = MappingPointer; - - /* 0 is the server client. */ - for (i = 1; i < currentMaxClients; i++) { - /* Don't send irrelevant events to naïve clients. */ - if (!clients[i] || clients[i]->clientState != ClientStateRunning) - continue; - - if (!XIShouldNotify(clients[i], dev)) - continue; - - WriteEventsToClient(clients[i], 1, &core_mn); - } - - xi_mn.type = DeviceMappingNotify; - xi_mn.request = MappingPointer; - xi_mn.deviceid = dev->id; - xi_mn.time = GetTimeInMillis(); - - SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1); -} - -/* - * Does what it says on the box, both for core and Xi. - * - * Faithfully reports any errors encountered while trying to apply the map - * to the requested device, faithfully ignores any errors encountered while - * trying to apply the map to its master/slaves. - */ -int -ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) -{ - int ret; - - /* If we can't perform the change on the requested device, bail out. */ - ret = check_butmap_change(dev, map, len, &client->errorValue, client); - if (ret != Success) - return ret; - do_butmap_change(dev, map, len, client); - - return Success; -} - -/* Check if a modifier map change is okay with the device. - * Returns -1 for BadValue, as it collides with MappingBusy; this particular - * caveat can be removed with LegalModifier, as we have no other reason to - * set MappingFailed. Sigh. */ -static int -check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap) -{ - int ret, i; - XkbDescPtr xkb; - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (ret != Success) - return ret; - - if (!dev->key) - return BadMatch; - xkb = dev->key->xkbInfo->desc; - - for (i = 0; i < MAP_LENGTH; i++) { - if (!modmap[i]) - continue; - - /* Check that all the new modifiers fall within the advertised - * keycode range. */ - if (i < xkb->min_key_code || i > xkb->max_key_code) { - client->errorValue = i; - return -1; - } - - /* Make sure the mapping is okay with the DDX. */ - if (!LegalModifier(i, dev)) { - client->errorValue = i; - return MappingFailed; - } - - /* None of the new modifiers may be down while we change the - * map. */ - if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { - client->errorValue = i; - return MappingBusy; - } - } - - /* None of the old modifiers may be down while we change the map, - * either. */ - for (i = xkb->min_key_code; i < xkb->max_key_code; i++) { - if (!xkb->map->modmap[i]) - continue; - if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { - client->errorValue = i; - return MappingBusy; - } - } - - return Success; -} - -static int -check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, - DeviceIntPtr slave, CARD8 *modmap) -{ - XkbDescPtr master_xkb, slave_xkb; - int i, j; - - if (!slave->key || !master->key) - return 0; - - master_xkb = master->key->xkbInfo->desc; - slave_xkb = slave->key->xkbInfo->desc; - - /* Ignore devices with a clearly different keymap. */ - if (slave_xkb->min_key_code != master_xkb->min_key_code || - slave_xkb->max_key_code != master_xkb->max_key_code) - return 0; - - for (i = 0; i < MAP_LENGTH; i++) { - if (!modmap[i]) - continue; - - /* If we have different symbols for any modifier on an - * extended keyboard, ignore the whole remap request. */ - for (j = 0; - j < XkbKeyNumSyms(slave_xkb, i) && - j < XkbKeyNumSyms(master_xkb, i); - j++) - if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) - return 0; - } - - if (check_modmap_change(client, slave, modmap) != Success) - return 0; - - return 1; -} - -/* Actually change the modifier map, and send notifications. Cannot fail. */ -static void -do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) -{ - XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient); -} - -/* Rebuild modmap (key -> mod) from map (mod -> key). */ -static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap, - int max_keys_per_mod) -{ - int i, len = max_keys_per_mod * 8; - - memset(modmap, 0, MAP_LENGTH); - - for (i = 0; i < len; i++) { - if (!modkeymap[i]) - continue; - - if (modkeymap[i] >= MAP_LENGTH) - return BadValue; - - if (modmap[modkeymap[i]]) - return BadValue; - - modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod); - } - - return Success; -} - -int -change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, - int max_keys_per_mod) -{ - int ret; - CARD8 modmap[MAP_LENGTH]; - DeviceIntPtr tmp; - - ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); - if (ret != Success) - return ret; - - /* If we can't perform the change on the requested device, bail out. */ - ret = check_modmap_change(client, dev, modmap); - if (ret != Success) - return ret; - do_modmap_change(client, dev, modmap); - - /* Change any attached masters/slaves. */ - if (IsMaster(dev)) { - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (!IsMaster(tmp) && tmp->u.master == dev) - if (check_modmap_change_slave(client, dev, tmp, modmap)) - do_modmap_change(client, tmp, modmap); - } - } - else if (dev->u.master && dev->u.master->u.lastSlave == dev) { - /* If this fails, expect the results to be weird. */ - if (check_modmap_change(client, dev->u.master, modmap)) - do_modmap_change(client, dev->u.master, modmap); - } - - return Success; -} - -int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, - KeyCode **modkeymap_out, int *max_keys_per_mod_out) -{ - CARD8 keys_per_mod[8]; - int max_keys_per_mod; - KeyCode *modkeymap = NULL; - int i, j, ret; - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); - if (ret != Success) - return ret; - - if (!dev->key) - return BadMatch; - - /* Count the number of keys per modifier to determine how wide we - * should make the map. */ - max_keys_per_mod = 0; - for (i = 0; i < 8; i++) - keys_per_mod[i] = 0; - for (i = 8; i < MAP_LENGTH; i++) { - for (j = 0; j < 8; j++) { - if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { - if (++keys_per_mod[j] > max_keys_per_mod) - max_keys_per_mod = keys_per_mod[j]; - } - } - } - - if (max_keys_per_mod != 0) { - modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode)); - if (!modkeymap) - return BadAlloc; - - for (i = 0; i < 8; i++) - keys_per_mod[i] = 0; - - for (i = 8; i < MAP_LENGTH; i++) { - for (j = 0; j < 8; j++) { - if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { - modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; - keys_per_mod[j]++; - } - } - } - } - - *max_keys_per_mod_out = max_keys_per_mod; - *modkeymap_out = modkeymap; - - return Success; -} - -/** - * Duplicate the InputAttributes in the most obvious way. - * No special memory handling is used to give drivers the maximum - * flexibility with the data. Drivers should be able to call realloc on the - * product string if needed and perform similar operations. - */ -InputAttributes* -DuplicateInputAttributes(InputAttributes *attrs) -{ - InputAttributes *new_attr; - int ntags = 0; - char **tags, **new_tags; - - if (!attrs) - return NULL; - - if (!(new_attr = calloc(1, sizeof(InputAttributes)))) - goto unwind; - - if (attrs->product && !(new_attr->product = strdup(attrs->product))) - goto unwind; - if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor))) - goto unwind; - if (attrs->device && !(new_attr->device = strdup(attrs->device))) - goto unwind; - if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id))) - goto unwind; - if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id))) - goto unwind; - - new_attr->flags = attrs->flags; - - if ((tags = attrs->tags)) - { - while(*tags++) - ntags++; - - new_attr->tags = calloc(ntags + 1, sizeof(char*)); - if (!new_attr->tags) - goto unwind; - - tags = attrs->tags; - new_tags = new_attr->tags; - - while(*tags) - { - *new_tags = strdup(*tags); - if (!*new_tags) - goto unwind; - - tags++; - new_tags++; - } - } - - return new_attr; - -unwind: - FreeInputAttributes(new_attr); - return NULL; -} - -void -FreeInputAttributes(InputAttributes *attrs) -{ - char **tags; - - if (!attrs) - return; - - free(attrs->product); - free(attrs->vendor); - free(attrs->device); - free(attrs->pnp_id); - free(attrs->usb_id); - - if ((tags = attrs->tags)) - while(*tags) - free(*tags++); - - free(attrs->tags); - free(attrs); -} - -/** - * Alloc a valuator mask large enough for num_valuators. - */ -ValuatorMask* -valuator_mask_new(int num_valuators) -{ - /* alloc a fixed size mask for now and ignore num_valuators. in the - * flying-car future, when we can dynamically alloc the masks and are - * not constrained by signals, we can start using num_valuators */ - ValuatorMask *mask = calloc(1, sizeof(ValuatorMask)); - mask->last_bit = -1; - return mask; -} - -/** - * Sets a range of valuators between first_valuator and num_valuators with - * the data in the valuators array. All other values are set to 0. - */ -void -valuator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators, - const int* valuators) -{ - int i; - - valuator_mask_zero(mask); - - for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++) - valuator_mask_set(mask, i, valuators[i - first_valuator]); -} - -/** - * Reset mask to zero. - */ -void -valuator_mask_zero(ValuatorMask *mask) -{ - memset(mask, 0, sizeof(*mask)); - mask->last_bit = -1; -} - -/** - * Returns the current size of the mask (i.e. the highest number of - * valuators currently set + 1). - */ -int -valuator_mask_size(const ValuatorMask *mask) -{ - return mask->last_bit + 1; -} - -/** - * Returns the number of valuators set in the given mask. - */ -int -valuator_mask_num_valuators(const ValuatorMask *mask) -{ - return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS)); -} - -/** - * Return true if the valuator is set in the mask, or false otherwise. - */ -int -valuator_mask_isset(const ValuatorMask *mask, int valuator) -{ - return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator); -} - -/** - * Set the valuator to the given data. - */ -void -valuator_mask_set(ValuatorMask *mask, int valuator, int data) -{ - mask->last_bit = max(valuator, mask->last_bit); - SetBit(mask->mask, valuator); - mask->valuators[valuator] = data; -} - -/** - * Return the requested valuator value. If the mask bit is not set for the - * given valuator, the returned value is undefined. - */ -int -valuator_mask_get(const ValuatorMask *mask, int valuator) -{ - return mask->valuators[valuator]; -} - -/** - * Remove the valuator from the mask. - */ -void -valuator_mask_unset(ValuatorMask *mask, int valuator) -{ - if (mask->last_bit >= valuator) { - int i, lastbit = -1; - - ClearBit(mask->mask, valuator); - mask->valuators[valuator] = 0; - - for (i = 0; i <= mask->last_bit; i++) - if (valuator_mask_isset(mask, i)) - lastbit = max(lastbit, i); - mask->last_bit = lastbit; - } -} - -void -valuator_mask_copy(ValuatorMask *dest, const ValuatorMask *src) -{ - if (src) - memcpy(dest, src, sizeof(*dest)); - else - valuator_mask_zero(dest); -} - -int -CountBits(const uint8_t *mask, int len) -{ - int i; - int ret = 0; - - for (i = 0; i < len; i++) - if (BitIsOn(mask, i)) - ret++; - - return ret; -} +/* + * Copyright © 2008 Daniel Stone + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Daniel Stone + */ + +#ifdef HAVE_DIX_CONFIG_H +#include "dix-config.h" +#endif + +#include "exevents.h" +#include "exglobals.h" +#include "misc.h" +#include "input.h" +#include "inputstr.h" +#include "xace.h" +#include "xkbsrv.h" +#include "xkbstr.h" +#include "inpututils.h" + +/* Check if a button map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy. */ +static int +check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out, + ClientPtr client) +{ + int i, ret; + + if (!dev || !dev->button) + { + client->errorValue = (dev) ? dev->id : 0; + return BadDevice; + } + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (ret != Success) + { + client->errorValue = dev->id; + return ret; + } + + for (i = 0; i < len; i++) { + if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1]) + return MappingBusy; + } + + return Success; +} + +static void +do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) +{ + int i; + xEvent core_mn; + deviceMappingNotify xi_mn; + + /* The map in ButtonClassRec refers to button numbers, whereas the + * protocol is zero-indexed. Sigh. */ + memcpy(&(dev->button->map[1]), map, len); + + core_mn.u.u.type = MappingNotify; + core_mn.u.mappingNotify.request = MappingPointer; + + /* 0 is the server client. */ + for (i = 1; i < currentMaxClients; i++) { + /* Don't send irrelevant events to naïve clients. */ + if (!clients[i] || clients[i]->clientState != ClientStateRunning) + continue; + + if (!XIShouldNotify(clients[i], dev)) + continue; + + WriteEventsToClient(clients[i], 1, &core_mn); + } + + xi_mn.type = DeviceMappingNotify; + xi_mn.request = MappingPointer; + xi_mn.deviceid = dev->id; + xi_mn.time = GetTimeInMillis(); + + SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1); +} + +/* + * Does what it says on the box, both for core and Xi. + * + * Faithfully reports any errors encountered while trying to apply the map + * to the requested device, faithfully ignores any errors encountered while + * trying to apply the map to its master/slaves. + */ +int +ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) +{ + int ret; + + /* If we can't perform the change on the requested device, bail out. */ + ret = check_butmap_change(dev, map, len, &client->errorValue, client); + if (ret != Success) + return ret; + do_butmap_change(dev, map, len, client); + + return Success; +} + +/* Check if a modifier map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy; this particular + * caveat can be removed with LegalModifier, as we have no other reason to + * set MappingFailed. Sigh. */ +static int +check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap) +{ + int ret, i; + XkbDescPtr xkb; + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (ret != Success) + return ret; + + if (!dev->key) + return BadMatch; + xkb = dev->key->xkbInfo->desc; + + for (i = 0; i < MAP_LENGTH; i++) { + if (!modmap[i]) + continue; + + /* Check that all the new modifiers fall within the advertised + * keycode range. */ + if (i < xkb->min_key_code || i > xkb->max_key_code) { + client->errorValue = i; + return -1; + } + + /* Make sure the mapping is okay with the DDX. */ + if (!LegalModifier(i, dev)) { + client->errorValue = i; + return MappingFailed; + } + + /* None of the new modifiers may be down while we change the + * map. */ + if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { + client->errorValue = i; + return MappingBusy; + } + } + + /* None of the old modifiers may be down while we change the map, + * either. */ + for (i = xkb->min_key_code; i < xkb->max_key_code; i++) { + if (!xkb->map->modmap[i]) + continue; + if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { + client->errorValue = i; + return MappingBusy; + } + } + + return Success; +} + +static int +check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, + DeviceIntPtr slave, CARD8 *modmap) +{ + XkbDescPtr master_xkb, slave_xkb; + int i, j; + + if (!slave->key || !master->key) + return 0; + + master_xkb = master->key->xkbInfo->desc; + slave_xkb = slave->key->xkbInfo->desc; + + /* Ignore devices with a clearly different keymap. */ + if (slave_xkb->min_key_code != master_xkb->min_key_code || + slave_xkb->max_key_code != master_xkb->max_key_code) + return 0; + + for (i = 0; i < MAP_LENGTH; i++) { + if (!modmap[i]) + continue; + + /* If we have different symbols for any modifier on an + * extended keyboard, ignore the whole remap request. */ + for (j = 0; + j < XkbKeyNumSyms(slave_xkb, i) && + j < XkbKeyNumSyms(master_xkb, i); + j++) + if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) + return 0; + } + + if (check_modmap_change(client, slave, modmap) != Success) + return 0; + + return 1; +} + +/* Actually change the modifier map, and send notifications. Cannot fail. */ +static void +do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) +{ + XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient); +} + +/* Rebuild modmap (key -> mod) from map (mod -> key). */ +static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap, + int max_keys_per_mod) +{ + int i, len = max_keys_per_mod * 8; + + memset(modmap, 0, MAP_LENGTH); + + for (i = 0; i < len; i++) { + if (!modkeymap[i]) + continue; + + if (modkeymap[i] >= MAP_LENGTH) + return BadValue; + + if (modmap[modkeymap[i]]) + return BadValue; + + modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod); + } + + return Success; +} + +int +change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, + int max_keys_per_mod) +{ + int ret; + CARD8 modmap[MAP_LENGTH]; + DeviceIntPtr tmp; + + ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); + if (ret != Success) + return ret; + + /* If we can't perform the change on the requested device, bail out. */ + ret = check_modmap_change(client, dev, modmap); + if (ret != Success) + return ret; + do_modmap_change(client, dev, modmap); + + /* Change any attached masters/slaves. */ + if (IsMaster(dev)) { + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if (!IsMaster(tmp) && tmp->u.master == dev) + if (check_modmap_change_slave(client, dev, tmp, modmap)) + do_modmap_change(client, tmp, modmap); + } + } + else if (dev->u.master && dev->u.master->u.lastSlave == dev) { + /* If this fails, expect the results to be weird. */ + if (check_modmap_change(client, dev->u.master, modmap)) + do_modmap_change(client, dev->u.master, modmap); + } + + return Success; +} + +int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, + KeyCode **modkeymap_out, int *max_keys_per_mod_out) +{ + CARD8 keys_per_mod[8]; + int max_keys_per_mod; + KeyCode *modkeymap = NULL; + int i, j, ret; + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); + if (ret != Success) + return ret; + + if (!dev->key) + return BadMatch; + + /* Count the number of keys per modifier to determine how wide we + * should make the map. */ + max_keys_per_mod = 0; + for (i = 0; i < 8; i++) + keys_per_mod[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0; j < 8; j++) { + if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { + if (++keys_per_mod[j] > max_keys_per_mod) + max_keys_per_mod = keys_per_mod[j]; + } + } + } + + if (max_keys_per_mod != 0) { + modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode)); + if (!modkeymap) + return BadAlloc; + + for (i = 0; i < 8; i++) + keys_per_mod[i] = 0; + + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0; j < 8; j++) { + if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { + modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; + keys_per_mod[j]++; + } + } + } + } + + *max_keys_per_mod_out = max_keys_per_mod; + *modkeymap_out = modkeymap; + + return Success; +} + +/** + * Duplicate the InputAttributes in the most obvious way. + * No special memory handling is used to give drivers the maximum + * flexibility with the data. Drivers should be able to call realloc on the + * product string if needed and perform similar operations. + */ +InputAttributes* +DuplicateInputAttributes(InputAttributes *attrs) +{ + InputAttributes *new_attr; + int ntags = 0; + char **tags, **new_tags; + + if (!attrs) + return NULL; + + if (!(new_attr = calloc(1, sizeof(InputAttributes)))) + goto unwind; + + if (attrs->product && !(new_attr->product = strdup(attrs->product))) + goto unwind; + if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor))) + goto unwind; + if (attrs->device && !(new_attr->device = strdup(attrs->device))) + goto unwind; + if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id))) + goto unwind; + if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id))) + goto unwind; + + new_attr->flags = attrs->flags; + + if ((tags = attrs->tags)) + { + while(*tags++) + ntags++; + + new_attr->tags = calloc(ntags + 1, sizeof(char*)); + if (!new_attr->tags) + goto unwind; + + tags = attrs->tags; + new_tags = new_attr->tags; + + while(*tags) + { + *new_tags = strdup(*tags); + if (!*new_tags) + goto unwind; + + tags++; + new_tags++; + } + } + + return new_attr; + +unwind: + FreeInputAttributes(new_attr); + return NULL; +} + +void +FreeInputAttributes(InputAttributes *attrs) +{ + char **tags; + + if (!attrs) + return; + + free(attrs->product); + free(attrs->vendor); + free(attrs->device); + free(attrs->pnp_id); + free(attrs->usb_id); + + if ((tags = attrs->tags)) + while(*tags) + free(*tags++); + + free(attrs->tags); + free(attrs); +} + +/** + * Alloc a valuator mask large enough for num_valuators. + */ +ValuatorMask* +valuator_mask_new(int num_valuators) +{ + /* alloc a fixed size mask for now and ignore num_valuators. in the + * flying-car future, when we can dynamically alloc the masks and are + * not constrained by signals, we can start using num_valuators */ + ValuatorMask *mask = calloc(1, sizeof(ValuatorMask)); + mask->last_bit = -1; + return mask; +} + +void +valuator_mask_free(ValuatorMask **mask) +{ + free(*mask); + *mask = NULL; +} + + +/** + * Sets a range of valuators between first_valuator and num_valuators with + * the data in the valuators array. All other values are set to 0. + */ +void +valuator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators, + const int* valuators) +{ + int i; + + valuator_mask_zero(mask); + + for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++) + valuator_mask_set(mask, i, valuators[i - first_valuator]); +} + +/** + * Reset mask to zero. + */ +void +valuator_mask_zero(ValuatorMask *mask) +{ + memset(mask, 0, sizeof(*mask)); + mask->last_bit = -1; +} + +/** + * Returns the current size of the mask (i.e. the highest number of + * valuators currently set + 1). + */ +int +valuator_mask_size(const ValuatorMask *mask) +{ + return mask->last_bit + 1; +} + +/** + * Returns the number of valuators set in the given mask. + */ +int +valuator_mask_num_valuators(const ValuatorMask *mask) +{ + return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS)); +} + +/** + * Return true if the valuator is set in the mask, or false otherwise. + */ +int +valuator_mask_isset(const ValuatorMask *mask, int valuator) +{ + return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator); +} + +/** + * Set the valuator to the given data. + */ +void +valuator_mask_set(ValuatorMask *mask, int valuator, int data) +{ + mask->last_bit = max(valuator, mask->last_bit); + SetBit(mask->mask, valuator); + mask->valuators[valuator] = data; +} + +/** + * Return the requested valuator value. If the mask bit is not set for the + * given valuator, the returned value is undefined. + */ +int +valuator_mask_get(const ValuatorMask *mask, int valuator) +{ + return mask->valuators[valuator]; +} + +/** + * Remove the valuator from the mask. + */ +void +valuator_mask_unset(ValuatorMask *mask, int valuator) +{ + if (mask->last_bit >= valuator) { + int i, lastbit = -1; + + ClearBit(mask->mask, valuator); + mask->valuators[valuator] = 0; + + for (i = 0; i <= mask->last_bit; i++) + if (valuator_mask_isset(mask, i)) + lastbit = max(lastbit, i); + mask->last_bit = lastbit; + } +} + +void +valuator_mask_copy(ValuatorMask *dest, const ValuatorMask *src) +{ + if (src) + memcpy(dest, src, sizeof(*dest)); + else + valuator_mask_zero(dest); +} + +int +CountBits(const uint8_t *mask, int len) +{ + int i; + int ret = 0; + + for (i = 0; i < len; i++) + if (BitIsOn(mask, i)) + ret++; + + return ret; +} diff --git a/xorg-server/dix/resource.c b/xorg-server/dix/resource.c index bec68753e..26d2c72aa 100644 --- a/xorg-server/dix/resource.c +++ b/xorg-server/dix/resource.c @@ -1,973 +1,965 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL 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. - -********************************************************/ -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ -/* XSERVER_DTRACE additions: - * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* Routines to manage various kinds of resources: - * - * CreateNewResourceType, CreateNewResourceClass, InitClientResources, - * FakeClientID, AddResource, FreeResource, FreeClientResources, - * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange - */ - -/* - * A resource ID is a 32 bit quantity, the upper 2 bits of which are - * off-limits for client-visible resources. The next 8 bits are - * used as client ID, and the low 22 bits come from the client. - * A resource ID is "hashed" by extracting and xoring subfields - * (varying with the size of the hash table). - * - * It is sometimes necessary for the server to create an ID that looks - * like it belongs to a client. This ID, however, must not be one - * the client actually can create, or we have the potential for conflict. - * The 31st bit of the ID is reserved for the server's use for this - * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to - * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a - * resource "owned" by the client. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "misc.h" -#include "os.h" -#include "resource.h" -#include "dixstruct.h" -#include "opaque.h" -#include "windowstr.h" -#include "dixfont.h" -#include "colormap.h" -#include "inputstr.h" -#include "dixevents.h" -#include "dixgrabs.h" -#include "cursor.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "xace.h" -#include -#include "registry.h" - -#ifdef XSERVER_DTRACE -#include -typedef const char *string; -#include "Xserver-dtrace.h" - -#define TypeNameString(t) LookupResourceName(t) -#endif - -static void RebuildTable( - int /*client*/ -); - -#define SERVER_MINID 32 - -#define INITBUCKETS 64 -#define INITHASHSIZE 6 -#define MAXHASHSIZE 11 - -typedef struct _Resource { - struct _Resource *next; - XID id; - RESTYPE type; - pointer value; -} ResourceRec, *ResourcePtr; -#define NullResource ((ResourcePtr)NULL) - -typedef struct _ClientResource { - ResourcePtr *resources; - int elements; - int buckets; - int hashsize; /* log(2)(buckets) */ - XID fakeID; - XID endFakeID; - XID expectID; -} ClientResourceRec; - -RESTYPE lastResourceType; -static RESTYPE lastResourceClass; -RESTYPE TypeMask; - -struct ResourceType { - DeleteType deleteFunc; - int errorValue; -}; - -static struct ResourceType *resourceTypes; -static const struct ResourceType predefTypes[] = { - [RT_NONE & (RC_LASTPREDEF - 1)] = { - .deleteFunc = (DeleteType)NoopDDA, - .errorValue = BadValue, - }, - [RT_WINDOW & (RC_LASTPREDEF - 1)] = { - .deleteFunc = DeleteWindow, - .errorValue = BadWindow, - }, - [RT_PIXMAP & (RC_LASTPREDEF - 1)] = { - .deleteFunc = dixDestroyPixmap, - .errorValue = BadPixmap, - }, - [RT_GC & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeGC, - .errorValue = BadGC, - }, - [RT_FONT & (RC_LASTPREDEF - 1)] = { - .deleteFunc = CloseFont, - .errorValue = BadFont, - }, - [RT_CURSOR & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeCursor, - .errorValue = BadCursor, - }, - [RT_COLORMAP & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeColormap, - .errorValue = BadColor, - }, - [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeClientPixels, - .errorValue = BadColor, - }, - [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = { - .deleteFunc = OtherClientGone, - .errorValue = BadValue, - }, - [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = { - .deleteFunc = DeletePassiveGrab, - .errorValue = BadValue, - }, -}; - -CallbackListPtr ResourceStateCallback; - -static _X_INLINE void -CallResourceStateCallback(ResourceState state, ResourceRec *res) -{ - if (ResourceStateCallback) { - ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; - CallCallbacks(&ResourceStateCallback, &rsi); - } -} - -RESTYPE -CreateNewResourceType(DeleteType deleteFunc, char *name) -{ - RESTYPE next = lastResourceType + 1; - struct ResourceType *types; - - if (next & lastResourceClass) - return 0; - types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); - if (!types) - return 0; - - lastResourceType = next; - resourceTypes = types; - resourceTypes[next].deleteFunc = deleteFunc; - resourceTypes[next].errorValue = BadValue; - - /* Called even if name is NULL, to remove any previous entry */ - RegisterResourceName(next, name); - - return next; -} - -void -SetResourceTypeErrorValue(RESTYPE type, int errorValue) -{ - resourceTypes[type & TypeMask].errorValue = errorValue; -} - -RESTYPE -CreateNewResourceClass(void) -{ - RESTYPE next = lastResourceClass >> 1; - - if (next & lastResourceType) - return 0; - lastResourceClass = next; - TypeMask = next - 1; - return next; -} - -static ClientResourceRec clientTable[MAXCLIENTS]; - -/***************** - * InitClientResources - * When a new client is created, call this to allocate space - * in resource table - *****************/ - -Bool -InitClientResources(ClientPtr client) -{ - int i, j; - - if (client == serverClient) - { - lastResourceType = RT_LASTPREDEF; - lastResourceClass = RC_LASTPREDEF; - TypeMask = RC_LASTPREDEF - 1; - free(resourceTypes); - resourceTypes = malloc(sizeof(predefTypes)); - if (!resourceTypes) - return FALSE; - memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); - } - clientTable[i = client->index].resources = - malloc(INITBUCKETS*sizeof(ResourcePtr)); - if (!clientTable[i].resources) - return FALSE; - clientTable[i].buckets = INITBUCKETS; - clientTable[i].elements = 0; - clientTable[i].hashsize = INITHASHSIZE; - /* Many IDs allocated from the server client are visible to clients, - * so we don't use the SERVER_BIT for them, but we have to start - * past the magic value constants used in the protocol. For normal - * clients, we can start from zero, with SERVER_BIT set. - */ - clientTable[i].fakeID = client->clientAsMask | - (client->index ? SERVER_BIT : SERVER_MINID); - clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; - clientTable[i].expectID = client->clientAsMask; - for (j=0; j>6) ^ (id>>12)))); - case 7: - return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); - case 8: - return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); - case 9: - return ((int)(0x1FF & (id ^ (id>>9)))); - case 10: - return ((int)(0x3FF & (id ^ (id>>10)))); - case 11: - return ((int)(0x7FF & (id ^ (id>>11)))); - } - return -1; -} - -static XID -AvailableID( - int client, - XID id, - XID maxid, - XID goodid) -{ - ResourcePtr res; - - if ((goodid >= id) && (goodid <= maxid)) - return goodid; - for (; id <= maxid; id++) - { - res = clientTable[client].resources[Hash(client, id)]; - while (res && (res->id != id)) - res = res->next; - if (!res) - return id; - } - return 0; -} - -void -GetXIDRange(int client, Bool server, XID *minp, XID *maxp) -{ - XID id, maxid; - ResourcePtr *resp; - ResourcePtr res; - int i; - XID goodid; - - id = (Mask)client << CLIENTOFFSET; - if (server) - id |= client ? SERVER_BIT : SERVER_MINID; - maxid = id | RESOURCE_ID_MASK; - goodid = 0; - for (resp = clientTable[client].resources, i = clientTable[client].buckets; - --i >= 0;) - { - for (res = *resp++; res; res = res->next) - { - if ((res->id < id) || (res->id > maxid)) - continue; - if (((res->id - id) >= (maxid - res->id)) ? - (goodid = AvailableID(client, id, res->id - 1, goodid)) : - !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) - maxid = res->id - 1; - else - id = res->id + 1; - } - } - if (id > maxid) - id = maxid = 0; - *minp = id; - *maxp = maxid; -} - -/** - * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. - * This function tries to find count unused XIDs for the given client. It - * puts the IDs in the array pids and returns the number found, which should - * almost always be the number requested. - * - * The circumstances that lead to a call to this function are very rare. - * Xlib must run out of IDs while trying to generate a request that wants - * multiple ID's, like the Multi-buffering CreateImageBuffers request. - * - * No rocket science in the implementation; just iterate over all - * possible IDs for the given client and pick the first count IDs - * that aren't in use. A more efficient algorithm could probably be - * invented, but this will be used so rarely that this should suffice. - */ - -unsigned int -GetXIDList(ClientPtr pClient, unsigned count, XID *pids) -{ - unsigned int found = 0; - XID rc, id = pClient->clientAsMask; - XID maxid; - pointer val; - - maxid = id | RESOURCE_ID_MASK; - while ( (found < count) && (id <= maxid) ) - { - rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, - DixGetAttrAccess); - if (rc == BadValue) - { - pids[found++] = id; - } - id++; - } - return found; -} - -/* - * Return the next usable fake client ID. - * - * Normally this is just the next one in line, but if we've used the last - * in the range, we need to find a new range of safe IDs to avoid - * over-running another client. - */ - -XID -FakeClientID(int client) -{ - XID id, maxid; - - id = clientTable[client].fakeID++; - if (id != clientTable[client].endFakeID) - return id; - GetXIDRange(client, TRUE, &id, &maxid); - if (!id) { - if (!client) - FatalError("FakeClientID: server internal ids exhausted\n"); - MarkClientException(clients[client]); - id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); - maxid = id | RESOURCE_ID_MASK; - } - clientTable[client].fakeID = id + 1; - clientTable[client].endFakeID = maxid + 1; - return id; -} - -Bool -AddResource(XID id, RESTYPE type, pointer value) -{ - int client; - ClientResourceRec *rrec; - ResourcePtr res, *head; - -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); -#endif - client = CLIENT_ID(id); - rrec = &clientTable[client]; - if (!rrec->buckets) - { - ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n", - (unsigned long)id, type, (unsigned long)value, client); - FatalError("client not in use\n"); - } - if ((rrec->elements >= 4*rrec->buckets) && - (rrec->hashsize < MAXHASHSIZE)) - RebuildTable(client); - head = &rrec->resources[Hash(client, id)]; - res = malloc(sizeof(ResourceRec)); - if (!res) - { - (*resourceTypes[type & TypeMask].deleteFunc)(value, id); - return FALSE; - } - res->next = *head; - res->id = id; - res->type = type; - res->value = value; - *head = res; - rrec->elements++; - if (!(id & SERVER_BIT) && (id >= rrec->expectID)) - rrec->expectID = id + 1; - CallResourceStateCallback(ResourceStateAdding, res); - return TRUE; -} - -static void -RebuildTable(int client) -{ - int j; - ResourcePtr res, next; - ResourcePtr **tails, *resources; - ResourcePtr **tptr, *rptr; - - /* - * For now, preserve insertion order, since some ddx layers depend - * on resources being free in the opposite order they are added. - */ - - j = 2 * clientTable[client].buckets; - tails = malloc(j * sizeof(ResourcePtr *)); - if (!tails) - return; - resources = malloc(j * sizeof(ResourcePtr)); - if (!resources) - { - free(tails); - return; - } - for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) - { - *rptr = NullResource; - *tptr = rptr; - } - clientTable[client].hashsize++; - for (j = clientTable[client].buckets, - rptr = clientTable[client].resources; - --j >= 0; - rptr++) - { - for (res = *rptr; res; res = next) - { - next = res->next; - res->next = NullResource; - tptr = &tails[Hash(client, res->id)]; - **tptr = res; - *tptr = &res->next; - } - } - free(tails); - clientTable[client].buckets *= 2; - free(clientTable[client].resources); - clientTable[client].resources = resources; -} - -void -FreeResource(XID id, RESTYPE skipDeleteFuncType) -{ - int cid; - ResourcePtr res; - ResourcePtr *prev, *head; - int *eltptr; - int elements; - - if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) - { - head = &clientTable[cid].resources[Hash(cid, id)]; - eltptr = &clientTable[cid].elements; - - prev = head; - while ( (res = *prev) ) - { - if (res->id == id) - { - RESTYPE rtype = res->type; - -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(res->id, res->type, - res->value, TypeNameString(res->type)); -#endif - *prev = res->next; - elements = --*eltptr; - - CallResourceStateCallback(ResourceStateFreeing, res); - - if (rtype != skipDeleteFuncType) - (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id); - free(res); - if (*eltptr != elements) - prev = head; /* prev may no longer be valid */ - } - else - prev = &res->next; - } - } -} - - -void -FreeResourceByType(XID id, RESTYPE type, Bool skipFree) -{ - int cid; - ResourcePtr res; - ResourcePtr *prev, *head; - if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) - { - head = &clientTable[cid].resources[Hash(cid, id)]; - - prev = head; - while ( (res = *prev) ) - { - if (res->id == id && res->type == type) - { -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(res->id, res->type, - res->value, TypeNameString(res->type)); -#endif - *prev = res->next; - clientTable[cid].elements--; - - CallResourceStateCallback(ResourceStateFreeing, res); - - if (!skipFree) - (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id); - free(res); - break; - } - else - prev = &res->next; - } - } -} - -/* - * Change the value associated with a resource id. Caller - * is responsible for "doing the right thing" with the old - * data - */ - -Bool -ChangeResourceValue (XID id, RESTYPE rtype, pointer value) -{ - int cid; - ResourcePtr res; - - if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) - { - res = clientTable[cid].resources[Hash(cid, id)]; - - for (; res; res = res->next) - if ((res->id == id) && (res->type == rtype)) - { - res->value = value; - return TRUE; - } - } - return FALSE; -} - -/* Note: if func adds or deletes resources, then func can get called - * more than once for some resources. If func adds new resources, - * func might or might not get called for them. func cannot both - * add and delete an equal number of resources! - */ - -void -FindClientResourcesByType( - ClientPtr client, - RESTYPE type, - FindResType func, - pointer cdata -){ - ResourcePtr *resources; - ResourcePtr this, next; - int i, elements; - int *eltptr; - - if (!client) - client = serverClient; - - resources = clientTable[client->index].resources; - eltptr = &clientTable[client->index].elements; - for (i = 0; i < clientTable[client->index].buckets; i++) - { - for (this = resources[i]; this; this = next) - { - next = this->next; - if (!type || this->type == type) { - elements = *eltptr; - (*func)(this->value, this->id, cdata); - if (*eltptr != elements) - next = resources[i]; /* start over */ - } - } - } -} - -void -FindAllClientResources( - ClientPtr client, - FindAllRes func, - pointer cdata -){ - ResourcePtr *resources; - ResourcePtr this, next; - int i, elements; - int *eltptr; - - if (!client) - client = serverClient; - - resources = clientTable[client->index].resources; - eltptr = &clientTable[client->index].elements; - for (i = 0; i < clientTable[client->index].buckets; i++) - { - for (this = resources[i]; this; this = next) - { - next = this->next; - elements = *eltptr; - (*func)(this->value, this->id, this->type, cdata); - if (*eltptr != elements) - next = resources[i]; /* start over */ - } - } -} - - -pointer -LookupClientResourceComplex( - ClientPtr client, - RESTYPE type, - FindComplexResType func, - pointer cdata -){ - ResourcePtr *resources; - ResourcePtr this, next; - pointer value; - int i; - - if (!client) - client = serverClient; - - resources = clientTable[client->index].resources; - for (i = 0; i < clientTable[client->index].buckets; i++) { - for (this = resources[i]; this; this = next) { - next = this->next; - if (!type || this->type == type) { - /* workaround func freeing the type as DRI1 does */ - value = this->value; - if((*func)(value, this->id, cdata)) - return value; - } - } - } - return NULL; -} - - -void -FreeClientNeverRetainResources(ClientPtr client) -{ - ResourcePtr *resources; - ResourcePtr this; - ResourcePtr *prev; - int j, elements; - int *eltptr; - - if (!client) - return; - - resources = clientTable[client->index].resources; - eltptr = &clientTable[client->index].elements; - for (j=0; j < clientTable[client->index].buckets; j++) - { - prev = &resources[j]; - while ( (this = *prev) ) - { - RESTYPE rtype = this->type; - if (rtype & RC_NEVERRETAIN) - { -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(this->id, this->type, - this->value, TypeNameString(this->type)); -#endif - *prev = this->next; - clientTable[client->index].elements--; - - CallResourceStateCallback(ResourceStateFreeing, this); - - elements = *eltptr; - (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); - free(this); - if (*eltptr != elements) - prev = &resources[j]; /* prev may no longer be valid */ - } - else - prev = &this->next; - } - } -} - -void -FreeClientResources(ClientPtr client) -{ - ResourcePtr *resources; - ResourcePtr this; - int j; - - /* This routine shouldn't be called with a null client, but just in - case ... */ - - if (!client) - return; - - HandleSaveSet(client); - - resources = clientTable[client->index].resources; - for (j=0; j < clientTable[client->index].buckets; j++) - { - /* It may seem silly to update the head of this resource list as - we delete the members, since the entire list will be deleted any way, - but there are some resource deletion functions "FreeClientPixels" for - one which do a LookupID on another resource id (a Colormap id in this - case), so the resource list must be kept valid up to the point that - it is deleted, so every time we delete a resource, we must update the - head, just like in FreeResource. I hope that this doesn't slow down - mass deletion appreciably. PRH */ - - ResourcePtr *head; - - head = &resources[j]; - - for (this = *head; this; this = *head) - { - RESTYPE rtype = this->type; -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(this->id, this->type, - this->value, TypeNameString(this->type)); -#endif - *head = this->next; - clientTable[client->index].elements--; - - CallResourceStateCallback(ResourceStateFreeing, this); - - (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); - free(this); - } - } - free(clientTable[client->index].resources); - clientTable[client->index].resources = NULL; - clientTable[client->index].buckets = 0; -} - -void -FreeAllResources(void) -{ - int i; - - for (i = currentMaxClients; --i >= 0; ) - { - if (clientTable[i].buckets) - FreeClientResources(clients[i]); - } -} - -Bool -LegalNewID(XID id, ClientPtr client) -{ - pointer val; - int rc; - -#ifdef PANORAMIX - XID minid, maxid; - - if (!noPanoramiXExtension) { - minid = client->clientAsMask | (client->index ? - SERVER_BIT : SERVER_MINID); - maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; - if ((id >= minid) && (id <= maxid)) - return TRUE; - } -#endif /* PANORAMIX */ - if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) - { - if (clientTable[client->index].expectID <= id) - return TRUE; - - rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, - DixGetAttrAccess); - return rc == BadValue; - } - return FALSE; -} - -int -dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, - ClientPtr client, Mask mode) -{ - int cid = CLIENT_ID(id); - ResourcePtr res = NULL; - - *result = NULL; - if ((rtype & TypeMask) > lastResourceType) - return BadImplementation; - - if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { - res = clientTable[cid].resources[Hash(cid, id)]; - - for (; res; res = res->next) - if (res->id == id && res->type == rtype) - break; - } - if (!res) - return resourceTypes[rtype & TypeMask].errorValue; - - if (client) { - client->errorValue = id; - cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, - res->value, RT_NONE, NULL, mode); - if (cid == BadValue) - return resourceTypes[rtype & TypeMask].errorValue; - if (cid != Success) - return cid; - } - - *result = res->value; - return Success; -} - -int -dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, - ClientPtr client, Mask mode) -{ - int cid = CLIENT_ID(id); - ResourcePtr res = NULL; - - *result = NULL; - - if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { - res = clientTable[cid].resources[Hash(cid, id)]; - - for (; res; res = res->next) - if (res->id == id && (res->type & rclass)) - break; - } - if (!res) - return BadValue; - - if (client) { - client->errorValue = id; - cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, - res->value, RT_NONE, NULL, mode); - if (cid != Success) - return cid; - } - - *result = res->value; - return Success; -} +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +********************************************************/ +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ +/* XSERVER_DTRACE additions: + * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Routines to manage various kinds of resources: + * + * CreateNewResourceType, CreateNewResourceClass, InitClientResources, + * FakeClientID, AddResource, FreeResource, FreeClientResources, + * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange + */ + +/* + * A resource ID is a 32 bit quantity, the upper 2 bits of which are + * off-limits for client-visible resources. The next 8 bits are + * used as client ID, and the low 22 bits come from the client. + * A resource ID is "hashed" by extracting and xoring subfields + * (varying with the size of the hash table). + * + * It is sometimes necessary for the server to create an ID that looks + * like it belongs to a client. This ID, however, must not be one + * the client actually can create, or we have the potential for conflict. + * The 31st bit of the ID is reserved for the server's use for this + * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to + * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a + * resource "owned" by the client. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "os.h" +#include "resource.h" +#include "dixstruct.h" +#include "opaque.h" +#include "windowstr.h" +#include "dixfont.h" +#include "colormap.h" +#include "inputstr.h" +#include "dixevents.h" +#include "dixgrabs.h" +#include "cursor.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "xace.h" +#include +#include "registry.h" + +#ifdef XSERVER_DTRACE +#include +typedef const char *string; +#include "Xserver-dtrace.h" + +#define TypeNameString(t) LookupResourceName(t) +#endif + +static void RebuildTable( + int /*client*/ +); + +#define SERVER_MINID 32 + +#define INITBUCKETS 64 +#define INITHASHSIZE 6 +#define MAXHASHSIZE 11 + +typedef struct _Resource { + struct _Resource *next; + XID id; + RESTYPE type; + pointer value; +} ResourceRec, *ResourcePtr; + +typedef struct _ClientResource { + ResourcePtr *resources; + int elements; + int buckets; + int hashsize; /* log(2)(buckets) */ + XID fakeID; + XID endFakeID; +} ClientResourceRec; + +RESTYPE lastResourceType; +static RESTYPE lastResourceClass; +RESTYPE TypeMask; + +struct ResourceType { + DeleteType deleteFunc; + int errorValue; +}; + +static struct ResourceType *resourceTypes; +static const struct ResourceType predefTypes[] = { + [RT_NONE & (RC_LASTPREDEF - 1)] = { + .deleteFunc = (DeleteType)NoopDDA, + .errorValue = BadValue, + }, + [RT_WINDOW & (RC_LASTPREDEF - 1)] = { + .deleteFunc = DeleteWindow, + .errorValue = BadWindow, + }, + [RT_PIXMAP & (RC_LASTPREDEF - 1)] = { + .deleteFunc = dixDestroyPixmap, + .errorValue = BadPixmap, + }, + [RT_GC & (RC_LASTPREDEF - 1)] = { + .deleteFunc = FreeGC, + .errorValue = BadGC, + }, + [RT_FONT & (RC_LASTPREDEF - 1)] = { + .deleteFunc = CloseFont, + .errorValue = BadFont, + }, + [RT_CURSOR & (RC_LASTPREDEF - 1)] = { + .deleteFunc = FreeCursor, + .errorValue = BadCursor, + }, + [RT_COLORMAP & (RC_LASTPREDEF - 1)] = { + .deleteFunc = FreeColormap, + .errorValue = BadColor, + }, + [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = { + .deleteFunc = FreeClientPixels, + .errorValue = BadColor, + }, + [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = { + .deleteFunc = OtherClientGone, + .errorValue = BadValue, + }, + [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = { + .deleteFunc = DeletePassiveGrab, + .errorValue = BadValue, + }, +}; + +CallbackListPtr ResourceStateCallback; + +static _X_INLINE void +CallResourceStateCallback(ResourceState state, ResourceRec *res) +{ + if (ResourceStateCallback) { + ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; + CallCallbacks(&ResourceStateCallback, &rsi); + } +} + +RESTYPE +CreateNewResourceType(DeleteType deleteFunc, char *name) +{ + RESTYPE next = lastResourceType + 1; + struct ResourceType *types; + + if (next & lastResourceClass) + return 0; + types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); + if (!types) + return 0; + + lastResourceType = next; + resourceTypes = types; + resourceTypes[next].deleteFunc = deleteFunc; + resourceTypes[next].errorValue = BadValue; + + /* Called even if name is NULL, to remove any previous entry */ + RegisterResourceName(next, name); + + return next; +} + +void +SetResourceTypeErrorValue(RESTYPE type, int errorValue) +{ + resourceTypes[type & TypeMask].errorValue = errorValue; +} + +RESTYPE +CreateNewResourceClass(void) +{ + RESTYPE next = lastResourceClass >> 1; + + if (next & lastResourceType) + return 0; + lastResourceClass = next; + TypeMask = next - 1; + return next; +} + +static ClientResourceRec clientTable[MAXCLIENTS]; + +/***************** + * InitClientResources + * When a new client is created, call this to allocate space + * in resource table + *****************/ + +Bool +InitClientResources(ClientPtr client) +{ + int i, j; + + if (client == serverClient) + { + lastResourceType = RT_LASTPREDEF; + lastResourceClass = RC_LASTPREDEF; + TypeMask = RC_LASTPREDEF - 1; + free(resourceTypes); + resourceTypes = malloc(sizeof(predefTypes)); + if (!resourceTypes) + return FALSE; + memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); + } + clientTable[i = client->index].resources = + malloc(INITBUCKETS*sizeof(ResourcePtr)); + if (!clientTable[i].resources) + return FALSE; + clientTable[i].buckets = INITBUCKETS; + clientTable[i].elements = 0; + clientTable[i].hashsize = INITHASHSIZE; + /* Many IDs allocated from the server client are visible to clients, + * so we don't use the SERVER_BIT for them, but we have to start + * past the magic value constants used in the protocol. For normal + * clients, we can start from zero, with SERVER_BIT set. + */ + clientTable[i].fakeID = client->clientAsMask | + (client->index ? SERVER_BIT : SERVER_MINID); + clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; + for (j=0; j>6) ^ (id>>12)))); + case 7: + return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); + case 8: + return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); + case 9: + return ((int)(0x1FF & (id ^ (id>>9)))); + case 10: + return ((int)(0x3FF & (id ^ (id>>10)))); + case 11: + return ((int)(0x7FF & (id ^ (id>>11)))); + } + return -1; +} + +static XID +AvailableID( + int client, + XID id, + XID maxid, + XID goodid) +{ + ResourcePtr res; + + if ((goodid >= id) && (goodid <= maxid)) + return goodid; + for (; id <= maxid; id++) + { + res = clientTable[client].resources[Hash(client, id)]; + while (res && (res->id != id)) + res = res->next; + if (!res) + return id; + } + return 0; +} + +void +GetXIDRange(int client, Bool server, XID *minp, XID *maxp) +{ + XID id, maxid; + ResourcePtr *resp; + ResourcePtr res; + int i; + XID goodid; + + id = (Mask)client << CLIENTOFFSET; + if (server) + id |= client ? SERVER_BIT : SERVER_MINID; + maxid = id | RESOURCE_ID_MASK; + goodid = 0; + for (resp = clientTable[client].resources, i = clientTable[client].buckets; + --i >= 0;) + { + for (res = *resp++; res; res = res->next) + { + if ((res->id < id) || (res->id > maxid)) + continue; + if (((res->id - id) >= (maxid - res->id)) ? + (goodid = AvailableID(client, id, res->id - 1, goodid)) : + !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) + maxid = res->id - 1; + else + id = res->id + 1; + } + } + if (id > maxid) + id = maxid = 0; + *minp = id; + *maxp = maxid; +} + +/** + * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. + * This function tries to find count unused XIDs for the given client. It + * puts the IDs in the array pids and returns the number found, which should + * almost always be the number requested. + * + * The circumstances that lead to a call to this function are very rare. + * Xlib must run out of IDs while trying to generate a request that wants + * multiple ID's, like the Multi-buffering CreateImageBuffers request. + * + * No rocket science in the implementation; just iterate over all + * possible IDs for the given client and pick the first count IDs + * that aren't in use. A more efficient algorithm could probably be + * invented, but this will be used so rarely that this should suffice. + */ + +unsigned int +GetXIDList(ClientPtr pClient, unsigned count, XID *pids) +{ + unsigned int found = 0; + XID rc, id = pClient->clientAsMask; + XID maxid; + pointer val; + + maxid = id | RESOURCE_ID_MASK; + while ( (found < count) && (id <= maxid) ) + { + rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, + DixGetAttrAccess); + if (rc == BadValue) + { + pids[found++] = id; + } + id++; + } + return found; +} + +/* + * Return the next usable fake client ID. + * + * Normally this is just the next one in line, but if we've used the last + * in the range, we need to find a new range of safe IDs to avoid + * over-running another client. + */ + +XID +FakeClientID(int client) +{ + XID id, maxid; + + id = clientTable[client].fakeID++; + if (id != clientTable[client].endFakeID) + return id; + GetXIDRange(client, TRUE, &id, &maxid); + if (!id) { + if (!client) + FatalError("FakeClientID: server internal ids exhausted\n"); + MarkClientException(clients[client]); + id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); + maxid = id | RESOURCE_ID_MASK; + } + clientTable[client].fakeID = id + 1; + clientTable[client].endFakeID = maxid + 1; + return id; +} + +Bool +AddResource(XID id, RESTYPE type, pointer value) +{ + int client; + ClientResourceRec *rrec; + ResourcePtr res, *head; + +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); +#endif + client = CLIENT_ID(id); + rrec = &clientTable[client]; + if (!rrec->buckets) + { + ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n", + (unsigned long)id, type, (unsigned long)value, client); + FatalError("client not in use\n"); + } + if ((rrec->elements >= 4*rrec->buckets) && + (rrec->hashsize < MAXHASHSIZE)) + RebuildTable(client); + head = &rrec->resources[Hash(client, id)]; + res = malloc(sizeof(ResourceRec)); + if (!res) + { + (*resourceTypes[type & TypeMask].deleteFunc)(value, id); + return FALSE; + } + res->next = *head; + res->id = id; + res->type = type; + res->value = value; + *head = res; + rrec->elements++; + CallResourceStateCallback(ResourceStateAdding, res); + return TRUE; +} + +static void +RebuildTable(int client) +{ + int j; + ResourcePtr res, next; + ResourcePtr **tails, *resources; + ResourcePtr **tptr, *rptr; + + /* + * For now, preserve insertion order, since some ddx layers depend + * on resources being free in the opposite order they are added. + */ + + j = 2 * clientTable[client].buckets; + tails = malloc(j * sizeof(ResourcePtr *)); + if (!tails) + return; + resources = malloc(j * sizeof(ResourcePtr)); + if (!resources) + { + free(tails); + return; + } + for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) + { + *rptr = NULL; + *tptr = rptr; + } + clientTable[client].hashsize++; + for (j = clientTable[client].buckets, + rptr = clientTable[client].resources; + --j >= 0; + rptr++) + { + for (res = *rptr; res; res = next) + { + next = res->next; + res->next = NULL; + tptr = &tails[Hash(client, res->id)]; + **tptr = res; + *tptr = &res->next; + } + } + free(tails); + clientTable[client].buckets *= 2; + free(clientTable[client].resources); + clientTable[client].resources = resources; +} + +void +FreeResource(XID id, RESTYPE skipDeleteFuncType) +{ + int cid; + ResourcePtr res; + ResourcePtr *prev, *head; + int *eltptr; + int elements; + + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + head = &clientTable[cid].resources[Hash(cid, id)]; + eltptr = &clientTable[cid].elements; + + prev = head; + while ( (res = *prev) ) + { + if (res->id == id) + { + RESTYPE rtype = res->type; + +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(res->id, res->type, + res->value, TypeNameString(res->type)); +#endif + *prev = res->next; + elements = --*eltptr; + + CallResourceStateCallback(ResourceStateFreeing, res); + + if (rtype != skipDeleteFuncType) + (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id); + free(res); + if (*eltptr != elements) + prev = head; /* prev may no longer be valid */ + } + else + prev = &res->next; + } + } +} + + +void +FreeResourceByType(XID id, RESTYPE type, Bool skipFree) +{ + int cid; + ResourcePtr res; + ResourcePtr *prev, *head; + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + head = &clientTable[cid].resources[Hash(cid, id)]; + + prev = head; + while ( (res = *prev) ) + { + if (res->id == id && res->type == type) + { +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(res->id, res->type, + res->value, TypeNameString(res->type)); +#endif + *prev = res->next; + clientTable[cid].elements--; + + CallResourceStateCallback(ResourceStateFreeing, res); + + if (!skipFree) + (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id); + free(res); + break; + } + else + prev = &res->next; + } + } +} + +/* + * Change the value associated with a resource id. Caller + * is responsible for "doing the right thing" with the old + * data + */ + +Bool +ChangeResourceValue (XID id, RESTYPE rtype, pointer value) +{ + int cid; + ResourcePtr res; + + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + res = clientTable[cid].resources[Hash(cid, id)]; + + for (; res; res = res->next) + if ((res->id == id) && (res->type == rtype)) + { + res->value = value; + return TRUE; + } + } + return FALSE; +} + +/* Note: if func adds or deletes resources, then func can get called + * more than once for some resources. If func adds new resources, + * func might or might not get called for them. func cannot both + * add and delete an equal number of resources! + */ + +void +FindClientResourcesByType( + ClientPtr client, + RESTYPE type, + FindResType func, + pointer cdata +){ + ResourcePtr *resources; + ResourcePtr this, next; + int i, elements; + int *eltptr; + + if (!client) + client = serverClient; + + resources = clientTable[client->index].resources; + eltptr = &clientTable[client->index].elements; + for (i = 0; i < clientTable[client->index].buckets; i++) + { + for (this = resources[i]; this; this = next) + { + next = this->next; + if (!type || this->type == type) { + elements = *eltptr; + (*func)(this->value, this->id, cdata); + if (*eltptr != elements) + next = resources[i]; /* start over */ + } + } + } +} + +void +FindAllClientResources( + ClientPtr client, + FindAllRes func, + pointer cdata +){ + ResourcePtr *resources; + ResourcePtr this, next; + int i, elements; + int *eltptr; + + if (!client) + client = serverClient; + + resources = clientTable[client->index].resources; + eltptr = &clientTable[client->index].elements; + for (i = 0; i < clientTable[client->index].buckets; i++) + { + for (this = resources[i]; this; this = next) + { + next = this->next; + elements = *eltptr; + (*func)(this->value, this->id, this->type, cdata); + if (*eltptr != elements) + next = resources[i]; /* start over */ + } + } +} + + +pointer +LookupClientResourceComplex( + ClientPtr client, + RESTYPE type, + FindComplexResType func, + pointer cdata +){ + ResourcePtr *resources; + ResourcePtr this, next; + pointer value; + int i; + + if (!client) + client = serverClient; + + resources = clientTable[client->index].resources; + for (i = 0; i < clientTable[client->index].buckets; i++) { + for (this = resources[i]; this; this = next) { + next = this->next; + if (!type || this->type == type) { + /* workaround func freeing the type as DRI1 does */ + value = this->value; + if((*func)(value, this->id, cdata)) + return value; + } + } + } + return NULL; +} + + +void +FreeClientNeverRetainResources(ClientPtr client) +{ + ResourcePtr *resources; + ResourcePtr this; + ResourcePtr *prev; + int j, elements; + int *eltptr; + + if (!client) + return; + + resources = clientTable[client->index].resources; + eltptr = &clientTable[client->index].elements; + for (j=0; j < clientTable[client->index].buckets; j++) + { + prev = &resources[j]; + while ( (this = *prev) ) + { + RESTYPE rtype = this->type; + if (rtype & RC_NEVERRETAIN) + { +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(this->id, this->type, + this->value, TypeNameString(this->type)); +#endif + *prev = this->next; + clientTable[client->index].elements--; + + CallResourceStateCallback(ResourceStateFreeing, this); + + elements = *eltptr; + (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); + free(this); + if (*eltptr != elements) + prev = &resources[j]; /* prev may no longer be valid */ + } + else + prev = &this->next; + } + } +} + +void +FreeClientResources(ClientPtr client) +{ + ResourcePtr *resources; + ResourcePtr this; + int j; + + /* This routine shouldn't be called with a null client, but just in + case ... */ + + if (!client) + return; + + HandleSaveSet(client); + + resources = clientTable[client->index].resources; + for (j=0; j < clientTable[client->index].buckets; j++) + { + /* It may seem silly to update the head of this resource list as + we delete the members, since the entire list will be deleted any way, + but there are some resource deletion functions "FreeClientPixels" for + one which do a LookupID on another resource id (a Colormap id in this + case), so the resource list must be kept valid up to the point that + it is deleted, so every time we delete a resource, we must update the + head, just like in FreeResource. I hope that this doesn't slow down + mass deletion appreciably. PRH */ + + ResourcePtr *head; + + head = &resources[j]; + + for (this = *head; this; this = *head) + { + RESTYPE rtype = this->type; +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(this->id, this->type, + this->value, TypeNameString(this->type)); +#endif + *head = this->next; + clientTable[client->index].elements--; + + CallResourceStateCallback(ResourceStateFreeing, this); + + (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); + free(this); + } + } + free(clientTable[client->index].resources); + clientTable[client->index].resources = NULL; + clientTable[client->index].buckets = 0; +} + +void +FreeAllResources(void) +{ + int i; + + for (i = currentMaxClients; --i >= 0; ) + { + if (clientTable[i].buckets) + FreeClientResources(clients[i]); + } +} + +Bool +LegalNewID(XID id, ClientPtr client) +{ + pointer val; + int rc; + +#ifdef PANORAMIX + XID minid, maxid; + + if (!noPanoramiXExtension) { + minid = client->clientAsMask | (client->index ? + SERVER_BIT : SERVER_MINID); + maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; + if ((id >= minid) && (id <= maxid)) + return TRUE; + } +#endif /* PANORAMIX */ + if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) + { + rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, + DixGetAttrAccess); + return rc == BadValue; + } + return FALSE; +} + +int +dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, + ClientPtr client, Mask mode) +{ + int cid = CLIENT_ID(id); + ResourcePtr res = NULL; + + *result = NULL; + if ((rtype & TypeMask) > lastResourceType) + return BadImplementation; + + if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { + res = clientTable[cid].resources[Hash(cid, id)]; + + for (; res; res = res->next) + if (res->id == id && res->type == rtype) + break; + } + if (!res) + return resourceTypes[rtype & TypeMask].errorValue; + + if (client) { + client->errorValue = id; + cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, + res->value, RT_NONE, NULL, mode); + if (cid == BadValue) + return resourceTypes[rtype & TypeMask].errorValue; + if (cid != Success) + return cid; + } + + *result = res->value; + return Success; +} + +int +dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, + ClientPtr client, Mask mode) +{ + int cid = CLIENT_ID(id); + ResourcePtr res = NULL; + + *result = NULL; + + if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { + res = clientTable[cid].resources[Hash(cid, id)]; + + for (; res; res = res->next) + if (res->id == id && (res->type & rclass)) + break; + } + if (!res) + return BadValue; + + if (client) { + client->errorValue = id; + cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, + res->value, RT_NONE, NULL, mode); + if (cid != Success) + return cid; + } + + *result = res->value; + return Success; +} diff --git a/xorg-server/hw/dmx/config/xdmxconfig.c b/xorg-server/hw/dmx/config/xdmxconfig.c index 033b52512..c67077aec 100644 --- a/xorg-server/hw/dmx/config/xdmxconfig.c +++ b/xorg-server/hw/dmx/config/xdmxconfig.c @@ -142,7 +142,7 @@ static void dmxConfigGetDims(int *maxWidth, int *maxHeight) DMXConfigEntryPtr e; *maxWidth = dmxConfigWallWidth = 0; - *maxWidth = dmxConfigWallHeight = 0; + *maxHeight = dmxConfigWallHeight = 0; if (!dmxConfigCurrent) return; dmxConfigWallWidth = dmxConfigCurrent->width; diff --git a/xorg-server/hw/dmx/dmxextension.c b/xorg-server/hw/dmx/dmxextension.c index 97f2a04b0..bd326ce2a 100644 --- a/xorg-server/hw/dmx/dmxextension.c +++ b/xorg-server/hw/dmx/dmxextension.c @@ -1,1618 +1,1620 @@ -/* - * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Author: - * Rickard E. (Rik) Faith - * Kevin E. Martin - * - */ - -/** \file - * This file provides the only interface to the X server extension support - * in programs/Xserver/Xext. Those programs should only include dmxext.h - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include - -#include "dmx.h" -#include "dmxinit.h" -#include "dmxextension.h" -#include "dmxwindow.h" -#include "dmxcb.h" -#include "dmxcursor.h" -#include "dmxpixmap.h" -#include "dmxgc.h" -#include "dmxfont.h" -#include "dmxcmap.h" -#include "dmxpict.h" -#include "dmxinput.h" -#include "dmxsync.h" -#include "dmxscrinit.h" -#include "input/dmxinputinit.h" - -#include "windowstr.h" -#include "inputstr.h" /* For DeviceIntRec */ -#include /* For DMX_BAD_* */ -#include "cursorstr.h" - -/* The default font is declared in dix/globals.c, but is not included in - * _any_ header files. */ -extern FontPtr defaultFont; - -/** This routine provides information to the DMX protocol extension - * about a particular screen. */ -Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr) -{ - DMXScreenInfo *dmxScreen; - - if (physical < 0 || physical >= dmxNumScreens) return FALSE; - - dmxScreen = &dmxScreens[physical]; - attr->displayName = dmxScreen->name; -#ifdef PANORAMIX - attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0; -#else - attr->logicalScreen = dmxScreen->index; -#endif - - attr->screenWindowWidth = dmxScreen->scrnWidth; - attr->screenWindowHeight = dmxScreen->scrnHeight; - attr->screenWindowXoffset = dmxScreen->scrnX; - attr->screenWindowYoffset = dmxScreen->scrnY; - - attr->rootWindowWidth = dmxScreen->rootWidth; - attr->rootWindowHeight = dmxScreen->rootHeight; - attr->rootWindowXoffset = dmxScreen->rootX; - attr->rootWindowYoffset = dmxScreen->rootY; - - attr->rootWindowXorigin = dmxScreen->rootXOrigin; - attr->rootWindowYorigin = dmxScreen->rootYOrigin; - - return TRUE; -} - -/** This routine provides information to the DMX protocol extension - * about a particular window. */ -Bool dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr) -{ - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - attr->screen = pWindow->drawable.pScreen->myNum; - attr->window = pWinPriv->window; - - attr->pos.x = pWindow->drawable.x; - attr->pos.y = pWindow->drawable.y; - attr->pos.width = pWindow->drawable.width; - attr->pos.height = pWindow->drawable.height; - - if (!pWinPriv->window || pWinPriv->offscreen) { - attr->vis.x = 0; - attr->vis.y = 0; - attr->vis.height = 0; - attr->vis.width = 0; - return pWinPriv->window ? TRUE : FALSE; - } - - /* Compute display-relative coordinates */ - attr->vis.x = pWindow->drawable.x; - attr->vis.y = pWindow->drawable.y; - attr->vis.width = pWindow->drawable.width; - attr->vis.height = pWindow->drawable.height; - - if (attr->pos.x < 0) { - attr->vis.x -= attr->pos.x; - attr->vis.width = attr->pos.x + attr->pos.width - attr->vis.x; - } - if (attr->pos.x + attr->pos.width > pWindow->drawable.pScreen->width) { - if (attr->pos.x < 0) - attr->vis.width = pWindow->drawable.pScreen->width; - else - attr->vis.width = pWindow->drawable.pScreen->width - attr->pos.x; - } - if (attr->pos.y < 0) { - attr->vis.y -= attr->pos.y; - attr->vis.height = attr->pos.y + attr->pos.height - attr->vis.y; - } - if (attr->pos.y + attr->pos.height > pWindow->drawable.pScreen->height) { - if (attr->pos.y < 0) - attr->vis.height = pWindow->drawable.pScreen->height; - else - attr->vis.height = pWindow->drawable.pScreen->height - attr->pos.y; - } - - /* Convert to window-relative coordinates */ - attr->vis.x -= attr->pos.x; - attr->vis.y -= attr->pos.y; - - return TRUE; -} - -void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr) -{ - attr->width = dmxGlobalWidth; - attr->height = dmxGlobalHeight; - attr->shiftX = 0; /* NOTE: The upper left hand corner of */ - attr->shiftY = 0; /* the desktop is always <0,0>. */ -} - -/** Return the total number of devices, not just #dmxNumInputs. The - * number returned should be the same as that returned by - * XListInputDevices. */ -int dmxGetInputCount(void) -{ - int i, total; - - for (total = i = 0; i < dmxNumInputs; i++) total += dmxInputs[i].numDevs; - return total; -} - -/** Return information about the device with id = \a deviceId. This - * information is primarily for the #ProcDMXGetInputAttributes() - * function, which does not have access to the appropriate data - * structure. */ -int dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr) -{ - int i, j; - DMXInputInfo *dmxInput; - - if (deviceId < 0) return -1; - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; - if (deviceId != dmxLocal->pDevice->id) continue; - attr->isCore = !!dmxLocal->isCore; - attr->sendsCore = !!dmxLocal->sendsCore; - attr->detached = !!dmxInput->detached; - attr->physicalScreen = -1; - attr->physicalId = -1; - attr->name = NULL; - switch (dmxLocal->extType) { - case DMX_LOCAL_TYPE_LOCAL: - attr->inputType = 0; - break; - case DMX_LOCAL_TYPE_CONSOLE: - attr->inputType = 1; - attr->name = dmxInput->name; - attr->physicalId = dmxLocal->deviceId; - break; - case DMX_LOCAL_TYPE_BACKEND: - case DMX_LOCAL_TYPE_COMMON: - attr->inputType = 2; - attr->physicalScreen = dmxInput->scrnIdx; - attr->name = dmxInput->name; - attr->physicalId = dmxLocal->deviceId; - break; - } - return 0; /* Success */ - } - } - return -1; /* Failure */ -} - -/** Reinitialized the cursor boundaries. */ -static void dmxAdjustCursorBoundaries(void) -{ - int i; - - dmxReInitOrigins(); - dmxInitOverlap(); - dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); - dmxConnectionBlockCallback(); - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (!dmxInput->detached) dmxInputReInit(dmxInput); - } - - dmxCheckCursor(); - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (!dmxInput->detached) dmxInputLateReInit(dmxInput); - } -} - -/** Add an input with the specified attributes. If the input is added, - * the physical id is returned in \a deviceId. */ -int dmxAddInput(DMXInputAttributesPtr attr, int *id) -{ - int retcode = BadValue; - - if (attr->inputType == 1) /* console */ - retcode = dmxInputAttachConsole(attr->name, attr->sendsCore, id); - else if (attr->inputType == 2) /* backend */ - retcode = dmxInputAttachBackend(attr->physicalScreen, - attr->sendsCore,id); - - if (retcode == Success) { - /* Adjust the cursor boundaries */ - dmxAdjustCursorBoundaries(); - - /* Force completion of the changes */ - dmxSync(NULL, TRUE); - } - - return retcode; -} - -/** Remove the input with physical id \a id. */ -int dmxRemoveInput(int id) -{ - return dmxInputDetachId(id); -} - -/** Return the value of #dmxNumScreens -- the total number of backend - * screens in use (these are logical screens and may be larger than the - * number of backend displays). */ -unsigned long dmxGetNumScreens(void) -{ - return dmxNumScreens; -} - -/** Make sure that #dmxCreateAndRealizeWindow has been called for \a - * pWindow. */ -void dmxForceWindowCreation(WindowPtr pWindow) -{ - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - if (!pWinPriv->window) dmxCreateAndRealizeWindow(pWindow, TRUE); -} - -/** Flush pending syncs for all screens. */ -void dmxFlushPendingSyncs(void) -{ - dmxSync(NULL, TRUE); -} - -/** Update DMX's screen resources to match those of the newly moved - * and/or resized "root" window. */ -void dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - WindowPtr pRoot = pScreen->root; - WindowPtr pChild; - Bool anyMarked = FALSE; - - /* Handle special case where width and/or height are zero */ - if (w == 0 || h == 0) { - w = 1; - h = 1; - } - - /* Change screen size */ - pScreen->width = w; - pScreen->height = h; - - /* Reset the root window's drawable's size */ - pRoot->drawable.width = w; - pRoot->drawable.height = h; - - /* Set the root window's new winSize and borderSize */ - pRoot->winSize.extents.x1 = 0; - pRoot->winSize.extents.y1 = 0; - pRoot->winSize.extents.x2 = w; - pRoot->winSize.extents.y2 = h; - - pRoot->borderSize.extents.x1 = 0; - pRoot->borderSize.extents.y1 = 0; - pRoot->borderSize.extents.x2 = w; - pRoot->borderSize.extents.y2 = h; - - /* Recompute this screen's mmWidth & mmHeight */ - pScreen->mmWidth = - (w * 254 + dmxScreen->beXDPI * 5) / (dmxScreen->beXDPI * 10); - pScreen->mmHeight = - (h * 254 + dmxScreen->beYDPI * 5) / (dmxScreen->beYDPI * 10); - - /* Recompute this screen's window's clip rects as follows: */ - /* 1. Mark all of root's children's windows */ - for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) - anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, - (WindowPtr *)NULL); - - /* 2. Set the root window's borderClip */ - pRoot->borderClip.extents.x1 = 0; - pRoot->borderClip.extents.y1 = 0; - pRoot->borderClip.extents.x2 = w; - pRoot->borderClip.extents.y2 = h; - - /* 3. Set the root window's clipList */ - if (anyMarked) { - /* If any windows have been marked, set the root window's - * clipList to be broken since it will be recalculated in - * ValidateTree() - */ - RegionBreak(&pRoot->clipList); - } else { - /* Otherwise, we just set it directly since there are no - * windows visible on this screen - */ - pRoot->clipList.extents.x1 = 0; - pRoot->clipList.extents.y1 = 0; - pRoot->clipList.extents.x2 = w; - pRoot->clipList.extents.y2 = h; - } - - /* 4. Revalidate all clip rects and generate expose events */ - if (anyMarked) { - pScreen->ValidateTree(pRoot, NULL, VTBroken); - pScreen->HandleExposures(pRoot); - if (pScreen->PostValidateTree) - pScreen->PostValidateTree(pRoot, NULL, VTBroken); - } -} - -#ifdef PANORAMIX -#include "panoramiXsrv.h" - -/** Change the "screen" window attributes by resizing the actual window - * on the back-end display (if necessary). */ -static void dmxConfigureScreenWindow(int idx, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - ScreenPtr pScreen = screenInfo.screens[idx]; - - /* Resize "screen" window */ - if (dmxScreen->scrnX != x || - dmxScreen->scrnY != y || - dmxScreen->scrnWidth != w || - dmxScreen->scrnHeight != h) { - dmxResizeScreenWindow(pScreen, x, y, w, h); - } - - /* Change "screen" window values */ - dmxScreen->scrnX = x; - dmxScreen->scrnY = y; - dmxScreen->scrnWidth = w; - dmxScreen->scrnHeight = h; -} - -/** Change the "root" window position and size by resizing the actual - * window on the back-end display (if necessary) and updating all of - * DMX's resources by calling #dmxUpdateScreenResources. */ -static void dmxConfigureRootWindow(int idx, int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - WindowPtr pRoot = screenInfo.screens[idx]->root; - - /* NOTE: Either this function or the ones that it calls must handle - * the case where w == 0 || h == 0. Currently, the functions that - * this one calls handle that case. */ - - /* 1. Resize "root" window */ - if (dmxScreen->rootX != x || - dmxScreen->rootY != y || - dmxScreen->rootWidth != w || - dmxScreen->rootHeight != h) { - dmxResizeRootWindow(pRoot, x, y, w, h); - } - - /* 2. Update all of the screen's resources associated with this root - * window */ - if (dmxScreen->rootWidth != w || - dmxScreen->rootHeight != h) { - dmxUpdateScreenResources(screenInfo.screens[idx], x, y, w, h); - } - - /* Change "root" window values */ - dmxScreen->rootX = x; - dmxScreen->rootY = y; - dmxScreen->rootWidth = w; - dmxScreen->rootHeight = h; -} - -/** Change the "root" window's origin by updating DMX's internal data - * structures (dix and Xinerama) to use the new origin and adjust the - * positions of windows that overlap this "root" window. */ -static void dmxSetRootWindowOrigin(int idx, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - ScreenPtr pScreen = screenInfo.screens[idx]; - WindowPtr pRoot = pScreen->root; - WindowPtr pChild; - int xoff; - int yoff; - - /* Change "root" window's origin */ - dmxScreen->rootXOrigin = x; - dmxScreen->rootYOrigin = y; - - /* Compute offsets here in case has been changed above */ - xoff = x - pScreen->x; - yoff = y - pScreen->y; - - /* Adjust the root window's position */ - pScreen->x = dmxScreen->rootXOrigin; - pScreen->y = dmxScreen->rootYOrigin; - - /* Recalculate the Xinerama regions and data structs */ - XineramaReinitData(pScreen); - - /* Adjust each of the root window's children */ - if (!idx) ReinitializeRootWindow(screenInfo.screens[0]->root, xoff, yoff); - pChild = pRoot->firstChild; - while (pChild) { - /* Adjust child window's position */ - pScreen->MoveWindow(pChild, - pChild->origin.x - wBorderWidth(pChild) - xoff, - pChild->origin.y - wBorderWidth(pChild) - yoff, - pChild->nextSib, - VTMove); - - /* Note that the call to MoveWindow will eventually call - * dmxPositionWindow which will automatically create a - * window if it is now exposed on screen (for lazy window - * creation optimization) and it will properly set the - * offscreen flag. - */ - - pChild = pChild->nextSib; - } -} - -/** Configure the attributes of each "screen" and "root" window. */ -int dmxConfigureScreenWindows(int nscreens, - CARD32 *screens, - DMXScreenAttributesPtr attribs, - int *errorScreen) -{ - int i; - - for (i = 0; i < nscreens; i++) { - DMXScreenAttributesPtr attr = &attribs[i]; - int idx = screens[i]; - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - - if (errorScreen) *errorScreen = i; - - if (!dmxScreen->beDisplay) return DMX_BAD_VALUE; - - /* Check for illegal values */ - if (idx < 0 || idx >= dmxNumScreens) return BadValue; - - /* The "screen" and "root" windows must have valid sizes */ - if (attr->screenWindowWidth <= 0 || attr->screenWindowHeight <= 0 || - attr->rootWindowWidth < 0 || attr->rootWindowHeight < 0) - return DMX_BAD_VALUE; - - /* The "screen" window must fit entirely within the BE display */ - if (attr->screenWindowXoffset < 0 || - attr->screenWindowYoffset < 0 || - attr->screenWindowXoffset - + attr->screenWindowWidth > (unsigned)dmxScreen->beWidth || - attr->screenWindowYoffset - + attr->screenWindowHeight > (unsigned)dmxScreen->beHeight) - return DMX_BAD_VALUE; - - /* The "root" window must fit entirely within the "screen" window */ - if (attr->rootWindowXoffset < 0 || - attr->rootWindowYoffset < 0 || - attr->rootWindowXoffset - + attr->rootWindowWidth > attr->screenWindowWidth || - attr->rootWindowYoffset - + attr->rootWindowHeight > attr->screenWindowHeight) - return DMX_BAD_VALUE; - - /* The "root" window must not expose unaddressable coordinates */ - if (attr->rootWindowXorigin < 0 || - attr->rootWindowYorigin < 0 || - attr->rootWindowXorigin + attr->rootWindowWidth > 32767 || - attr->rootWindowYorigin + attr->rootWindowHeight > 32767) - return DMX_BAD_VALUE; - - /* The "root" window must fit within the global bounding box */ - if (attr->rootWindowXorigin - + attr->rootWindowWidth > (unsigned)dmxGlobalWidth || - attr->rootWindowYorigin - + attr->rootWindowHeight > (unsigned)dmxGlobalHeight) - return DMX_BAD_VALUE; - - /* FIXME: Handle the rest of the illegal value checking */ - } - - /* No illegal values found */ - if (errorScreen) *errorScreen = 0; - - for (i = 0; i < nscreens; i++) { - DMXScreenAttributesPtr attr = &attribs[i]; - int idx = screens[i]; - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - - dmxLog(dmxInfo, "Changing screen #%d attributes " - "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d " - "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n", - idx, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - attr->screenWindowWidth, attr->screenWindowHeight, - attr->screenWindowXoffset, attr->screenWindowYoffset, - attr->rootWindowWidth, attr->rootWindowHeight, - attr->rootWindowXoffset, attr->rootWindowYoffset, - attr->rootWindowXorigin, attr->rootWindowYorigin); - - /* Configure "screen" window */ - dmxConfigureScreenWindow(idx, - attr->screenWindowXoffset, - attr->screenWindowYoffset, - attr->screenWindowWidth, - attr->screenWindowHeight); - - /* Configure "root" window */ - dmxConfigureRootWindow(idx, - attr->rootWindowXoffset, - attr->rootWindowYoffset, - attr->rootWindowWidth, - attr->rootWindowHeight); - - - /* Set "root" window's origin */ - dmxSetRootWindowOrigin(idx, - attr->rootWindowXorigin, - attr->rootWindowYorigin); - } - - /* Adjust the cursor boundaries */ - dmxAdjustCursorBoundaries(); - - /* Force completion of the changes */ - dmxSync(NULL, TRUE); - - return Success; -} - -/** Configure the attributes of the global desktop. */ -int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs) -{ - if (attribs->width <= 0 || attribs->width >= 32767 || - attribs->height <= 0 || attribs->height >= 32767) - return DMX_BAD_VALUE; - - /* If the desktop is shrinking, adjust the "root" windows on each - * "screen" window to only show the visible desktop. Also, handle - * the special case where the desktop shrinks such that the it no - * longer overlaps an portion of a "screen" window. */ - if (attribs->width < dmxGlobalWidth || attribs->height < dmxGlobalHeight) { - int i; - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxScreen->rootXOrigin - + dmxScreen->rootWidth > attribs->width || - dmxScreen->rootYOrigin - + dmxScreen->rootHeight > attribs->height) { - int w, h; - if ((w = attribs->width - dmxScreen->rootXOrigin) < 0) w = 0; - if ((h = attribs->height - dmxScreen->rootYOrigin) < 0) h = 0; - if (w > dmxScreen->scrnWidth) w = dmxScreen->scrnWidth; - if (h > dmxScreen->scrnHeight) h = dmxScreen->scrnHeight; - if (w > dmxScreen->rootWidth) w = dmxScreen->rootWidth; - if (h > dmxScreen->rootHeight) h = dmxScreen->rootHeight; - dmxConfigureRootWindow(i, - dmxScreen->rootX, - dmxScreen->rootY, - w, h); - } - } - } - - /* Set the global width/height */ - dmxSetWidthHeight(attribs->width, attribs->height); - - /* Handle shift[XY] changes */ - if (attribs->shiftX || attribs->shiftY) { - int i; - for (i = 0; i < dmxNumScreens; i++) { - ScreenPtr pScreen = screenInfo.screens[i]; - WindowPtr pChild = pScreen->root->firstChild; - while (pChild) { - /* Adjust child window's position */ - pScreen->MoveWindow(pChild, - pChild->origin.x - wBorderWidth(pChild) - - attribs->shiftX, - pChild->origin.y - wBorderWidth(pChild) - - attribs->shiftY, - pChild->nextSib, - VTMove); - - /* Note that the call to MoveWindow will eventually call - * dmxPositionWindow which will automatically create a - * window if it is now exposed on screen (for lazy - * window creation optimization) and it will properly - * set the offscreen flag. - */ - - pChild = pChild->nextSib; - } - } - } - - /* Update connection block, Xinerama, etc. -- these appears to - * already be handled in dmxConnectionBlockCallback(), which is - * called from dmxAdjustCursorBoundaries() [below]. */ - - /* Adjust the cursor boundaries */ - dmxAdjustCursorBoundaries(); - - /* Force completion of the changes */ - dmxSync(NULL, TRUE); - - return Success; -} -#endif - -/** Create the scratch GCs per depth. */ -static void dmxBECreateScratchGCs(int scrnNum) -{ - ScreenPtr pScreen = screenInfo.screens[scrnNum]; - GCPtr *ppGC = pScreen->GCperDepth; - int i; - - for (i = 0; i <= pScreen->numDepths; i++) - dmxBECreateGC(pScreen, ppGC[i]); -} - -#ifdef PANORAMIX -static Bool FoundPixImage; - -/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs - * to have its image restored. When it is found, see if there is - * another screen with the same image. If so, copy the pixmap image - * from the existing screen to the newly created pixmap. */ -static void dmxBERestorePixmapImage(pointer value, XID id, RESTYPE type, - pointer p) -{ - if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { - PixmapPtr pDst = (PixmapPtr)p; - int idx = pDst->drawable.pScreen->myNum; - PanoramiXRes *pXinPix = (PanoramiXRes *)value; - PixmapPtr pPix; - int i; - - dixLookupResourceByType((pointer*) &pPix, pXinPix->info[idx].id, - RT_PIXMAP, NullClient, DixUnknownAccess); - if (pPix != pDst) return; /* Not a match.... Next! */ - - for (i = 0; i < PanoramiXNumScreens; i++) { - PixmapPtr pSrc; - dmxPixPrivPtr pSrcPriv = NULL; - - if (i == idx) continue; /* Self replication is bad */ - - dixLookupResourceByType((pointer*) &pSrc, pXinPix->info[i].id, - RT_PIXMAP, NullClient, DixUnknownAccess); - pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); - if (pSrcPriv->pixmap) { - DMXScreenInfo *dmxSrcScreen = &dmxScreens[i]; - DMXScreenInfo *dmxDstScreen = &dmxScreens[idx]; - dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst); - XImage *img; - int j; - XlibGC gc = NULL; - - /* This should never happen, but just in case.... */ - if (pSrc->drawable.width != pDst->drawable.width || - pSrc->drawable.height != pDst->drawable.height) - return; - - /* Copy from src pixmap to dst pixmap */ - img = XGetImage(dmxSrcScreen->beDisplay, - pSrcPriv->pixmap, - 0, 0, - pSrc->drawable.width, pSrc->drawable.height, - -1, - ZPixmap); - - for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) { - if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) { - unsigned long m; - XGCValues v; - - m = GCFunction | GCPlaneMask | GCClipMask; - v.function = GXcopy; - v.plane_mask = AllPlanes; - v.clip_mask = None; - - gc = XCreateGC(dmxDstScreen->beDisplay, - dmxDstScreen->scrnDefDrawables[j], - m, &v); - break; - } - } - - if (gc) { - XPutImage(dmxDstScreen->beDisplay, - pDstPriv->pixmap, - gc, img, 0, 0, 0, 0, - pDst->drawable.width, pDst->drawable.height); - XFreeGC(dmxDstScreen->beDisplay, gc); - FoundPixImage = True; - } else { - dmxLog(dmxWarning, "Could not create GC\n"); - } - - XDestroyImage(img); - return; - } - } - } -} -#endif - -/** Restore the pixmap image either from another screen or from an image - * that was saved when the screen was previously detached. */ -static void dmxBERestorePixmap(PixmapPtr pPixmap) -{ -#ifdef PANORAMIX - int i; - - /* If Xinerama is not active, there's nothing we can do (see comment - * in #else below for more info). */ - if (noPanoramiXExtension) { - dmxLog(dmxWarning, "Cannot restore pixmap image\n"); - return; - } - - FoundPixImage = False; - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindAllClientResources(clients[i], dmxBERestorePixmapImage, - (pointer)pPixmap); - - /* No corresponding pixmap image was found on other screens, so we - * need to copy it from the saved image when the screen was detached - * (if available). */ - if (!FoundPixImage) { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - - if (pPixPriv->detachedImage) { - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - XlibGC gc = NULL; - - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (dmxScreen->bePixmapFormats[i].depth == - pPixPriv->detachedImage->depth) { - unsigned long m; - XGCValues v; - - m = GCFunction | GCPlaneMask | GCClipMask; - v.function = GXcopy; - v.plane_mask = AllPlanes; - v.clip_mask = None; - - gc = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnDefDrawables[i], - m, &v); - break; - } - } - - if (gc) { - XPutImage(dmxScreen->beDisplay, - pPixPriv->pixmap, - gc, - pPixPriv->detachedImage, - 0, 0, 0, 0, - pPixmap->drawable.width, pPixmap->drawable.height); - XFreeGC(dmxScreen->beDisplay, gc); - } else { - dmxLog(dmxWarning, "Cannot restore pixmap image\n"); - } - - XDestroyImage(pPixPriv->detachedImage); - pPixPriv->detachedImage = NULL; - } else { - dmxLog(dmxWarning, "Cannot restore pixmap image\n"); - } - } -#else - /* If Xinerama is not enabled, then there is no other copy of the - * pixmap image that we can restore. Saving all pixmap data is not - * a feasible option since there is no mechanism for updating pixmap - * data when a screen is detached, which means that the data that - * was previously saved would most likely be out of date. */ - dmxLog(dmxWarning, "Cannot restore pixmap image\n"); - return; -#endif -} - -/** Create resources on the back-end server. This function is called - * from #dmxAttachScreen() via the dix layer's FindAllResources - * function. It walks all resources, compares them to the screen - * number passed in as \a n and calls the appropriate DMX function to - * create the associated resource on the back-end server. */ -static void dmxBECreateResources(pointer value, XID id, RESTYPE type, - pointer n) -{ - int scrnNum = (int)n; - ScreenPtr pScreen = screenInfo.screens[scrnNum]; - - if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { - /* Window resources are created below in dmxBECreateWindowTree */ - } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { - PixmapPtr pPix = value; - if (pPix->drawable.pScreen->myNum == scrnNum) { - dmxBECreatePixmap(pPix); - dmxBERestorePixmap(pPix); - } - } else if ((type & TypeMask) == (RT_GC & TypeMask)) { - GCPtr pGC = value; - if (pGC->pScreen->myNum == scrnNum) { - /* Create the GC on the back-end server */ - dmxBECreateGC(pScreen, pGC); - /* Create any pixmaps associated with this GC */ - if (!pGC->tileIsPixel) { - dmxBECreatePixmap(pGC->tile.pixmap); - dmxBERestorePixmap(pGC->tile.pixmap); - } - if (pGC->stipple != pScreen->PixmapPerDepth[0]) { - dmxBECreatePixmap(pGC->stipple); - dmxBERestorePixmap(pGC->stipple); - } - if (pGC->font != defaultFont) { - (void)dmxBELoadFont(pScreen, pGC->font); - } - /* Update the GC on the back-end server */ - dmxChangeGC(pGC, -1L); - } - } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { - (void)dmxBELoadFont(pScreen, (FontPtr)value); - } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { - dmxBECreateCursor(pScreen, (CursorPtr)value); - } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { - ColormapPtr pCmap = value; - if (pCmap->pScreen->myNum == scrnNum) - (void)dmxBECreateColormap((ColormapPtr)value); -#if 0 - /* TODO: Recreate Picture and GlyphSet resources */ - } else if ((type & TypeMask) == (PictureType & TypeMask)) { - /* Picture resources are created when windows are created */ - } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { - dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); -#endif - } else { - /* Other resource types??? */ - } -} - -/** Create window hierachy on back-end server. The window tree is - * created in a special order (bottom most subwindow first) so that the - * #dmxCreateNonRootWindow() function does not need to recursively call - * itself to create each window's parents. This is required so that we - * have the opportunity to create each window's border and background - * pixmaps (where appropriate) before the window is created. */ -static void dmxBECreateWindowTree(int idx) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - WindowPtr pRoot = screenInfo.screens[idx]->root; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); - WindowPtr pWin; - - /* Create the pixmaps associated with the root window */ - if (!pRoot->borderIsPixel) { - dmxBECreatePixmap(pRoot->border.pixmap); - dmxBERestorePixmap(pRoot->border.pixmap); - } - if (pRoot->backgroundState == BackgroundPixmap) { - dmxBECreatePixmap(pRoot->background.pixmap); - dmxBERestorePixmap(pRoot->background.pixmap); - } - - /* Create root window first */ - dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pRoot); - XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); - - pWin = pRoot->lastChild; - while (pWin) { - pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - - /* Create the pixmaps regardless of whether or not the - * window is created or not due to lazy window creation. - */ - if (!pWin->borderIsPixel) { - dmxBECreatePixmap(pWin->border.pixmap); - dmxBERestorePixmap(pWin->border.pixmap); - } - if (pWin->backgroundState == BackgroundPixmap) { - dmxBECreatePixmap(pWin->background.pixmap); - dmxBERestorePixmap(pWin->background.pixmap); - } - - /* Reset the window attributes */ - dmxGetDefaultWindowAttributes(pWin, - &pWinPriv->cmap, - &pWinPriv->visual); - - /* Create the window */ - if (pWinPriv->mapped && !pWinPriv->offscreen) - dmxCreateAndRealizeWindow(pWin, TRUE); - - /* Next, create the bottom-most child */ - if (pWin->lastChild) { - pWin = pWin->lastChild; - continue; - } - - /* If the window has no children, move on to the next higher window */ - while (!pWin->prevSib && (pWin != pRoot)) - pWin = pWin->parent; - - if (pWin->prevSib) { - pWin = pWin->prevSib; - continue; - } - - /* When we reach the root window, we are finished */ - if (pWin == pRoot) - break; - } -} - -/* Refresh screen by generating exposure events for all windows */ -static void dmxForceExposures(int idx) -{ - ScreenPtr pScreen = screenInfo.screens[idx]; - WindowPtr pRoot = pScreen->root; - Bool anyMarked = FALSE; - WindowPtr pChild; - - for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) - anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, - (WindowPtr *)NULL); - if (anyMarked) { - /* If any windows have been marked, set the root window's - * clipList to be broken since it will be recalculated in - * ValidateTree() - */ - RegionBreak(&pRoot->clipList); - pScreen->ValidateTree(pRoot, NULL, VTBroken); - pScreen->HandleExposures(pRoot); - if (pScreen->PostValidateTree) - pScreen->PostValidateTree(pRoot, NULL, VTBroken); - } -} - -/** Compare the new and old screens to see if they are compatible. */ -static Bool dmxCompareScreens(DMXScreenInfo *new, DMXScreenInfo *old) -{ - int i; - - if (new->beWidth != old->beWidth) return FALSE; - if (new->beHeight != old->beHeight) return FALSE; - if (new->beDepth != old->beDepth) return FALSE; - if (new->beBPP != old->beBPP) return FALSE; - - if (new->beNumDepths != old->beNumDepths) return FALSE; - for (i = 0; i < old->beNumDepths; i++) - if (new->beDepths[i] != old->beDepths[i]) return FALSE; - - if (new->beNumPixmapFormats != old->beNumPixmapFormats) return FALSE; - for (i = 0; i < old->beNumPixmapFormats; i++) { - if (new->bePixmapFormats[i].depth != - old->bePixmapFormats[i].depth) return FALSE; - if (new->bePixmapFormats[i].bits_per_pixel != - old->bePixmapFormats[i].bits_per_pixel) return FALSE; - if (new->bePixmapFormats[i].scanline_pad != - old->bePixmapFormats[i].scanline_pad) return FALSE; - } - - if (new->beNumVisuals != old->beNumVisuals) return FALSE; - for (i = 0; i < old->beNumVisuals; i++) { - if (new->beVisuals[i].visualid != - old->beVisuals[i].visualid) return FALSE; - if (new->beVisuals[i].screen != - old->beVisuals[i].screen) return FALSE; - if (new->beVisuals[i].depth != - old->beVisuals[i].depth) return FALSE; - if (new->beVisuals[i].class != - old->beVisuals[i].class) return FALSE; - if (new->beVisuals[i].red_mask != - old->beVisuals[i].red_mask) return FALSE; - if (new->beVisuals[i].green_mask != - old->beVisuals[i].green_mask) return FALSE; - if (new->beVisuals[i].blue_mask != - old->beVisuals[i].blue_mask) return FALSE; - if (new->beVisuals[i].colormap_size != - old->beVisuals[i].colormap_size) return FALSE; - if (new->beVisuals[i].bits_per_rgb != - old->beVisuals[i].bits_per_rgb) return FALSE; - } - - if (new->beDefVisualIndex != old->beDefVisualIndex) return FALSE; - - return TRUE; -} - -/** Restore Render's picture */ -static void dmxBERestoreRenderPict(pointer value, XID id, pointer n) -{ - PicturePtr pPicture = value; /* The picture */ - DrawablePtr pDraw = pPicture->pDrawable; /* The picture's drawable */ - int scrnNum = (int)n; - - if (pDraw->pScreen->myNum != scrnNum) { - /* Picture not on the screen we are restoring*/ - return; - } - - if (pDraw->type == DRAWABLE_PIXMAP) { - PixmapPtr pPixmap = (PixmapPtr)pDraw; - - /* Create and restore the pixmap drawable */ - dmxBECreatePixmap(pPixmap); - dmxBERestorePixmap(pPixmap); - } - - dmxBECreatePicture(pPicture); -} - -/** Restore Render's glyphs */ -static void dmxBERestoreRenderGlyph(pointer value, XID id, pointer n) -{ - GlyphSetPtr glyphSet = value; - int scrnNum = (int)n; - dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); - DMXScreenInfo *dmxScreen = &dmxScreens[scrnNum]; - GlyphRefPtr table; - char *images; - Glyph *gids; - XGlyphInfo *glyphs; - char *pos; - int beret; - int len_images = 0; - int i; - int ctr; - - if (glyphPriv->glyphSets[scrnNum]) { - /* Only restore glyphs on the screen we are attaching */ - return; - } - - /* First we must create the glyph set on the backend. */ - if ((beret = dmxBECreateGlyphSet(scrnNum, glyphSet)) != Success) { - dmxLog(dmxWarning, - "\tdmxBERestoreRenderGlyph failed to create glyphset!\n"); - return; - } - - /* Now for the complex part, restore the glyph data */ - table = glyphSet->hash.table; - - /* We need to know how much memory to allocate for this part */ - for (i = 0; i < glyphSet->hash.hashSet->size; i++) { - GlyphRefPtr gr = &table[i]; - GlyphPtr gl = gr->glyph; - - if (!gl || gl == DeletedGlyph) continue; - len_images += gl->size - sizeof(gl->info); - } - - /* Now allocate the memory we need */ - images = calloc(len_images, sizeof(char)); - gids = malloc(glyphSet->hash.tableEntries*sizeof(Glyph)); - glyphs = malloc(glyphSet->hash.tableEntries*sizeof(XGlyphInfo)); - - pos = images; - ctr = 0; - - /* Fill the allocated memory with the proper data */ - for (i = 0; i < glyphSet->hash.hashSet->size; i++) { - GlyphRefPtr gr = &table[i]; - GlyphPtr gl = gr->glyph; - - if (!gl || gl == DeletedGlyph) continue; - - /* First lets put the data into gids */ - gids[ctr] = gr->signature; - - /* Next do the glyphs data structures */ - glyphs[ctr].width = gl->info.width; - glyphs[ctr].height = gl->info.height; - glyphs[ctr].x = gl->info.x; - glyphs[ctr].y = gl->info.y; - glyphs[ctr].xOff = gl->info.xOff; - glyphs[ctr].yOff = gl->info.yOff; - - /* Copy the images from the DIX's data into the buffer */ - memcpy(pos, gl+1, gl->size - sizeof(gl->info)); - pos += gl->size - sizeof(gl->info); - ctr++; - } - - /* Now restore the glyph data */ - XRenderAddGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[scrnNum], - gids,glyphs, glyphSet->hash.tableEntries, images, - len_images); - - /* Clean up */ - free(images); - free(gids); - free(glyphs); -} - -/** Reattach previously detached back-end screen. */ -int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) -{ - ScreenPtr pScreen; - DMXScreenInfo *dmxScreen; - CARD32 scrnNum = idx; - DMXScreenInfo oldDMXScreen; - int i; - - /* Return failure if dynamic addition/removal of screens is disabled */ - if (!dmxAddRemoveScreens) { - dmxLog(dmxWarning, - "Attempting to add a screen, but the AddRemoveScreen\n"); - dmxLog(dmxWarning, - "extension has not been enabled. To enable this extension\n"); - dmxLog(dmxWarning, - "add the \"-addremovescreens\" option either to the command\n"); - dmxLog(dmxWarning, - "line or in the configuration file.\n"); - return 1; - } - - /* Cannot add a screen that does not exist */ - if (idx < 0 || idx >= dmxNumScreens) return 1; - pScreen = screenInfo.screens[idx]; - dmxScreen = &dmxScreens[idx]; - - /* Cannot attach to a screen that is already opened */ - if (dmxScreen->beDisplay) { - dmxLog(dmxWarning, - "Attempting to add screen #%d but a screen already exists\n", - idx); - return 1; - } - - dmxLogOutput(dmxScreen, "Attaching screen #%d\n", idx); - - /* Save old info */ - oldDMXScreen = *dmxScreen; - - /* Copy the name to the new screen */ - dmxScreen->name = strdup(attr->displayName); - - /* Open display and get all of the screen info */ - if (!dmxOpenDisplay(dmxScreen)) { - dmxLog(dmxWarning, - "dmxOpenDisplay: Unable to open display %s\n", - dmxScreen->name); - - /* Restore the old screen */ - *dmxScreen = oldDMXScreen; - return 1; - } - - dmxSetErrorHandler(dmxScreen); - dmxCheckForWM(dmxScreen); - dmxGetScreenAttribs(dmxScreen); - - if (!dmxGetVisualInfo(dmxScreen)) { - dmxLog(dmxWarning, "dmxGetVisualInfo: No matching visuals found\n"); - XFree(dmxScreen->beVisuals); - XCloseDisplay(dmxScreen->beDisplay); - - /* Restore the old screen */ - *dmxScreen = oldDMXScreen; - return 1; - } - - dmxGetColormaps(dmxScreen); - dmxGetPixmapFormats(dmxScreen); - - /* Verify that the screen to be added has the same info as the - * previously added screen. */ - if (!dmxCompareScreens(dmxScreen, &oldDMXScreen)) { - dmxLog(dmxWarning, - "New screen data (%s) does not match previously\n", - dmxScreen->name); - dmxLog(dmxWarning, - "attached screen data (%s)\n", - oldDMXScreen.name); - dmxLog(dmxWarning, - "All data must match in order to attach to screen #%d\n", - idx); - XFree(dmxScreen->beVisuals); - XFree(dmxScreen->beDepths); - XFree(dmxScreen->bePixmapFormats); - XCloseDisplay(dmxScreen->beDisplay); - - /* Restore the old screen */ - *dmxScreen = oldDMXScreen; - return 1; - } - - /* Initialize the BE screen resources */ - dmxBEScreenInit(idx, screenInfo.screens[idx]); - - /* TODO: Handle GLX visual initialization. GLXProxy needs to be - * updated to handle dynamic addition/removal of screens. */ - - /* Create default stipple */ - dmxBECreatePixmap(pScreen->PixmapPerDepth[0]); - dmxBERestorePixmap(pScreen->PixmapPerDepth[0]); - - /* Create the scratch GCs */ - dmxBECreateScratchGCs(idx); - - /* Create the default font */ - (void)dmxBELoadFont(pScreen, defaultFont); - - /* Create all resources that don't depend on windows */ - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindAllClientResources(clients[i], dmxBECreateResources, - (pointer)idx); - - /* Create window hierarchy (top down) */ - dmxBECreateWindowTree(idx); - - /* Restore the picture state for RENDER */ - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindClientResourcesByType(clients[i],PictureType, - dmxBERestoreRenderPict,(pointer)idx); - - /* Restore the glyph state for RENDER */ - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindClientResourcesByType(clients[i],GlyphSetType, - dmxBERestoreRenderGlyph,(pointer)idx); - - /* Refresh screen by generating exposure events for all windows */ - dmxForceExposures(idx); - - dmxSync(&dmxScreens[idx], TRUE); - - /* We used these to compare the old and new screens. They are no - * longer needed since we have a newly attached screen, so we can - * now free the old screen's resources. */ - XFree(oldDMXScreen.beVisuals); - XFree(oldDMXScreen.beDepths); - XFree(oldDMXScreen.bePixmapFormats); - /* TODO: should oldDMXScreen.name be freed?? */ - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL); - else -#endif - return 0; /* Success */ -} - -/* - * Resources that may have state on the BE server and need to be freed: - * - * RT_NONE - * RT_WINDOW - * RT_PIXMAP - * RT_GC - * RT_FONT - * RT_CURSOR - * RT_COLORMAP - * RT_CMAPENTRY - * RT_OTHERCLIENT - * RT_PASSIVEGRAB - * XRT_WINDOW - * XRT_PIXMAP - * XRT_GC - * XRT_COLORMAP - * XRT_PICTURE - * PictureType - * PictFormatType - * GlyphSetType - * ClientType - * EventType - * RT_INPUTCLIENT - * XETrapType - * RTCounter - * RTAwait - * RTAlarmClient - * RT_XKBCLIENT - * RTContext - * TagResType - * StalledResType - * SecurityAuthorizationResType - * RTEventClient - * __glXContextRes - * __glXClientRes - * __glXPixmapRes - * __glXWindowRes - * __glXPbufferRes - */ - -#ifdef PANORAMIX -/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs - * to have its image saved. */ -static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, - pointer p) -{ - if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { - PixmapPtr pDst = (PixmapPtr)p; - int idx = pDst->drawable.pScreen->myNum; - PanoramiXRes *pXinPix = (PanoramiXRes *)value; - PixmapPtr pPix; - int i; - - dixLookupResourceByType((pointer*) &pPix, pXinPix->info[idx].id, - RT_PIXMAP, NullClient, DixUnknownAccess); - if (pPix != pDst) return; /* Not a match.... Next! */ - - for (i = 0; i < PanoramiXNumScreens; i++) { - PixmapPtr pSrc; - dmxPixPrivPtr pSrcPriv = NULL; - - if (i == idx) continue; /* Self replication is bad */ - - dixLookupResourceByType((pointer*) &pSrc, pXinPix->info[i].id, - RT_PIXMAP, NullClient, DixUnknownAccess); - pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); - if (pSrcPriv->pixmap) { - FoundPixImage = True; - return; - } - } - } -} -#endif - -/** Save the pixmap image only when there is not another screen with - * that pixmap from which the image can be read when the screen is - * reattached. To do this, we first try to find a pixmap on another - * screen corresponding to the one we are trying to save. If we find - * one, then we do not need to save the image data since during - * reattachment, the image data can be read from that other pixmap. - * However, if we do not find one, then we need to save the image data. - * The common case for these are for the default stipple and root - * tile. */ -static void dmxBESavePixmap(PixmapPtr pPixmap) -{ -#ifdef PANORAMIX - int i; - - /* If Xinerama is not active, there's nothing we can do (see comment - * in #else below for more info). */ - if (noPanoramiXExtension) return; - - FoundPixImage = False; - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindAllClientResources(clients[i], dmxBEFindPixmapImage, - (pointer)pPixmap); - - /* Save the image only if there is no other screens that have a - * pixmap that corresponds to the one we are trying to save. */ - if (!FoundPixImage) { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - - if (!pPixPriv->detachedImage) { - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay, - pPixPriv->pixmap, - 0, 0, - pPixmap->drawable.width, - pPixmap->drawable.height, - -1, - ZPixmap); - if (!pPixPriv->detachedImage) - dmxLog(dmxWarning, "Cannot save pixmap image\n"); - } - } -#else - /* NOTE: The only time there is a pixmap on another screen that - * corresponds to the one we are trying to save is when Xinerama is - * active. Otherwise, the pixmap image data is only stored on a - * single screen, which means that once it is detached, that data is - * lost. We could save the data here, but then that would require - * us to implement the ability for Xdmx to keep the pixmap up to - * date while the screen is detached, which is beyond the scope of - * the current project. */ - return; -#endif -} - -/** Destroy resources on the back-end server. This function is called - * from #dmxDetachScreen() via the dix layer's FindAllResources - * function. It walks all resources, compares them to the screen - * number passed in as \a n and calls the appropriate DMX function to - * free the associated resource on the back-end server. */ -static void dmxBEDestroyResources(pointer value, XID id, RESTYPE type, - pointer n) -{ - int scrnNum = (int)n; - ScreenPtr pScreen = screenInfo.screens[scrnNum]; - - if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { - /* Window resources are destroyed below in dmxBEDestroyWindowTree */ - } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { - PixmapPtr pPix = value; - if (pPix->drawable.pScreen->myNum == scrnNum) { - dmxBESavePixmap(pPix); - dmxBEFreePixmap(pPix); - } - } else if ((type & TypeMask) == (RT_GC & TypeMask)) { - GCPtr pGC = value; - if (pGC->pScreen->myNum == scrnNum) - dmxBEFreeGC(pGC); - } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { - dmxBEFreeFont(pScreen, (FontPtr)value); - } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { - dmxBEFreeCursor(pScreen, (CursorPtr)value); - } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { - ColormapPtr pCmap = value; - if (pCmap->pScreen->myNum == scrnNum) - dmxBEFreeColormap((ColormapPtr)value); - } else if ((type & TypeMask) == (PictureType & TypeMask)) { - PicturePtr pPict = value; - if (pPict->pDrawable->pScreen->myNum == scrnNum) { - /* Free the pixmaps on the backend if needed */ - if (pPict->pDrawable->type == DRAWABLE_PIXMAP) { - PixmapPtr pPixmap = (PixmapPtr)(pPict->pDrawable); - dmxBESavePixmap(pPixmap); - dmxBEFreePixmap(pPixmap); - } - dmxBEFreePicture((PicturePtr)value); - } - } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { - dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); - } else { - /* Other resource types??? */ - } -} - -/** Destroy the scratch GCs that are created per depth. */ -static void dmxBEDestroyScratchGCs(int scrnNum) -{ - ScreenPtr pScreen = screenInfo.screens[scrnNum]; - GCPtr *ppGC = pScreen->GCperDepth; - int i; - - for (i = 0; i <= pScreen->numDepths; i++) - dmxBEFreeGC(ppGC[i]); -} - -/** Destroy window hierachy on back-end server. To ensure that all - * XDestroyWindow() calls succeed, they must be performed in a bottom - * up order so that windows are not destroyed before their children. - * XDestroyWindow(), which is called from #dmxBEDestroyWindow(), will - * destroy a window as well as all of it's children. */ -static void dmxBEDestroyWindowTree(int idx) -{ - WindowPtr pWin = screenInfo.screens[idx]->root; - WindowPtr pChild = pWin; - - while (1) { - if (pChild->firstChild) { - pChild = pChild->firstChild; - continue; - } - - /* Destroy the window */ - dmxBEDestroyWindow(pChild); - - /* Make sure we destroy the window's border and background - * pixmaps if they exist */ - if (!pChild->borderIsPixel) { - dmxBESavePixmap(pChild->border.pixmap); - dmxBEFreePixmap(pChild->border.pixmap); - } - if (pChild->backgroundState == BackgroundPixmap) { - dmxBESavePixmap(pChild->background.pixmap); - dmxBEFreePixmap(pChild->background.pixmap); - } - - while (!pChild->nextSib && (pChild != pWin)) { - pChild = pChild->parent; - dmxBEDestroyWindow(pChild); - if (!pChild->borderIsPixel) { - dmxBESavePixmap(pChild->border.pixmap); - dmxBEFreePixmap(pChild->border.pixmap); - } - if (pChild->backgroundState == BackgroundPixmap) { - dmxBESavePixmap(pChild->background.pixmap); - dmxBEFreePixmap(pChild->background.pixmap); - } - } - - if (pChild == pWin) - break; - - pChild = pChild->nextSib; - } -} - -/** Detach back-end screen. */ -int dmxDetachScreen(int idx) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - int i; - - /* Return failure if dynamic addition/removal of screens is disabled */ - if (!dmxAddRemoveScreens) { - dmxLog(dmxWarning, - "Attempting to remove a screen, but the AddRemoveScreen\n"); - dmxLog(dmxWarning, - "extension has not been enabled. To enable this extension\n"); - dmxLog(dmxWarning, - "add the \"-addremovescreens\" option either to the command\n"); - dmxLog(dmxWarning, - "line or in the configuration file.\n"); - return 1; - } - - /* Cannot remove a screen that does not exist */ - if (idx < 0 || idx >= dmxNumScreens) return 1; - - /* Cannot detach from a screen that is not opened */ - if (!dmxScreen->beDisplay) { - dmxLog(dmxWarning, - "Attempting to remove screen #%d but it has not been opened\n", - idx); - return 1; - } - - dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx); - - /* Detach input */ - dmxInputDetachAll(dmxScreen); - - /* Save all relevant state (TODO) */ - - /* Free all non-window resources related to this screen */ - for (i = currentMaxClients; --i >= 0; ) - if (clients[i]) - FindAllClientResources(clients[i], dmxBEDestroyResources, - (pointer)idx); - - /* Free scratch GCs */ - dmxBEDestroyScratchGCs(idx); - - /* Free window resources related to this screen */ - dmxBEDestroyWindowTree(idx); - - /* Free default stipple */ - dmxBESavePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); - dmxBEFreePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); - - /* Free the remaining screen resources and close the screen */ - dmxBECloseScreen(screenInfo.screens[idx]); - - /* Adjust the cursor boundaries (paints detached console window) */ - dmxAdjustCursorBoundaries(); - - return 0; /* Success */ -} +/* + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Author: + * Rickard E. (Rik) Faith + * Kevin E. Martin + * + */ + +/** \file + * This file provides the only interface to the X server extension support + * in programs/Xserver/Xext. Those programs should only include dmxext.h + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include + +#include "dmx.h" +#include "dmxinit.h" +#include "dmxextension.h" +#include "dmxwindow.h" +#include "dmxcb.h" +#include "dmxcursor.h" +#include "dmxpixmap.h" +#include "dmxgc.h" +#include "dmxfont.h" +#include "dmxcmap.h" +#include "dmxpict.h" +#include "dmxinput.h" +#include "dmxsync.h" +#include "dmxscrinit.h" +#include "input/dmxinputinit.h" + +#include "windowstr.h" +#include "inputstr.h" /* For DeviceIntRec */ +#include /* For DMX_BAD_* */ +#include "cursorstr.h" + +/* The default font is declared in dix/globals.c, but is not included in + * _any_ header files. */ +extern FontPtr defaultFont; + +/** This routine provides information to the DMX protocol extension + * about a particular screen. */ +Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr) +{ + DMXScreenInfo *dmxScreen; + + if (physical < 0 || physical >= dmxNumScreens) return FALSE; + + dmxScreen = &dmxScreens[physical]; + attr->displayName = dmxScreen->name; +#ifdef PANORAMIX + attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0; +#else + attr->logicalScreen = dmxScreen->index; +#endif + + attr->screenWindowWidth = dmxScreen->scrnWidth; + attr->screenWindowHeight = dmxScreen->scrnHeight; + attr->screenWindowXoffset = dmxScreen->scrnX; + attr->screenWindowYoffset = dmxScreen->scrnY; + + attr->rootWindowWidth = dmxScreen->rootWidth; + attr->rootWindowHeight = dmxScreen->rootHeight; + attr->rootWindowXoffset = dmxScreen->rootX; + attr->rootWindowYoffset = dmxScreen->rootY; + + attr->rootWindowXorigin = dmxScreen->rootXOrigin; + attr->rootWindowYorigin = dmxScreen->rootYOrigin; + + return TRUE; +} + +/** This routine provides information to the DMX protocol extension + * about a particular window. */ +Bool dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + attr->screen = pWindow->drawable.pScreen->myNum; + attr->window = pWinPriv->window; + + attr->pos.x = pWindow->drawable.x; + attr->pos.y = pWindow->drawable.y; + attr->pos.width = pWindow->drawable.width; + attr->pos.height = pWindow->drawable.height; + + if (!pWinPriv->window || pWinPriv->offscreen) { + attr->vis.x = 0; + attr->vis.y = 0; + attr->vis.height = 0; + attr->vis.width = 0; + return pWinPriv->window ? TRUE : FALSE; + } + + /* Compute display-relative coordinates */ + attr->vis.x = pWindow->drawable.x; + attr->vis.y = pWindow->drawable.y; + attr->vis.width = pWindow->drawable.width; + attr->vis.height = pWindow->drawable.height; + + if (attr->pos.x < 0) { + attr->vis.x -= attr->pos.x; + attr->vis.width = attr->pos.x + attr->pos.width - attr->vis.x; + } + if (attr->pos.x + attr->pos.width > pWindow->drawable.pScreen->width) { + if (attr->pos.x < 0) + attr->vis.width = pWindow->drawable.pScreen->width; + else + attr->vis.width = pWindow->drawable.pScreen->width - attr->pos.x; + } + if (attr->pos.y < 0) { + attr->vis.y -= attr->pos.y; + attr->vis.height = attr->pos.y + attr->pos.height - attr->vis.y; + } + if (attr->pos.y + attr->pos.height > pWindow->drawable.pScreen->height) { + if (attr->pos.y < 0) + attr->vis.height = pWindow->drawable.pScreen->height; + else + attr->vis.height = pWindow->drawable.pScreen->height - attr->pos.y; + } + + /* Convert to window-relative coordinates */ + attr->vis.x -= attr->pos.x; + attr->vis.y -= attr->pos.y; + + return TRUE; +} + +void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr) +{ + attr->width = dmxGlobalWidth; + attr->height = dmxGlobalHeight; + attr->shiftX = 0; /* NOTE: The upper left hand corner of */ + attr->shiftY = 0; /* the desktop is always <0,0>. */ +} + +/** Return the total number of devices, not just #dmxNumInputs. The + * number returned should be the same as that returned by + * XListInputDevices. */ +int dmxGetInputCount(void) +{ + int i, total; + + for (total = i = 0; i < dmxNumInputs; i++) total += dmxInputs[i].numDevs; + return total; +} + +/** Return information about the device with id = \a deviceId. This + * information is primarily for the #ProcDMXGetInputAttributes() + * function, which does not have access to the appropriate data + * structure. */ +int dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr) +{ + int i, j; + DMXInputInfo *dmxInput; + + if (deviceId < 0) return -1; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (deviceId != dmxLocal->pDevice->id) continue; + attr->isCore = !!dmxLocal->isCore; + attr->sendsCore = !!dmxLocal->sendsCore; + attr->detached = !!dmxInput->detached; + attr->physicalScreen = -1; + attr->physicalId = -1; + attr->name = NULL; + switch (dmxLocal->extType) { + case DMX_LOCAL_TYPE_LOCAL: + attr->inputType = 0; + break; + case DMX_LOCAL_TYPE_CONSOLE: + attr->inputType = 1; + attr->name = dmxInput->name; + attr->physicalId = dmxLocal->deviceId; + break; + case DMX_LOCAL_TYPE_BACKEND: + case DMX_LOCAL_TYPE_COMMON: + attr->inputType = 2; + attr->physicalScreen = dmxInput->scrnIdx; + attr->name = dmxInput->name; + attr->physicalId = dmxLocal->deviceId; + break; + } + return 0; /* Success */ + } + } + return -1; /* Failure */ +} + +/** Reinitialized the cursor boundaries. */ +static void dmxAdjustCursorBoundaries(void) +{ + int i; + + dmxReInitOrigins(); + dmxInitOverlap(); + dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); + dmxConnectionBlockCallback(); + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (!dmxInput->detached) dmxInputReInit(dmxInput); + } + + dmxCheckCursor(); + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (!dmxInput->detached) dmxInputLateReInit(dmxInput); + } +} + +/** Add an input with the specified attributes. If the input is added, + * the physical id is returned in \a deviceId. */ +int dmxAddInput(DMXInputAttributesPtr attr, int *id) +{ + int retcode = BadValue; + + if (attr->inputType == 1) /* console */ + retcode = dmxInputAttachConsole(attr->name, attr->sendsCore, id); + else if (attr->inputType == 2) /* backend */ + retcode = dmxInputAttachBackend(attr->physicalScreen, + attr->sendsCore,id); + + if (retcode == Success) { + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + } + + return retcode; +} + +/** Remove the input with physical id \a id. */ +int dmxRemoveInput(int id) +{ + return dmxInputDetachId(id); +} + +/** Return the value of #dmxNumScreens -- the total number of backend + * screens in use (these are logical screens and may be larger than the + * number of backend displays). */ +unsigned long dmxGetNumScreens(void) +{ + return dmxNumScreens; +} + +/** Make sure that #dmxCreateAndRealizeWindow has been called for \a + * pWindow. */ +void dmxForceWindowCreation(WindowPtr pWindow) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + if (!pWinPriv->window) dmxCreateAndRealizeWindow(pWindow, TRUE); +} + +/** Flush pending syncs for all screens. */ +void dmxFlushPendingSyncs(void) +{ + dmxSync(NULL, TRUE); +} + +/** Update DMX's screen resources to match those of the newly moved + * and/or resized "root" window. */ +void dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pRoot = pScreen->root; + WindowPtr pChild; + Bool anyMarked = FALSE; + + /* Handle special case where width and/or height are zero */ + if (w == 0 || h == 0) { + w = 1; + h = 1; + } + + /* Change screen size */ + pScreen->width = w; + pScreen->height = h; + + /* Reset the root window's drawable's size */ + pRoot->drawable.width = w; + pRoot->drawable.height = h; + + /* Set the root window's new winSize and borderSize */ + pRoot->winSize.extents.x1 = 0; + pRoot->winSize.extents.y1 = 0; + pRoot->winSize.extents.x2 = w; + pRoot->winSize.extents.y2 = h; + + pRoot->borderSize.extents.x1 = 0; + pRoot->borderSize.extents.y1 = 0; + pRoot->borderSize.extents.x2 = w; + pRoot->borderSize.extents.y2 = h; + + /* Recompute this screen's mmWidth & mmHeight */ + pScreen->mmWidth = + (w * 254 + dmxScreen->beXDPI * 5) / (dmxScreen->beXDPI * 10); + pScreen->mmHeight = + (h * 254 + dmxScreen->beYDPI * 5) / (dmxScreen->beYDPI * 10); + + /* Recompute this screen's window's clip rects as follows: */ + /* 1. Mark all of root's children's windows */ + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) + anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, + (WindowPtr *)NULL); + + /* 2. Set the root window's borderClip */ + pRoot->borderClip.extents.x1 = 0; + pRoot->borderClip.extents.y1 = 0; + pRoot->borderClip.extents.x2 = w; + pRoot->borderClip.extents.y2 = h; + + /* 3. Set the root window's clipList */ + if (anyMarked) { + /* If any windows have been marked, set the root window's + * clipList to be broken since it will be recalculated in + * ValidateTree() + */ + RegionBreak(&pRoot->clipList); + } else { + /* Otherwise, we just set it directly since there are no + * windows visible on this screen + */ + pRoot->clipList.extents.x1 = 0; + pRoot->clipList.extents.y1 = 0; + pRoot->clipList.extents.x2 = w; + pRoot->clipList.extents.y2 = h; + } + + /* 4. Revalidate all clip rects and generate expose events */ + if (anyMarked) { + pScreen->ValidateTree(pRoot, NULL, VTBroken); + pScreen->HandleExposures(pRoot); + if (pScreen->PostValidateTree) + pScreen->PostValidateTree(pRoot, NULL, VTBroken); + } +} + +#ifdef PANORAMIX +#include "panoramiXsrv.h" + +/** Change the "screen" window attributes by resizing the actual window + * on the back-end display (if necessary). */ +static void dmxConfigureScreenWindow(int idx, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + ScreenPtr pScreen = screenInfo.screens[idx]; + + /* Resize "screen" window */ + if (dmxScreen->scrnX != x || + dmxScreen->scrnY != y || + dmxScreen->scrnWidth != w || + dmxScreen->scrnHeight != h) { + dmxResizeScreenWindow(pScreen, x, y, w, h); + } + + /* Change "screen" window values */ + dmxScreen->scrnX = x; + dmxScreen->scrnY = y; + dmxScreen->scrnWidth = w; + dmxScreen->scrnHeight = h; +} + +/** Change the "root" window position and size by resizing the actual + * window on the back-end display (if necessary) and updating all of + * DMX's resources by calling #dmxUpdateScreenResources. */ +static void dmxConfigureRootWindow(int idx, int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + WindowPtr pRoot = screenInfo.screens[idx]->root; + + /* NOTE: Either this function or the ones that it calls must handle + * the case where w == 0 || h == 0. Currently, the functions that + * this one calls handle that case. */ + + /* 1. Resize "root" window */ + if (dmxScreen->rootX != x || + dmxScreen->rootY != y || + dmxScreen->rootWidth != w || + dmxScreen->rootHeight != h) { + dmxResizeRootWindow(pRoot, x, y, w, h); + } + + /* 2. Update all of the screen's resources associated with this root + * window */ + if (dmxScreen->rootWidth != w || + dmxScreen->rootHeight != h) { + dmxUpdateScreenResources(screenInfo.screens[idx], x, y, w, h); + } + + /* Change "root" window values */ + dmxScreen->rootX = x; + dmxScreen->rootY = y; + dmxScreen->rootWidth = w; + dmxScreen->rootHeight = h; +} + +/** Change the "root" window's origin by updating DMX's internal data + * structures (dix and Xinerama) to use the new origin and adjust the + * positions of windows that overlap this "root" window. */ +static void dmxSetRootWindowOrigin(int idx, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + ScreenPtr pScreen = screenInfo.screens[idx]; + WindowPtr pRoot = pScreen->root; + WindowPtr pChild; + int xoff; + int yoff; + + /* Change "root" window's origin */ + dmxScreen->rootXOrigin = x; + dmxScreen->rootYOrigin = y; + + /* Compute offsets here in case has been changed above */ + xoff = x - pScreen->x; + yoff = y - pScreen->y; + + /* Adjust the root window's position */ + pScreen->x = dmxScreen->rootXOrigin; + pScreen->y = dmxScreen->rootYOrigin; + + /* Recalculate the Xinerama regions and data structs */ + XineramaReinitData(pScreen); + + /* Adjust each of the root window's children */ + if (!idx) ReinitializeRootWindow(screenInfo.screens[0]->root, xoff, yoff); + pChild = pRoot->firstChild; + while (pChild) { + /* Adjust child window's position */ + pScreen->MoveWindow(pChild, + pChild->origin.x - wBorderWidth(pChild) - xoff, + pChild->origin.y - wBorderWidth(pChild) - yoff, + pChild->nextSib, + VTMove); + + /* Note that the call to MoveWindow will eventually call + * dmxPositionWindow which will automatically create a + * window if it is now exposed on screen (for lazy window + * creation optimization) and it will properly set the + * offscreen flag. + */ + + pChild = pChild->nextSib; + } +} + +/** Configure the attributes of each "screen" and "root" window. */ +int dmxConfigureScreenWindows(int nscreens, + CARD32 *screens, + DMXScreenAttributesPtr attribs, + int *errorScreen) +{ + int i; + + for (i = 0; i < nscreens; i++) { + DMXScreenAttributesPtr attr = &attribs[i]; + int idx = screens[i]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + if (errorScreen) *errorScreen = i; + + if (!dmxScreen->beDisplay) return DMX_BAD_VALUE; + + /* Check for illegal values */ + if (idx < 0 || idx >= dmxNumScreens) return BadValue; + + /* The "screen" and "root" windows must have valid sizes */ + if (attr->screenWindowWidth <= 0 || attr->screenWindowHeight <= 0 || + attr->rootWindowWidth < 0 || attr->rootWindowHeight < 0) + return DMX_BAD_VALUE; + + /* The "screen" window must fit entirely within the BE display */ + if (attr->screenWindowXoffset < 0 || + attr->screenWindowYoffset < 0 || + attr->screenWindowXoffset + + attr->screenWindowWidth > (unsigned)dmxScreen->beWidth || + attr->screenWindowYoffset + + attr->screenWindowHeight > (unsigned)dmxScreen->beHeight) + return DMX_BAD_VALUE; + + /* The "root" window must fit entirely within the "screen" window */ + if (attr->rootWindowXoffset < 0 || + attr->rootWindowYoffset < 0 || + attr->rootWindowXoffset + + attr->rootWindowWidth > attr->screenWindowWidth || + attr->rootWindowYoffset + + attr->rootWindowHeight > attr->screenWindowHeight) + return DMX_BAD_VALUE; + + /* The "root" window must not expose unaddressable coordinates */ + if (attr->rootWindowXorigin < 0 || + attr->rootWindowYorigin < 0 || + attr->rootWindowXorigin + attr->rootWindowWidth > 32767 || + attr->rootWindowYorigin + attr->rootWindowHeight > 32767) + return DMX_BAD_VALUE; + + /* The "root" window must fit within the global bounding box */ + if (attr->rootWindowXorigin + + attr->rootWindowWidth > (unsigned)dmxGlobalWidth || + attr->rootWindowYorigin + + attr->rootWindowHeight > (unsigned)dmxGlobalHeight) + return DMX_BAD_VALUE; + + /* FIXME: Handle the rest of the illegal value checking */ + } + + /* No illegal values found */ + if (errorScreen) *errorScreen = 0; + + for (i = 0; i < nscreens; i++) { + DMXScreenAttributesPtr attr = &attribs[i]; + int idx = screens[i]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + dmxLog(dmxInfo, "Changing screen #%d attributes " + "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d " + "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n", + idx, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + attr->screenWindowWidth, attr->screenWindowHeight, + attr->screenWindowXoffset, attr->screenWindowYoffset, + attr->rootWindowWidth, attr->rootWindowHeight, + attr->rootWindowXoffset, attr->rootWindowYoffset, + attr->rootWindowXorigin, attr->rootWindowYorigin); + + /* Configure "screen" window */ + dmxConfigureScreenWindow(idx, + attr->screenWindowXoffset, + attr->screenWindowYoffset, + attr->screenWindowWidth, + attr->screenWindowHeight); + + /* Configure "root" window */ + dmxConfigureRootWindow(idx, + attr->rootWindowXoffset, + attr->rootWindowYoffset, + attr->rootWindowWidth, + attr->rootWindowHeight); + + + /* Set "root" window's origin */ + dmxSetRootWindowOrigin(idx, + attr->rootWindowXorigin, + attr->rootWindowYorigin); + } + + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + + return Success; +} + +/** Configure the attributes of the global desktop. */ +int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs) +{ + if (attribs->width <= 0 || attribs->width >= 32767 || + attribs->height <= 0 || attribs->height >= 32767) + return DMX_BAD_VALUE; + + /* If the desktop is shrinking, adjust the "root" windows on each + * "screen" window to only show the visible desktop. Also, handle + * the special case where the desktop shrinks such that the it no + * longer overlaps an portion of a "screen" window. */ + if (attribs->width < dmxGlobalWidth || attribs->height < dmxGlobalHeight) { + int i; + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxScreen->rootXOrigin + + dmxScreen->rootWidth > attribs->width || + dmxScreen->rootYOrigin + + dmxScreen->rootHeight > attribs->height) { + int w, h; + if ((w = attribs->width - dmxScreen->rootXOrigin) < 0) w = 0; + if ((h = attribs->height - dmxScreen->rootYOrigin) < 0) h = 0; + if (w > dmxScreen->scrnWidth) w = dmxScreen->scrnWidth; + if (h > dmxScreen->scrnHeight) h = dmxScreen->scrnHeight; + if (w > dmxScreen->rootWidth) w = dmxScreen->rootWidth; + if (h > dmxScreen->rootHeight) h = dmxScreen->rootHeight; + dmxConfigureRootWindow(i, + dmxScreen->rootX, + dmxScreen->rootY, + w, h); + } + } + } + + /* Set the global width/height */ + dmxSetWidthHeight(attribs->width, attribs->height); + + /* Handle shift[XY] changes */ + if (attribs->shiftX || attribs->shiftY) { + int i; + for (i = 0; i < dmxNumScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + WindowPtr pChild = pScreen->root->firstChild; + while (pChild) { + /* Adjust child window's position */ + pScreen->MoveWindow(pChild, + pChild->origin.x - wBorderWidth(pChild) + - attribs->shiftX, + pChild->origin.y - wBorderWidth(pChild) + - attribs->shiftY, + pChild->nextSib, + VTMove); + + /* Note that the call to MoveWindow will eventually call + * dmxPositionWindow which will automatically create a + * window if it is now exposed on screen (for lazy + * window creation optimization) and it will properly + * set the offscreen flag. + */ + + pChild = pChild->nextSib; + } + } + } + + /* Update connection block, Xinerama, etc. -- these appears to + * already be handled in dmxConnectionBlockCallback(), which is + * called from dmxAdjustCursorBoundaries() [below]. */ + + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + + return Success; +} +#endif + +/** Create the scratch GCs per depth. */ +static void dmxBECreateScratchGCs(int scrnNum) +{ + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + GCPtr *ppGC = pScreen->GCperDepth; + int i; + + for (i = 0; i <= pScreen->numDepths; i++) + dmxBECreateGC(pScreen, ppGC[i]); +} + +#ifdef PANORAMIX +static Bool FoundPixImage; + +/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs + * to have its image restored. When it is found, see if there is + * another screen with the same image. If so, copy the pixmap image + * from the existing screen to the newly created pixmap. */ +static void dmxBERestorePixmapImage(pointer value, XID id, RESTYPE type, + pointer p) +{ + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPix = (PanoramiXRes *)value; + PixmapPtr pPix; + int i; + + dixLookupResourceByType((pointer*) &pPix, pXinPix->info[idx].id, + RT_PIXMAP, NullClient, DixUnknownAccess); + if (pPix != pDst) return; /* Not a match.... Next! */ + + for (i = 0; i < PanoramiXNumScreens; i++) { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + dixLookupResourceByType((pointer*) &pSrc, pXinPix->info[i].id, + RT_PIXMAP, NullClient, DixUnknownAccess); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); + if (pSrcPriv->pixmap) { + DMXScreenInfo *dmxSrcScreen = &dmxScreens[i]; + DMXScreenInfo *dmxDstScreen = &dmxScreens[idx]; + dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst); + XImage *img; + int j; + XlibGC gc = NULL; + + /* This should never happen, but just in case.... */ + if (pSrc->drawable.width != pDst->drawable.width || + pSrc->drawable.height != pDst->drawable.height) + return; + + /* Copy from src pixmap to dst pixmap */ + img = XGetImage(dmxSrcScreen->beDisplay, + pSrcPriv->pixmap, + 0, 0, + pSrc->drawable.width, pSrc->drawable.height, + -1, + ZPixmap); + + for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) { + if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) { + unsigned long m; + XGCValues v; + + m = GCFunction | GCPlaneMask | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + gc = XCreateGC(dmxDstScreen->beDisplay, + dmxDstScreen->scrnDefDrawables[j], + m, &v); + break; + } + } + + if (gc) { + XPutImage(dmxDstScreen->beDisplay, + pDstPriv->pixmap, + gc, img, 0, 0, 0, 0, + pDst->drawable.width, pDst->drawable.height); + XFreeGC(dmxDstScreen->beDisplay, gc); + FoundPixImage = True; + } else { + dmxLog(dmxWarning, "Could not create GC\n"); + } + + XDestroyImage(img); + return; + } + } + } +} +#endif + +/** Restore the pixmap image either from another screen or from an image + * that was saved when the screen was previously detached. */ +static void dmxBERestorePixmap(PixmapPtr pPixmap) +{ +#ifdef PANORAMIX + int i; + + /* If Xinerama is not active, there's nothing we can do (see comment + * in #else below for more info). */ + if (noPanoramiXExtension) { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + return; + } + + FoundPixImage = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBERestorePixmapImage, + (pointer)pPixmap); + + /* No corresponding pixmap image was found on other screens, so we + * need to copy it from the saved image when the screen was detached + * (if available). */ + if (!FoundPixImage) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (pPixPriv->detachedImage) { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + XlibGC gc = NULL; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->bePixmapFormats[i].depth == + pPixPriv->detachedImage->depth) { + unsigned long m; + XGCValues v; + + m = GCFunction | GCPlaneMask | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + gc = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i], + m, &v); + break; + } + } + + if (gc) { + XPutImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + gc, + pPixPriv->detachedImage, + 0, 0, 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height); + XFreeGC(dmxScreen->beDisplay, gc); + } else { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + } + + XDestroyImage(pPixPriv->detachedImage); + pPixPriv->detachedImage = NULL; + } else { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + } + } +#else + /* If Xinerama is not enabled, then there is no other copy of the + * pixmap image that we can restore. Saving all pixmap data is not + * a feasible option since there is no mechanism for updating pixmap + * data when a screen is detached, which means that the data that + * was previously saved would most likely be out of date. */ + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + return; +#endif +} + +/** Create resources on the back-end server. This function is called + * from #dmxAttachScreen() via the dix layer's FindAllResources + * function. It walks all resources, compares them to the screen + * number passed in as \a n and calls the appropriate DMX function to + * create the associated resource on the back-end server. */ +static void dmxBECreateResources(pointer value, XID id, RESTYPE type, + pointer n) +{ + int scrnNum = (uintptr_t)n; + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + + if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { + /* Window resources are created below in dmxBECreateWindowTree */ + } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { + PixmapPtr pPix = value; + if (pPix->drawable.pScreen->myNum == scrnNum) { + dmxBECreatePixmap(pPix); + dmxBERestorePixmap(pPix); + } + } else if ((type & TypeMask) == (RT_GC & TypeMask)) { + GCPtr pGC = value; + if (pGC->pScreen->myNum == scrnNum) { + /* Create the GC on the back-end server */ + dmxBECreateGC(pScreen, pGC); + /* Create any pixmaps associated with this GC */ + if (!pGC->tileIsPixel) { + dmxBECreatePixmap(pGC->tile.pixmap); + dmxBERestorePixmap(pGC->tile.pixmap); + } + if (pGC->stipple != pScreen->PixmapPerDepth[0]) { + dmxBECreatePixmap(pGC->stipple); + dmxBERestorePixmap(pGC->stipple); + } + if (pGC->font != defaultFont) { + (void)dmxBELoadFont(pScreen, pGC->font); + } + /* Update the GC on the back-end server */ + dmxChangeGC(pGC, -1L); + } + } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { + (void)dmxBELoadFont(pScreen, (FontPtr)value); + } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { + dmxBECreateCursor(pScreen, (CursorPtr)value); + } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { + ColormapPtr pCmap = value; + if (pCmap->pScreen->myNum == scrnNum) + (void)dmxBECreateColormap((ColormapPtr)value); +#if 0 + /* TODO: Recreate Picture and GlyphSet resources */ + } else if ((type & TypeMask) == (PictureType & TypeMask)) { + /* Picture resources are created when windows are created */ + } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { + dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); +#endif + } else { + /* Other resource types??? */ + } +} + +/** Create window hierachy on back-end server. The window tree is + * created in a special order (bottom most subwindow first) so that the + * #dmxCreateNonRootWindow() function does not need to recursively call + * itself to create each window's parents. This is required so that we + * have the opportunity to create each window's border and background + * pixmaps (where appropriate) before the window is created. */ +static void dmxBECreateWindowTree(int idx) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + WindowPtr pRoot = screenInfo.screens[idx]->root; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); + WindowPtr pWin; + + /* Create the pixmaps associated with the root window */ + if (!pRoot->borderIsPixel) { + dmxBECreatePixmap(pRoot->border.pixmap); + dmxBERestorePixmap(pRoot->border.pixmap); + } + if (pRoot->backgroundState == BackgroundPixmap) { + dmxBECreatePixmap(pRoot->background.pixmap); + dmxBERestorePixmap(pRoot->background.pixmap); + } + + /* Create root window first */ + dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pRoot); + XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); + + pWin = pRoot->lastChild; + while (pWin) { + pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + + /* Create the pixmaps regardless of whether or not the + * window is created or not due to lazy window creation. + */ + if (!pWin->borderIsPixel) { + dmxBECreatePixmap(pWin->border.pixmap); + dmxBERestorePixmap(pWin->border.pixmap); + } + if (pWin->backgroundState == BackgroundPixmap) { + dmxBECreatePixmap(pWin->background.pixmap); + dmxBERestorePixmap(pWin->background.pixmap); + } + + /* Reset the window attributes */ + dmxGetDefaultWindowAttributes(pWin, + &pWinPriv->cmap, + &pWinPriv->visual); + + /* Create the window */ + if (pWinPriv->mapped && !pWinPriv->offscreen) + dmxCreateAndRealizeWindow(pWin, TRUE); + + /* Next, create the bottom-most child */ + if (pWin->lastChild) { + pWin = pWin->lastChild; + continue; + } + + /* If the window has no children, move on to the next higher window */ + while (!pWin->prevSib && (pWin != pRoot)) + pWin = pWin->parent; + + if (pWin->prevSib) { + pWin = pWin->prevSib; + continue; + } + + /* When we reach the root window, we are finished */ + if (pWin == pRoot) + break; + } +} + +/* Refresh screen by generating exposure events for all windows */ +static void dmxForceExposures(int idx) +{ + ScreenPtr pScreen = screenInfo.screens[idx]; + WindowPtr pRoot = pScreen->root; + Bool anyMarked = FALSE; + WindowPtr pChild; + + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) + anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, + (WindowPtr *)NULL); + if (anyMarked) { + /* If any windows have been marked, set the root window's + * clipList to be broken since it will be recalculated in + * ValidateTree() + */ + RegionBreak(&pRoot->clipList); + pScreen->ValidateTree(pRoot, NULL, VTBroken); + pScreen->HandleExposures(pRoot); + if (pScreen->PostValidateTree) + pScreen->PostValidateTree(pRoot, NULL, VTBroken); + } +} + +/** Compare the new and old screens to see if they are compatible. */ +static Bool dmxCompareScreens(DMXScreenInfo *new, DMXScreenInfo *old) +{ + int i; + + if (new->beWidth != old->beWidth) return FALSE; + if (new->beHeight != old->beHeight) return FALSE; + if (new->beDepth != old->beDepth) return FALSE; + if (new->beBPP != old->beBPP) return FALSE; + + if (new->beNumDepths != old->beNumDepths) return FALSE; + for (i = 0; i < old->beNumDepths; i++) + if (new->beDepths[i] != old->beDepths[i]) return FALSE; + + if (new->beNumPixmapFormats != old->beNumPixmapFormats) return FALSE; + for (i = 0; i < old->beNumPixmapFormats; i++) { + if (new->bePixmapFormats[i].depth != + old->bePixmapFormats[i].depth) return FALSE; + if (new->bePixmapFormats[i].bits_per_pixel != + old->bePixmapFormats[i].bits_per_pixel) return FALSE; + if (new->bePixmapFormats[i].scanline_pad != + old->bePixmapFormats[i].scanline_pad) return FALSE; + } + + if (new->beNumVisuals != old->beNumVisuals) return FALSE; + for (i = 0; i < old->beNumVisuals; i++) { + if (new->beVisuals[i].visualid != + old->beVisuals[i].visualid) return FALSE; + if (new->beVisuals[i].screen != + old->beVisuals[i].screen) return FALSE; + if (new->beVisuals[i].depth != + old->beVisuals[i].depth) return FALSE; + if (new->beVisuals[i].class != + old->beVisuals[i].class) return FALSE; + if (new->beVisuals[i].red_mask != + old->beVisuals[i].red_mask) return FALSE; + if (new->beVisuals[i].green_mask != + old->beVisuals[i].green_mask) return FALSE; + if (new->beVisuals[i].blue_mask != + old->beVisuals[i].blue_mask) return FALSE; + if (new->beVisuals[i].colormap_size != + old->beVisuals[i].colormap_size) return FALSE; + if (new->beVisuals[i].bits_per_rgb != + old->beVisuals[i].bits_per_rgb) return FALSE; + } + + if (new->beDefVisualIndex != old->beDefVisualIndex) return FALSE; + + return TRUE; +} + +/** Restore Render's picture */ +static void dmxBERestoreRenderPict(pointer value, XID id, pointer n) +{ + PicturePtr pPicture = value; /* The picture */ + DrawablePtr pDraw = pPicture->pDrawable; /* The picture's drawable */ + int scrnNum = (uintptr_t)n; + + if (pDraw->pScreen->myNum != scrnNum) { + /* Picture not on the screen we are restoring*/ + return; + } + + if (pDraw->type == DRAWABLE_PIXMAP) { + PixmapPtr pPixmap = (PixmapPtr)pDraw; + + /* Create and restore the pixmap drawable */ + dmxBECreatePixmap(pPixmap); + dmxBERestorePixmap(pPixmap); + } + + dmxBECreatePicture(pPicture); +} + +/** Restore Render's glyphs */ +static void dmxBERestoreRenderGlyph(pointer value, XID id, pointer n) +{ + GlyphSetPtr glyphSet = value; + int scrnNum = (uintptr_t)n; + dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + DMXScreenInfo *dmxScreen = &dmxScreens[scrnNum]; + GlyphRefPtr table; + char *images; + Glyph *gids; + XGlyphInfo *glyphs; + char *pos; + int beret; + int len_images = 0; + int i; + int ctr; + + if (glyphPriv->glyphSets[scrnNum]) { + /* Only restore glyphs on the screen we are attaching */ + return; + } + + /* First we must create the glyph set on the backend. */ + if ((beret = dmxBECreateGlyphSet(scrnNum, glyphSet)) != Success) { + dmxLog(dmxWarning, + "\tdmxBERestoreRenderGlyph failed to create glyphset!\n"); + return; + } + + /* Now for the complex part, restore the glyph data */ + table = glyphSet->hash.table; + + /* We need to know how much memory to allocate for this part */ + for (i = 0; i < glyphSet->hash.hashSet->size; i++) { + GlyphRefPtr gr = &table[i]; + GlyphPtr gl = gr->glyph; + + if (!gl || gl == DeletedGlyph) continue; + len_images += gl->size - sizeof(gl->info); + } + + /* Now allocate the memory we need */ + images = calloc(len_images, sizeof(char)); + gids = malloc(glyphSet->hash.tableEntries*sizeof(Glyph)); + glyphs = malloc(glyphSet->hash.tableEntries*sizeof(XGlyphInfo)); + + pos = images; + ctr = 0; + + /* Fill the allocated memory with the proper data */ + for (i = 0; i < glyphSet->hash.hashSet->size; i++) { + GlyphRefPtr gr = &table[i]; + GlyphPtr gl = gr->glyph; + + if (!gl || gl == DeletedGlyph) continue; + + /* First lets put the data into gids */ + gids[ctr] = gr->signature; + + /* Next do the glyphs data structures */ + glyphs[ctr].width = gl->info.width; + glyphs[ctr].height = gl->info.height; + glyphs[ctr].x = gl->info.x; + glyphs[ctr].y = gl->info.y; + glyphs[ctr].xOff = gl->info.xOff; + glyphs[ctr].yOff = gl->info.yOff; + + /* Copy the images from the DIX's data into the buffer */ + memcpy(pos, gl+1, gl->size - sizeof(gl->info)); + pos += gl->size - sizeof(gl->info); + ctr++; + } + + /* Now restore the glyph data */ + XRenderAddGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[scrnNum], + gids,glyphs, glyphSet->hash.tableEntries, images, + len_images); + + /* Clean up */ + free(images); + free(gids); + free(glyphs); +} + +/** Reattach previously detached back-end screen. */ +int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) +{ + ScreenPtr pScreen; + DMXScreenInfo *dmxScreen; + CARD32 scrnNum = idx; + DMXScreenInfo oldDMXScreen; + int i; + + /* Return failure if dynamic addition/removal of screens is disabled */ + if (!dmxAddRemoveScreens) { + dmxLog(dmxWarning, + "Attempting to add a screen, but the AddRemoveScreen\n"); + dmxLog(dmxWarning, + "extension has not been enabled. To enable this extension\n"); + dmxLog(dmxWarning, + "add the \"-addremovescreens\" option either to the command\n"); + dmxLog(dmxWarning, + "line or in the configuration file.\n"); + return 1; + } + + /* Cannot add a screen that does not exist */ + if (idx < 0 || idx >= dmxNumScreens) return 1; + pScreen = screenInfo.screens[idx]; + dmxScreen = &dmxScreens[idx]; + + /* Cannot attach to a screen that is already opened */ + if (dmxScreen->beDisplay) { + dmxLog(dmxWarning, + "Attempting to add screen #%d but a screen already exists\n", + idx); + return 1; + } + + dmxLogOutput(dmxScreen, "Attaching screen #%d\n", idx); + + /* Save old info */ + oldDMXScreen = *dmxScreen; + + /* Copy the name to the new screen */ + dmxScreen->name = strdup(attr->displayName); + + /* Open display and get all of the screen info */ + if (!dmxOpenDisplay(dmxScreen)) { + dmxLog(dmxWarning, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreen->name); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + dmxSetErrorHandler(dmxScreen); + dmxCheckForWM(dmxScreen); + dmxGetScreenAttribs(dmxScreen); + + if (!dmxGetVisualInfo(dmxScreen)) { + dmxLog(dmxWarning, "dmxGetVisualInfo: No matching visuals found\n"); + XFree(dmxScreen->beVisuals); + XCloseDisplay(dmxScreen->beDisplay); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + dmxGetColormaps(dmxScreen); + dmxGetPixmapFormats(dmxScreen); + + /* Verify that the screen to be added has the same info as the + * previously added screen. */ + if (!dmxCompareScreens(dmxScreen, &oldDMXScreen)) { + dmxLog(dmxWarning, + "New screen data (%s) does not match previously\n", + dmxScreen->name); + dmxLog(dmxWarning, + "attached screen data (%s)\n", + oldDMXScreen.name); + dmxLog(dmxWarning, + "All data must match in order to attach to screen #%d\n", + idx); + XFree(dmxScreen->beVisuals); + XFree(dmxScreen->beDepths); + XFree(dmxScreen->bePixmapFormats); + XCloseDisplay(dmxScreen->beDisplay); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + /* Initialize the BE screen resources */ + dmxBEScreenInit(idx, screenInfo.screens[idx]); + + /* TODO: Handle GLX visual initialization. GLXProxy needs to be + * updated to handle dynamic addition/removal of screens. */ + + /* Create default stipple */ + dmxBECreatePixmap(pScreen->PixmapPerDepth[0]); + dmxBERestorePixmap(pScreen->PixmapPerDepth[0]); + + /* Create the scratch GCs */ + dmxBECreateScratchGCs(idx); + + /* Create the default font */ + (void)dmxBELoadFont(pScreen, defaultFont); + + /* Create all resources that don't depend on windows */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBECreateResources, + (pointer)(uintptr_t)idx); + + /* Create window hierarchy (top down) */ + dmxBECreateWindowTree(idx); + + /* Restore the picture state for RENDER */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindClientResourcesByType(clients[i],PictureType, + dmxBERestoreRenderPict, + (pointer)(uintptr_t)idx); + + /* Restore the glyph state for RENDER */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindClientResourcesByType(clients[i],GlyphSetType, + dmxBERestoreRenderGlyph, + (pointer)(uintptr_t)idx); + + /* Refresh screen by generating exposure events for all windows */ + dmxForceExposures(idx); + + dmxSync(&dmxScreens[idx], TRUE); + + /* We used these to compare the old and new screens. They are no + * longer needed since we have a newly attached screen, so we can + * now free the old screen's resources. */ + XFree(oldDMXScreen.beVisuals); + XFree(oldDMXScreen.beDepths); + XFree(oldDMXScreen.bePixmapFormats); + /* TODO: should oldDMXScreen.name be freed?? */ + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL); + else +#endif + return 0; /* Success */ +} + +/* + * Resources that may have state on the BE server and need to be freed: + * + * RT_NONE + * RT_WINDOW + * RT_PIXMAP + * RT_GC + * RT_FONT + * RT_CURSOR + * RT_COLORMAP + * RT_CMAPENTRY + * RT_OTHERCLIENT + * RT_PASSIVEGRAB + * XRT_WINDOW + * XRT_PIXMAP + * XRT_GC + * XRT_COLORMAP + * XRT_PICTURE + * PictureType + * PictFormatType + * GlyphSetType + * ClientType + * EventType + * RT_INPUTCLIENT + * XETrapType + * RTCounter + * RTAwait + * RTAlarmClient + * RT_XKBCLIENT + * RTContext + * TagResType + * StalledResType + * SecurityAuthorizationResType + * RTEventClient + * __glXContextRes + * __glXClientRes + * __glXPixmapRes + * __glXWindowRes + * __glXPbufferRes + */ + +#ifdef PANORAMIX +/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs + * to have its image saved. */ +static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, + pointer p) +{ + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPix = (PanoramiXRes *)value; + PixmapPtr pPix; + int i; + + dixLookupResourceByType((pointer*) &pPix, pXinPix->info[idx].id, + RT_PIXMAP, NullClient, DixUnknownAccess); + if (pPix != pDst) return; /* Not a match.... Next! */ + + for (i = 0; i < PanoramiXNumScreens; i++) { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + dixLookupResourceByType((pointer*) &pSrc, pXinPix->info[i].id, + RT_PIXMAP, NullClient, DixUnknownAccess); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); + if (pSrcPriv->pixmap) { + FoundPixImage = True; + return; + } + } + } +} +#endif + +/** Save the pixmap image only when there is not another screen with + * that pixmap from which the image can be read when the screen is + * reattached. To do this, we first try to find a pixmap on another + * screen corresponding to the one we are trying to save. If we find + * one, then we do not need to save the image data since during + * reattachment, the image data can be read from that other pixmap. + * However, if we do not find one, then we need to save the image data. + * The common case for these are for the default stipple and root + * tile. */ +static void dmxBESavePixmap(PixmapPtr pPixmap) +{ +#ifdef PANORAMIX + int i; + + /* If Xinerama is not active, there's nothing we can do (see comment + * in #else below for more info). */ + if (noPanoramiXExtension) return; + + FoundPixImage = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEFindPixmapImage, + (pointer)pPixmap); + + /* Save the image only if there is no other screens that have a + * pixmap that corresponds to the one we are trying to save. */ + if (!FoundPixImage) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (!pPixPriv->detachedImage) { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + 0, 0, + pPixmap->drawable.width, + pPixmap->drawable.height, + -1, + ZPixmap); + if (!pPixPriv->detachedImage) + dmxLog(dmxWarning, "Cannot save pixmap image\n"); + } + } +#else + /* NOTE: The only time there is a pixmap on another screen that + * corresponds to the one we are trying to save is when Xinerama is + * active. Otherwise, the pixmap image data is only stored on a + * single screen, which means that once it is detached, that data is + * lost. We could save the data here, but then that would require + * us to implement the ability for Xdmx to keep the pixmap up to + * date while the screen is detached, which is beyond the scope of + * the current project. */ + return; +#endif +} + +/** Destroy resources on the back-end server. This function is called + * from #dmxDetachScreen() via the dix layer's FindAllResources + * function. It walks all resources, compares them to the screen + * number passed in as \a n and calls the appropriate DMX function to + * free the associated resource on the back-end server. */ +static void dmxBEDestroyResources(pointer value, XID id, RESTYPE type, + pointer n) +{ + int scrnNum = (uintptr_t)n; + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + + if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { + /* Window resources are destroyed below in dmxBEDestroyWindowTree */ + } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { + PixmapPtr pPix = value; + if (pPix->drawable.pScreen->myNum == scrnNum) { + dmxBESavePixmap(pPix); + dmxBEFreePixmap(pPix); + } + } else if ((type & TypeMask) == (RT_GC & TypeMask)) { + GCPtr pGC = value; + if (pGC->pScreen->myNum == scrnNum) + dmxBEFreeGC(pGC); + } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { + dmxBEFreeFont(pScreen, (FontPtr)value); + } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { + dmxBEFreeCursor(pScreen, (CursorPtr)value); + } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { + ColormapPtr pCmap = value; + if (pCmap->pScreen->myNum == scrnNum) + dmxBEFreeColormap((ColormapPtr)value); + } else if ((type & TypeMask) == (PictureType & TypeMask)) { + PicturePtr pPict = value; + if (pPict->pDrawable->pScreen->myNum == scrnNum) { + /* Free the pixmaps on the backend if needed */ + if (pPict->pDrawable->type == DRAWABLE_PIXMAP) { + PixmapPtr pPixmap = (PixmapPtr)(pPict->pDrawable); + dmxBESavePixmap(pPixmap); + dmxBEFreePixmap(pPixmap); + } + dmxBEFreePicture((PicturePtr)value); + } + } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { + dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); + } else { + /* Other resource types??? */ + } +} + +/** Destroy the scratch GCs that are created per depth. */ +static void dmxBEDestroyScratchGCs(int scrnNum) +{ + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + GCPtr *ppGC = pScreen->GCperDepth; + int i; + + for (i = 0; i <= pScreen->numDepths; i++) + dmxBEFreeGC(ppGC[i]); +} + +/** Destroy window hierachy on back-end server. To ensure that all + * XDestroyWindow() calls succeed, they must be performed in a bottom + * up order so that windows are not destroyed before their children. + * XDestroyWindow(), which is called from #dmxBEDestroyWindow(), will + * destroy a window as well as all of it's children. */ +static void dmxBEDestroyWindowTree(int idx) +{ + WindowPtr pWin = screenInfo.screens[idx]->root; + WindowPtr pChild = pWin; + + while (1) { + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + /* Destroy the window */ + dmxBEDestroyWindow(pChild); + + /* Make sure we destroy the window's border and background + * pixmaps if they exist */ + if (!pChild->borderIsPixel) { + dmxBESavePixmap(pChild->border.pixmap); + dmxBEFreePixmap(pChild->border.pixmap); + } + if (pChild->backgroundState == BackgroundPixmap) { + dmxBESavePixmap(pChild->background.pixmap); + dmxBEFreePixmap(pChild->background.pixmap); + } + + while (!pChild->nextSib && (pChild != pWin)) { + pChild = pChild->parent; + dmxBEDestroyWindow(pChild); + if (!pChild->borderIsPixel) { + dmxBESavePixmap(pChild->border.pixmap); + dmxBEFreePixmap(pChild->border.pixmap); + } + if (pChild->backgroundState == BackgroundPixmap) { + dmxBESavePixmap(pChild->background.pixmap); + dmxBEFreePixmap(pChild->background.pixmap); + } + } + + if (pChild == pWin) + break; + + pChild = pChild->nextSib; + } +} + +/** Detach back-end screen. */ +int dmxDetachScreen(int idx) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + int i; + + /* Return failure if dynamic addition/removal of screens is disabled */ + if (!dmxAddRemoveScreens) { + dmxLog(dmxWarning, + "Attempting to remove a screen, but the AddRemoveScreen\n"); + dmxLog(dmxWarning, + "extension has not been enabled. To enable this extension\n"); + dmxLog(dmxWarning, + "add the \"-addremovescreens\" option either to the command\n"); + dmxLog(dmxWarning, + "line or in the configuration file.\n"); + return 1; + } + + /* Cannot remove a screen that does not exist */ + if (idx < 0 || idx >= dmxNumScreens) return 1; + + /* Cannot detach from a screen that is not opened */ + if (!dmxScreen->beDisplay) { + dmxLog(dmxWarning, + "Attempting to remove screen #%d but it has not been opened\n", + idx); + return 1; + } + + dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx); + + /* Detach input */ + dmxInputDetachAll(dmxScreen); + + /* Save all relevant state (TODO) */ + + /* Free all non-window resources related to this screen */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEDestroyResources, + (pointer)(uintptr_t)idx); + + /* Free scratch GCs */ + dmxBEDestroyScratchGCs(idx); + + /* Free window resources related to this screen */ + dmxBEDestroyWindowTree(idx); + + /* Free default stipple */ + dmxBESavePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + dmxBEFreePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + + /* Free the remaining screen resources and close the screen */ + dmxBECloseScreen(screenInfo.screens[idx]); + + /* Adjust the cursor boundaries (paints detached console window) */ + dmxAdjustCursorBoundaries(); + + return 0; /* Success */ +} diff --git a/xorg-server/hw/dmx/dmxgc.c b/xorg-server/hw/dmx/dmxgc.c index 10e93c110..f10f9a074 100644 --- a/xorg-server/hw/dmx/dmxgc.c +++ b/xorg-server/hw/dmx/dmxgc.c @@ -1,421 +1,416 @@ -/* - * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Authors: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for GCs. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxgc.h" -#include "dmxgcops.h" -#include "dmxpixmap.h" -#include "dmxfont.h" - -#include "gcstruct.h" -#include "pixmapstr.h" -#include "migc.h" - -static GCFuncs dmxGCFuncs = { - dmxValidateGC, - dmxChangeGC, - dmxCopyGC, - dmxDestroyGC, - dmxChangeClip, - dmxDestroyClip, - dmxCopyClip, -}; - -static GCOps dmxGCOps = { - dmxFillSpans, - dmxSetSpans, - dmxPutImage, - dmxCopyArea, - dmxCopyPlane, - dmxPolyPoint, - dmxPolylines, - dmxPolySegment, - dmxPolyRectangle, - dmxPolyArc, - dmxFillPolygon, - dmxPolyFillRect, - dmxPolyFillArc, - dmxPolyText8, - dmxPolyText16, - dmxImageText8, - dmxImageText16, - dmxImageGlyphBlt, - dmxPolyGlyphBlt, - dmxPushPixels -}; - -/** Initialize the GC on \a pScreen */ -Bool dmxInitGC(ScreenPtr pScreen) -{ - if (!dixRegisterPrivateKey(&dmxGCPrivateKeyRec, PRIVATE_GC, sizeof(dmxGCPrivRec))) - return FALSE; - return TRUE; -} - -/** Create the GC on the back-end server. */ -void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - int i; - - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { - unsigned long mask; - XGCValues gcvals; - - mask = GCGraphicsExposures; - gcvals.graphics_exposures = FALSE; - - /* Create GC in the back-end servers */ - pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnDefDrawables[i], - mask, &gcvals); - break; - } - } -} - -/** Create a graphics context on the back-end server associated /a pGC's - * screen. */ -Bool dmxCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - Bool ret; - - DMX_UNWRAP(CreateGC, dmxScreen, pScreen); - if ((ret = pScreen->CreateGC(pGC))) { - /* Save the old funcs */ - pGCPriv->funcs = pGC->funcs; - pGCPriv->ops = NULL; - - pGC->funcs = &dmxGCFuncs; - - if (dmxScreen->beDisplay) { - dmxBECreateGC(pScreen, pGC); - } else { - pGCPriv->gc = NULL; - } - - /* Check for "magic special case" - * 1. see CreateGC in dix/gc.c for more info - * 2. see dmxChangeGC for more info - */ - pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); - } - DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); - - return ret; -} - -/** Validate a graphics context, \a pGC, locally in the DMX server and - * recompute the composite clip, if necessary. */ -void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) -{ - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - DMX_GC_FUNC_PROLOGUE(pGC); -#if 0 - pGC->funcs->ValidateGC(pGC, changes, pDrawable); -#endif - - if (pDrawable->type == DRAWABLE_WINDOW || - pDrawable->type == DRAWABLE_PIXMAP) { - /* Save the old ops, since we're about to change the ops in the - * epilogue. - */ - pGCPriv->ops = pGC->ops; - } else { - pGCPriv->ops = NULL; - } - - /* If the client clip is different or moved OR the subwindowMode has - * changed OR the window's clip has changed since the last - * validation, then we need to recompute the composite clip. - */ - if ((changes & (GCClipXOrigin | - GCClipYOrigin | - GCClipMask | - GCSubwindowMode)) || - (pDrawable->serialNumber != - (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { - miComputeCompositeClip(pGC, pDrawable); - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Set the values in the graphics context on the back-end server - * associated with \a pGC's screen. */ -void dmxChangeGC(GCPtr pGC, unsigned long mask) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XGCValues v; - - DMX_GC_FUNC_PROLOGUE(pGC); -#if 0 - pGC->funcs->ChangeGC(pGC, mask); -#endif - - /* Handle "magic special case" from CreateGC */ - if (pGCPriv->msc) { - /* The "magic special case" is used to handle the case where a - * foreground pixel is set when the GC is created so that a - * "pseudo default-tile" can be created and used in case the - * fillstyle was set to FillTiled. This specific case is tested - * in xtest (XCreateGC test #3). What has happened in dix by - * the time it reaches here is (1) the pGC->tile.pixel has been - * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a - * tile has also been set, then pGC->tileIsPixel is unset and - * pGC->tile.pixmap is initialized; else, the default tile is - * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is - * initialized to the "pseudo default-tile". In either case, - * pGC->tile.pixmap is set; however, in the "magic special case" - * the mask is not updated to allow us to detect that we should - * initialize the GCTile in the back-end server. Thus, we catch - * this case in dmxCreateGC and add GCTile to the mask here. - * Are there any cases that I've missed? - */ - - /* Make sure that the tile.pixmap is set, just in case the user - * set GCTile in the mask but forgot to set vals.pixmap - */ - if (pGC->tile.pixmap) mask |= GCTile; - - /* This only happens once when the GC is created */ - pGCPriv->msc = FALSE; - } - - /* Update back-end server's gc */ - if (mask & GCFunction) v.function = pGC->alu; - if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; - if (mask & GCForeground) v.foreground = pGC->fgPixel; - if (mask & GCBackground) v.background = pGC->bgPixel; - if (mask & GCLineWidth) v.line_width = pGC->lineWidth; - if (mask & GCLineStyle) v.line_style = pGC->lineStyle; - if (mask & GCCapStyle) v.cap_style = pGC->capStyle; - if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; - if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; - if (mask & GCFillRule) v.fill_rule = pGC->fillRule; - if (mask & GCTile) { - if (pGC->tileIsPixel) { - mask &= ~GCTile; - } else { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); - v.tile = (Drawable)pPixPriv->pixmap; - } - } - if (mask & GCStipple) { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); - v.stipple = (Drawable)pPixPriv->pixmap; - } - if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; - if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; - if (mask & GCFont) { - if (dmxScreen->beDisplay) { - dmxFontPrivPtr pFontPriv; - pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); - v.font = pFontPriv->font[pScreen->myNum]->fid; - } else { - mask &= ~GCFont; - } - } - if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; - - /* Graphics exposures are not needed on the back-ends since they can - be generated on the front-end thereby saving bandwidth. */ - if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; - - if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; - if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; - if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ - if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; - if (mask & GCDashList) { - mask &= ~GCDashList; - if (dmxScreen->beDisplay) - XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, - pGC->dashOffset, (char *)pGC->dash, - pGC->numInDashList); - } - if (mask & GCArcMode) v.arc_mode = pGC->arcMode; - - if (mask && dmxScreen->beDisplay) { - XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); - dmxSync(dmxScreen, FALSE); - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with - * \a pGCSrc's screen. */ -void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) -{ - ScreenPtr pScreen = pGCSrc->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); - dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); - - DMX_GC_FUNC_PROLOGUE(pGCDst); - pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); - - /* Copy the GC on the back-end server */ - if (dmxScreen->beDisplay) - XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); - - DMX_GC_FUNC_EPILOGUE(pGCDst); -} - -/** Free the \a pGC on the back-end server. */ -Bool dmxBEFreeGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - if (pGCPriv->gc) { - XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); - pGCPriv->gc = NULL; - return TRUE; - } - - return FALSE; -} - -/** Destroy the graphics context, \a pGC and free the corresponding GC - * on the back-end server. */ -void dmxDestroyGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMX_GC_FUNC_PROLOGUE(pGC); - - /* Free the GC on the back-end server */ - if (dmxScreen->beDisplay) - dmxBEFreeGC(pGC); - - pGC->funcs->DestroyGC(pGC); - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Change the clip rects for a GC. */ -void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XRectangle *pRects; - BoxPtr pBox; - int i, nRects; - - DMX_GC_FUNC_PROLOGUE(pGC); - pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); - - /* Set the client clip on the back-end server */ - switch (pGC->clientClipType) { - case CT_NONE: - if (dmxScreen->beDisplay) - XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); - break; - - case CT_REGION: - if (dmxScreen->beDisplay) { - nRects = RegionNumRects((RegionPtr)pGC->clientClip); - pRects = malloc(nRects * sizeof(*pRects)); - pBox = RegionRects((RegionPtr)pGC->clientClip); - - for (i = 0; i < nRects; i++) { - pRects[i].x = pBox[i].x1; - pRects[i].y = pBox[i].y1; - pRects[i].width = pBox[i].x2 - pBox[i].x1; - pRects[i].height = pBox[i].y2 - pBox[i].y1; - } - - XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, - pGC->clipOrg.x, pGC->clipOrg.y, - pRects, nRects, Unsorted); - - free(pRects); - } - break; - - case CT_PIXMAP: - case CT_UNSORTED: - case CT_YSORTED: - case CT_YXSORTED: - case CT_YXBANDED: - /* These clip types are condensed down to either NONE or REGION - in the mi code */ - break; - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Destroy a GC's clip rects. */ -void dmxDestroyClip(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - DMX_GC_FUNC_PROLOGUE(pGC); - pGC->funcs->DestroyClip(pGC); - - /* Set the client clip on the back-end server to None */ - if (dmxScreen->beDisplay) - XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Copy a GC's clip rects. */ -void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) -{ - DMX_GC_FUNC_PROLOGUE(pGCDst); - pGCDst->funcs->CopyClip(pGCDst, pGCSrc); - DMX_GC_FUNC_EPILOGUE(pGCDst); -} +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for GCs. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxgc.h" +#include "dmxgcops.h" +#include "dmxpixmap.h" +#include "dmxfont.h" + +#include "gcstruct.h" +#include "pixmapstr.h" +#include "migc.h" + +static GCFuncs dmxGCFuncs = { + dmxValidateGC, + dmxChangeGC, + dmxCopyGC, + dmxDestroyGC, + dmxChangeClip, + dmxDestroyClip, + dmxCopyClip, +}; + +static GCOps dmxGCOps = { + dmxFillSpans, + dmxSetSpans, + dmxPutImage, + dmxCopyArea, + dmxCopyPlane, + dmxPolyPoint, + dmxPolylines, + dmxPolySegment, + dmxPolyRectangle, + dmxPolyArc, + dmxFillPolygon, + dmxPolyFillRect, + dmxPolyFillArc, + dmxPolyText8, + dmxPolyText16, + dmxImageText8, + dmxImageText16, + dmxImageGlyphBlt, + dmxPolyGlyphBlt, + dmxPushPixels +}; + +/** Initialize the GC on \a pScreen */ +Bool dmxInitGC(ScreenPtr pScreen) +{ + if (!dixRegisterPrivateKey(&dmxGCPrivateKeyRec, PRIVATE_GC, sizeof(dmxGCPrivRec))) + return FALSE; + return TRUE; +} + +/** Create the GC on the back-end server. */ +void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + int i; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { + unsigned long mask; + XGCValues gcvals; + + mask = GCGraphicsExposures; + gcvals.graphics_exposures = FALSE; + + /* Create GC in the back-end servers */ + pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i], + mask, &gcvals); + break; + } + } +} + +/** Create a graphics context on the back-end server associated /a pGC's + * screen. */ +Bool dmxCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + Bool ret; + + DMX_UNWRAP(CreateGC, dmxScreen, pScreen); + if ((ret = pScreen->CreateGC(pGC))) { + /* Save the old funcs */ + pGCPriv->funcs = pGC->funcs; + pGCPriv->ops = NULL; + + pGC->funcs = &dmxGCFuncs; + + if (dmxScreen->beDisplay) { + dmxBECreateGC(pScreen, pGC); + } else { + pGCPriv->gc = NULL; + } + + /* Check for "magic special case" + * 1. see CreateGC in dix/gc.c for more info + * 2. see dmxChangeGC for more info + */ + pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); + } + DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); + + return ret; +} + +/** Validate a graphics context, \a pGC, locally in the DMX server and + * recompute the composite clip, if necessary. */ +void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + DMX_GC_FUNC_PROLOGUE(pGC); +#if 0 + pGC->funcs->ValidateGC(pGC, changes, pDrawable); +#endif + + if (pDrawable->type == DRAWABLE_WINDOW || + pDrawable->type == DRAWABLE_PIXMAP) { + /* Save the old ops, since we're about to change the ops in the + * epilogue. + */ + pGCPriv->ops = pGC->ops; + } else { + pGCPriv->ops = NULL; + } + + /* If the client clip is different or moved OR the subwindowMode has + * changed OR the window's clip has changed since the last + * validation, then we need to recompute the composite clip. + */ + if ((changes & (GCClipXOrigin | + GCClipYOrigin | + GCClipMask | + GCSubwindowMode)) || + (pDrawable->serialNumber != + (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { + miComputeCompositeClip(pGC, pDrawable); + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Set the values in the graphics context on the back-end server + * associated with \a pGC's screen. */ +void dmxChangeGC(GCPtr pGC, unsigned long mask) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + XGCValues v; + + DMX_GC_FUNC_PROLOGUE(pGC); +#if 0 + pGC->funcs->ChangeGC(pGC, mask); +#endif + + /* Handle "magic special case" from CreateGC */ + if (pGCPriv->msc) { + /* The "magic special case" is used to handle the case where a + * foreground pixel is set when the GC is created so that a + * "pseudo default-tile" can be created and used in case the + * fillstyle was set to FillTiled. This specific case is tested + * in xtest (XCreateGC test #3). What has happened in dix by + * the time it reaches here is (1) the pGC->tile.pixel has been + * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a + * tile has also been set, then pGC->tileIsPixel is unset and + * pGC->tile.pixmap is initialized; else, the default tile is + * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is + * initialized to the "pseudo default-tile". In either case, + * pGC->tile.pixmap is set; however, in the "magic special case" + * the mask is not updated to allow us to detect that we should + * initialize the GCTile in the back-end server. Thus, we catch + * this case in dmxCreateGC and add GCTile to the mask here. + * Are there any cases that I've missed? + */ + + /* Make sure that the tile.pixmap is set, just in case the user + * set GCTile in the mask but forgot to set vals.pixmap + */ + if (pGC->tile.pixmap) mask |= GCTile; + + /* This only happens once when the GC is created */ + pGCPriv->msc = FALSE; + } + + /* Update back-end server's gc */ + if (mask & GCFunction) v.function = pGC->alu; + if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; + if (mask & GCForeground) v.foreground = pGC->fgPixel; + if (mask & GCBackground) v.background = pGC->bgPixel; + if (mask & GCLineWidth) v.line_width = pGC->lineWidth; + if (mask & GCLineStyle) v.line_style = pGC->lineStyle; + if (mask & GCCapStyle) v.cap_style = pGC->capStyle; + if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; + if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; + if (mask & GCFillRule) v.fill_rule = pGC->fillRule; + if (mask & GCTile) { + if (pGC->tileIsPixel) { + mask &= ~GCTile; + } else { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); + v.tile = (Drawable)pPixPriv->pixmap; + } + } + if (mask & GCStipple) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); + v.stipple = (Drawable)pPixPriv->pixmap; + } + if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; + if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; + if (mask & GCFont) { + if (dmxScreen->beDisplay) { + dmxFontPrivPtr pFontPriv; + pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); + v.font = pFontPriv->font[pScreen->myNum]->fid; + } else { + mask &= ~GCFont; + } + } + if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; + + /* Graphics exposures are not needed on the back-ends since they can + be generated on the front-end thereby saving bandwidth. */ + if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; + + if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; + if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; + if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ + if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; + if (mask & GCDashList) { + mask &= ~GCDashList; + if (dmxScreen->beDisplay) + XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, + pGC->dashOffset, (char *)pGC->dash, + pGC->numInDashList); + } + if (mask & GCArcMode) v.arc_mode = pGC->arcMode; + + if (mask && dmxScreen->beDisplay) { + XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); + dmxSync(dmxScreen, FALSE); + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with + * \a pGCSrc's screen. */ +void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) +{ + ScreenPtr pScreen = pGCSrc->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); + dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); + + DMX_GC_FUNC_PROLOGUE(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); + + /* Copy the GC on the back-end server */ + if (dmxScreen->beDisplay) + XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); + + DMX_GC_FUNC_EPILOGUE(pGCDst); +} + +/** Free the \a pGC on the back-end server. */ +Bool dmxBEFreeGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + if (pGCPriv->gc) { + XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); + pGCPriv->gc = NULL; + return TRUE; + } + + return FALSE; +} + +/** Destroy the graphics context, \a pGC and free the corresponding GC + * on the back-end server. */ +void dmxDestroyGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMX_GC_FUNC_PROLOGUE(pGC); + + /* Free the GC on the back-end server */ + if (dmxScreen->beDisplay) + dmxBEFreeGC(pGC); + + pGC->funcs->DestroyGC(pGC); + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Change the clip rects for a GC. */ +void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + XRectangle *pRects; + BoxPtr pBox; + int i, nRects; + + DMX_GC_FUNC_PROLOGUE(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + + /* Set the client clip on the back-end server */ + switch (pGC->clientClipType) { + case CT_NONE: + if (dmxScreen->beDisplay) + XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + break; + + case CT_REGION: + if (dmxScreen->beDisplay) { + nRects = RegionNumRects((RegionPtr)pGC->clientClip); + pRects = malloc(nRects * sizeof(*pRects)); + pBox = RegionRects((RegionPtr)pGC->clientClip); + + for (i = 0; i < nRects; i++) { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, + pGC->clipOrg.x, pGC->clipOrg.y, + pRects, nRects, Unsorted); + + free(pRects); + } + break; + + case CT_PIXMAP: + /* Condensed down to REGION in the mi code */ + break; + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Destroy a GC's clip rects. */ +void dmxDestroyClip(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + DMX_GC_FUNC_PROLOGUE(pGC); + pGC->funcs->DestroyClip(pGC); + + /* Set the client clip on the back-end server to None */ + if (dmxScreen->beDisplay) + XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Copy a GC's clip rects. */ +void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + DMX_GC_FUNC_PROLOGUE(pGCDst); + pGCDst->funcs->CopyClip(pGCDst, pGCSrc); + DMX_GC_FUNC_EPILOGUE(pGCDst); +} diff --git a/xorg-server/hw/dmx/input/dmxinputinit.c b/xorg-server/hw/dmx/input/dmxinputinit.c index 4b10ecb17..5cbd620c9 100644 --- a/xorg-server/hw/dmx/input/dmxinputinit.c +++ b/xorg-server/hw/dmx/input/dmxinputinit.c @@ -1,1306 +1,1274 @@ -/* - * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Authors: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * This file provides generic input support. Functions here set up - * input and lead to the calling of low-level device drivers for - * input. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_WINDOW_DEBUG 0 - -#include "dmxinputinit.h" -#include "dmxextension.h" /* For dmxInputCount */ - -#include "dmxdummy.h" -#include "dmxbackend.h" -#include "dmxconsole.h" -#include "dmxcommon.h" -#include "dmxevents.h" -#include "dmxmotion.h" -#include "dmxprop.h" -#include "config/dmxconfig.h" -#include "dmxcursor.h" - -#include "lnx-keyboard.h" -#include "lnx-ms.h" -#include "lnx-ps2.h" -#include "usb-keyboard.h" -#include "usb-mouse.h" -#include "usb-other.h" -#include "usb-common.h" - -#include "dmxsigio.h" -#include "dmxarg.h" - -#include "inputstr.h" -#include "input.h" -#include "mipointer.h" -#include "windowstr.h" -#include "mi.h" -#include "xkbsrv.h" - -#include -#include -#include "exevents.h" -#include "extinit.h" - -DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; - -static DMXLocalInputInfoRec DMXDummyMou = { - "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo -}; - -static DMXLocalInputInfoRec DMXDummyKbd = { - "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo -}; - -static DMXLocalInputInfoRec DMXBackendMou = { - "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, - dmxBackendCreatePrivate, dmxBackendDestroyPrivate, - dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, - dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, - NULL, NULL, NULL, - dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, - dmxCommonMouCtrl -}; - -static DMXLocalInputInfoRec DMXBackendKbd = { - "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, - 1, /* With backend-mou or console-mou */ - dmxCommonCopyPrivate, NULL, - dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, - dmxCommonKbdOn, dmxCommonKbdOff, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, dmxCommonKbdCtrl, dmxCommonKbdBell -}; - -static DMXLocalInputInfoRec DMXConsoleMou = { - "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, - dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, - dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, - dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, - NULL, NULL, NULL, - dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, - dmxCommonMouCtrl -}; - -static DMXLocalInputInfoRec DMXConsoleKbd = { - "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, - 1, /* With backend-mou or console-mou */ - dmxCommonCopyPrivate, NULL, - dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, - dmxCommonKbdOn, dmxCommonKbdOff, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, dmxCommonKbdCtrl, dmxCommonKbdBell -}; - -static DMXLocalInputInfoRec DMXCommonOth = { - "common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1, - dmxCommonCopyPrivate, NULL, - NULL, NULL, NULL, dmxCommonOthGetInfo, - dmxCommonOthOn, dmxCommonOthOff -}; - - -static DMXLocalInputInfoRec DMXLocalDevices[] = { - /* Dummy drivers that can compile on any OS */ -#ifdef __linux__ - /* Linux-specific drivers */ - { - "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, - kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, - kbdLinuxOn, kbdLinuxOff, NULL, - kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, - kbdLinuxRead, NULL, NULL, NULL, - NULL, kbdLinuxCtrl, kbdLinuxBell - }, - { - "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - msLinuxCreatePrivate, msLinuxDestroyPrivate, - msLinuxInit, NULL, NULL, msLinuxGetInfo, - msLinuxOn, msLinuxOff, NULL, - msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, - msLinuxRead - }, - { - "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, - ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, - ps2LinuxOn, ps2LinuxOff, NULL, - ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, - ps2LinuxRead - }, -#endif -#ifdef __linux__ - /* USB drivers, currently only for - Linux, but relatively easy to port to - other OSs */ - { - "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - kbdUSBInit, NULL, NULL, kbdUSBGetInfo, - kbdUSBOn, usbOff, NULL, - NULL, NULL, NULL, - kbdUSBRead, NULL, NULL, NULL, - NULL, kbdUSBCtrl - }, - { - "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - mouUSBInit, NULL, NULL, mouUSBGetInfo, - mouUSBOn, usbOff, NULL, - NULL, NULL, NULL, - mouUSBRead - }, - { - "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - othUSBInit, NULL, NULL, othUSBGetInfo, - othUSBOn, usbOff, NULL, - NULL, NULL, NULL, - othUSBRead - }, -#endif - { - "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo - }, - { - "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo - }, - { NULL } /* Must be last */ -}; - - -#if 11 /*BP*/ -void -DDXRingBell(int volume, int pitch, int duration) -{ - /* NO-OP */ -} - -/* taken from kdrive/src/kinput.c: */ -static void -dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ -#if 0 - KdKeyboardInfo *ki; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDevice->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) - return; - - KdSetLeds(ki, ctrl->leds); - ki->bellPitch = ctrl->bell_pitch; - ki->bellDuration = ctrl->bell_duration; -#endif -} - -/* taken from kdrive/src/kinput.c: */ -static void -dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) -{ -#if 0 - KeybdCtrl *ctrl = arg; - KdKeyboardInfo *ki = NULL; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDev->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) - return; - - KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); -#endif -} - -#endif /*BP*/ - -static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, - PtrCtrl *ctrl) -{ - if (!dmxLocal) return; - dmxLocal->mctrl = *ctrl; - if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); -} - -/** Change the pointer control information for the \a pDevice. If the - * device sends core events, then also change the control information - * for all of the pointer devices that send core events. */ -void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxChangePointerControl(dmxInput->devs[j], ctrl); - } - } else { /* Do for this device only */ - _dmxChangePointerControl(dmxLocal, ctrl); - } -} - -static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, - KeybdCtrl *ctrl) -{ - dmxLocal->kctrl = *ctrl; - if (dmxLocal->kCtrl) { - dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); - if (dmxLocal->pDevice->kbdfeed) { - XkbEventCauseRec cause; - XkbSetCauseUnknown(&cause); - /* Generate XKB events, as necessary */ - XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, - NULL, &cause); - } - } -} - - -/** Change the keyboard control information for the \a pDevice. If the - * device sends core events, then also change the control information - * for all of the keyboard devices that send core events. */ -void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); - } - } else { /* Do for this device only */ - _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); - } -} - -static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) -{ - if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, - percent, - dmxLocal->kctrl.bell, - dmxLocal->kctrl.bell_pitch, - dmxLocal->kctrl.bell_duration); -} - -/** Sound the bell on the device. If the device send core events, then - * sound the bell on all of the devices that send core events. */ -void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, - pointer ctrl, int unknown) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxKeyboardBellProc(dmxInput->devs[j], percent); - } - } else { /* Do for this device only */ - _dmxKeyboardBellProc(dmxLocal, percent); - } -} - -static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) -{ - if (names->keycodes) XFree(names->keycodes); - if (names->types) XFree(names->types); - if (names->compat) XFree(names->compat); - if (names->symbols) XFree(names->symbols); - if (names->geometry) XFree(names->geometry); -} - - -static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) -{ - GETDMXINPUTFROMPDEVICE; - XkbRMLVOSet rmlvo; - - rmlvo.rules = dmxConfigGetXkbRules(); - rmlvo.model = dmxConfigGetXkbModel(); - rmlvo.layout = dmxConfigGetXkbLayout(); - rmlvo.variant = dmxConfigGetXkbVariant(); - rmlvo.options = dmxConfigGetXkbOptions(); - - XkbSetRulesDflts(&rmlvo); - if (!info->force && (dmxInput->keycodes - || dmxInput->symbols - || dmxInput->geometry)) { - if (info->freenames) dmxKeyboardFreeNames(&info->names); - info->freenames = 0; - info->names.keycodes = dmxInput->keycodes; - info->names.types = NULL; - info->names.compat = NULL; - info->names.symbols = dmxInput->symbols; - info->names.geometry = dmxInput->geometry; - - dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", - info->names.keycodes); - if (info->names.symbols && *info->names.symbols) - dmxLogInputCont(dmxInput, " %s", info->names.symbols); - if (info->names.geometry && *info->names.geometry) - dmxLogInputCont(dmxInput, " %s", info->names.geometry); - dmxLogInputCont(dmxInput, "\n"); - } else if (info->names.keycodes) { - dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", - info->names.keycodes); - if (info->names.symbols && *info->names.symbols) - dmxLogInputCont(dmxInput, " %s", info->names.symbols); - if (info->names.geometry && *info->names.geometry) - dmxLogInputCont(dmxInput, " %s", info->names.geometry); - dmxLogInputCont(dmxInput, "\n"); - } else { - dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", - dmxConfigGetXkbRules(), - dmxConfigGetXkbLayout(), - dmxConfigGetXkbModel(), - dmxConfigGetXkbVariant() - ? dmxConfigGetXkbVariant() : "", - dmxConfigGetXkbOptions() - ? dmxConfigGetXkbOptions() : ""); - } - InitKeyboardDeviceStruct(pDevice, &rmlvo, - dmxKeyboardBellProc, - dmxKeyboardKbdCtrlProc); - - if (info->freenames) dmxKeyboardFreeNames(&info->names); - - return Success; -} - - -static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) -{ - GETDMXINPUTFROMPDEVICE; - int fd; - DMXLocalInitInfo info; - int i; - Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ - Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ - - if (dmxInput->detached) return Success; - - memset(&info, 0, sizeof(info)); - switch (what) { - case DEVICE_INIT: - if (dmxLocal->init) - dmxLocal->init(pDev); - if (dmxLocal->get_info) - dmxLocal->get_info(pDev, &info); - if (info.keyboard) { /* XKEYBOARD makes this a special case */ - dmxKeyboardOn(pDevice, &info); - break; - } - if (info.keyClass) { - XkbRMLVOSet rmlvo; - - rmlvo.rules = dmxConfigGetXkbRules(); - rmlvo.model = dmxConfigGetXkbModel(); - rmlvo.layout = dmxConfigGetXkbLayout(); - rmlvo.variant = dmxConfigGetXkbVariant(); - rmlvo.options = dmxConfigGetXkbOptions(); - - InitKeyboardDeviceStruct(pDevice, - &rmlvo, - dmxBell, dmxKbdCtrl); - } - if (info.buttonClass) { - InitButtonClassDeviceStruct(pDevice, info.numButtons, - btn_labels, info.map); - } - if (info.valuatorClass) { - if (info.numRelAxes && dmxLocal->sendsCore) { - InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, - axis_labels, - GetMaximumEventsNum(), - Relative); - for (i = 0; i < info.numRelAxes; i++) - InitValuatorAxisStruct(pDevice, i, axis_labels[i], - info.minval[i], info.maxval[i], - info.res[i], - info.minres[i], info.maxres[i], - Relative); - } else if (info.numRelAxes) { - InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, - axis_labels, - dmxPointerGetMotionBufferSize(), - Relative); - for (i = 0; i < info.numRelAxes; i++) - InitValuatorAxisStruct(pDevice, i, axis_labels[i], - info.minval[i], - info.maxval[i], info.res[i], - info.minres[i], info.maxres[i], - Relative); - } else if (info.numAbsAxes) { - InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, - axis_labels, - dmxPointerGetMotionBufferSize(), - Absolute); - for (i = 0; i < info.numAbsAxes; i++) - InitValuatorAxisStruct(pDevice, i, - axis_labels[i], - info.minval[i], info.maxval[i], - info.res[i], info.minres[i], - info.maxres[i], Absolute); - } - } - if (info.focusClass) InitFocusClassDeviceStruct(pDevice); - if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); - if (info.ptrFeedbackClass) - InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); - if (info.intFeedbackClass || info.strFeedbackClass) - dmxLog(dmxWarning, - "Integer and string feedback not supported for %s\n", - pDevice->name); - if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) - dmxLog(dmxWarning, - "Led and bel feedback not supported for non-keyboard %s\n", - pDevice->name); - break; - case DEVICE_ON: - if (!pDev->on) { - if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) - dmxSigioRegister(dmxInput, fd); - pDev->on = TRUE; - } - break; - case DEVICE_OFF: - case DEVICE_CLOSE: - /* This can get called twice consecutively: once for a - * detached screen (DEVICE_OFF), and then again at server - * generation time (DEVICE_CLOSE). */ - if (pDev->on) { - dmxSigioUnregister(dmxInput); - if (dmxLocal->off) dmxLocal->off(pDev); - pDev->on = FALSE; - } - break; - } - if (info.keySyms.map && info.freemap) { - XFree(info.keySyms.map); - info.keySyms.map = NULL; - } - if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); - return Success; -} - -static void dmxProcessInputEvents(DMXInputInfo *dmxInput) -{ - int i; - - mieqProcessInputEvents(); -#if 00 /*BP*/ - miPointerUpdate(); -#endif - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->process_input) { -#if 11 /*BP*/ - miPointerUpdateSprite(dmxInput->devs[i]->pDevice); -#endif - dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); - } - -#if 11 /*BP*/ - mieqProcessInputEvents(); -#endif -} - -static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, - DMXUpdateType type, - WindowPtr pWindow) -{ - int i; - -#ifdef PANORAMIX - if (!noPanoramiXExtension && pWindow && pWindow->parent != screenInfo.screens[0]->root) - return; -#endif -#if DMX_WINDOW_DEBUG - { - const char *name = "Unknown"; - switch (type) { - case DMX_UPDATE_REALIZE: name = "Realize"; break; - case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; - case DMX_UPDATE_RESTACK: name = "Restack"; break; - case DMX_UPDATE_COPY: name = "Copy"; break; - case DMX_UPDATE_RESIZE: name = "Resize"; break; - case DMX_UPDATE_REPARENT: name = "Repaint"; break; - } - dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); - } -#endif - - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->update_info) - dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, - type, pWindow); -} - -static void dmxCollectAll(DMXInputInfo *dmxInput) -{ - int i; - - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->collect_events) - dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, - dmxMotion, - dmxEnqueue, - dmxCheckSpecialKeys, DMX_BLOCK); -} - -static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, - pointer pReadMask) -{ - DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; - static unsigned long generation = 0; - - if (generation != serverGeneration) { - generation = serverGeneration; - dmxCollectAll(dmxInput); - } -} - -static void dmxSwitchReturn(pointer p) -{ - DMXInputInfo *dmxInput = p; - int i; - - dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); - - if (!dmxInput->vt_switched) - dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); - dmxSigioEnableInput(); - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i]->vt_post_switch) - dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); - dmxInput->vt_switched = 0; -} - -static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) -{ - DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; - int i; - - if (dmxInput->vt_switch_pending) { - dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i]->vt_pre_switch) - dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); - dmxInput->vt_switched = dmxInput->vt_switch_pending; - dmxInput->vt_switch_pending = 0; - for (i = 0; i < dmxInput->numDevs; i++) { - if (dmxInput->devs[i]->vt_switch) { - dmxSigioDisableInput(); - if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, - dmxInput->vt_switched, - dmxSwitchReturn, - dmxInput)) - dmxSwitchReturn(dmxInput); - break; /* Only call one vt_switch routine */ - } - } - } - dmxCollectAll(dmxInput); -} - -static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) -{ - static int k = 0; - static int m = 0; - static int o = 0; - static unsigned long dmxGeneration = 0; -#define LEN 32 - char * buf = malloc(LEN); - - if (dmxGeneration != serverGeneration) { - k = m = o = 0; - dmxGeneration = serverGeneration; - } - - switch (dmxLocal->type) { - case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; - case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; - default: XmuSnprintf(buf, LEN, "Other%d", o++); break; - } - - return buf; -} - -static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) -{ - DeviceIntPtr pDevice; - Atom atom; - const char *name = NULL; - char *devname; - DMXInputInfo *dmxInput; - - if (!dmxLocal) - return NULL; - dmxInput = &dmxInputs[dmxLocal->inputIdx]; - - if (dmxLocal->sendsCore) { - if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { - dmxLocal->isCore = 1; - dmxLocalCoreKeyboard = dmxLocal; - name = "keyboard"; - } - if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { - dmxLocal->isCore = 1; - dmxLocalCorePointer = dmxLocal; - name = "pointer"; - } - } - - if (!name) { - name = "extension"; - } - - if (!name) - dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); - - pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); - if (!pDevice) { - dmxLog(dmxError, "Too many devices -- cannot add device %s\n", - dmxLocal->name); - return NULL; - } - pDevice->public.devicePrivate = dmxLocal; - dmxLocal->pDevice = pDevice; - - devname = dmxMakeUniqueDeviceName(dmxLocal); - atom = MakeAtom((char *)devname, strlen(devname), TRUE); - pDevice->type = atom; - pDevice->name = devname; - - if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { -#if 00 /*BP*/ - miRegisterPointerDevice(screenInfo.screens[0], pDevice); -#else - /* Nothing? dmxDeviceOnOff() should get called to init, right? */ -#endif - } - - if (dmxLocal->create_private) - dmxLocal->private = dmxLocal->create_private(pDevice); - - dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", - dmxLocal->name, name, devname, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - - return pDevice; -} - -static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) -{ - DMXLocalInputInfoPtr pt; - - for (pt = &DMXLocalDevices[0]; pt->name; ++pt) - if (!strcmp(pt->name, name)) return pt; /* search for device name */ - return NULL; -} - -/** Copy the local input information from \a s into a new \a devs slot - * in \a dmxInput. */ -DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, - DMXLocalInputInfoPtr s) -{ - DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal)); - - if (!dmxLocal) - dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); - - memcpy(dmxLocal, s, sizeof(*dmxLocal)); - dmxLocal->inputIdx = dmxInput->inputIdx; - dmxLocal->sendsCore = dmxInput->core; - dmxLocal->savedSendsCore = dmxInput->core; - dmxLocal->deviceId = -1; - - ++dmxInput->numDevs; - dmxInput->devs = realloc(dmxInput->devs, - dmxInput->numDevs * sizeof(*dmxInput->devs)); - dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; - - return dmxLocal; -} - -static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) -{ - int i; - int help = 0; - DMXLocalInputInfoRec *pt; - - for (i = 1; i < dmxArgC(a); i++) { - const char *name = dmxArgV(a, i); - if ((pt = dmxLookupLocal(name))) { - dmxInputCopyLocal(dmxInput, pt); - } else { - if (strlen(name)) - dmxLog(dmxWarning, - "Could not find a driver called %s\n", name); - ++help; - } - } - if (help) { - dmxLog(dmxInfo, "Available local device drivers:\n"); - for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { - const char *type; - switch (pt->type) { - case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; - case DMX_LOCAL_MOUSE: type = "pointer"; break; - default: type = "unknown"; break; - } - dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); - } - dmxLog(dmxFatal, "Must have valid local device driver\n"); - } -} - -int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, _Xconst char *reason) -{ - return 0; -} - -static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) -{ - XExtensionVersion *ext; - XDeviceInfo *devices; - Display *display; - int num; - int i, j; - XextErrorHandler handler; - - if (!(display = XOpenDisplay(dmxInput->name))) return; - - /* Print out information about the XInput Extension. */ - handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); - ext = XGetExtensionVersion(display, INAME); - XSetExtensionErrorHandler(handler); - - if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { - dmxLogInput(dmxInput, "%s is not available\n", INAME); - } else { - dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", - dmxInput->name, INAME, - ext->major_version, ext->minor_version); - devices = XListInputDevices(display, &num); - - XFree(ext); - ext = NULL; - - /* Print a list of all devices */ - for (i = 0; i < num; i++) { - const char *use = "Unknown"; - switch (devices[i].use) { - case IsXPointer: use = "XPointer"; break; - case IsXKeyboard: use = "XKeyboard"; break; - case IsXExtensionDevice: use = "XExtensionDevice"; break; - case IsXExtensionPointer: use = "XExtensionPointer"; break; - case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; - } - dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", - devices[i].id, - devices[i].name ? devices[i].name : "", - use); - } - - /* Search for extensions */ - for (i = 0; i < num; i++) { - switch (devices[i].use) { - case IsXKeyboard: - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; - if (dmxL->type == DMX_LOCAL_KEYBOARD - && dmxL->deviceId < 0) { - dmxL->deviceId = devices[i].id; - dmxL->deviceName = (devices[i].name - ? strdup(devices[i].name) - : NULL); - } - } - break; - case IsXPointer: - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; - if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { - dmxL->deviceId = devices[i].id; - dmxL->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; -#if 0 - case IsXExtensionDevice: - case IsXExtensionKeyboard: - case IsXExtensionPointer: - if (doXI) { - if (!dmxInput->numDevs) { - dmxLog(dmxWarning, - "Cannot use remote (%s) XInput devices if" - " not also using core devices\n", - dmxInput->name); - } else { - dmxLocal = dmxInputCopyLocal(dmxInput, - &DMXCommonOth); - dmxLocal->isCore = FALSE; - dmxLocal->sendsCore = FALSE; - dmxLocal->deviceId = devices[i].id; - dmxLocal->deviceName = (devices[i].name - ? strdup(devices[i].name) - : NULL); - } - } - break; -#endif - } - } - XFreeDeviceList(devices); - } - XCloseDisplay(display); -} - -/** Re-initialize all the devices described in \a dmxInput. Called from - #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ -void dmxInputReInit(DMXInputInfo *dmxInput) -{ - int i; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (dmxLocal->reinit) - dmxLocal->reinit(&dmxLocal->pDevice->public); - } -} - -/** Re-initialize all the devices described in \a dmxInput. Called from - #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ -void dmxInputLateReInit(DMXInputInfo *dmxInput) -{ - int i; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (dmxLocal->latereinit) - dmxLocal->latereinit(&dmxLocal->pDevice->public); - } -} - -/** Initialize all of the devices described in \a dmxInput. */ -void dmxInputInit(DMXInputInfo *dmxInput) -{ - DeviceIntPtr pPointer = NULL, pKeyboard = NULL; - dmxArg a; - const char *name; - int i; - int doXI = 1; /* Include by default */ - int forceConsole = 0; - int doWindows = 1; /* On by default */ - int hasXkb = 0; - - a = dmxArgParse(dmxInput->name); - - for (i = 1; i < dmxArgC(a); i++) { - switch (hasXkb) { - case 1: - dmxInput->keycodes = xstrdup(dmxArgV(a, i)); - ++hasXkb; - break; - case 2: - dmxInput->symbols = xstrdup(dmxArgV(a, i)); - ++hasXkb; - break; - case 3: - dmxInput->geometry = xstrdup(dmxArgV(a, i)); - hasXkb = 0; - break; - case 0: - if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; - else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; - else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; - else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; - else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; - else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; - else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; - else { - dmxLog(dmxFatal, - "Unknown input argument: %s\n", dmxArgV(a, i)); - } - } - } - - name = dmxArgV(a, 0); - - if (!strcmp(name, "local")) { - dmxPopulateLocal(dmxInput, a); - } else if (!strcmp(name, "dummy")) { - dmxInputCopyLocal(dmxInput, &DMXDummyMou); - dmxInputCopyLocal(dmxInput, &DMXDummyKbd); - dmxLogInput(dmxInput, "Using dummy input\n"); - } else { - int found; - - for (found = 0, i = 0; i < dmxNumScreens; i++) { - if (dmxPropertySameDisplay(&dmxScreens[i], name)) { - if (dmxScreens[i].shared) - dmxLog(dmxFatal, - "Cannot take input from shared backend (%s)\n", - name); - if (!dmxInput->core) { - dmxLog(dmxWarning, - "Cannot use core devices on a backend (%s)" - " as XInput devices\n", name); - } else { - char *pt; - for (pt = (char *)dmxInput->name; pt && *pt; pt++) - if (*pt == ',') *pt = '\0'; - dmxInputCopyLocal(dmxInput, &DMXBackendMou); - dmxInputCopyLocal(dmxInput, &DMXBackendKbd); - dmxInput->scrnIdx = i; - dmxLogInput(dmxInput, - "Using backend input from %s\n", name); - } - ++found; - break; - } - } - if (!found || forceConsole) { - char *pt; - if (found) dmxInput->console = TRUE; - for (pt = (char *)dmxInput->name; pt && *pt; pt++) - if (*pt == ',') *pt = '\0'; - dmxInputCopyLocal(dmxInput, &DMXConsoleMou); - dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); - if (doWindows) { - dmxInput->windows = TRUE; - dmxInput->updateWindowInfo = dmxUpdateWindowInformation; - } - dmxLogInput(dmxInput, - "Using console input from %s (%s windows)\n", - name, doWindows ? "with" : "without"); - } - } - - dmxArgFree(a); - - /* Locate extensions we may be interested in */ - dmxInputScanForExtensions(dmxInput, doXI); - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - dmxLocal->pDevice = dmxAddDevice(dmxLocal); - if (dmxLocal->isCore) { - if (dmxLocal->type == DMX_LOCAL_MOUSE) - pPointer = dmxLocal->pDevice; - if (dmxLocal->type == DMX_LOCAL_KEYBOARD) - pKeyboard = dmxLocal->pDevice; - } - } - - dmxInput->processInputEvents = dmxProcessInputEvents; - dmxInput->detached = False; - - RegisterBlockAndWakeupHandlers(dmxBlockHandler, - dmxWakeupHandler, - (void *)dmxInput->inputIdx); -} - -static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) -{ - if (!local) return; - if (local->isCore && local->type == DMX_LOCAL_MOUSE) - dmxLocalCorePointer = NULL; - if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) - dmxLocalCoreKeyboard = NULL; - if (local->destroy_private) local->destroy_private(local->private); - free(local->history); - free(local->valuators); - free(local->deviceName); - local->private = NULL; - local->history = NULL; - local->deviceName = NULL; - free(local); -} - -/** Free all of the memory associated with \a dmxInput */ -void dmxInputFree(DMXInputInfo *dmxInput) -{ - int i; - - if (!dmxInput) return; - - free(dmxInput->keycodes); - free(dmxInput->symbols); - free(dmxInput->geometry); - - for (i = 0; i < dmxInput->numDevs; i++) { - dmxInputFreeLocal(dmxInput->devs[i]); - dmxInput->devs[i] = NULL; - } - free(dmxInput->devs); - dmxInput->devs = NULL; - dmxInput->numDevs = 0; - if (dmxInput->freename) free(dmxInput->name); - dmxInput->name = NULL; -} - -/** Log information about all of the known devices using #dmxLog(). */ -void dmxInputLogDevices(void) -{ - int i, j; - - dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); - dmxLog(dmxInfo, " Id Name Classes\n"); - for (j = 0; j < dmxNumInputs; j++) { - DMXInputInfo *dmxInput = &dmxInputs[j]; - const char *pt = strchr(dmxInput->name, ','); - int len = (pt - ? (size_t)(pt-dmxInput->name) - : strlen(dmxInput->name)); - - for (i = 0; i < dmxInput->numDevs; i++) { - DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; - if (pDevice) { - dmxLog(dmxInfo, " %2d%c %-20.20s", - pDevice->id, - dmxInput->detached ? 'D' : ' ', - pDevice->name); - if (pDevice->key) dmxLogCont(dmxInfo, " key"); - if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); - if (pDevice->button) dmxLogCont(dmxInfo, " btn"); - if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); - if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); - if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); - if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); - if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); - if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); - if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); - if (!pDevice->key && !pDevice->valuator && !pDevice->button - && !pDevice->focus && !pDevice->kbdfeed - && !pDevice->ptrfeed && !pDevice->intfeed - && !pDevice->stringfeed && !pDevice->bell - && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); - - dmxLogCont(dmxInfo, "\t[i%d/%*.*s", - dmxInput->inputIdx, len, len, dmxInput->name); - if (dmxInput->devs[i]->deviceId >= 0) - dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); - if (dmxInput->devs[i]->deviceName) - dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); - dmxLogCont(dmxInfo, "] %s\n", - dmxInput->devs[i]->isCore - ? "core" - : (dmxInput->devs[i]->sendsCore - ? "extension (sends core events)" - : "extension")); - } - } - } -} - -/** Detach an input */ -int dmxInputDetach(DMXInputInfo *dmxInput) -{ - int i; - - if (dmxInput->detached) return BadAccess; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", - dmxLocal->pDevice->id, - dmxLocal->pDevice->name, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - DisableDevice(dmxLocal->pDevice, TRUE); - } - dmxInput->detached = True; - dmxInputLogDevices(); - return 0; -} - -/** Search for input associated with \a dmxScreen, and detach. */ -void dmxInputDetachAll(DMXScreenInfo *dmxScreen) -{ - int i; - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); - } -} - -/** Search for input associated with \a deviceId, and detach. */ -int dmxInputDetachId(int id) -{ - DMXInputInfo *dmxInput = dmxInputLocateId(id); - - if (!dmxInput) return BadValue; - - return dmxInputDetach(dmxInput); -} - -DMXInputInfo *dmxInputLocateId(int id) -{ - int i, j; - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; - if (dmxLocal->pDevice->id == id) return dmxInput; - } - } - return NULL; -} - -static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) -{ - dmxInputInit(dmxInput); - InitAndStartDevices(); - if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; - dmxInputLogDevices(); - return 0; -} - -static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) -{ - int i; - - dmxInput->detached = False; - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (id) *id = dmxLocal->pDevice->id; - dmxLogInput(dmxInput, - "Attaching device id %d: %s%s\n", - dmxLocal->pDevice->id, - dmxLocal->pDevice->name, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - EnableDevice(dmxLocal->pDevice, TRUE); - } - dmxInputLogDevices(); - return 0; -} - -int dmxInputAttachConsole(const char *name, int isCore, int *id) -{ - DMXInputInfo *dmxInput; - int i; - - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx == -1 - && dmxInput->detached - && !strcmp(dmxInput->name, name)) { - /* Found match */ - dmxLogInput(dmxInput, "Reattaching detached console input\n"); - return dmxInputAttachOld(dmxInput, id); - } - } - - /* No match found */ - dmxInput = dmxConfigAddInput(xstrdup(name), isCore); - dmxInput->freename = TRUE; - dmxLogInput(dmxInput, "Attaching new console input\n"); - return dmxInputAttachNew(dmxInput, id); -} - -int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) -{ - DMXInputInfo *dmxInput; - DMXScreenInfo *dmxScreen; - int i; - - if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { - /* Found match */ - if (!dmxInput->detached) return BadAccess; /* Already attached */ - dmxScreen = &dmxScreens[physicalScreen]; - if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ - dmxLogInput(dmxInput, "Reattaching detached backend input\n"); - return dmxInputAttachOld(dmxInput, id); - } - } - /* No match found */ - dmxScreen = &dmxScreens[physicalScreen]; - if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ - dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); - dmxLogInput(dmxInput, "Attaching new backend input\n"); - return dmxInputAttachNew(dmxInput, id); -} +/* + * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * This file provides generic input support. Functions here set up + * input and lead to the calling of low-level device drivers for + * input. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxextension.h" /* For dmxInputCount */ + +#include "dmxdummy.h" +#include "dmxbackend.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxevents.h" +#include "dmxmotion.h" +#include "dmxprop.h" +#include "config/dmxconfig.h" +#include "dmxcursor.h" + +#include "lnx-keyboard.h" +#include "lnx-ms.h" +#include "lnx-ps2.h" +#include "usb-keyboard.h" +#include "usb-mouse.h" +#include "usb-other.h" +#include "usb-common.h" + +#include "dmxsigio.h" +#include "dmxarg.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" +#include "mi.h" +#include "xkbsrv.h" + +#include +#include +#include "exevents.h" +#include "extinit.h" + +DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; + +static DMXLocalInputInfoRec DMXDummyMou = { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo +}; + +static DMXLocalInputInfoRec DMXDummyKbd = { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo +}; + +static DMXLocalInputInfoRec DMXBackendMou = { + "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, + dmxBackendCreatePrivate, dmxBackendDestroyPrivate, + dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, + NULL, NULL, NULL, + dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXBackendKbd = { + "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXConsoleMou = { + "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, + dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, + NULL, NULL, NULL, + dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXConsoleKbd = { + "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXLocalDevices[] = { + /* Dummy drivers that can compile on any OS */ +#ifdef __linux__ + /* Linux-specific drivers */ + { + "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, + kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, + kbdLinuxOn, kbdLinuxOff, NULL, + kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, + kbdLinuxRead, NULL, NULL, NULL, + NULL, kbdLinuxCtrl, kbdLinuxBell + }, + { + "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + msLinuxCreatePrivate, msLinuxDestroyPrivate, + msLinuxInit, NULL, NULL, msLinuxGetInfo, + msLinuxOn, msLinuxOff, NULL, + msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, + msLinuxRead + }, + { + "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, + ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, + ps2LinuxOn, ps2LinuxOff, NULL, + ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, + ps2LinuxRead + }, +#endif +#ifdef __linux__ + /* USB drivers, currently only for + Linux, but relatively easy to port to + other OSs */ + { + "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + kbdUSBInit, NULL, NULL, kbdUSBGetInfo, + kbdUSBOn, usbOff, NULL, + NULL, NULL, NULL, + kbdUSBRead, NULL, NULL, NULL, + NULL, kbdUSBCtrl + }, + { + "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + mouUSBInit, NULL, NULL, mouUSBGetInfo, + mouUSBOn, usbOff, NULL, + NULL, NULL, NULL, + mouUSBRead + }, + { + "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + othUSBInit, NULL, NULL, othUSBGetInfo, + othUSBOn, usbOff, NULL, + NULL, NULL, NULL, + othUSBRead + }, +#endif + { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo + }, + { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo + }, + { NULL } /* Must be last */ +}; + + +#if 11 /*BP*/ +void +DDXRingBell(int volume, int pitch, int duration) +{ + /* NO-OP */ +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ +#if 0 + KdKeyboardInfo *ki; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDevice->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) + return; + + KdSetLeds(ki, ctrl->leds); + ki->bellPitch = ctrl->bell_pitch; + ki->bellDuration = ctrl->bell_duration; +#endif +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ +#if 0 + KeybdCtrl *ctrl = arg; + KdKeyboardInfo *ki = NULL; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDev->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) + return; + + KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); +#endif +} + +#endif /*BP*/ + +static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, + PtrCtrl *ctrl) +{ + if (!dmxLocal) return; + dmxLocal->mctrl = *ctrl; + if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); +} + +/** Change the pointer control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the pointer devices that send core events. */ +void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxChangePointerControl(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxChangePointerControl(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, + KeybdCtrl *ctrl) +{ + dmxLocal->kctrl = *ctrl; + if (dmxLocal->kCtrl) { + dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); + if (dmxLocal->pDevice->kbdfeed) { + XkbEventCauseRec cause; + XkbSetCauseUnknown(&cause); + /* Generate XKB events, as necessary */ + XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, + NULL, &cause); + } + } +} + + +/** Change the keyboard control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the keyboard devices that send core events. */ +void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) +{ + if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, + percent, + dmxLocal->kctrl.bell, + dmxLocal->kctrl.bell_pitch, + dmxLocal->kctrl.bell_duration); +} + +/** Sound the bell on the device. If the device send core events, then + * sound the bell on all of the devices that send core events. */ +void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, + pointer ctrl, int unknown) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardBellProc(dmxInput->devs[j], percent); + } + } else { /* Do for this device only */ + _dmxKeyboardBellProc(dmxLocal, percent); + } +} + +static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) +{ + if (names->keycodes) XFree(names->keycodes); + if (names->types) XFree(names->types); + if (names->compat) XFree(names->compat); + if (names->symbols) XFree(names->symbols); + if (names->geometry) XFree(names->geometry); +} + + +static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) +{ + GETDMXINPUTFROMPDEVICE; + XkbRMLVOSet rmlvo; + + rmlvo.rules = dmxConfigGetXkbRules(); + rmlvo.model = dmxConfigGetXkbModel(); + rmlvo.layout = dmxConfigGetXkbLayout(); + rmlvo.variant = dmxConfigGetXkbVariant(); + rmlvo.options = dmxConfigGetXkbOptions(); + + XkbSetRulesDflts(&rmlvo); + if (!info->force && (dmxInput->keycodes + || dmxInput->symbols + || dmxInput->geometry)) { + if (info->freenames) dmxKeyboardFreeNames(&info->names); + info->freenames = 0; + info->names.keycodes = dmxInput->keycodes; + info->names.types = NULL; + info->names.compat = NULL; + info->names.symbols = dmxInput->symbols; + info->names.geometry = dmxInput->geometry; + + dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else if (info->names.keycodes) { + dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else { + dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", + dmxConfigGetXkbRules(), + dmxConfigGetXkbLayout(), + dmxConfigGetXkbModel(), + dmxConfigGetXkbVariant() + ? dmxConfigGetXkbVariant() : "", + dmxConfigGetXkbOptions() + ? dmxConfigGetXkbOptions() : ""); + } + InitKeyboardDeviceStruct(pDevice, &rmlvo, + dmxKeyboardBellProc, + dmxKeyboardKbdCtrlProc); + + if (info->freenames) dmxKeyboardFreeNames(&info->names); + + return Success; +} + + +static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) +{ + GETDMXINPUTFROMPDEVICE; + int fd; + DMXLocalInitInfo info; + int i; + Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ + Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ + + if (dmxInput->detached) return Success; + + memset(&info, 0, sizeof(info)); + switch (what) { + case DEVICE_INIT: + if (dmxLocal->init) + dmxLocal->init(pDev); + if (dmxLocal->get_info) + dmxLocal->get_info(pDev, &info); + if (info.keyboard) { /* XKEYBOARD makes this a special case */ + dmxKeyboardOn(pDevice, &info); + break; + } + if (info.keyClass) { + XkbRMLVOSet rmlvo; + + rmlvo.rules = dmxConfigGetXkbRules(); + rmlvo.model = dmxConfigGetXkbModel(); + rmlvo.layout = dmxConfigGetXkbLayout(); + rmlvo.variant = dmxConfigGetXkbVariant(); + rmlvo.options = dmxConfigGetXkbOptions(); + + InitKeyboardDeviceStruct(pDevice, + &rmlvo, + dmxBell, dmxKbdCtrl); + } + if (info.buttonClass) { + InitButtonClassDeviceStruct(pDevice, info.numButtons, + btn_labels, info.map); + } + if (info.valuatorClass) { + if (info.numRelAxes && dmxLocal->sendsCore) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + axis_labels, + GetMaximumEventsNum(), + Relative); + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, axis_labels[i], + info.minval[i], info.maxval[i], + info.res[i], + info.minres[i], info.maxres[i], + Relative); + } else if (info.numRelAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + axis_labels, + dmxPointerGetMotionBufferSize(), + Relative); + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, axis_labels[i], + info.minval[i], + info.maxval[i], info.res[i], + info.minres[i], info.maxres[i], + Relative); + } else if (info.numAbsAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, + axis_labels, + dmxPointerGetMotionBufferSize(), + Absolute); + for (i = 0; i < info.numAbsAxes; i++) + InitValuatorAxisStruct(pDevice, i, + axis_labels[i], + info.minval[i], info.maxval[i], + info.res[i], info.minres[i], + info.maxres[i], Absolute); + } + } + if (info.focusClass) InitFocusClassDeviceStruct(pDevice); + if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); + if (info.ptrFeedbackClass) + InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); + if (info.intFeedbackClass || info.strFeedbackClass) + dmxLog(dmxWarning, + "Integer and string feedback not supported for %s\n", + pDevice->name); + if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) + dmxLog(dmxWarning, + "Led and bel feedback not supported for non-keyboard %s\n", + pDevice->name); + break; + case DEVICE_ON: + if (!pDev->on) { + if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) + dmxSigioRegister(dmxInput, fd); + pDev->on = TRUE; + } + break; + case DEVICE_OFF: + case DEVICE_CLOSE: + /* This can get called twice consecutively: once for a + * detached screen (DEVICE_OFF), and then again at server + * generation time (DEVICE_CLOSE). */ + if (pDev->on) { + dmxSigioUnregister(dmxInput); + if (dmxLocal->off) dmxLocal->off(pDev); + pDev->on = FALSE; + } + break; + } + if (info.keySyms.map && info.freemap) { + XFree(info.keySyms.map); + info.keySyms.map = NULL; + } + if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); + return Success; +} + +static void dmxProcessInputEvents(DMXInputInfo *dmxInput) +{ + int i; + + mieqProcessInputEvents(); +#if 00 /*BP*/ + miPointerUpdate(); +#endif + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->process_input) { +#if 11 /*BP*/ + miPointerUpdateSprite(dmxInput->devs[i]->pDevice); +#endif + dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); + } + +#if 11 /*BP*/ + mieqProcessInputEvents(); +#endif +} + +static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, + DMXUpdateType type, + WindowPtr pWindow) +{ + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension && pWindow && pWindow->parent != screenInfo.screens[0]->root) + return; +#endif +#if DMX_WINDOW_DEBUG + { + const char *name = "Unknown"; + switch (type) { + case DMX_UPDATE_REALIZE: name = "Realize"; break; + case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; + case DMX_UPDATE_RESTACK: name = "Restack"; break; + case DMX_UPDATE_COPY: name = "Copy"; break; + case DMX_UPDATE_RESIZE: name = "Resize"; break; + case DMX_UPDATE_REPARENT: name = "Repaint"; break; + } + dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); + } +#endif + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->update_info) + dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, + type, pWindow); +} + +static void dmxCollectAll(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->collect_events) + dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, + dmxMotion, + dmxEnqueue, + dmxCheckSpecialKeys, DMX_BLOCK); +} + +static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, + pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData]; + static unsigned long generation = 0; + + if (generation != serverGeneration) { + generation = serverGeneration; + dmxCollectAll(dmxInput); + } +} + +static void dmxSwitchReturn(pointer p) +{ + DMXInputInfo *dmxInput = p; + int i; + + dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); + + if (!dmxInput->vt_switched) + dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); + dmxSigioEnableInput(); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_post_switch) + dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = 0; +} + +static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData]; + int i; + + if (dmxInput->vt_switch_pending) { + dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_pre_switch) + dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = dmxInput->vt_switch_pending; + dmxInput->vt_switch_pending = 0; + for (i = 0; i < dmxInput->numDevs; i++) { + if (dmxInput->devs[i]->vt_switch) { + dmxSigioDisableInput(); + if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, + dmxInput->vt_switched, + dmxSwitchReturn, + dmxInput)) + dmxSwitchReturn(dmxInput); + break; /* Only call one vt_switch routine */ + } + } + } + dmxCollectAll(dmxInput); +} + +static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) +{ + static int k = 0; + static int m = 0; + static int o = 0; + static unsigned long dmxGeneration = 0; +#define LEN 32 + char * buf = malloc(LEN); + + if (dmxGeneration != serverGeneration) { + k = m = o = 0; + dmxGeneration = serverGeneration; + } + + switch (dmxLocal->type) { + case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; + case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; + default: XmuSnprintf(buf, LEN, "Other%d", o++); break; + } + + return buf; +} + +static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) +{ + DeviceIntPtr pDevice; + Atom atom; + const char *name = NULL; + char *devname; + DMXInputInfo *dmxInput; + + if (!dmxLocal) + return NULL; + dmxInput = &dmxInputs[dmxLocal->inputIdx]; + + if (dmxLocal->sendsCore) { + if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { + dmxLocal->isCore = 1; + dmxLocalCoreKeyboard = dmxLocal; + name = "keyboard"; + } + if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { + dmxLocal->isCore = 1; + dmxLocalCorePointer = dmxLocal; + name = "pointer"; + } + } + + if (!name) { + name = "extension"; + } + + if (!name) + dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); + + pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); + if (!pDevice) { + dmxLog(dmxError, "Too many devices -- cannot add device %s\n", + dmxLocal->name); + return NULL; + } + pDevice->public.devicePrivate = dmxLocal; + dmxLocal->pDevice = pDevice; + + devname = dmxMakeUniqueDeviceName(dmxLocal); + atom = MakeAtom((char *)devname, strlen(devname), TRUE); + pDevice->type = atom; + pDevice->name = devname; + + if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { +#if 00 /*BP*/ + miRegisterPointerDevice(screenInfo.screens[0], pDevice); +#else + /* Nothing? dmxDeviceOnOff() should get called to init, right? */ +#endif + } + + if (dmxLocal->create_private) + dmxLocal->private = dmxLocal->create_private(pDevice); + + dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", + dmxLocal->name, name, devname, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + + return pDevice; +} + +static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) +{ + DMXLocalInputInfoPtr pt; + + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) + if (!strcmp(pt->name, name)) return pt; /* search for device name */ + return NULL; +} + +/** Copy the local input information from \a s into a new \a devs slot + * in \a dmxInput. */ +DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, + DMXLocalInputInfoPtr s) +{ + DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal)); + + if (!dmxLocal) + dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); + + memcpy(dmxLocal, s, sizeof(*dmxLocal)); + dmxLocal->inputIdx = dmxInput->inputIdx; + dmxLocal->sendsCore = dmxInput->core; + dmxLocal->savedSendsCore = dmxInput->core; + dmxLocal->deviceId = -1; + + ++dmxInput->numDevs; + dmxInput->devs = realloc(dmxInput->devs, + dmxInput->numDevs * sizeof(*dmxInput->devs)); + dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; + + return dmxLocal; +} + +static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) +{ + int i; + int help = 0; + DMXLocalInputInfoRec *pt; + + for (i = 1; i < dmxArgC(a); i++) { + const char *name = dmxArgV(a, i); + if ((pt = dmxLookupLocal(name))) { + dmxInputCopyLocal(dmxInput, pt); + } else { + if (strlen(name)) + dmxLog(dmxWarning, + "Could not find a driver called %s\n", name); + ++help; + } + } + if (help) { + dmxLog(dmxInfo, "Available local device drivers:\n"); + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { + const char *type; + switch (pt->type) { + case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; + case DMX_LOCAL_MOUSE: type = "pointer"; break; + default: type = "unknown"; break; + } + dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); + } + dmxLog(dmxFatal, "Must have valid local device driver\n"); + } +} + +int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, _Xconst char *reason) +{ + return 0; +} + +static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) +{ + XExtensionVersion *ext; + XDeviceInfo *devices; + Display *display; + int num; + int i, j; + XextErrorHandler handler; + + if (!(display = XOpenDisplay(dmxInput->name))) return; + + /* Print out information about the XInput Extension. */ + handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); + ext = XGetExtensionVersion(display, INAME); + XSetExtensionErrorHandler(handler); + + if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { + dmxLogInput(dmxInput, "%s is not available\n", INAME); + } else { + dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", + dmxInput->name, INAME, + ext->major_version, ext->minor_version); + devices = XListInputDevices(display, &num); + + XFree(ext); + ext = NULL; + + /* Print a list of all devices */ + for (i = 0; i < num; i++) { + const char *use = "Unknown"; + switch (devices[i].use) { + case IsXPointer: use = "XPointer"; break; + case IsXKeyboard: use = "XKeyboard"; break; + case IsXExtensionDevice: use = "XExtensionDevice"; break; + case IsXExtensionPointer: use = "XExtensionPointer"; break; + case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; + } + dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", + devices[i].id, + devices[i].name ? devices[i].name : "", + use); + } + + /* Search for extensions */ + for (i = 0; i < num; i++) { + switch (devices[i].use) { + case IsXKeyboard: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_KEYBOARD + && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? strdup(devices[i].name) + : NULL); + } + } + break; + case IsXPointer: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; + } + } + XFreeDeviceList(devices); + } + XCloseDisplay(display); +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ +void dmxInputReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->reinit) + dmxLocal->reinit(&dmxLocal->pDevice->public); + } +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ +void dmxInputLateReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->latereinit) + dmxLocal->latereinit(&dmxLocal->pDevice->public); + } +} + +/** Initialize all of the devices described in \a dmxInput. */ +void dmxInputInit(DMXInputInfo *dmxInput) +{ + DeviceIntPtr pPointer = NULL, pKeyboard = NULL; + dmxArg a; + const char *name; + int i; + int doXI = 1; /* Include by default */ + int forceConsole = 0; + int doWindows = 1; /* On by default */ + int hasXkb = 0; + + a = dmxArgParse(dmxInput->name); + + for (i = 1; i < dmxArgC(a); i++) { + switch (hasXkb) { + case 1: + dmxInput->keycodes = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 2: + dmxInput->symbols = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 3: + dmxInput->geometry = xstrdup(dmxArgV(a, i)); + hasXkb = 0; + break; + case 0: + if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; + else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; + else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; + else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; + else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; + else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; + else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; + else { + dmxLog(dmxFatal, + "Unknown input argument: %s\n", dmxArgV(a, i)); + } + } + } + + name = dmxArgV(a, 0); + + if (!strcmp(name, "local")) { + dmxPopulateLocal(dmxInput, a); + } else if (!strcmp(name, "dummy")) { + dmxInputCopyLocal(dmxInput, &DMXDummyMou); + dmxInputCopyLocal(dmxInput, &DMXDummyKbd); + dmxLogInput(dmxInput, "Using dummy input\n"); + } else { + int found; + + for (found = 0, i = 0; i < dmxNumScreens; i++) { + if (dmxPropertySameDisplay(&dmxScreens[i], name)) { + if (dmxScreens[i].shared) + dmxLog(dmxFatal, + "Cannot take input from shared backend (%s)\n", + name); + if (!dmxInput->core) { + dmxLog(dmxWarning, + "Cannot use core devices on a backend (%s)" + " as XInput devices\n", name); + } else { + char *pt; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXBackendMou); + dmxInputCopyLocal(dmxInput, &DMXBackendKbd); + dmxInput->scrnIdx = i; + dmxLogInput(dmxInput, + "Using backend input from %s\n", name); + } + ++found; + break; + } + } + if (!found || forceConsole) { + char *pt; + if (found) dmxInput->console = TRUE; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXConsoleMou); + dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); + if (doWindows) { + dmxInput->windows = TRUE; + dmxInput->updateWindowInfo = dmxUpdateWindowInformation; + } + dmxLogInput(dmxInput, + "Using console input from %s (%s windows)\n", + name, doWindows ? "with" : "without"); + } + } + + dmxArgFree(a); + + /* Locate extensions we may be interested in */ + dmxInputScanForExtensions(dmxInput, doXI); + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLocal->pDevice = dmxAddDevice(dmxLocal); + if (dmxLocal->isCore) { + if (dmxLocal->type == DMX_LOCAL_MOUSE) + pPointer = dmxLocal->pDevice; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) + pKeyboard = dmxLocal->pDevice; + } + } + + dmxInput->processInputEvents = dmxProcessInputEvents; + dmxInput->detached = False; + + RegisterBlockAndWakeupHandlers(dmxBlockHandler, dmxWakeupHandler, + (void *)(uintptr_t)dmxInput->inputIdx); +} + +static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) +{ + if (!local) return; + if (local->isCore && local->type == DMX_LOCAL_MOUSE) + dmxLocalCorePointer = NULL; + if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) + dmxLocalCoreKeyboard = NULL; + if (local->destroy_private) local->destroy_private(local->private); + free(local->history); + free(local->valuators); + free(local->deviceName); + local->private = NULL; + local->history = NULL; + local->deviceName = NULL; + free(local); +} + +/** Free all of the memory associated with \a dmxInput */ +void dmxInputFree(DMXInputInfo *dmxInput) +{ + int i; + + if (!dmxInput) return; + + free(dmxInput->keycodes); + free(dmxInput->symbols); + free(dmxInput->geometry); + + for (i = 0; i < dmxInput->numDevs; i++) { + dmxInputFreeLocal(dmxInput->devs[i]); + dmxInput->devs[i] = NULL; + } + free(dmxInput->devs); + dmxInput->devs = NULL; + dmxInput->numDevs = 0; + if (dmxInput->freename) free(dmxInput->name); + dmxInput->name = NULL; +} + +/** Log information about all of the known devices using #dmxLog(). */ +void dmxInputLogDevices(void) +{ + int i, j; + + dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); + dmxLog(dmxInfo, " Id Name Classes\n"); + for (j = 0; j < dmxNumInputs; j++) { + DMXInputInfo *dmxInput = &dmxInputs[j]; + const char *pt = strchr(dmxInput->name, ','); + int len = (pt + ? (size_t)(pt-dmxInput->name) + : strlen(dmxInput->name)); + + for (i = 0; i < dmxInput->numDevs; i++) { + DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; + if (pDevice) { + dmxLog(dmxInfo, " %2d%c %-20.20s", + pDevice->id, + dmxInput->detached ? 'D' : ' ', + pDevice->name); + if (pDevice->key) dmxLogCont(dmxInfo, " key"); + if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); + if (pDevice->button) dmxLogCont(dmxInfo, " btn"); + if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); + if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); + if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); + if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); + if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); + if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); + if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); + if (!pDevice->key && !pDevice->valuator && !pDevice->button + && !pDevice->focus && !pDevice->kbdfeed + && !pDevice->ptrfeed && !pDevice->intfeed + && !pDevice->stringfeed && !pDevice->bell + && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); + + dmxLogCont(dmxInfo, "\t[i%d/%*.*s", + dmxInput->inputIdx, len, len, dmxInput->name); + if (dmxInput->devs[i]->deviceId >= 0) + dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); + if (dmxInput->devs[i]->deviceName) + dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); + dmxLogCont(dmxInfo, "] %s\n", + dmxInput->devs[i]->isCore + ? "core" + : (dmxInput->devs[i]->sendsCore + ? "extension (sends core events)" + : "extension")); + } + } + } +} + +/** Detach an input */ +int dmxInputDetach(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) return BadAccess; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + DisableDevice(dmxLocal->pDevice, TRUE); + } + dmxInput->detached = True; + dmxInputLogDevices(); + return 0; +} + +/** Search for input associated with \a dmxScreen, and detach. */ +void dmxInputDetachAll(DMXScreenInfo *dmxScreen) +{ + int i; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); + } +} + +/** Search for input associated with \a deviceId, and detach. */ +int dmxInputDetachId(int id) +{ + DMXInputInfo *dmxInput = dmxInputLocateId(id); + + if (!dmxInput) return BadValue; + + return dmxInputDetach(dmxInput); +} + +DMXInputInfo *dmxInputLocateId(int id) +{ + int i, j; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (dmxLocal->pDevice->id == id) return dmxInput; + } + } + return NULL; +} + +static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) +{ + dmxInputInit(dmxInput); + InitAndStartDevices(); + if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; + dmxInputLogDevices(); + return 0; +} + +static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) +{ + int i; + + dmxInput->detached = False; + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (id) *id = dmxLocal->pDevice->id; + dmxLogInput(dmxInput, + "Attaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + EnableDevice(dmxLocal->pDevice, TRUE); + } + dmxInputLogDevices(); + return 0; +} + +int dmxInputAttachConsole(const char *name, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + int i; + + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == -1 + && dmxInput->detached + && !strcmp(dmxInput->name, name)) { + /* Found match */ + dmxLogInput(dmxInput, "Reattaching detached console input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + + /* No match found */ + dmxInput = dmxConfigAddInput(xstrdup(name), isCore); + dmxInput->freename = TRUE; + dmxLogInput(dmxInput, "Attaching new console input\n"); + return dmxInputAttachNew(dmxInput, id); +} + +int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + DMXScreenInfo *dmxScreen; + int i; + + if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { + /* Found match */ + if (!dmxInput->detached) return BadAccess; /* Already attached */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxLogInput(dmxInput, "Reattaching detached backend input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + /* No match found */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); + dmxLogInput(dmxInput, "Attaching new backend input\n"); + return dmxInputAttachNew(dmxInput, id); +} diff --git a/xorg-server/hw/xfree86/doc/man/Makefile.am b/xorg-server/hw/xfree86/doc/man/Makefile.am index fe330a72c..80e22cbab 100644 --- a/xorg-server/hw/xfree86/doc/man/Makefile.am +++ b/xorg-server/hw/xfree86/doc/man/Makefile.am @@ -1,3 +1,3 @@ include $(top_srcdir)/manpages.am appman_PRE = Xorg.man -fileman_PRE = xorg.conf.man +fileman_PRE = xorg.conf.man xorg.conf.d.man diff --git a/xorg-server/hw/xfree86/doc/man/xorg.conf.d.man b/xorg-server/hw/xfree86/doc/man/xorg.conf.d.man new file mode 100644 index 000000000..6b3379ece --- /dev/null +++ b/xorg-server/hw/xfree86/doc/man/xorg.conf.d.man @@ -0,0 +1 @@ +.so man__filemansuffix__/xorg.conf.__filemansuffix__ diff --git a/xorg-server/hw/xwin/InitOutput.c b/xorg-server/hw/xwin/InitOutput.c index fea4a34f9..7faed0170 100644 --- a/xorg-server/hw/xwin/InitOutput.c +++ b/xorg-server/hw/xwin/InitOutput.c @@ -1,1108 +1,1111 @@ - -/* - -Copyright 1993, 1998 The Open Group -Copyright (C) Colin Harrison 2005-2008 - -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. - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall -not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization -from The Open Group. - -*/ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" -#include "winmsg.h" -#include "winconfig.h" -#include "winprefs.h" -#ifdef XWIN_CLIPBOARD -#include "X11/Xlocale.h" -#endif -#ifdef DPMSExtension -#include "dpmsproc.h" -#endif -#ifdef __CYGWIN__ -#include -#endif -#if defined(WIN32) -#include "xkbsrv.h" -#endif -#ifdef RELOCATE_PROJECTROOT -#include -typedef HRESULT (*SHGETFOLDERPATHPROC)( - HWND hwndOwner, - int nFolder, - HANDLE hToken, - DWORD dwFlags, - LPTSTR pszPath -); -#endif - -/* - * References to external symbols - */ -#ifdef XWIN_CLIPBOARD -extern Bool g_fUnicodeClipboard; -extern Bool g_fClipboardLaunched; -extern Bool g_fClipboardStarted; -extern pthread_t g_ptClipboardProc; -extern HWND g_hwndClipboard; -extern Bool g_fClipboard; -#endif - - -/* - module handle for dynamically loaded comctl32 library -*/ -static HMODULE g_hmodCommonControls = NULL; - -/* - * Function prototypes - */ - -#ifdef XWIN_CLIPBOARD -static void -winClipboardShutdown (void); -#endif - -#if defined(DDXOSVERRORF) -void -OsVendorVErrorF (const char *pszFormat, va_list va_args); -#endif - -static Bool -winCheckDisplayNumber (void); - -void -winLogCommandLine (int argc, char *argv[]); - -void -winLogVersionInfo (void); - -Bool -winValidateArgs (void); - -#ifdef RELOCATE_PROJECTROOT -const char * -winGetBaseDir(void); -#endif - -/* - * For the depth 24 pixmap we default to 32 bits per pixel, but - * we change this pixmap format later if we detect that the display - * is going to be running at 24 bits per pixel. - * - * FIXME: On second thought, don't DIBs only support 32 bits per pixel? - * DIBs are the underlying bitmap used for DirectDraw surfaces, so it - * seems that all pixmap formats with depth 24 would be 32 bits per pixel. - * Confirm whether depth 24 DIBs can have 24 bits per pixel, then remove/keep - * the bits per pixel adjustment and update this comment to reflect the - * situation. Harold Hunt - 2002/07/02 - */ - -static PixmapFormatRec g_PixmapFormats[] = { - { 1, 1, BITMAP_SCANLINE_PAD }, - { 4, 8, BITMAP_SCANLINE_PAD }, - { 8, 8, BITMAP_SCANLINE_PAD }, - { 15, 16, BITMAP_SCANLINE_PAD }, - { 16, 16, BITMAP_SCANLINE_PAD }, - { 24, 32, BITMAP_SCANLINE_PAD }, - { 32, 32, BITMAP_SCANLINE_PAD } -}; - -const int NUMFORMATS = sizeof (g_PixmapFormats) / sizeof (g_PixmapFormats[0]); - -#ifdef XWIN_CLIPBOARD -static void -winClipboardShutdown (void) -{ - /* Close down clipboard resources */ - if (g_fClipboard && g_fClipboardLaunched && g_fClipboardStarted) - { - /* Synchronously destroy the clipboard window */ - if (g_hwndClipboard != NULL) - { - SendMessage (g_hwndClipboard, WM_DESTROY, 0, 0); - /* NOTE: g_hwndClipboard is set to NULL in winclipboardthread.c */ - } - else - return; - - /* Wait for the clipboard thread to exit */ - pthread_join (g_ptClipboardProc, NULL); - - g_fClipboardLaunched = FALSE; - g_fClipboardStarted = FALSE; - - winDebug ("winClipboardShutdown - Clipboard thread has exited.\n"); - } -} -#endif - -void -ddxPushProviders(void) -{ -#ifdef XWIN_GLX_WINDOWS - if (g_fNativeGl) - { - /* install the native GL provider */ - glxWinPushNativeProvider(); - } -#endif -} - -#if defined(DDXBEFORERESET) -/* - * Called right before KillAllClients when the server is going to reset, - * allows us to shutdown our seperate threads cleanly. - */ - -void -ddxBeforeReset (void) -{ - winDebug ("ddxBeforeReset - Hello\n"); - -#ifdef XWIN_CLIPBOARD - winClipboardShutdown (); -#endif -} -#endif - - -/* See Porting Layer Definition - p. 57 */ -void -ddxGiveUp (void) -{ - int i; - -#if CYGDEBUG - winDebug ("ddxGiveUp\n"); -#endif - - /* Perform per-screen deinitialization */ - for (i = 0; i < g_iNumScreens; ++i) - { - /* Delete the tray icon */ - if (!g_ScreenInfo[i].fNoTrayIcon && g_ScreenInfo[i].pScreen) - winDeleteNotifyIcon (winGetScreenPriv (g_ScreenInfo[i].pScreen)); - } - -#ifdef XWIN_MULTIWINDOW - /* Notify the worker threads we're exiting */ - winDeinitMultiWindowWM (); -#endif - -#ifdef HAS_DEVWINDOWS - /* Close our handle to our message queue */ - if (g_fdMessageQueue != WIN_FD_INVALID) - { - /* Close /dev/windows */ - close (g_fdMessageQueue); - - /* Set the file handle to invalid */ - g_fdMessageQueue = WIN_FD_INVALID; - } -#endif - - if (!g_fLogInited) { - g_pszLogFile = LogInit (g_pszLogFile, NULL); - g_fLogInited = TRUE; - } - LogClose (); - - /* - * At this point we aren't creating any new screens, so - * we are guaranteed to not need the DirectDraw functions. - */ - winReleaseDDProcAddresses(); - - /* Unload our TrackMouseEvent function pointer */ - if (g_hmodCommonControls != NULL) - { - FreeLibrary (g_hmodCommonControls); - g_hmodCommonControls = NULL; - g_fpTrackMouseEvent = (FARPROC) (void (*)(void))NoopDDA; - } - - /* Free concatenated command line */ - free(g_pszCommandLine); - g_pszCommandLine = NULL; - - /* Remove our keyboard hook if it is installed */ - winRemoveKeyboardHookLL (); - - /* Tell Windows that we want to end the app */ - PostQuitMessage (0); -} - - -/* See Porting Layer Definition - p. 57 */ -void -AbortDDX (void) -{ -#if CYGDEBUG - winDebug ("AbortDDX\n"); -#endif - ddxGiveUp (); -} - -#ifdef __CYGWIN__ -/* hasmntopt is currently not implemented for cygwin */ -static const char *winCheckMntOpt(const struct mntent *mnt, const char *opt) -{ - const char *s; - size_t len; - if (mnt == NULL) - return NULL; - if (opt == NULL) - return NULL; - if (mnt->mnt_opts == NULL) - return NULL; - - len = strlen(opt); - s = strstr(mnt->mnt_opts, opt); - if (s == NULL) - return NULL; - if ((s == mnt->mnt_opts || *(s-1) == ',') && (s[len] == 0 || s[len] == ',')) - return (char *)opt; - return NULL; -} - -static void -winCheckMount(void) -{ - FILE *mnt; - struct mntent *ent; - - enum { none = 0, sys_root, user_root, sys_tmp, user_tmp } - level = none, curlevel; - BOOL binary = TRUE; - - mnt = setmntent("/etc/mtab", "r"); - if (mnt == NULL) - { - ErrorF("setmntent failed"); - return; - } - - while ((ent = getmntent(mnt)) != NULL) - { - BOOL system = (winCheckMntOpt(ent, "user") != NULL); - BOOL root = (strcmp(ent->mnt_dir, "/") == 0); - BOOL tmp = (strcmp(ent->mnt_dir, "/tmp") == 0); - - if (system) - { - if (root) - curlevel = sys_root; - else if (tmp) - curlevel = sys_tmp; - else - continue; - } - else - { - if (root) - curlevel = user_root; - else if (tmp) - curlevel = user_tmp; - else - continue; - } - - if (curlevel <= level) - continue; - level = curlevel; - - if ((winCheckMntOpt(ent, "binary") == NULL) && - (winCheckMntOpt(ent, "binmode") == NULL)) - binary = FALSE; - else - binary = TRUE; - } - - if (endmntent(mnt) != 1) - { - ErrorF("endmntent failed"); - return; - } - - if (!binary) - winMsg(X_WARNING, "/tmp mounted in textmode\n"); -} -#else -static void -winCheckMount(void) -{ -} -#endif - -#ifdef RELOCATE_PROJECTROOT -const char * -winGetBaseDir(void) -{ - static BOOL inited = FALSE; - static char buffer[MAX_PATH]; - if (!inited) - { - char *fendptr; - HMODULE module = GetModuleHandle(NULL); - DWORD size = GetModuleFileName(module, buffer, sizeof(buffer)); - if (sizeof(buffer) > 0) - buffer[sizeof(buffer)-1] = 0; - - fendptr = buffer + size; - while (fendptr > buffer) - { - if (*fendptr == '\\' || *fendptr == '/') - { - *fendptr = 0; - break; - } - fendptr--; - } - inited = TRUE; - } - return buffer; -} -#endif - -static void -winFixupPaths (void) -{ - BOOL changed_fontpath = FALSE; - MessageType font_from = X_DEFAULT; -#ifdef RELOCATE_PROJECTROOT - const char *basedir = winGetBaseDir(); - size_t basedirlen = strlen(basedir); -#endif - -#ifdef READ_FONTDIRS - { - /* Open fontpath configuration file */ - FILE *fontdirs = fopen(ETCX11DIR "/font-dirs", "rt"); - if (fontdirs != NULL) - { - char buffer[256]; - int needs_sep = TRUE; - int comment_block = FALSE; - - /* get default fontpath */ - char *fontpath = strdup(defaultFontPath); - size_t size = strlen(fontpath); - - /* read all lines */ - while (!feof(fontdirs)) - { - size_t blen; - char *hashchar; - char *str; - int has_eol = FALSE; - - /* read one line */ - str = fgets(buffer, sizeof(buffer), fontdirs); - if (str == NULL) /* stop on error or eof */ - break; - - if (strchr(str, '\n') != NULL) - has_eol = TRUE; - - /* check if block is continued comment */ - if (comment_block) - { - /* ignore all input */ - *str = 0; - blen = 0; - if (has_eol) /* check if line ended in this block */ - comment_block = FALSE; - } - else - { - /* find comment character. ignore all trailing input */ - hashchar = strchr(str, '#'); - if (hashchar != NULL) - { - *hashchar = 0; - if (!has_eol) /* mark next block as continued comment */ - comment_block = TRUE; - } - } - - /* strip whitespaces from beginning */ - while (*str == ' ' || *str == '\t') - str++; - - /* get size, strip whitespaces from end */ - blen = strlen(str); - while (blen > 0 && (str[blen-1] == ' ' || - str[blen-1] == '\t' || str[blen-1] == '\n')) - { - str[--blen] = 0; - } - - /* still something left to add? */ - if (blen > 0) - { - size_t newsize = size + blen; - /* reserve one character more for ',' */ - if (needs_sep) - newsize++; - - /* allocate memory */ - if (fontpath == NULL) - fontpath = malloc(newsize+1); - else - fontpath = realloc(fontpath, newsize+1); - - /* add separator */ - if (needs_sep) - { - fontpath[size] = ','; - size++; - needs_sep = FALSE; - } - - /* mark next line as new entry */ - if (has_eol) - needs_sep = TRUE; - - /* add block */ - strncpy(fontpath + size, str, blen); - fontpath[newsize] = 0; - size = newsize; - } - } - - /* cleanup */ - fclose(fontdirs); - defaultFontPath = strdup(fontpath); - free(fontpath); - changed_fontpath = TRUE; - font_from = X_CONFIG; - } - } -#endif /* READ_FONTDIRS */ -#ifdef RELOCATE_PROJECTROOT - { - const char *libx11dir = PROJECTROOT "/lib/X11"; - size_t libx11dir_len = strlen(libx11dir); - char *newfp = NULL; - size_t newfp_len = 0; - const char *endptr, *ptr, *oldptr = defaultFontPath; - - endptr = oldptr + strlen(oldptr); - ptr = strchr(oldptr, ','); - if (ptr == NULL) - ptr = endptr; - while (ptr != NULL) - { - size_t oldfp_len = (ptr - oldptr); - size_t newsize = oldfp_len; - char *newpath = malloc(newsize + 1); - strncpy(newpath, oldptr, newsize); - newpath[newsize] = 0; - - - if (strncmp(libx11dir, newpath, libx11dir_len) == 0) - { - char *compose; - newsize = newsize - libx11dir_len + basedirlen; - compose = malloc(newsize + 1); - strcpy(compose, basedir); - strncat(compose, newpath + libx11dir_len, newsize - basedirlen); - compose[newsize] = 0; - free(newpath); - newpath = compose; - } - - oldfp_len = newfp_len; - if (oldfp_len > 0) - newfp_len ++; /* space for separator */ - newfp_len += newsize; - - if (newfp == NULL) - newfp = malloc(newfp_len + 1); - else - newfp = realloc(newfp, newfp_len + 1); - - if (oldfp_len > 0) - { - strcpy(newfp + oldfp_len, ","); - oldfp_len++; - } - strcpy(newfp + oldfp_len, newpath); - - free(newpath); - - if (*ptr == 0) - { - oldptr = ptr; - ptr = NULL; - } else - { - oldptr = ptr + 1; - ptr = strchr(oldptr, ','); - if (ptr == NULL) - ptr = endptr; - } - } - - defaultFontPath = strdup(newfp); - free(newfp); - changed_fontpath = TRUE; - } -#endif /* RELOCATE_PROJECTROOT */ - if (changed_fontpath) - winMsg (font_from, "FontPath set to \"%s\"\n", defaultFontPath); - -#ifdef RELOCATE_PROJECTROOT - if (getenv("XKEYSYMDB") == NULL) - { - char buffer[MAX_PATH]; - snprintf(buffer, sizeof(buffer), "XKEYSYMDB=%s\\XKeysymDB", - basedir); - buffer[sizeof(buffer)-1] = 0; - putenv(buffer); - } - if (getenv("XERRORDB") == NULL) - { - char buffer[MAX_PATH]; - snprintf(buffer, sizeof(buffer), "XERRORDB=%s\\XErrorDB", - basedir); - buffer[sizeof(buffer)-1] = 0; - putenv(buffer); - } - if (getenv("XLOCALEDIR") == NULL) - { - char buffer[MAX_PATH]; - snprintf(buffer, sizeof(buffer), "XLOCALEDIR=%s\\locale", - basedir); - buffer[sizeof(buffer)-1] = 0; - putenv(buffer); - } - if (getenv("HOME") == NULL) - { - HMODULE shfolder; - SHGETFOLDERPATHPROC shgetfolderpath = NULL; - char buffer[MAX_PATH + 5]; - strncpy(buffer, "HOME=", 5); - - /* Try to load SHGetFolderPath from shfolder.dll and shell32.dll */ - - shfolder = LoadLibrary("shfolder.dll"); - /* fallback to shell32.dll */ - if (shfolder == NULL) - shfolder = LoadLibrary("shell32.dll"); - - /* resolve SHGetFolderPath */ - if (shfolder != NULL) - shgetfolderpath = (SHGETFOLDERPATHPROC)GetProcAddress(shfolder, "SHGetFolderPathA"); - - /* query appdata directory */ - if (shgetfolderpath && - shgetfolderpath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, - buffer + 5) == 0) - { - putenv(buffer); - } else - { - winMsg (X_ERROR, "Can not determine HOME directory\n"); - } - if (shfolder != NULL) - FreeLibrary(shfolder); - } - if (!g_fLogFileChanged) { - static char buffer[MAX_PATH]; - DWORD size = GetTempPath(sizeof(buffer), buffer); - if (size && size < sizeof(buffer)) - { - snprintf(buffer + size, sizeof(buffer) - size, - "XWin.%s.log", display); - buffer[sizeof(buffer)-1] = 0; - g_pszLogFile = buffer; - winMsg (X_DEFAULT, "Logfile set to \"%s\"\n", g_pszLogFile); - } - } - { - static char xkbbasedir[MAX_PATH]; - - snprintf(xkbbasedir, sizeof(xkbbasedir), "%s\\xkb", basedir); - if (sizeof(xkbbasedir) > 0) - xkbbasedir[sizeof(xkbbasedir)-1] = 0; - XkbBaseDirectory = xkbbasedir; - XkbBinDirectory = basedir; - } -#endif /* RELOCATE_PROJECTROOT */ -} - -void -OsVendorInit (void) -{ - /* Re-initialize global variables on server reset */ - winInitializeGlobals (); - - winFixupPaths(); - -#ifdef DDXOSVERRORF - if (!OsVendorVErrorFProc) - OsVendorVErrorFProc = OsVendorVErrorF; -#endif - - if (!g_fLogInited) { - /* keep this order. If LogInit fails it calls Abort which then calls - * ddxGiveUp where LogInit is called again and creates an infinite - * recursion. If we set g_fLogInited to TRUE before the init we - * avoid the second call - */ - g_fLogInited = TRUE; - g_pszLogFile = LogInit (g_pszLogFile, NULL); - } - LogSetParameter (XLOG_FLUSH, 1); - LogSetParameter (XLOG_VERBOSITY, g_iLogVerbose); - LogSetParameter (XLOG_FILE_VERBOSITY, g_iLogVerbose); - - /* Log the version information */ - if (serverGeneration == 1) - winLogVersionInfo (); - - winCheckMount(); - - /* Add a default screen if no screens were specified */ - if (g_iNumScreens == 0) - { - winDebug ("OsVendorInit - Creating default screen 0\n"); - - /* - * We need to initialize the default screen 0 if no -screen - * arguments were processed. - * - * Add a screen 0 using the defaults set by winInitializeDefaultScreens() - * and any additional default screen parameters given - */ - winInitializeScreens(1); - - /* We have to flag this as an explicit screen, even though it isn't */ - g_ScreenInfo[0].fExplicitScreen = TRUE; - } -} - - -static void -winUseMsg (void) -{ - ErrorF("\n"); - ErrorF("\n"); - ErrorF(EXECUTABLE_NAME " Device Dependent Usage:\n"); - ErrorF("\n"); - -#ifdef XWIN_CLIPBOARD - ErrorF ("-[no]clipboard\n" - "\tEnable [disable] the clipboard integration. Default is enabled.\n"); -#endif - - ErrorF ("-clipupdates num_boxes\n" - "\tUse a clipping region to constrain shadow update blits to\n" - "\tthe updated region when num_boxes, or more, are in the\n" - "\tupdated region.\n"); - -#ifdef XWIN_XF86CONFIG - ErrorF ("-config\n" - "\tSpecify a configuration file.\n"); - - ErrorF ("-configdir\n" - "\tSpecify a configuration directory.\n"); -#endif - - ErrorF ("-depth bits_per_pixel\n" - "\tSpecify an optional bitdepth to use in fullscreen mode\n" - "\twith a DirectDraw engine.\n"); - - ErrorF ("-emulate3buttons [timeout]\n" - "\tEmulate 3 button mouse with an optional timeout in\n" - "\tmilliseconds.\n"); - -#ifdef XWIN_EMULATEPSEUDO - ErrorF ("-emulatepseudo\n" - "\tCreate a depth 8 PseudoColor visual when running in\n" - "\tdepths 15, 16, 24, or 32, collectively known as TrueColor\n" - "\tdepths. The PseudoColor visual does not have correct colors,\n" - "\tand it may crash, but it at least allows you to run your\n" - "\tapplication in TrueColor modes.\n"); -#endif - - ErrorF ("-engine engine_type_id\n" - "\tOverride the server's automatically selected engine type:\n" - "\t\t1 - Shadow GDI\n" - "\t\t2 - Shadow DirectDraw\n" - "\t\t4 - Shadow DirectDraw4 Non-Locking\n" -#ifdef XWIN_NATIVEGDI - "\t\t16 - Native GDI - experimental\n" -#endif - ); - - ErrorF ("-fullscreen\n" - "\tRun the server in fullscreen mode.\n"); - - ErrorF ("-ignoreinput\n" - "\tIgnore keyboard and mouse input.\n"); - -#ifdef XWIN_MULTIWINDOWEXTWM - ErrorF ("-internalwm\n" - "\tRun the internal window manager.\n"); -#endif - -#ifdef XWIN_XF86CONFIG - ErrorF ("-keyboard\n" - "\tSpecify a keyboard device from the configuration file.\n"); -#endif - - ErrorF ("-[no]keyhook\n" - "\tGrab special Windows keypresses like Alt-Tab or the Menu " - "key.\n"); - - ErrorF ("-lesspointer\n" - "\tHide the windows mouse pointer when it is over any\n" - "\t" EXECUTABLE_NAME " window. This prevents ghost cursors appearing when\n" - "\tthe Windows cursor is drawn on top of the X cursor\n"); - - ErrorF ("-logfile filename\n" - "\tWrite log messages to .\n"); - - ErrorF ("-logverbose verbosity\n" - "\tSet the verbosity of log messages. [NOTE: Only a few messages\n" - "\trespect the settings yet]\n" - "\t\t0 - only print fatal error.\n" - "\t\t1 - print additional configuration information.\n" - "\t\t2 - print additional runtime information [default].\n" - "\t\t3 - print debugging and tracing information.\n"); - - ErrorF ("-[no]multimonitors or -[no]multiplemonitors\n" - "\tUse the entire virtual screen if multiple\n" - "\tmonitors are present.\n"); - -#ifdef XWIN_MULTIWINDOW - ErrorF ("-multiwindow\n" - "\tRun the server in multi-window mode.\n"); -#endif - -#ifdef XWIN_MULTIWINDOWEXTWM - ErrorF ("-mwextwm\n" - "\tRun the server in multi-window external window manager mode.\n"); -#endif - - ErrorF ("-nodecoration\n" - "\tDo not draw a window border, title bar, etc. Windowed\n" - "\tmode only.\n"); - -#ifdef XWIN_CLIPBOARD - ErrorF ("-nounicodeclipboard\n" - "\tDo not use Unicode clipboard even if on a NT-based platform.\n"); -#endif - - ErrorF ("-refresh rate_in_Hz\n" - "\tSpecify an optional refresh rate to use in fullscreen mode\n" - "\twith a DirectDraw engine.\n"); - - ErrorF ("-rootless\n" - "\tRun the server in rootless mode.\n"); - - ErrorF ("-screen scr_num [width height [x y] | [[WxH[+X+Y]][@m]] ]\n" - "\tEnable screen scr_num and optionally specify a width and\n" - "\theight and initial position for that screen. Additionally\n" - "\ta monitor number can be specified to start the server on,\n" - "\tat which point, all coordinates become relative to that\n" - "\tmonitor (Not for Windows NT4 and 95). Examples:\n" - "\t -screen 0 800x600+100+100@2 ; 2nd monitor offset 100,100 size 800x600\n" - "\t -screen 0 1024x768@3 ; 3rd monitor size 1024x768\n" - "\t -screen 0 @1 ; on 1st monitor using its full resolution (the default)\n"); - - ErrorF ("-scrollbars\n" - "\tIn windowed mode, allow screens bigger than the Windows desktop.\n" - "\tMoreover, if the window has decorations, one can now resize\n" - "\tit.\n"); - - ErrorF ("-silent-dup-error\n" - "\tIf another instance of " EXECUTABLE_NAME " with the same display number is running\n" - "\texit silently and don't display any error message.\n"); - - ErrorF ("-swcursor\n" - "\tDisable the usage of the Windows cursor and use the X11 software\n" - "\tcursor instead.\n"); - - ErrorF ("-[no]trayicon\n" - "\tDo not create a tray icon. Default is to create one\n" - "\ticon per screen. You can globally disable tray icons with\n" - "\t-notrayicon, then enable it for specific screens with\n" - "\t-trayicon for those screens.\n"); - - ErrorF ("-[no]unixkill\n" - "\tCtrl+Alt+Backspace exits the X Server.\n"); - -#ifdef XWIN_GLX_WINDOWS - ErrorF ("-[no]wgl\n" - "\tEnable the GLX extension to use the native Windows WGL interface for accelerated OpenGL\n"); -#endif - - ErrorF ("-[no]winkill\n" - "\tAlt+F4 exits the X Server.\n"); - - ErrorF ("-xkblayout XKBLayout\n" - "\tEquivalent to XKBLayout in XF86Config files.\n" - "\tFor example: -xkblayout de\n"); - - ErrorF ("-xkbmodel XKBModel\n" - "\tEquivalent to XKBModel in XF86Config files.\n"); - - ErrorF ("-xkboptions XKBOptions\n" - "\tEquivalent to XKBOptions in XF86Config files.\n"); - - ErrorF ("-xkbrules XKBRules\n" - "\tEquivalent to XKBRules in XF86Config files.\n"); - - ErrorF ("-xkbvariant XKBVariant\n" - "\tEquivalent to XKBVariant in XF86Config files.\n" - "\tFor example: -xkbvariant nodeadkeys\n"); -} - -/* See Porting Layer Definition - p. 57 */ -void -ddxUseMsg(void) -{ - /* Set a flag so that FatalError won't give duplicate warning message */ - g_fSilentFatalError = TRUE; - - winUseMsg(); - - /* Log file will not be opened for UseMsg unless we open it now */ - if (!g_fLogInited) { - g_pszLogFile = LogInit (g_pszLogFile, NULL); - g_fLogInited = TRUE; - } - LogClose (); - - /* Notify user where UseMsg text can be found.*/ - if (!g_fNoHelpMessageBox) - winMessageBoxF ("The " PROJECT_NAME " help text has been printed to " - "%s.\n" - "Please open %s to read the help text.\n", - MB_ICONINFORMATION, g_pszLogFile, g_pszLogFile); -} - -/* See Porting Layer Definition - p. 20 */ -/* - * Do any global initialization, then initialize each screen. - * - * NOTE: We use ddxProcessArgument, so we don't need to touch argc and argv - */ - -void -InitOutput (ScreenInfo *screenInfo, int argc, char *argv[]) -{ - int i; - - /* Log the command line */ - winLogCommandLine (argc, argv); - -#if CYGDEBUG - winDebug ("InitOutput\n"); -#endif - - /* Validate command-line arguments */ - if (serverGeneration == 1 && !winValidateArgs ()) - { - FatalError ("InitOutput - Invalid command-line arguments found. " - "Exiting.\n"); - } - - /* Check for duplicate invocation on same display number.*/ - if (serverGeneration == 1 && !winCheckDisplayNumber ()) - { - if (g_fSilentDupError) - g_fSilentFatalError = TRUE; - FatalError ("InitOutput - Duplicate invocation on display " - "number: %s. Exiting.\n", display); - } - -#ifdef XWIN_XF86CONFIG - /* Try to read the xorg.conf-style configuration file */ - if (!winReadConfigfile ()) - winErrorFVerb (1, "InitOutput - Error reading config file\n"); -#else - winMsg(X_INFO, "xorg.conf is not supported\n"); - winMsg(X_INFO, "See http://x.cygwin.com/docs/faq/cygwin-x-faq.html " - "for more information\n"); - winConfigFiles (); -#endif - - /* Load preferences from XWinrc file */ - LoadPreferences(); - - /* Setup global screen info parameters */ - screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - screenInfo->numPixmapFormats = NUMFORMATS; - - /* Describe how we want common pixmap formats padded */ - for (i = 0; i < NUMFORMATS; i++) - { - screenInfo->formats[i] = g_PixmapFormats[i]; - } - - /* Load pointers to DirectDraw functions */ - winGetDDProcAddresses (); - - /* Detect supported engines */ - winDetectSupportedEngines (); - - /* Load common controls library */ - g_hmodCommonControls = LoadLibraryEx ("comctl32.dll", NULL, 0); - - /* Load TrackMouseEvent function pointer */ - g_fpTrackMouseEvent = GetProcAddress (g_hmodCommonControls, - "_TrackMouseEvent"); - if (g_fpTrackMouseEvent == NULL) - { - winErrorFVerb (1, "InitOutput - Could not get pointer to function\n" - "\t_TrackMouseEvent in comctl32.dll. Try installing\n" - "\tInternet Explorer 3.0 or greater if you have not\n" - "\talready.\n"); - - /* Free the library since we won't need it */ - FreeLibrary (g_hmodCommonControls); - g_hmodCommonControls = NULL; - - /* Set function pointer to point to no operation function */ - g_fpTrackMouseEvent = (FARPROC) (void (*)(void))NoopDDA; - } - - /* Store the instance handle */ - g_hInstance = GetModuleHandle (NULL); - - /* Initialize each screen */ - for (i = 0; i < g_iNumScreens; ++i) - { - /* Initialize the screen */ - if (-1 == AddScreen (winScreenInit, argc, argv)) - { - FatalError ("InitOutput - Couldn't add screen %d", i); - } - } - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - - /* Generate a cookie used by internal clients for authorization */ - if (g_fXdmcpEnabled || g_fAuthEnabled) - winGenerateAuthorization (); - - /* Perform some one time initialization */ - if (1 == serverGeneration) - { - /* - * setlocale applies to all threads in the current process. - * Apply locale specified in LANG environment variable. - */ - setlocale (LC_ALL, ""); - } -#endif - -#if CYGDEBUG || YES - winDebug ("InitOutput - Returning.\n"); -#endif -} - - -/* - * winCheckDisplayNumber - Check if another instance of Cygwin/X is - * already running on the same display number. If no one exists, - * make a mutex to prevent new instances from running on the same display. - * - * return FALSE if the display number is already used. - */ - -static Bool -winCheckDisplayNumber (void) -{ - int nDisp; - HANDLE mutex; - char name[MAX_PATH]; - char * pszPrefix = '\0'; - OSVERSIONINFO osvi = {0}; - - /* Check display range */ - nDisp = atoi (display); - if (nDisp < 0 || nDisp > 65535) - { - ErrorF ("winCheckDisplayNumber - Bad display number: %d\n", nDisp); - return FALSE; - } - - /* Set first character of mutex name to null */ - name[0] = '\0'; - - /* Get operating system version information */ - osvi.dwOSVersionInfoSize = sizeof (osvi); - GetVersionEx (&osvi); - - /* Want a mutex shared among all terminals on NT > 4.0 */ - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT - && osvi.dwMajorVersion >= 5) - { - pszPrefix = "Global\\"; - } - - /* Setup Cygwin/X specific part of name */ - snprintf (name, sizeof(name), "%sCYGWINX_DISPLAY:%d", pszPrefix, nDisp); - - /* Windows automatically releases the mutex when this process exits */ - mutex = CreateMutex (NULL, FALSE, name); - if (!mutex) - { - LPVOID lpMsgBuf; - - /* Display a fancy error message */ - FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError (), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, - 0, NULL); - ErrorF ("winCheckDisplayNumber - CreateMutex failed: %s\n", - (LPSTR)lpMsgBuf); - LocalFree (lpMsgBuf); - - return FALSE; - } - if (GetLastError () == ERROR_ALREADY_EXISTS) - { - ErrorF ("winCheckDisplayNumber - " - PROJECT_NAME " is already running on display %d\n", - nDisp); - return FALSE; - } - - return TRUE; -} + +/* + +Copyright 1993, 1998 The Open Group +Copyright (C) Colin Harrison 2005-2008 + +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. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" +#include "winmsg.h" +#include "winconfig.h" +#include "winprefs.h" +#ifdef XWIN_CLIPBOARD +#include "X11/Xlocale.h" +#endif +#ifdef DPMSExtension +#include "dpmsproc.h" +#endif +#ifdef __CYGWIN__ +#include +#endif +#if defined(WIN32) +#include "xkbsrv.h" +#endif +#ifdef RELOCATE_PROJECTROOT +#include +typedef HRESULT (*SHGETFOLDERPATHPROC)( + HWND hwndOwner, + int nFolder, + HANDLE hToken, + DWORD dwFlags, + LPTSTR pszPath +); +#endif + +/* + * References to external symbols + */ +#ifdef XWIN_CLIPBOARD +extern Bool g_fUnicodeClipboard; +extern Bool g_fClipboardLaunched; +extern Bool g_fClipboardStarted; +extern pthread_t g_ptClipboardProc; +extern HWND g_hwndClipboard; +extern Bool g_fClipboard; +#endif + + +/* + module handle for dynamically loaded comctl32 library +*/ +static HMODULE g_hmodCommonControls = NULL; + +/* + * Function prototypes + */ + +#ifdef XWIN_CLIPBOARD +static void +winClipboardShutdown (void); +#endif + +#if defined(DDXOSVERRORF) +void +OsVendorVErrorF (const char *pszFormat, va_list va_args); +#endif + +static Bool +winCheckDisplayNumber (void); + +void +winLogCommandLine (int argc, char *argv[]); + +void +winLogVersionInfo (void); + +Bool +winValidateArgs (void); + +#ifdef RELOCATE_PROJECTROOT +const char * +winGetBaseDir(void); +#endif + +/* + * For the depth 24 pixmap we default to 32 bits per pixel, but + * we change this pixmap format later if we detect that the display + * is going to be running at 24 bits per pixel. + * + * FIXME: On second thought, don't DIBs only support 32 bits per pixel? + * DIBs are the underlying bitmap used for DirectDraw surfaces, so it + * seems that all pixmap formats with depth 24 would be 32 bits per pixel. + * Confirm whether depth 24 DIBs can have 24 bits per pixel, then remove/keep + * the bits per pixel adjustment and update this comment to reflect the + * situation. Harold Hunt - 2002/07/02 + */ + +static PixmapFormatRec g_PixmapFormats[] = { + { 1, 1, BITMAP_SCANLINE_PAD }, + { 4, 8, BITMAP_SCANLINE_PAD }, + { 8, 8, BITMAP_SCANLINE_PAD }, + { 15, 16, BITMAP_SCANLINE_PAD }, + { 16, 16, BITMAP_SCANLINE_PAD }, + { 24, 32, BITMAP_SCANLINE_PAD }, + { 32, 32, BITMAP_SCANLINE_PAD } +}; + +const int NUMFORMATS = sizeof (g_PixmapFormats) / sizeof (g_PixmapFormats[0]); + +#ifdef XWIN_CLIPBOARD +static void +winClipboardShutdown (void) +{ + /* Close down clipboard resources */ + if (g_fClipboard && g_fClipboardLaunched && g_fClipboardStarted) + { + /* Synchronously destroy the clipboard window */ + if (g_hwndClipboard != NULL) + { + SendMessage (g_hwndClipboard, WM_DESTROY, 0, 0); + /* NOTE: g_hwndClipboard is set to NULL in winclipboardthread.c */ + } + else + return; + + /* Wait for the clipboard thread to exit */ + pthread_join (g_ptClipboardProc, NULL); + + g_fClipboardLaunched = FALSE; + g_fClipboardStarted = FALSE; + + winDebug ("winClipboardShutdown - Clipboard thread has exited.\n"); + } +} +#endif + +void +ddxPushProviders(void) +{ +#ifdef XWIN_GLX_WINDOWS + if (g_fNativeGl) + { + /* install the native GL provider */ + glxWinPushNativeProvider(); + } +#endif +} + +#if defined(DDXBEFORERESET) +/* + * Called right before KillAllClients when the server is going to reset, + * allows us to shutdown our seperate threads cleanly. + */ + +void +ddxBeforeReset (void) +{ + winDebug ("ddxBeforeReset - Hello\n"); + +#ifdef XWIN_CLIPBOARD + winClipboardShutdown (); +#endif +} +#endif + + +/* See Porting Layer Definition - p. 57 */ +void +ddxGiveUp (void) +{ + int i; + +#if CYGDEBUG + winDebug ("ddxGiveUp\n"); +#endif + + /* Perform per-screen deinitialization */ + for (i = 0; i < g_iNumScreens; ++i) + { + /* Delete the tray icon */ + if (!g_ScreenInfo[i].fNoTrayIcon && g_ScreenInfo[i].pScreen) + winDeleteNotifyIcon (winGetScreenPriv (g_ScreenInfo[i].pScreen)); + } + +#ifdef XWIN_MULTIWINDOW + /* Notify the worker threads we're exiting */ + winDeinitMultiWindowWM (); +#endif + +#ifdef HAS_DEVWINDOWS + /* Close our handle to our message queue */ + if (g_fdMessageQueue != WIN_FD_INVALID) + { + /* Close /dev/windows */ + close (g_fdMessageQueue); + + /* Set the file handle to invalid */ + g_fdMessageQueue = WIN_FD_INVALID; + } +#endif + + if (!g_fLogInited) { + g_pszLogFile = LogInit (g_pszLogFile, NULL); + g_fLogInited = TRUE; + } + LogClose (); + + /* + * At this point we aren't creating any new screens, so + * we are guaranteed to not need the DirectDraw functions. + */ + winReleaseDDProcAddresses(); + + /* Unload our TrackMouseEvent function pointer */ + if (g_hmodCommonControls != NULL) + { + FreeLibrary (g_hmodCommonControls); + g_hmodCommonControls = NULL; + g_fpTrackMouseEvent = (FARPROC) (void (*)(void))NoopDDA; + } + + /* Free concatenated command line */ + free(g_pszCommandLine); + g_pszCommandLine = NULL; + + /* Remove our keyboard hook if it is installed */ + winRemoveKeyboardHookLL (); + + /* Tell Windows that we want to end the app */ + PostQuitMessage (0); +} + + +/* See Porting Layer Definition - p. 57 */ +void +AbortDDX (void) +{ +#if CYGDEBUG + winDebug ("AbortDDX\n"); +#endif + ddxGiveUp (); +} + +#ifdef __CYGWIN__ +/* hasmntopt is currently not implemented for cygwin */ +static const char *winCheckMntOpt(const struct mntent *mnt, const char *opt) +{ + const char *s; + size_t len; + if (mnt == NULL) + return NULL; + if (opt == NULL) + return NULL; + if (mnt->mnt_opts == NULL) + return NULL; + + len = strlen(opt); + s = strstr(mnt->mnt_opts, opt); + if (s == NULL) + return NULL; + if ((s == mnt->mnt_opts || *(s-1) == ',') && (s[len] == 0 || s[len] == ',')) + return (char *)opt; + return NULL; +} + +static void +winCheckMount(void) +{ + FILE *mnt; + struct mntent *ent; + + enum { none = 0, sys_root, user_root, sys_tmp, user_tmp } + level = none, curlevel; + BOOL binary = TRUE; + + mnt = setmntent("/etc/mtab", "r"); + if (mnt == NULL) + { + ErrorF("setmntent failed"); + return; + } + + while ((ent = getmntent(mnt)) != NULL) + { + BOOL system = (winCheckMntOpt(ent, "user") != NULL); + BOOL root = (strcmp(ent->mnt_dir, "/") == 0); + BOOL tmp = (strcmp(ent->mnt_dir, "/tmp") == 0); + + if (system) + { + if (root) + curlevel = sys_root; + else if (tmp) + curlevel = sys_tmp; + else + continue; + } + else + { + if (root) + curlevel = user_root; + else if (tmp) + curlevel = user_tmp; + else + continue; + } + + if (curlevel <= level) + continue; + level = curlevel; + + if ((winCheckMntOpt(ent, "binary") == NULL) && + (winCheckMntOpt(ent, "binmode") == NULL)) + binary = FALSE; + else + binary = TRUE; + } + + if (endmntent(mnt) != 1) + { + ErrorF("endmntent failed"); + return; + } + + if (!binary) + winMsg(X_WARNING, "/tmp mounted in textmode\n"); +} +#else +static void +winCheckMount(void) +{ +} +#endif + +#ifdef RELOCATE_PROJECTROOT +const char * +winGetBaseDir(void) +{ + static BOOL inited = FALSE; + static char buffer[MAX_PATH]; + if (!inited) + { + char *fendptr; + HMODULE module = GetModuleHandle(NULL); + DWORD size = GetModuleFileName(module, buffer, sizeof(buffer)); + if (sizeof(buffer) > 0) + buffer[sizeof(buffer)-1] = 0; + + fendptr = buffer + size; + while (fendptr > buffer) + { + if (*fendptr == '\\' || *fendptr == '/') + { + *fendptr = 0; + break; + } + fendptr--; + } + inited = TRUE; + } + return buffer; +} +#endif + +static void +winFixupPaths (void) +{ + BOOL changed_fontpath = FALSE; + MessageType font_from = X_DEFAULT; +#ifdef RELOCATE_PROJECTROOT + const char *basedir = winGetBaseDir(); + size_t basedirlen = strlen(basedir); +#endif + +#ifdef READ_FONTDIRS + { + /* Open fontpath configuration file */ + FILE *fontdirs = fopen(ETCX11DIR "/font-dirs", "rt"); + if (fontdirs != NULL) + { + char buffer[256]; + int needs_sep = TRUE; + int comment_block = FALSE; + + /* get default fontpath */ + char *fontpath = strdup(defaultFontPath); + size_t size = strlen(fontpath); + + /* read all lines */ + while (!feof(fontdirs)) + { + size_t blen; + char *hashchar; + char *str; + int has_eol = FALSE; + + /* read one line */ + str = fgets(buffer, sizeof(buffer), fontdirs); + if (str == NULL) /* stop on error or eof */ + break; + + if (strchr(str, '\n') != NULL) + has_eol = TRUE; + + /* check if block is continued comment */ + if (comment_block) + { + /* ignore all input */ + *str = 0; + blen = 0; + if (has_eol) /* check if line ended in this block */ + comment_block = FALSE; + } + else + { + /* find comment character. ignore all trailing input */ + hashchar = strchr(str, '#'); + if (hashchar != NULL) + { + *hashchar = 0; + if (!has_eol) /* mark next block as continued comment */ + comment_block = TRUE; + } + } + + /* strip whitespaces from beginning */ + while (*str == ' ' || *str == '\t') + str++; + + /* get size, strip whitespaces from end */ + blen = strlen(str); + while (blen > 0 && (str[blen-1] == ' ' || + str[blen-1] == '\t' || str[blen-1] == '\n')) + { + str[--blen] = 0; + } + + /* still something left to add? */ + if (blen > 0) + { + size_t newsize = size + blen; + /* reserve one character more for ',' */ + if (needs_sep) + newsize++; + + /* allocate memory */ + if (fontpath == NULL) + fontpath = malloc(newsize+1); + else + fontpath = realloc(fontpath, newsize+1); + + /* add separator */ + if (needs_sep) + { + fontpath[size] = ','; + size++; + needs_sep = FALSE; + } + + /* mark next line as new entry */ + if (has_eol) + needs_sep = TRUE; + + /* add block */ + strncpy(fontpath + size, str, blen); + fontpath[newsize] = 0; + size = newsize; + } + } + + /* cleanup */ + fclose(fontdirs); + defaultFontPath = strdup(fontpath); + free(fontpath); + changed_fontpath = TRUE; + font_from = X_CONFIG; + } + } +#endif /* READ_FONTDIRS */ +#ifdef RELOCATE_PROJECTROOT + { + const char *libx11dir = PROJECTROOT "/lib/X11"; + size_t libx11dir_len = strlen(libx11dir); + char *newfp = NULL; + size_t newfp_len = 0; + const char *endptr, *ptr, *oldptr = defaultFontPath; + + endptr = oldptr + strlen(oldptr); + ptr = strchr(oldptr, ','); + if (ptr == NULL) + ptr = endptr; + while (ptr != NULL) + { + size_t oldfp_len = (ptr - oldptr); + size_t newsize = oldfp_len; + char *newpath = malloc(newsize + 1); + strncpy(newpath, oldptr, newsize); + newpath[newsize] = 0; + + + if (strncmp(libx11dir, newpath, libx11dir_len) == 0) + { + char *compose; + newsize = newsize - libx11dir_len + basedirlen; + compose = malloc(newsize + 1); + strcpy(compose, basedir); + strncat(compose, newpath + libx11dir_len, newsize - basedirlen); + compose[newsize] = 0; + free(newpath); + newpath = compose; + } + + oldfp_len = newfp_len; + if (oldfp_len > 0) + newfp_len ++; /* space for separator */ + newfp_len += newsize; + + if (newfp == NULL) + newfp = malloc(newfp_len + 1); + else + newfp = realloc(newfp, newfp_len + 1); + + if (oldfp_len > 0) + { + strcpy(newfp + oldfp_len, ","); + oldfp_len++; + } + strcpy(newfp + oldfp_len, newpath); + + free(newpath); + + if (*ptr == 0) + { + oldptr = ptr; + ptr = NULL; + } else + { + oldptr = ptr + 1; + ptr = strchr(oldptr, ','); + if (ptr == NULL) + ptr = endptr; + } + } + + defaultFontPath = strdup(newfp); + free(newfp); + changed_fontpath = TRUE; + } +#endif /* RELOCATE_PROJECTROOT */ + if (changed_fontpath) + winMsg (font_from, "FontPath set to \"%s\"\n", defaultFontPath); + +#ifdef RELOCATE_PROJECTROOT + if (getenv("XKEYSYMDB") == NULL) + { + char buffer[MAX_PATH]; + snprintf(buffer, sizeof(buffer), "XKEYSYMDB=%s\\XKeysymDB", + basedir); + buffer[sizeof(buffer)-1] = 0; + putenv(buffer); + } + if (getenv("XERRORDB") == NULL) + { + char buffer[MAX_PATH]; + snprintf(buffer, sizeof(buffer), "XERRORDB=%s\\XErrorDB", + basedir); + buffer[sizeof(buffer)-1] = 0; + putenv(buffer); + } + if (getenv("XLOCALEDIR") == NULL) + { + char buffer[MAX_PATH]; + snprintf(buffer, sizeof(buffer), "XLOCALEDIR=%s\\locale", + basedir); + buffer[sizeof(buffer)-1] = 0; + putenv(buffer); + } + if (getenv("HOME") == NULL) + { + HMODULE shfolder; + SHGETFOLDERPATHPROC shgetfolderpath = NULL; + char buffer[MAX_PATH + 5]; + strncpy(buffer, "HOME=", 5); + + /* Try to load SHGetFolderPath from shfolder.dll and shell32.dll */ + + shfolder = LoadLibrary("shfolder.dll"); + /* fallback to shell32.dll */ + if (shfolder == NULL) + shfolder = LoadLibrary("shell32.dll"); + + /* resolve SHGetFolderPath */ + if (shfolder != NULL) + shgetfolderpath = (SHGETFOLDERPATHPROC)GetProcAddress(shfolder, "SHGetFolderPathA"); + + /* query appdata directory */ + if (shgetfolderpath && + shgetfolderpath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, + buffer + 5) == 0) + { + putenv(buffer); + } else + { + winMsg (X_ERROR, "Can not determine HOME directory\n"); + } + if (shfolder != NULL) + FreeLibrary(shfolder); + } + if (!g_fLogFileChanged) { + static char buffer[MAX_PATH]; + DWORD size = GetTempPath(sizeof(buffer), buffer); + if (size && size < sizeof(buffer)) + { + snprintf(buffer + size, sizeof(buffer) - size, + "XWin.%s.log", display); + buffer[sizeof(buffer)-1] = 0; + g_pszLogFile = buffer; + winMsg (X_DEFAULT, "Logfile set to \"%s\"\n", g_pszLogFile); + } + } + { + static char xkbbasedir[MAX_PATH]; + + snprintf(xkbbasedir, sizeof(xkbbasedir), "%s\\xkb", basedir); + if (sizeof(xkbbasedir) > 0) + xkbbasedir[sizeof(xkbbasedir)-1] = 0; + XkbBaseDirectory = xkbbasedir; + XkbBinDirectory = basedir; + } +#endif /* RELOCATE_PROJECTROOT */ +} + +void +OsVendorInit (void) +{ + /* Re-initialize global variables on server reset */ + winInitializeGlobals (); + + winFixupPaths(); + +#ifdef DDXOSVERRORF + if (!OsVendorVErrorFProc) + OsVendorVErrorFProc = OsVendorVErrorF; +#endif + + if (!g_fLogInited) { + /* keep this order. If LogInit fails it calls Abort which then calls + * ddxGiveUp where LogInit is called again and creates an infinite + * recursion. If we set g_fLogInited to TRUE before the init we + * avoid the second call + */ + g_fLogInited = TRUE; + g_pszLogFile = LogInit (g_pszLogFile, NULL); + } + LogSetParameter (XLOG_FLUSH, 1); + LogSetParameter (XLOG_VERBOSITY, g_iLogVerbose); + LogSetParameter (XLOG_FILE_VERBOSITY, g_iLogVerbose); + + /* Log the version information */ + if (serverGeneration == 1) + winLogVersionInfo (); + + winCheckMount(); + + /* Add a default screen if no screens were specified */ + if (g_iNumScreens == 0) + { + winDebug ("OsVendorInit - Creating default screen 0\n"); + + /* + * We need to initialize the default screen 0 if no -screen + * arguments were processed. + * + * Add a screen 0 using the defaults set by winInitializeDefaultScreens() + * and any additional default screen parameters given + */ + winInitializeScreens(1); + + /* We have to flag this as an explicit screen, even though it isn't */ + g_ScreenInfo[0].fExplicitScreen = TRUE; + } +} + + +static void +winUseMsg (void) +{ + ErrorF("\n"); + ErrorF("\n"); + ErrorF(EXECUTABLE_NAME " Device Dependent Usage:\n"); + ErrorF("\n"); + +#ifdef XWIN_CLIPBOARD + ErrorF ("-[no]clipboard\n" + "\tEnable [disable] the clipboard integration. Default is enabled.\n"); +#endif + + ErrorF ("-clipupdates num_boxes\n" + "\tUse a clipping region to constrain shadow update blits to\n" + "\tthe updated region when num_boxes, or more, are in the\n" + "\tupdated region.\n"); + +#ifdef XWIN_XF86CONFIG + ErrorF ("-config\n" + "\tSpecify a configuration file.\n"); + + ErrorF ("-configdir\n" + "\tSpecify a configuration directory.\n"); +#endif + + ErrorF ("-depth bits_per_pixel\n" + "\tSpecify an optional bitdepth to use in fullscreen mode\n" + "\twith a DirectDraw engine.\n"); + + ErrorF ("-emulate3buttons [timeout]\n" + "\tEmulate 3 button mouse with an optional timeout in\n" + "\tmilliseconds.\n"); + +#ifdef XWIN_EMULATEPSEUDO + ErrorF ("-emulatepseudo\n" + "\tCreate a depth 8 PseudoColor visual when running in\n" + "\tdepths 15, 16, 24, or 32, collectively known as TrueColor\n" + "\tdepths. The PseudoColor visual does not have correct colors,\n" + "\tand it may crash, but it at least allows you to run your\n" + "\tapplication in TrueColor modes.\n"); +#endif + + ErrorF ("-engine engine_type_id\n" + "\tOverride the server's automatically selected engine type:\n" + "\t\t1 - Shadow GDI\n" + "\t\t2 - Shadow DirectDraw\n" + "\t\t4 - Shadow DirectDraw4 Non-Locking\n" +#ifdef XWIN_PRIMARYFB + "\t\t8 - Primary DirectDraw - obsolete\n" +#endif +#ifdef XWIN_NATIVEGDI + "\t\t16 - Native GDI - experimental\n" +#endif + ); + + ErrorF ("-fullscreen\n" + "\tRun the server in fullscreen mode.\n"); + + ErrorF ("-ignoreinput\n" + "\tIgnore keyboard and mouse input.\n"); + +#ifdef XWIN_MULTIWINDOWEXTWM + ErrorF ("-internalwm\n" + "\tRun the internal window manager.\n"); +#endif + +#ifdef XWIN_XF86CONFIG + ErrorF ("-keyboard\n" + "\tSpecify a keyboard device from the configuration file.\n"); +#endif + + ErrorF ("-[no]keyhook\n" + "\tGrab special Windows keypresses like Alt-Tab or the Menu " + "key.\n"); + + ErrorF ("-lesspointer\n" + "\tHide the windows mouse pointer when it is over any\n" + "\t" EXECUTABLE_NAME " window. This prevents ghost cursors appearing when\n" + "\tthe Windows cursor is drawn on top of the X cursor\n"); + + ErrorF ("-logfile filename\n" + "\tWrite log messages to .\n"); + + ErrorF ("-logverbose verbosity\n" + "\tSet the verbosity of log messages. [NOTE: Only a few messages\n" + "\trespect the settings yet]\n" + "\t\t0 - only print fatal error.\n" + "\t\t1 - print additional configuration information.\n" + "\t\t2 - print additional runtime information [default].\n" + "\t\t3 - print debugging and tracing information.\n"); + + ErrorF ("-[no]multimonitors or -[no]multiplemonitors\n" + "\tUse the entire virtual screen if multiple\n" + "\tmonitors are present.\n"); + +#ifdef XWIN_MULTIWINDOW + ErrorF ("-multiwindow\n" + "\tRun the server in multi-window mode.\n"); +#endif + +#ifdef XWIN_MULTIWINDOWEXTWM + ErrorF ("-mwextwm\n" + "\tRun the server in multi-window external window manager mode.\n"); +#endif + + ErrorF ("-nodecoration\n" + "\tDo not draw a window border, title bar, etc. Windowed\n" + "\tmode only.\n"); + +#ifdef XWIN_CLIPBOARD + ErrorF ("-nounicodeclipboard\n" + "\tDo not use Unicode clipboard even if on a NT-based platform.\n"); +#endif + + ErrorF ("-refresh rate_in_Hz\n" + "\tSpecify an optional refresh rate to use in fullscreen mode\n" + "\twith a DirectDraw engine.\n"); + + ErrorF ("-resize=none|scrollbars|randr" + "\tIn windowed mode, [don't] allow resizing of the window. 'scrollbars'\n" + "\tmode gives the window scrollbars as needed, 'randr' mode uses the RANR\n" + "\textension to resize the X screen.\n"); + + ErrorF ("-rootless\n" + "\tRun the server in rootless mode.\n"); + + ErrorF ("-screen scr_num [width height [x y] | [[WxH[+X+Y]][@m]] ]\n" + "\tEnable screen scr_num and optionally specify a width and\n" + "\theight and initial position for that screen. Additionally\n" + "\ta monitor number can be specified to start the server on,\n" + "\tat which point, all coordinates become relative to that\n" + "\tmonitor (Not for Windows NT4 and 95). Examples:\n" + "\t -screen 0 800x600+100+100@2 ; 2nd monitor offset 100,100 size 800x600\n" + "\t -screen 0 1024x768@3 ; 3rd monitor size 1024x768\n" + "\t -screen 0 @1 ; on 1st monitor using its full resolution (the default)\n"); + + ErrorF ("-silent-dup-error\n" + "\tIf another instance of " EXECUTABLE_NAME " with the same display number is running\n" + "\texit silently and don't display any error message.\n"); + + ErrorF ("-swcursor\n" + "\tDisable the usage of the Windows cursor and use the X11 software\n" + "\tcursor instead.\n"); + + ErrorF ("-[no]trayicon\n" + "\tDo not create a tray icon. Default is to create one\n" + "\ticon per screen. You can globally disable tray icons with\n" + "\t-notrayicon, then enable it for specific screens with\n" + "\t-trayicon for those screens.\n"); + + ErrorF ("-[no]unixkill\n" + "\tCtrl+Alt+Backspace exits the X Server.\n"); + +#ifdef XWIN_GLX_WINDOWS + ErrorF ("-[no]wgl\n" + "\tEnable the GLX extension to use the native Windows WGL interface for accelerated OpenGL\n"); +#endif + + ErrorF ("-[no]winkill\n" + "\tAlt+F4 exits the X Server.\n"); + + ErrorF ("-xkblayout XKBLayout\n" + "\tEquivalent to XKBLayout in XF86Config files.\n" + "\tFor example: -xkblayout de\n"); + + ErrorF ("-xkbmodel XKBModel\n" + "\tEquivalent to XKBModel in XF86Config files.\n"); + + ErrorF ("-xkboptions XKBOptions\n" + "\tEquivalent to XKBOptions in XF86Config files.\n"); + + ErrorF ("-xkbrules XKBRules\n" + "\tEquivalent to XKBRules in XF86Config files.\n"); + + ErrorF ("-xkbvariant XKBVariant\n" + "\tEquivalent to XKBVariant in XF86Config files.\n" + "\tFor example: -xkbvariant nodeadkeys\n"); +} + +/* See Porting Layer Definition - p. 57 */ +void +ddxUseMsg(void) +{ + /* Set a flag so that FatalError won't give duplicate warning message */ + g_fSilentFatalError = TRUE; + + winUseMsg(); + + /* Log file will not be opened for UseMsg unless we open it now */ + if (!g_fLogInited) { + g_pszLogFile = LogInit (g_pszLogFile, NULL); + g_fLogInited = TRUE; + } + LogClose (); + + /* Notify user where UseMsg text can be found.*/ + if (!g_fNoHelpMessageBox) + winMessageBoxF ("The " PROJECT_NAME " help text has been printed to " + "%s.\n" + "Please open %s to read the help text.\n", + MB_ICONINFORMATION, g_pszLogFile, g_pszLogFile); +} + +/* See Porting Layer Definition - p. 20 */ +/* + * Do any global initialization, then initialize each screen. + * + * NOTE: We use ddxProcessArgument, so we don't need to touch argc and argv + */ + +void +InitOutput (ScreenInfo *screenInfo, int argc, char *argv[]) +{ + int i; + + /* Log the command line */ + winLogCommandLine (argc, argv); + +#if CYGDEBUG + winDebug ("InitOutput\n"); +#endif + + /* Validate command-line arguments */ + if (serverGeneration == 1 && !winValidateArgs ()) + { + FatalError ("InitOutput - Invalid command-line arguments found. " + "Exiting.\n"); + } + + /* Check for duplicate invocation on same display number.*/ + if (serverGeneration == 1 && !winCheckDisplayNumber ()) + { + if (g_fSilentDupError) + g_fSilentFatalError = TRUE; + FatalError ("InitOutput - Duplicate invocation on display " + "number: %s. Exiting.\n", display); + } + +#ifdef XWIN_XF86CONFIG + /* Try to read the xorg.conf-style configuration file */ + if (!winReadConfigfile ()) + winErrorFVerb (1, "InitOutput - Error reading config file\n"); +#else + winMsg(X_INFO, "xorg.conf is not supported\n"); + winMsg(X_INFO, "See http://x.cygwin.com/docs/faq/cygwin-x-faq.html " + "for more information\n"); + winConfigFiles (); +#endif + + /* Load preferences from XWinrc file */ + LoadPreferences(); + + /* Setup global screen info parameters */ + screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + screenInfo->numPixmapFormats = NUMFORMATS; + + /* Describe how we want common pixmap formats padded */ + for (i = 0; i < NUMFORMATS; i++) + { + screenInfo->formats[i] = g_PixmapFormats[i]; + } + + /* Load pointers to DirectDraw functions */ + winGetDDProcAddresses (); + + /* Detect supported engines */ + winDetectSupportedEngines (); + + /* Load common controls library */ + g_hmodCommonControls = LoadLibraryEx ("comctl32.dll", NULL, 0); + + /* Load TrackMouseEvent function pointer */ + g_fpTrackMouseEvent = GetProcAddress (g_hmodCommonControls, + "_TrackMouseEvent"); + if (g_fpTrackMouseEvent == NULL) + { + winErrorFVerb (1, "InitOutput - Could not get pointer to function\n" + "\t_TrackMouseEvent in comctl32.dll. Try installing\n" + "\tInternet Explorer 3.0 or greater if you have not\n" + "\talready.\n"); + + /* Free the library since we won't need it */ + FreeLibrary (g_hmodCommonControls); + g_hmodCommonControls = NULL; + + /* Set function pointer to point to no operation function */ + g_fpTrackMouseEvent = (FARPROC) (void (*)(void))NoopDDA; + } + + /* Store the instance handle */ + g_hInstance = GetModuleHandle (NULL); + + /* Initialize each screen */ + for (i = 0; i < g_iNumScreens; ++i) + { + /* Initialize the screen */ + if (-1 == AddScreen (winScreenInit, argc, argv)) + { + FatalError ("InitOutput - Couldn't add screen %d", i); + } + } + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + + /* Generate a cookie used by internal clients for authorization */ + if (g_fXdmcpEnabled || g_fAuthEnabled) + winGenerateAuthorization (); + + /* Perform some one time initialization */ + if (1 == serverGeneration) + { + /* + * setlocale applies to all threads in the current process. + * Apply locale specified in LANG environment variable. + */ + setlocale (LC_ALL, ""); + } +#endif + +#if CYGDEBUG || YES + winDebug ("InitOutput - Returning.\n"); +#endif +} + + +/* + * winCheckDisplayNumber - Check if another instance of Cygwin/X is + * already running on the same display number. If no one exists, + * make a mutex to prevent new instances from running on the same display. + * + * return FALSE if the display number is already used. + */ + +static Bool +winCheckDisplayNumber (void) +{ + int nDisp; + HANDLE mutex; + char name[MAX_PATH]; + char * pszPrefix = '\0'; + OSVERSIONINFO osvi = {0}; + + /* Check display range */ + nDisp = atoi (display); + if (nDisp < 0 || nDisp > 65535) + { + ErrorF ("winCheckDisplayNumber - Bad display number: %d\n", nDisp); + return FALSE; + } + + /* Set first character of mutex name to null */ + name[0] = '\0'; + + /* Get operating system version information */ + osvi.dwOSVersionInfoSize = sizeof (osvi); + GetVersionEx (&osvi); + + /* Want a mutex shared among all terminals on NT > 4.0 */ + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT + && osvi.dwMajorVersion >= 5) + { + pszPrefix = "Global\\"; + } + + /* Setup Cygwin/X specific part of name */ + snprintf (name, sizeof(name), "%sCYGWINX_DISPLAY:%d", pszPrefix, nDisp); + + /* Windows automatically releases the mutex when this process exits */ + mutex = CreateMutex (NULL, FALSE, name); + if (!mutex) + { + LPVOID lpMsgBuf; + + /* Display a fancy error message */ + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError (), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + ErrorF ("winCheckDisplayNumber - CreateMutex failed: %s\n", + (LPSTR)lpMsgBuf); + LocalFree (lpMsgBuf); + + return FALSE; + } + if (GetLastError () == ERROR_ALREADY_EXISTS) + { + ErrorF ("winCheckDisplayNumber - " + PROJECT_NAME " is already running on display %d\n", + nDisp); + return FALSE; + } + + return TRUE; +} diff --git a/xorg-server/hw/xwin/Makefile.am b/xorg-server/hw/xwin/Makefile.am index f6a75df2c..ce2edb2e6 100644 --- a/xorg-server/hw/xwin/Makefile.am +++ b/xorg-server/hw/xwin/Makefile.am @@ -87,6 +87,7 @@ SRCS = InitInput.c \ winkeybd.c \ winkeyhook.c \ winmisc.c \ + winmonitors.c \ winmouse.c \ winmsg.c \ winmultiwindowclass.c \ diff --git a/xorg-server/hw/xwin/man/XWin.man b/xorg-server/hw/xwin/man/XWin.man index 51268f69a..e7933c9c8 100644 --- a/xorg-server/hw/xwin/man/XWin.man +++ b/xorg-server/hw/xwin/man/XWin.man @@ -103,7 +103,7 @@ Examples: .SH OPTIONS CONTROLLING THE APPEARANCE OF THE X SCREEN WINDOWS These parameters only apply to windowed mode screens i.e. not -in \fB-multwindow\fP or \fB-rootless\fP mode +in \fB-multiwindow\fP or \fB-rootless\fP mode. .TP 8 .B "\-fullscreen" The X server window takes the full screen, covering completely the @@ -115,10 +115,52 @@ etc. This parameter is ignored when the \fB\-fullscreen\fP parameter is specified. .TP 8 .B \-scrollbars -In windowed mode, allow screens bigger than the \fIWindows\fP desktop. -Moreover, if the window has decorations, one can now resize it. -This parameter is ignored when the \fB\-fullscreen\fP parameter is specified. +Alternative name for \fB\-resize=scrollbars\fP. + +.SH OPTIONS CONTROLLING RESIZE BEHAVIOUR +.TP 8 +.B \-resize[=none|scrollbars|randr] +Select the resize mode of an X screen. + +.RS +.IP \fB\-resize=none\fP 8 +(default). The screen is not resizable. + +In windowed mode, if the window has decorations, a fixed frame is used. + +.IP \fB\-resize=scrollbars\fP 8 +The screen window is resizeable, but the screen is not resizable. + +In windowed mode, if the window has decorations, a resizing frame is used. +Scrollbars are drawn when needed to allow the entire X screen +to viewed by adjusting them. + +This also permits screens bigger than the \fIWindows\fP virtual desktop to be used. + +This parameter is ignored in \fB-multiwindow\fP or \fB-rootless\fP mode. +Alternative name is \fB\-scrollbars\fP. + +.IP \fB\-resize=randr\fP 8 +The screen is resizable and the screen window is resizeable. +In windowed mode, if the window has decorations, a resizing frame is used. + +Resizing the \fIWindows\fP window will use the RANDR extension to change +the size of the X screen. Likewise, changing the size of +the X screen using the RANDR extension will cause the size +of the \fIWindows\fP window containing the X screen to be changed. + +In \fB-multiwindow\fP or \fB-rootless\fP mode, if the X screen is +of the same dimensions as a Windows monitor or the virtual desktop, +the X server will respond to the WM_DISPLAYCHANGED sent when those +dimensions change by resizing the X screen. Changing the size +of the X screen using the RANDR extension is not permitted. + +The maximum dimensions of the screen are the dimensions of the \fIWindows\fP virtual desktop. + +.IP \fB\--resize\fP 8 +on its own is equivalent to \fB\--resize=randr\fP +.RE .SH OPTIONS CONTROLLING WINDOWS INTEGRATION .TP 8 @@ -190,15 +232,27 @@ respectively). .TP 8 .B "\-engine \fIengine_type_id\fP" This option, which is intended for Cygwin/X developers, -overrides the server's automatically selected engine type. This -parameter will be ignored if the specified engine type is not -supported on the current system. The supported engine type ids are 1 -- Shadow GDI, 2 - Shadow DirectDraw, and 4 - Shadow DirectDraw Non-Locking. -Additionally, there are engines with type ids -8 - Primary DirectDraw (obsolete) and 16 - Native GDI (experimental and barely functional). -Default behavior is to determine the engine with optimum performance that +overrides the server's automatically selected drawing engine type. This +parameter will be ignored if the specified drawing engine type is not +supported on the current system. + +Default behavior is to select the drawing engine with optimum performance that supports the specified depth and window configuration. +The engine type ids are: +.RS +.IP 1 4 +Shadow GDI +.IP 2 4 +Shadow DirectDraw +.IP 4 4 +Shadow DirectDraw Non-Locking +.IP 8 4 +Primary DirectDraw (unsupported, obsolete) +.IP 16 4 +Native GDI (unsupported, experimental and barely functional) +.RE + .SH FULLSCREEN OPTIONS .TP 8 .B "\-depth \fIdepth\fP" @@ -322,12 +376,9 @@ X(__miscmansuffix__), Xserver(1), xdm(1), xinit(1), XWinrc(__filemansuffix__), s .SH BUGS .I XWin -and this man page still have many limitations. Some of the more obvious -ones are: -.br -- The display mode can not be changed once the X server has started. -.br -- The \fIXWin\fP software is continuously developing; it is therefore possible that +and this man page still have many limitations. + +The \fIXWin\fP software is continuously developing; it is therefore possible that this man page is not up to date. It is always prudent to look also at the output of \fIXWin -help\fP in order to check the options that are operative. diff --git a/xorg-server/hw/xwin/win.h b/xorg-server/hw/xwin/win.h index e790d2d73..3f40fdbe0 100644 --- a/xorg-server/hw/xwin/win.h +++ b/xorg-server/hw/xwin/win.h @@ -1,1459 +1,1491 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - * Kensuke Matsuzaki - */ - -#ifndef _WIN_H_ -#define _WIN_H_ - -#ifndef NO -#define NO 0 -#endif -#ifndef YES -#define YES 1 -#endif - -/* Turn debug messages on or off */ -#ifndef CYGDEBUG -#define CYGDEBUG NO -#endif - -/* WM_XBUTTON Messages. They should go into w32api. */ -#ifndef WM_XBUTTONDOWN -# define WM_XBUTTONDOWN 523 -#endif -#ifndef WM_XBUTTONUP -# define WM_XBUTTONUP 524 -#endif -#ifndef WM_XBUTTONDBLCLK -# define WM_XBUTTONDBLCLK 525 -#endif - - -#define WIN_DEFAULT_BPP 0 -#define WIN_DEFAULT_WHITEPIXEL 255 -#define WIN_DEFAULT_BLACKPIXEL 0 -#define WIN_DEFAULT_LINEBIAS 0 -#define WIN_DEFAULT_E3B_TIME 50 /* milliseconds */ -#define WIN_DEFAULT_DPI 75 -#define WIN_DEFAULT_REFRESH 0 -#define WIN_DEFAULT_WIN_KILL TRUE -#define WIN_DEFAULT_UNIX_KILL FALSE -#define WIN_DEFAULT_CLIP_UPDATES_NBOXES 0 -#ifdef XWIN_EMULATEPSEUDO -#define WIN_DEFAULT_EMULATE_PSEUDO FALSE -#endif -#define WIN_DEFAULT_USER_GAVE_HEIGHT_AND_WIDTH FALSE - -#define WIN_DIB_MAXIMUM_SIZE 0x08000000 /* 16 MB on Windows 95, 98, Me */ -#define WIN_DIB_MAXIMUM_SIZE_MB (WIN_DIB_MAXIMUM_SIZE / 8 / 1024 / 1024) - -/* - * Windows only supports 256 color palettes - */ -#define WIN_NUM_PALETTE_ENTRIES 256 - -/* - * Number of times to call Restore in an attempt to restore the primary surface - */ -#define WIN_REGAIN_SURFACE_RETRIES 1 - -/* - * Build a supported display depths mask by shifting one to the left - * by the number of bits in the supported depth. - */ -#define WIN_SUPPORTED_BPPS ( (1 << (32 - 1)) | (1 << (24 - 1)) \ - | (1 << (16 - 1)) | (1 << (15 - 1)) \ - | (1 << ( 8 - 1))) -#define WIN_CHECK_DEPTH YES - -/* - * Timer IDs for WM_TIMER - */ -#define WIN_E3B_TIMER_ID 1 -#define WIN_POLLING_MOUSE_TIMER_ID 2 - -#define MOUSE_POLLING_INTERVAL 50 - -#define WIN_E3B_OFF -1 -#define WIN_FD_INVALID -1 - -#define WIN_SERVER_NONE 0x0L /* 0 */ -#define WIN_SERVER_SHADOW_GDI 0x1L /* 1 */ -#define WIN_SERVER_SHADOW_DD 0x2L /* 2 */ -#define WIN_SERVER_SHADOW_DDNL 0x4L /* 4 */ -#ifdef XWIN_PRIMARYFB -#define WIN_SERVER_PRIMARY_DD 0x8L /* 8 */ -#endif -#ifdef XWIN_NATIVEGDI -# define WIN_SERVER_NATIVE_GDI 0x10L /* 16 */ -#endif - -#define AltMapIndex Mod1MapIndex -#define NumLockMapIndex Mod2MapIndex -#define AltLangMapIndex Mod3MapIndex -#define KanaMapIndex Mod4MapIndex -#define ScrollLockMapIndex Mod5MapIndex - -#define WIN_MOD_LALT 0x00000001 -#define WIN_MOD_RALT 0x00000002 -#define WIN_MOD_LCONTROL 0x00000004 -#define WIN_MOD_RCONTROL 0x00000008 - -#define WIN_24BPP_MASK_RED 0x00FF0000 -#define WIN_24BPP_MASK_GREEN 0x0000FF00 -#define WIN_24BPP_MASK_BLUE 0x000000FF - -#define WIN_MAX_KEYS_PER_KEY 4 - -#include -#include -#include - -#include -#if defined(XWIN_MULTIWINDOWEXTWM) || defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) -#define HANDLE void * -#include -#undef HANDLE -#endif - -#ifdef HAS_MMAP -#include -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif /* MAP_FILE */ -#endif /* HAS_MMAP */ - -#include -#include -#include -#include -#include "scrnintstr.h" -#include "pixmapstr.h" -#include "pixmap.h" -#include "region.h" -#include "gcstruct.h" -#include "colormap.h" -#include "colormapst.h" -#include "miscstruct.h" -#include "servermd.h" -#include "windowstr.h" -#include "mi.h" -#include "micmap.h" -#include "mifillarc.h" -#include "mifpoly.h" -#include "mibstore.h" -#include "input.h" -#include "mipointer.h" -#include "X11/keysym.h" -#include "mibstore.h" -#include "micoord.h" -#include "dix.h" -#include "miline.h" -#include "shadow.h" -#include "fb.h" -#include "rootless.h" - -#include "mipict.h" -#include "picturestr.h" - -#ifdef RANDR -#include "randrstr.h" -#endif - -/* - * Windows headers - */ -#include "winms.h" -#include "winresource.h" - - -/* - * Define Windows constants - */ - -#define WM_TRAYICON (WM_USER + 1000) -#define WM_INIT_SYS_MENU (WM_USER + 1001) -#define WM_GIVEUP (WM_USER + 1002) - - -/* Local includes */ -#include "winwindow.h" -#include "winmsg.h" - - -/* - * Debugging macros - */ - -#if CYGDEBUG -#define DEBUG_MSG(str,...) \ -if (fDebugProcMsg) \ -{ \ - char *pszTemp; \ - int iLength; \ - if (asprintf (&pszTemp, str, ##__VA_ARGS__) != -1) { \ - MessageBox (NULL, pszTemp, szFunctionName, MB_OK); \ - free (pszTemp); \ - } \ -} -#else -#define DEBUG_MSG(str,...) -#endif - -#if CYGDEBUG -#define DEBUG_FN_NAME(str) PTSTR szFunctionName = str -#else -#define DEBUG_FN_NAME(str) -#endif - -#if CYGDEBUG || YES -#define DEBUGVARS BOOL fDebugProcMsg = FALSE -#else -#define DEBUGVARS -#endif - -#if CYGDEBUG || YES -#define DEBUGPROC_MSG fDebugProcMsg = TRUE -#else -#define DEBUGPROC_MSG -#endif - -#define PROFILEPOINT(point,thresh)\ -{\ -static unsigned int PROFPT##point = 0;\ -if (++PROFPT##point % thresh == 0)\ -ErrorF (#point ": PROFILEPOINT hit %u times\n", PROFPT##point);\ -} - - -/* We use xor this macro for detecting toggle key state changes */ -#define WIN_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) - -#define DEFINE_ATOM_HELPER(func,atom_name) \ -static Atom func (void) { \ - static int generation; \ - static Atom atom; \ - if (generation != serverGeneration) { \ - generation = serverGeneration; \ - atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ - } \ - return atom; \ -} - -/* - * Typedefs for engine dependent function pointers - */ - -typedef Bool (*winAllocateFBProcPtr)(ScreenPtr); - -typedef void (*winShadowUpdateProcPtr)(ScreenPtr, shadowBufPtr); - -typedef Bool (*winCloseScreenProcPtr)(int, ScreenPtr); - -typedef Bool (*winInitVisualsProcPtr)(ScreenPtr); - -typedef Bool (*winAdjustVideoModeProcPtr)(ScreenPtr); - -typedef Bool (*winCreateBoundingWindowProcPtr)(ScreenPtr); - -typedef Bool (*winFinishScreenInitProcPtr)(int, ScreenPtr, int, char **); - -typedef Bool (*winBltExposedRegionsProcPtr)(ScreenPtr); - -typedef Bool (*winActivateAppProcPtr)(ScreenPtr); - -typedef Bool (*winRedrawScreenProcPtr)(ScreenPtr pScreen); - -typedef Bool (*winRealizeInstalledPaletteProcPtr)(ScreenPtr pScreen); - -typedef Bool (*winInstallColormapProcPtr)(ColormapPtr pColormap); - -typedef Bool (*winStoreColorsProcPtr)(ColormapPtr pmap, - int ndef, xColorItem *pdefs); - -typedef Bool (*winCreateColormapProcPtr)(ColormapPtr pColormap); - -typedef Bool (*winDestroyColormapProcPtr)(ColormapPtr pColormap); - -typedef Bool (*winHotKeyAltTabProcPtr)(ScreenPtr); - -typedef Bool (*winCreatePrimarySurfaceProcPtr)(ScreenPtr); - -typedef Bool (*winReleasePrimarySurfaceProcPtr)(ScreenPtr); - -typedef Bool (*winFinishCreateWindowsWindowProcPtr)(WindowPtr pWin); - -typedef Bool (*winCreateScreenResourcesProc)(ScreenPtr); - - -/* - * GC (graphics context) privates - */ - -typedef struct -{ - HDC hdc; - HDC hdcMem; -} winPrivGCRec, *winPrivGCPtr; - - -/* - * Pixmap privates - */ - -typedef struct -{ - HDC hdcSelected; - HBITMAP hBitmap; - BYTE *pbBits; - DWORD dwScanlineBytes; - BITMAPINFOHEADER *pbmih; -} winPrivPixmapRec, *winPrivPixmapPtr; - - -/* - * Colormap privates - */ - -typedef struct -{ - HPALETTE hPalette; - LPDIRECTDRAWPALETTE lpDDPalette; - RGBQUAD rgbColors[WIN_NUM_PALETTE_ENTRIES]; - PALETTEENTRY peColors[WIN_NUM_PALETTE_ENTRIES]; -} winPrivCmapRec, *winPrivCmapPtr; - -/* - * Windows Cursor handling. - */ - -typedef struct { - /* from GetSystemMetrics */ - int sm_cx; - int sm_cy; - - BOOL visible; - HCURSOR handle; - QueryBestSizeProcPtr QueryBestSize; - miPointerSpriteFuncPtr spriteFuncs; -} winCursorRec; - -/* - * Screen information structure that we need before privates are available - * in the server startup sequence. - */ - -typedef struct -{ - ScreenPtr pScreen; - - /* Did the user specify a height and width? */ - Bool fUserGaveHeightAndWidth; - - DWORD dwScreen; - DWORD dwUserWidth; - DWORD dwUserHeight; - DWORD dwWidth; - DWORD dwHeight; - DWORD dwWidth_mm; - DWORD dwHeight_mm; - DWORD dwPaddedWidth; - - /* Did the user specify a screen position? */ - Bool fUserGavePosition; - DWORD dwInitialX; - DWORD dwInitialY; - - /* - * dwStride is the number of whole pixels that occupy a scanline, - * including those pixels that are not displayed. This is basically - * a rounding up of the width. - */ - DWORD dwStride; - - /* Offset of the screen in the window when using scrollbars */ - DWORD dwXOffset; - DWORD dwYOffset; - - DWORD dwBPP; - DWORD dwDepth; - DWORD dwRefreshRate; - char *pfb; - DWORD dwEngine; - DWORD dwEnginePreferred; - DWORD dwClipUpdatesNBoxes; -#ifdef XWIN_EMULATEPSEUDO - Bool fEmulatePseudo; -#endif - Bool fFullScreen; - Bool fDecoration; -#ifdef XWIN_MULTIWINDOWEXTWM - Bool fMWExtWM; - Bool fInternalWM; - Bool fAnotherWMRunning; -#endif - Bool fRootless; -#ifdef XWIN_MULTIWINDOW - Bool fMultiWindow; -#endif -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - Bool fMultiMonitorOverride; -#endif - Bool fMultipleMonitors; - Bool fLessPointer; - Bool fScrollbars; - Bool fNoTrayIcon; - int iE3BTimeout; - /* Windows (Alt+F4) and Unix (Ctrl+Alt+Backspace) Killkey */ - Bool fUseWinKillKey; - Bool fUseUnixKillKey; - Bool fIgnoreInput; - - /* Did the user explicitly set this screen? */ - Bool fExplicitScreen; -} winScreenInfo, *winScreenInfoPtr; - - -/* - * Screen privates - */ - -typedef struct _winPrivScreenRec -{ - winScreenInfoPtr pScreenInfo; - - Bool fEnabled; - Bool fClosed; - Bool fActive; - Bool fBadDepth; - - int iDeltaZ; - - int iConnectedClients; - - CloseScreenProcPtr CloseScreen; - - DWORD dwRedMask; - DWORD dwGreenMask; - DWORD dwBlueMask; - DWORD dwBitsPerRGB; - - DWORD dwModeKeyStates; - - /* Handle to icons that must be freed */ - HICON hiconNotifyIcon; - - /* Last width, height, and depth of the Windows display */ - DWORD dwLastWindowsWidth; - DWORD dwLastWindowsHeight; - DWORD dwLastWindowsBitsPixel; - - /* Palette management */ - ColormapPtr pcmapInstalled; - - /* Pointer to the root visual so we only have to look it up once */ - VisualPtr pRootVisual; - - /* 3 button emulation variables */ - int iE3BCachedPress; - Bool fE3BFakeButton2Sent; - - /* Privates used by shadow fb GDI server */ - HBITMAP hbmpShadow; - HDC hdcScreen; - HDC hdcShadow; - HWND hwndScreen; - - /* Privates used by shadow fb and primary fb DirectDraw servers */ - LPDIRECTDRAW pdd; - LPDIRECTDRAWSURFACE2 pddsPrimary; - LPDIRECTDRAW2 pdd2; - - /* Privates used by shadow fb DirectDraw server */ - LPDIRECTDRAWSURFACE2 pddsShadow; - LPDDSURFACEDESC pddsdShadow; - - /* Privates used by primary fb DirectDraw server */ - LPDIRECTDRAWSURFACE2 pddsOffscreen; - LPDDSURFACEDESC pddsdOffscreen; - LPDDSURFACEDESC pddsdPrimary; - - /* Privates used by shadow fb DirectDraw Nonlocking server */ - LPDIRECTDRAW4 pdd4; - LPDIRECTDRAWSURFACE4 pddsShadow4; - LPDIRECTDRAWSURFACE4 pddsPrimary4; - BOOL fRetryCreateSurface; - - /* Privates used by both shadow fb DirectDraw servers */ - LPDIRECTDRAWCLIPPER pddcPrimary; - -#ifdef XWIN_MULTIWINDOWEXTWM - /* Privates used by multi-window external window manager */ - RootlessFrameID widTop; - Bool fRestacking; -#endif - -#ifdef XWIN_MULTIWINDOW - /* Privates used by multi-window */ - pthread_t ptWMProc; - pthread_t ptXMsgProc; - void *pWMInfo; -#endif - -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - /* Privates used by both multi-window and rootless */ - Bool fRootWindowShown; -#endif - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - /* Privates used for any module running in a seperate thread */ - pthread_mutex_t pmServerStarted; - Bool fServerStarted; -#endif - - /* Engine specific functions */ - winAllocateFBProcPtr pwinAllocateFB; - winShadowUpdateProcPtr pwinShadowUpdate; - winCloseScreenProcPtr pwinCloseScreen; - winInitVisualsProcPtr pwinInitVisuals; - winAdjustVideoModeProcPtr pwinAdjustVideoMode; - winCreateBoundingWindowProcPtr pwinCreateBoundingWindow; - winFinishScreenInitProcPtr pwinFinishScreenInit; - winBltExposedRegionsProcPtr pwinBltExposedRegions; - winActivateAppProcPtr pwinActivateApp; - winRedrawScreenProcPtr pwinRedrawScreen; - winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette; - winInstallColormapProcPtr pwinInstallColormap; - winStoreColorsProcPtr pwinStoreColors; - winCreateColormapProcPtr pwinCreateColormap; - winDestroyColormapProcPtr pwinDestroyColormap; - winHotKeyAltTabProcPtr pwinHotKeyAltTab; - winCreatePrimarySurfaceProcPtr pwinCreatePrimarySurface; - winReleasePrimarySurfaceProcPtr pwinReleasePrimarySurface; - - winCreateScreenResourcesProc pwinCreateScreenResources; - -#ifdef XWIN_MULTIWINDOW - /* Window Procedures for MultiWindow mode */ - winFinishCreateWindowsWindowProcPtr pwinFinishCreateWindowsWindow; -#endif - - /* Window Procedures for Rootless mode */ - CreateWindowProcPtr CreateWindow; - DestroyWindowProcPtr DestroyWindow; - PositionWindowProcPtr PositionWindow; - ChangeWindowAttributesProcPtr ChangeWindowAttributes; - RealizeWindowProcPtr RealizeWindow; - UnrealizeWindowProcPtr UnrealizeWindow; - ValidateTreeProcPtr ValidateTree; - PostValidateTreeProcPtr PostValidateTree; - WindowExposuresProcPtr WindowExposures; - CopyWindowProcPtr CopyWindow; - ClearToBackgroundProcPtr ClearToBackground; - ClipNotifyProcPtr ClipNotify; - RestackWindowProcPtr RestackWindow; - ReparentWindowProcPtr ReparentWindow; - ResizeWindowProcPtr ResizeWindow; - MoveWindowProcPtr MoveWindow; - SetShapeProcPtr SetShape; - - winCursorRec cursor; -} winPrivScreenRec; - - -#ifdef XWIN_MULTIWINDOWEXTWM -typedef struct { - RootlessWindowPtr pFrame; - HWND hWnd; - int dwWidthBytes; - BITMAPINFOHEADER *pbmihShadow; - HBITMAP hbmpShadow; - HDC hdcShadow; - HDC hdcScreen; - BOOL fResized; - BOOL fRestackingNow; - BOOL fClose; - BOOL fMovingOrSizing; - BOOL fDestroyed;//for debug - char *pfb; -} win32RootlessWindowRec, *win32RootlessWindowPtr; -#endif - - -typedef struct { - pointer value; - XID id; -} WindowIDPairRec, *WindowIDPairPtr; - - -/* - * Extern declares for general global variables - */ - -#include "winglobals.h" - -extern winScreenInfo * g_ScreenInfo; -extern miPointerScreenFuncRec g_winPointerCursorFuncs; -extern DWORD g_dwEvents; -#ifdef HAS_DEVWINDOWS -extern int g_fdMessageQueue; -#endif -extern DevPrivateKeyRec g_iScreenPrivateKeyRec; -#define g_iScreenPrivateKey (&g_iScreenPrivateKeyRec) -extern DevPrivateKeyRec g_iCmapPrivateKeyRec; -#define g_iCmapPrivateKey (&g_iCmapPrivateKeyRec) -extern DevPrivateKeyRec g_iGCPrivateKeyRec; -#define g_iGCPrivateKey (&g_iGCPrivateKeyRec) -extern DevPrivateKeyRec g_iPixmapPrivateKeyRec; -#define g_iPixmapPrivateKey (&g_iPixmapPrivateKeyRec) -extern DevPrivateKeyRec g_iWindowPrivateKeyRec; -#define g_iWindowPrivateKey (&g_iWindowPrivateKeyRec) - -extern unsigned long g_ulServerGeneration; -extern DWORD g_dwEnginesSupported; -extern HINSTANCE g_hInstance; -extern int g_copyROP[]; -extern int g_patternROP[]; -extern const char * g_pszQueryHost; -extern DeviceIntPtr g_pwinPointer; -extern DeviceIntPtr g_pwinKeyboard; - -/* - * Extern declares for dynamically loaded library function pointers - */ - -extern FARPROC g_fpDirectDrawCreate; -extern FARPROC g_fpDirectDrawCreateClipper; -extern FARPROC g_fpTrackMouseEvent; - - -/* - * Screen privates macros - */ - -#define winGetScreenPriv(pScreen) ((winPrivScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey)) - -#define winSetScreenPriv(pScreen,v) \ - dixSetPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey, v) - -#define winScreenPriv(pScreen) \ - winPrivScreenPtr pScreenPriv = winGetScreenPriv(pScreen) - - -/* - * Colormap privates macros - */ - -#define winGetCmapPriv(pCmap) ((winPrivCmapPtr) \ - dixLookupPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey)) - -#define winSetCmapPriv(pCmap,v) \ - dixSetPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey, v) - -#define winCmapPriv(pCmap) \ - winPrivCmapPtr pCmapPriv = winGetCmapPriv(pCmap) - - -/* - * GC privates macros - */ - -#define winGetGCPriv(pGC) ((winPrivGCPtr) \ - dixLookupPrivate(&(pGC)->devPrivates, g_iGCPrivateKey)) - -#define winSetGCPriv(pGC,v) \ - dixSetPrivate(&(pGC)->devPrivates, g_iGCPrivateKey, v) - -#define winGCPriv(pGC) \ - winPrivGCPtr pGCPriv = winGetGCPriv(pGC) - - -/* - * Pixmap privates macros - */ - -#define winGetPixmapPriv(pPixmap) ((winPrivPixmapPtr) \ - dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey)) - -#define winSetPixmapPriv(pPixmap,v) \ - dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey, v) - -#define winPixmapPriv(pPixmap) \ - winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap) - - -/* - * Window privates macros - */ - -#define winGetWindowPriv(pWin) ((winPrivWinPtr) \ - dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey)) - -#define winSetWindowPriv(pWin,v) \ - dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey, v) - -#define winWindowPriv(pWin) \ - winPrivWinPtr pWinPriv = winGetWindowPriv(pWin) - -/* - * wrapper macros - */ -#define _WIN_WRAP(priv, real, mem, func) {\ - priv->mem = real->mem; \ - real->mem = func; \ -} - -#define _WIN_UNWRAP(priv, real, mem) {\ - real->mem = priv->mem; \ -} - -#define WIN_WRAP(mem, func) _WIN_WRAP(pScreenPriv, pScreen, mem, func) - -#define WIN_UNWRAP(mem) _WIN_UNWRAP(pScreenPriv, pScreen, mem) - -/* - * BEGIN DDX and DIX Function Prototypes - */ - - -/* - * winallpriv.c - */ - -Bool -winAllocatePrivates (ScreenPtr pScreen); - -Bool -winInitCmapPrivates (ColormapPtr pCmap, int index); - -Bool -winAllocateCmapPrivates (ColormapPtr pCmap); - - -/* - * winauth.c - */ - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) -Bool -winGenerateAuthorization (void); -void winSetAuthorization(void); -#endif - - -/* - * winblock.c - */ - -void -winBlockHandler (int nScreen, - pointer pBlockData, - pointer pTimeout, - pointer pReadMask); - - -#ifdef XWIN_NATIVEGDI -/* - * winclip.c - */ - -RegionPtr -winPixmapToRegionNativeGDI (PixmapPtr pPix); -#endif - - -#ifdef XWIN_CLIPBOARD -/* - * winclipboardinit.c - */ - -Bool -winInitClipboard (void); - -void -winFixClipboardChain (void); -#endif - - -/* - * wincmap.c - */ - -void -winSetColormapFunctions (ScreenPtr pScreen); - -Bool -winCreateDefColormap (ScreenPtr pScreen); - - -/* - * wincreatewnd.c - */ - -Bool -winCreateBoundingWindowFullScreen (ScreenPtr pScreen); - -Bool -winCreateBoundingWindowWindowed (ScreenPtr pScreen); - - -/* - * windialogs.c - */ - -void -winDisplayExitDialog (winPrivScreenPtr pScreenPriv); - -void -winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv); - -void -winDisplayAboutDialog (winPrivScreenPtr pScreenPriv); - - -/* - * winengine.c - */ - -void -winDetectSupportedEngines (void); - -Bool -winSetEngine (ScreenPtr pScreen); - -Bool -winGetDDProcAddresses (void); - -void -winReleaseDDProcAddresses(void); - - -/* - * winerror.c - */ - -#ifdef DDXOSVERRORF -void -OSVenderVErrorF (const char *pszFormat, va_list va_args); -#endif - -void -winMessageBoxF (const char *pszError, UINT uType, ...); - - -#ifdef XWIN_NATIVEGDI -/* - * winfillsp.c - */ - -void -winFillSpansNativeGDI (DrawablePtr pDrawable, - GCPtr pGC, - int nSpans, - DDXPointPtr pPoints, - int *pWidths, - int fSorted); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winfont.c - */ - -Bool -winRealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); - -Bool -winUnrealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * wingc.c - */ - -Bool -winCreateGCNativeGDI (GCPtr pGC); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * wingetsp.c - */ - -void -winGetSpansNativeGDI (DrawablePtr pDrawable, - int wMax, - DDXPointPtr pPoints, - int *pWidths, - int nSpans, - char *pDst); -#endif - - -/* - * winglobals.c - */ - -void -winInitializeGlobals (void); - - -/* - * winkeybd.c - */ - -void -winTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode); - -int -winKeybdProc (DeviceIntPtr pDeviceInt, int iState); - -void -winInitializeModeKeyStates (void); - -void -winRestoreModeKeyStates (void); - -Bool -winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam); - -void -winKeybdReleaseKeys (void); - -void -winSendKeyEvent (DWORD dwKey, Bool fDown); - -BOOL -winCheckKeyPressed(WPARAM wParam, LPARAM lParam); - -void -winFixShiftKeys (int iScanCode); - -/* - * winkeyhook.c - */ - -Bool -winInstallKeyboardHookLL (void); - -void -winRemoveKeyboardHookLL (void); - - -/* - * winmisc.c - */ - -#ifdef XWIN_NATIVEGDI -void -winQueryBestSizeNativeGDI (int class, unsigned short *pWidth, - unsigned short *pHeight, ScreenPtr pScreen); -#endif - -CARD8 -winCountBits (DWORD dw); - -Bool -winUpdateFBPointer (ScreenPtr pScreen, void *pbits); - -#ifdef XWIN_NATIVEGDI -BOOL -winPaintBackground (HWND hwnd, COLORREF colorref); -#endif - - -/* - * winmouse.c - */ - -int -winMouseProc (DeviceIntPtr pDeviceInt, int iState); - -int -winMouseWheel (ScreenPtr pScreen, int iDeltaZ); - -void -winMouseButtonsSendEvent (int iEventType, int iButton); - -int -winMouseButtonsHandle (ScreenPtr pScreen, - int iEventType, int iButton, - WPARAM wParam); - -void -winEnqueueMotion(int x, int y); - -#ifdef XWIN_NATIVEGDI -/* - * winnativegdi.c - */ - -HBITMAP -winCreateDIBNativeGDI (int iWidth, int iHeight, int iDepth, - BYTE **ppbBits, BITMAPINFO **ppbmi); - -Bool -winSetEngineFunctionsNativeGDI (ScreenPtr pScreen); -#endif - - -#ifdef XWIN_PRIMARYFB -/* - * winpfbddd.c - */ - -Bool -winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winpixmap.c - */ - -PixmapPtr -winCreatePixmapNativeGDI (ScreenPtr pScreen, int width, int height, int depth, - unsigned usage_hint); - -Bool -winDestroyPixmapNativeGDI (PixmapPtr pPixmap); - -Bool -winModifyPixmapHeaderNativeGDI (PixmapPtr pPixmap, - int iWidth, int iHeight, - int iDepth, - int iBitsPerPixel, - int devKind, - pointer pPixData); -#endif - -#ifdef XWIN_NATIVEGDI -/* - * winpolyline.c - */ - -void -winPolyLineNativeGDI (DrawablePtr pDrawable, - GCPtr pGC, - int mode, - int npt, - DDXPointPtr ppt); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winpushpxl.c - */ - -void -winPushPixels (GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, - int dx, int dy, int xOrg, int yOrg); -#endif - - -/* - * winscrinit.c - */ - -Bool -winScreenInit (int index, - ScreenPtr pScreen, - int argc, char **argv); - -Bool -winFinishScreenInitFB (int index, - ScreenPtr pScreen, - int argc, char **argv); - -#if defined(XWIN_NATIVEGDI) -Bool -winFinishScreenInitNativeGDI (int index, - ScreenPtr pScreen, - int argc, char **argv); -#endif - - -#ifdef XWIN_NATIVEGDI -/* - * winsetsp.c - */ - -void -winSetSpansNativeGDI (DrawablePtr pDrawable, - GCPtr pGC, - char *pSrc, - DDXPointPtr pPoints, - int *pWidth, - int nSpans, - int fSorted); -#endif - - -/* - * winshaddd.c - */ - -Bool -winSetEngineFunctionsShadowDD (ScreenPtr pScreen); - - -/* - * winshadddnl.c - */ - -Bool -winSetEngineFunctionsShadowDDNL (ScreenPtr pScreen); - - -/* - * winshadgdi.c - */ - -Bool -winSetEngineFunctionsShadowGDI (ScreenPtr pScreen); - - -/* - * winwakeup.c - */ - -void -winWakeupHandler (int nScreen, - pointer pWakeupData, - unsigned long ulResult, - pointer pReadmask); - - -/* - * winwindow.c - */ - -#ifdef XWIN_NATIVEGDI -Bool -winCreateWindowNativeGDI (WindowPtr pWin); - -Bool -winDestroyWindowNativeGDI (WindowPtr pWin); - -Bool -winPositionWindowNativeGDI (WindowPtr pWin, int x, int y); - -void -winCopyWindowNativeGDI (WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc); - -Bool -winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask); - -Bool -winUnmapWindowNativeGDI (WindowPtr pWindow); - -Bool -winMapWindowNativeGDI (WindowPtr pWindow); -#endif - -Bool -winCreateWindowRootless (WindowPtr pWindow); - -Bool -winDestroyWindowRootless (WindowPtr pWindow); - -Bool -winPositionWindowRootless (WindowPtr pWindow, int x, int y); - -Bool -winChangeWindowAttributesRootless (WindowPtr pWindow, unsigned long mask); - -Bool -winUnmapWindowRootless (WindowPtr pWindow); - -Bool -winMapWindowRootless (WindowPtr pWindow); - -void -winSetShapeRootless (WindowPtr pWindow, int kind); - - -/* - * winmultiwindowicons.c - Used by both multi-window and Win32Rootless - */ - -HICON -winXIconToHICON (WindowPtr pWin, int iconSize); - -void -winSelectIcons(WindowPtr pWin, HICON *pIcon, HICON *pSmallIcon); - -#ifdef XWIN_MULTIWINDOW -/* - * winmultiwindowshape.c - */ - -void -winReshapeMultiWindow (WindowPtr pWin); - -void -winSetShapeMultiWindow (WindowPtr pWindow, int kind); - -void -winUpdateRgnMultiWindow (WindowPtr pWindow); -#endif - - -#ifdef XWIN_MULTIWINDOW -/* - * winmultiwindowwindow.c - */ - -Bool -winCreateWindowMultiWindow (WindowPtr pWindow); - -Bool -winDestroyWindowMultiWindow (WindowPtr pWindow); - -Bool -winPositionWindowMultiWindow (WindowPtr pWindow, int x, int y); - -Bool -winChangeWindowAttributesMultiWindow (WindowPtr pWindow, unsigned long mask); - -Bool -winUnmapWindowMultiWindow (WindowPtr pWindow); - -Bool -winMapWindowMultiWindow (WindowPtr pWindow); - -void -winReparentWindowMultiWindow (WindowPtr pWin, WindowPtr pPriorParent); - -void -winRestackWindowMultiWindow (WindowPtr pWin, WindowPtr pOldNextSib); - -void -winReorderWindowsMultiWindow (void); - -void -winResizeWindowMultiWindow (WindowPtr pWin, int x, int y, unsigned int w, - unsigned int h, WindowPtr pSib); -void -winMoveWindowMultiWindow (WindowPtr pWin, int x, int y, - WindowPtr pSib, VTKind kind); - -void -winCopyWindowMultiWindow (WindowPtr pWin, DDXPointRec oldpt, - RegionPtr oldRegion); - -XID -winGetWindowID (WindowPtr pWin); - -int -winAdjustXWindow (WindowPtr pWin, HWND hwnd); -#endif - - -#ifdef XWIN_MULTIWINDOW -/* - * winmultiwindowwndproc.c - */ - -LRESULT CALLBACK -winTopLevelWindowProc (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam); -#endif - - -/* - * wintrayicon.c - */ - -void -winInitNotifyIcon (winPrivScreenPtr pScreenPriv); - -void -winDeleteNotifyIcon (winPrivScreenPtr pScreenPriv); - -LRESULT -winHandleIconMessage (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam, - winPrivScreenPtr pScreenPriv); - - -/* - * winwndproc.c - */ - -LRESULT CALLBACK -winWindowProc (HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam); - - -#ifdef XWIN_MULTIWINDOWEXTWM -/* - * winwin32rootless.c - */ - -Bool -winMWExtWMCreateFrame (RootlessWindowPtr pFrame, ScreenPtr pScreen, - int newX, int newY, RegionPtr pShape); - -void -winMWExtWMDestroyFrame (RootlessFrameID wid); - -void -winMWExtWMMoveFrame (RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); - -void -winMWExtWMResizeFrame (RootlessFrameID wid, ScreenPtr pScreen, - int newX, int newY, unsigned int newW, unsigned int newH, - unsigned int gravity); - -void -winMWExtWMRestackFrame (RootlessFrameID wid, RootlessFrameID nextWid); - -void -winMWExtWMReshapeFrame (RootlessFrameID wid, RegionPtr pShape); - -void -winMWExtWMUnmapFrame (RootlessFrameID wid); - -void -winMWExtWMStartDrawing (RootlessFrameID wid, char **pixelData, int *bytesPerRow); - -void -winMWExtWMStopDrawing (RootlessFrameID wid, Bool flush); - -void -winMWExtWMUpdateRegion (RootlessFrameID wid, RegionPtr pDamage); - -void -winMWExtWMDamageRects (RootlessFrameID wid, int count, const BoxRec *rects, - int shift_x, int shift_y); - -void -winMWExtWMRootlessSwitchWindow (RootlessWindowPtr pFrame, WindowPtr oldWin); - -void -winMWExtWMCopyBytes (unsigned int width, unsigned int height, - const void *src, unsigned int srcRowBytes, - void *dst, unsigned int dstRowBytes); - -void -winMWExtWMCopyWindow (RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, - int dx, int dy); -#endif - - -#ifdef XWIN_MULTIWINDOWEXTWM -/* - * winwin32rootlesswindow.c - */ - -void -winMWExtWMReorderWindows (ScreenPtr pScreen); - -void -winMWExtWMMoveXWindow (WindowPtr pWin, int x, int y); - -void -winMWExtWMResizeXWindow (WindowPtr pWin, int w, int h); - -void -winMWExtWMMoveResizeXWindow (WindowPtr pWin, int x, int y, int w, int h); - -void -winMWExtWMUpdateIcon (Window id); - -void -winMWExtWMUpdateWindowDecoration (win32RootlessWindowPtr pRLWinPriv, - winScreenInfoPtr pScreenInfo); - -wBOOL CALLBACK -winMWExtWMDecorateWindow (HWND hwnd, LPARAM lParam); - -Bool -winIsInternalWMRunning (winScreenInfoPtr pScreenInfo); - -void -winMWExtWMRestackWindows (ScreenPtr pScreen); -#endif - - -#ifdef XWIN_MULTIWINDOWEXTWM -/* - * winwin32rootlesswndproc.c - */ - -LRESULT CALLBACK -winMWExtWMWindowProc (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam); -#endif - - -/* - * winwindowswm.c - */ - -void -winWindowsWMSendEvent (int type, unsigned int mask, int which, int arg, - Window window, int x, int y, int w, int h); - -void -winWindowsWMExtensionInit (void); - -/* - * wincursor.c - */ - -Bool -winInitCursor (ScreenPtr pScreen); - -/* - * winprocarg.c - */ -void -winInitializeScreens(int maxscreens); - -/* - * END DDX and DIX Function Prototypes - */ - -#endif /* _WIN_H_ */ - +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + * Kensuke Matsuzaki + */ + +#ifndef _WIN_H_ +#define _WIN_H_ + +#ifndef NO +#define NO 0 +#endif +#ifndef YES +#define YES 1 +#endif + +/* Turn debug messages on or off */ +#ifndef CYGDEBUG +#define CYGDEBUG NO +#endif + +/* WM_XBUTTON Messages. They should go into w32api. */ +#ifndef WM_XBUTTONDOWN +# define WM_XBUTTONDOWN 523 +#endif +#ifndef WM_XBUTTONUP +# define WM_XBUTTONUP 524 +#endif +#ifndef WM_XBUTTONDBLCLK +# define WM_XBUTTONDBLCLK 525 +#endif + + +#define WIN_DEFAULT_BPP 0 +#define WIN_DEFAULT_WHITEPIXEL 255 +#define WIN_DEFAULT_BLACKPIXEL 0 +#define WIN_DEFAULT_LINEBIAS 0 +#define WIN_DEFAULT_E3B_TIME 50 /* milliseconds */ +#define WIN_DEFAULT_DPI 75 +#define WIN_DEFAULT_REFRESH 0 +#define WIN_DEFAULT_WIN_KILL TRUE +#define WIN_DEFAULT_UNIX_KILL FALSE +#define WIN_DEFAULT_CLIP_UPDATES_NBOXES 0 +#ifdef XWIN_EMULATEPSEUDO +#define WIN_DEFAULT_EMULATE_PSEUDO FALSE +#endif +#define WIN_DEFAULT_USER_GAVE_HEIGHT_AND_WIDTH FALSE + +/* + * Windows only supports 256 color palettes + */ +#define WIN_NUM_PALETTE_ENTRIES 256 + +/* + * Number of times to call Restore in an attempt to restore the primary surface + */ +#define WIN_REGAIN_SURFACE_RETRIES 1 + +/* + * Build a supported display depths mask by shifting one to the left + * by the number of bits in the supported depth. + */ +#define WIN_SUPPORTED_BPPS ( (1 << (32 - 1)) | (1 << (24 - 1)) \ + | (1 << (16 - 1)) | (1 << (15 - 1)) \ + | (1 << ( 8 - 1))) +#define WIN_CHECK_DEPTH YES + +/* + * Timer IDs for WM_TIMER + */ +#define WIN_E3B_TIMER_ID 1 +#define WIN_POLLING_MOUSE_TIMER_ID 2 + +#define MOUSE_POLLING_INTERVAL 50 + +#define WIN_E3B_OFF -1 +#define WIN_FD_INVALID -1 + +#define WIN_SERVER_NONE 0x0L /* 0 */ +#define WIN_SERVER_SHADOW_GDI 0x1L /* 1 */ +#define WIN_SERVER_SHADOW_DD 0x2L /* 2 */ +#define WIN_SERVER_SHADOW_DDNL 0x4L /* 4 */ +#ifdef XWIN_PRIMARYFB +#define WIN_SERVER_PRIMARY_DD 0x8L /* 8 */ +#endif +#ifdef XWIN_NATIVEGDI +# define WIN_SERVER_NATIVE_GDI 0x10L /* 16 */ +#endif + +#define AltMapIndex Mod1MapIndex +#define NumLockMapIndex Mod2MapIndex +#define AltLangMapIndex Mod3MapIndex +#define KanaMapIndex Mod4MapIndex +#define ScrollLockMapIndex Mod5MapIndex + +#define WIN_MOD_LALT 0x00000001 +#define WIN_MOD_RALT 0x00000002 +#define WIN_MOD_LCONTROL 0x00000004 +#define WIN_MOD_RCONTROL 0x00000008 + +#define WIN_24BPP_MASK_RED 0x00FF0000 +#define WIN_24BPP_MASK_GREEN 0x0000FF00 +#define WIN_24BPP_MASK_BLUE 0x000000FF + +#define WIN_MAX_KEYS_PER_KEY 4 + +#include +#include +#include + +#include +#if defined(XWIN_MULTIWINDOWEXTWM) || defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) +#define HANDLE void * +#include +#undef HANDLE +#endif + +#ifdef HAS_MMAP +#include +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif /* MAP_FILE */ +#endif /* HAS_MMAP */ + +#include +#include +#include +#include +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "pixmap.h" +#include "region.h" +#include "gcstruct.h" +#include "colormap.h" +#include "colormapst.h" +#include "miscstruct.h" +#include "servermd.h" +#include "windowstr.h" +#include "mi.h" +#include "micmap.h" +#include "mifillarc.h" +#include "mifpoly.h" +#include "mibstore.h" +#include "input.h" +#include "mipointer.h" +#include "X11/keysym.h" +#include "mibstore.h" +#include "micoord.h" +#include "dix.h" +#include "miline.h" +#include "shadow.h" +#include "fb.h" +#include "rootless.h" + +#include "mipict.h" +#include "picturestr.h" + +#ifdef RANDR +#include "randrstr.h" +#endif + +/* + * Windows headers + */ +#include "winms.h" +#include "winresource.h" + + +/* + * Define Windows constants + */ + +#define WM_TRAYICON (WM_USER + 1000) +#define WM_INIT_SYS_MENU (WM_USER + 1001) +#define WM_GIVEUP (WM_USER + 1002) + + +/* Local includes */ +#include "winwindow.h" +#include "winmsg.h" + + +/* + * Debugging macros + */ + +#if CYGDEBUG +#define DEBUG_MSG(str,...) \ +if (fDebugProcMsg) \ +{ \ + char *pszTemp; \ + int iLength; \ + if (asprintf (&pszTemp, str, ##__VA_ARGS__) != -1) { \ + MessageBox (NULL, pszTemp, szFunctionName, MB_OK); \ + free (pszTemp); \ + } \ +} +#else +#define DEBUG_MSG(str,...) +#endif + +#if CYGDEBUG +#define DEBUG_FN_NAME(str) PTSTR szFunctionName = str +#else +#define DEBUG_FN_NAME(str) +#endif + +#if CYGDEBUG || YES +#define DEBUGVARS BOOL fDebugProcMsg = FALSE +#else +#define DEBUGVARS +#endif + +#if CYGDEBUG || YES +#define DEBUGPROC_MSG fDebugProcMsg = TRUE +#else +#define DEBUGPROC_MSG +#endif + +#define PROFILEPOINT(point,thresh)\ +{\ +static unsigned int PROFPT##point = 0;\ +if (++PROFPT##point % thresh == 0)\ +ErrorF (#point ": PROFILEPOINT hit %u times\n", PROFPT##point);\ +} + + +/* We use xor this macro for detecting toggle key state changes */ +#define WIN_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) + +#define DEFINE_ATOM_HELPER(func,atom_name) \ +static Atom func (void) { \ + static int generation; \ + static Atom atom; \ + if (generation != serverGeneration) { \ + generation = serverGeneration; \ + atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ + } \ + return atom; \ +} + +/* + * Typedefs for engine dependent function pointers + */ + +typedef Bool (*winAllocateFBProcPtr)(ScreenPtr); + +typedef void (*winFreeFBProcPtr)(ScreenPtr); + +typedef void (*winShadowUpdateProcPtr)(ScreenPtr, shadowBufPtr); + +typedef Bool (*winInitScreenProcPtr)(ScreenPtr); + +typedef Bool (*winCloseScreenProcPtr)(int, ScreenPtr); + +typedef Bool (*winInitVisualsProcPtr)(ScreenPtr); + +typedef Bool (*winAdjustVideoModeProcPtr)(ScreenPtr); + +typedef Bool (*winCreateBoundingWindowProcPtr)(ScreenPtr); + +typedef Bool (*winFinishScreenInitProcPtr)(int, ScreenPtr, int, char **); + +typedef Bool (*winBltExposedRegionsProcPtr)(ScreenPtr); + +typedef Bool (*winActivateAppProcPtr)(ScreenPtr); + +typedef Bool (*winRedrawScreenProcPtr)(ScreenPtr pScreen); + +typedef Bool (*winRealizeInstalledPaletteProcPtr)(ScreenPtr pScreen); + +typedef Bool (*winInstallColormapProcPtr)(ColormapPtr pColormap); + +typedef Bool (*winStoreColorsProcPtr)(ColormapPtr pmap, + int ndef, xColorItem *pdefs); + +typedef Bool (*winCreateColormapProcPtr)(ColormapPtr pColormap); + +typedef Bool (*winDestroyColormapProcPtr)(ColormapPtr pColormap); + +typedef Bool (*winHotKeyAltTabProcPtr)(ScreenPtr); + +typedef Bool (*winCreatePrimarySurfaceProcPtr)(ScreenPtr); + +typedef Bool (*winReleasePrimarySurfaceProcPtr)(ScreenPtr); + +typedef Bool (*winFinishCreateWindowsWindowProcPtr)(WindowPtr pWin); + +typedef Bool (*winCreateScreenResourcesProc)(ScreenPtr); + +#ifdef XWIN_NATIVEGDI +/* Typedefs for native GDI wrappers */ +typedef Bool (*RealizeFontPtr) (ScreenPtr pScreen, FontPtr pFont); +typedef Bool (*UnrealizeFontPtr)(ScreenPtr pScreen, FontPtr pFont); +#endif + + +/* + * GC (graphics context) privates + */ + +typedef struct +{ + HDC hdc; + HDC hdcMem; +} winPrivGCRec, *winPrivGCPtr; + + +/* + * Pixmap privates + */ + +typedef struct +{ + HDC hdcSelected; + HBITMAP hBitmap; + BYTE *pbBits; + DWORD dwScanlineBytes; + BITMAPINFOHEADER *pbmih; +} winPrivPixmapRec, *winPrivPixmapPtr; + + +/* + * Colormap privates + */ + +typedef struct +{ + HPALETTE hPalette; + LPDIRECTDRAWPALETTE lpDDPalette; + RGBQUAD rgbColors[WIN_NUM_PALETTE_ENTRIES]; + PALETTEENTRY peColors[WIN_NUM_PALETTE_ENTRIES]; +} winPrivCmapRec, *winPrivCmapPtr; + +/* + * Windows Cursor handling. + */ + +typedef struct { + /* from GetSystemMetrics */ + int sm_cx; + int sm_cy; + + BOOL visible; + HCURSOR handle; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; +} winCursorRec; + +/* + * Resize modes + */ +typedef enum { + notAllowed, + resizeWithScrollbars, + resizeWithRandr +} winResizeMode; + +/* + * Screen information structure that we need before privates are available + * in the server startup sequence. + */ + +typedef struct +{ + ScreenPtr pScreen; + + /* Did the user specify a height and width? */ + Bool fUserGaveHeightAndWidth; + + DWORD dwScreen; + + int iMonitor; + DWORD dwUserWidth; + DWORD dwUserHeight; + DWORD dwWidth; + DWORD dwHeight; + DWORD dwPaddedWidth; + + /* Did the user specify a screen position? */ + Bool fUserGavePosition; + DWORD dwInitialX; + DWORD dwInitialY; + + /* + * dwStride is the number of whole pixels that occupy a scanline, + * including those pixels that are not displayed. This is basically + * a rounding up of the width. + */ + DWORD dwStride; + + /* Offset of the screen in the window when using scrollbars */ + DWORD dwXOffset; + DWORD dwYOffset; + + DWORD dwBPP; + DWORD dwDepth; + DWORD dwRefreshRate; + char *pfb; + DWORD dwEngine; + DWORD dwEnginePreferred; + DWORD dwClipUpdatesNBoxes; +#ifdef XWIN_EMULATEPSEUDO + Bool fEmulatePseudo; +#endif + Bool fFullScreen; + Bool fDecoration; +#ifdef XWIN_MULTIWINDOWEXTWM + Bool fMWExtWM; + Bool fInternalWM; + Bool fAnotherWMRunning; +#endif + Bool fRootless; +#ifdef XWIN_MULTIWINDOW + Bool fMultiWindow; +#endif +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + Bool fMultiMonitorOverride; +#endif + Bool fMultipleMonitors; + Bool fLessPointer; + winResizeMode iResizeMode; + Bool fNoTrayIcon; + int iE3BTimeout; + /* Windows (Alt+F4) and Unix (Ctrl+Alt+Backspace) Killkey */ + Bool fUseWinKillKey; + Bool fUseUnixKillKey; + Bool fIgnoreInput; + + /* Did the user explicitly set this screen? */ + Bool fExplicitScreen; +} winScreenInfo, *winScreenInfoPtr; + + +/* + * Screen privates + */ + +typedef struct _winPrivScreenRec +{ + winScreenInfoPtr pScreenInfo; + + Bool fEnabled; + Bool fClosed; + Bool fActive; + Bool fBadDepth; + + int iDeltaZ; + + int iConnectedClients; + + CloseScreenProcPtr CloseScreen; + + DWORD dwRedMask; + DWORD dwGreenMask; + DWORD dwBlueMask; + DWORD dwBitsPerRGB; + + DWORD dwModeKeyStates; + + /* Handle to icons that must be freed */ + HICON hiconNotifyIcon; + + /* Palette management */ + ColormapPtr pcmapInstalled; + + /* Pointer to the root visual so we only have to look it up once */ + VisualPtr pRootVisual; + + /* 3 button emulation variables */ + int iE3BCachedPress; + Bool fE3BFakeButton2Sent; + + /* Privates used by shadow fb GDI server */ + HBITMAP hbmpShadow; + HDC hdcScreen; + HDC hdcShadow; + HWND hwndScreen; + BITMAPINFOHEADER *pbmih; + + /* Privates used by shadow fb and primary fb DirectDraw servers */ + LPDIRECTDRAW pdd; + LPDIRECTDRAWSURFACE2 pddsPrimary; + LPDIRECTDRAW2 pdd2; + + /* Privates used by shadow fb DirectDraw server */ + LPDIRECTDRAWSURFACE2 pddsShadow; + LPDDSURFACEDESC pddsdShadow; + + /* Privates used by primary fb DirectDraw server */ + LPDIRECTDRAWSURFACE2 pddsOffscreen; + LPDDSURFACEDESC pddsdOffscreen; + LPDDSURFACEDESC pddsdPrimary; + + /* Privates used by shadow fb DirectDraw Nonlocking server */ + LPDIRECTDRAW4 pdd4; + LPDIRECTDRAWSURFACE4 pddsShadow4; + LPDIRECTDRAWSURFACE4 pddsPrimary4; + BOOL fRetryCreateSurface; + + /* Privates used by both shadow fb DirectDraw servers */ + LPDIRECTDRAWCLIPPER pddcPrimary; + +#ifdef XWIN_MULTIWINDOWEXTWM + /* Privates used by multi-window external window manager */ + RootlessFrameID widTop; + Bool fRestacking; +#endif + +#ifdef XWIN_MULTIWINDOW + /* Privates used by multi-window */ + pthread_t ptWMProc; + pthread_t ptXMsgProc; + void *pWMInfo; +#endif + +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + /* Privates used by both multi-window and rootless */ + Bool fRootWindowShown; +#endif + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + /* Privates used for any module running in a seperate thread */ + pthread_mutex_t pmServerStarted; + Bool fServerStarted; +#endif + + /* Engine specific functions */ + winAllocateFBProcPtr pwinAllocateFB; + winFreeFBProcPtr pwinFreeFB; + winShadowUpdateProcPtr pwinShadowUpdate; + winInitScreenProcPtr pwinInitScreen; + winCloseScreenProcPtr pwinCloseScreen; + winInitVisualsProcPtr pwinInitVisuals; + winAdjustVideoModeProcPtr pwinAdjustVideoMode; + winCreateBoundingWindowProcPtr pwinCreateBoundingWindow; + winFinishScreenInitProcPtr pwinFinishScreenInit; + winBltExposedRegionsProcPtr pwinBltExposedRegions; + winActivateAppProcPtr pwinActivateApp; + winRedrawScreenProcPtr pwinRedrawScreen; + winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette; + winInstallColormapProcPtr pwinInstallColormap; + winStoreColorsProcPtr pwinStoreColors; + winCreateColormapProcPtr pwinCreateColormap; + winDestroyColormapProcPtr pwinDestroyColormap; + winHotKeyAltTabProcPtr pwinHotKeyAltTab; + winCreatePrimarySurfaceProcPtr pwinCreatePrimarySurface; + winReleasePrimarySurfaceProcPtr pwinReleasePrimarySurface; + + winCreateScreenResourcesProc pwinCreateScreenResources; + +#ifdef XWIN_MULTIWINDOW + /* Window Procedures for MultiWindow mode */ + winFinishCreateWindowsWindowProcPtr pwinFinishCreateWindowsWindow; +#endif + + /* Window Procedures for Rootless mode */ + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + ValidateTreeProcPtr ValidateTree; + PostValidateTreeProcPtr PostValidateTree; + WindowExposuresProcPtr WindowExposures; + CopyWindowProcPtr CopyWindow; + ClearToBackgroundProcPtr ClearToBackground; + ClipNotifyProcPtr ClipNotify; + RestackWindowProcPtr RestackWindow; + ReparentWindowProcPtr ReparentWindow; + ResizeWindowProcPtr ResizeWindow; + MoveWindowProcPtr MoveWindow; + SetShapeProcPtr SetShape; + + winCursorRec cursor; + +#ifdef XWIN_NATIVEGDI + RealizeFontPtr RealizeFont; + UnrealizeFontPtr UnrealizeFont; +#endif + +} winPrivScreenRec; + + +#ifdef XWIN_MULTIWINDOWEXTWM +typedef struct { + RootlessWindowPtr pFrame; + HWND hWnd; + int dwWidthBytes; + BITMAPINFOHEADER *pbmihShadow; + HBITMAP hbmpShadow; + HDC hdcShadow; + HDC hdcScreen; + BOOL fResized; + BOOL fRestackingNow; + BOOL fClose; + BOOL fMovingOrSizing; + BOOL fDestroyed;//for debug + char *pfb; +} win32RootlessWindowRec, *win32RootlessWindowPtr; +#endif + + +typedef struct { + pointer value; + XID id; +} WindowIDPairRec, *WindowIDPairPtr; + + +/* + * Extern declares for general global variables + */ + +#include "winglobals.h" + +extern winScreenInfo * g_ScreenInfo; +extern miPointerScreenFuncRec g_winPointerCursorFuncs; +extern DWORD g_dwEvents; +#ifdef HAS_DEVWINDOWS +extern int g_fdMessageQueue; +#endif +extern DevPrivateKeyRec g_iScreenPrivateKeyRec; +#define g_iScreenPrivateKey (&g_iScreenPrivateKeyRec) +extern DevPrivateKeyRec g_iCmapPrivateKeyRec; +#define g_iCmapPrivateKey (&g_iCmapPrivateKeyRec) +extern DevPrivateKeyRec g_iGCPrivateKeyRec; +#define g_iGCPrivateKey (&g_iGCPrivateKeyRec) +extern DevPrivateKeyRec g_iPixmapPrivateKeyRec; +#define g_iPixmapPrivateKey (&g_iPixmapPrivateKeyRec) +extern DevPrivateKeyRec g_iWindowPrivateKeyRec; +#define g_iWindowPrivateKey (&g_iWindowPrivateKeyRec) + +extern unsigned long g_ulServerGeneration; +extern DWORD g_dwEnginesSupported; +extern HINSTANCE g_hInstance; +extern int g_copyROP[]; +extern int g_patternROP[]; +extern const char * g_pszQueryHost; +extern DeviceIntPtr g_pwinPointer; +extern DeviceIntPtr g_pwinKeyboard; + +/* + * Extern declares for dynamically loaded library function pointers + */ + +extern FARPROC g_fpDirectDrawCreate; +extern FARPROC g_fpDirectDrawCreateClipper; +extern FARPROC g_fpTrackMouseEvent; + + +/* + * Screen privates macros + */ + +#define winGetScreenPriv(pScreen) ((winPrivScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey)) + +#define winSetScreenPriv(pScreen,v) \ + dixSetPrivate(&(pScreen)->devPrivates, g_iScreenPrivateKey, v) + +#define winScreenPriv(pScreen) \ + winPrivScreenPtr pScreenPriv = winGetScreenPriv(pScreen) + + +/* + * Colormap privates macros + */ + +#define winGetCmapPriv(pCmap) ((winPrivCmapPtr) \ + dixLookupPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey)) + +#define winSetCmapPriv(pCmap,v) \ + dixSetPrivate(&(pCmap)->devPrivates, g_iCmapPrivateKey, v) + +#define winCmapPriv(pCmap) \ + winPrivCmapPtr pCmapPriv = winGetCmapPriv(pCmap) + + +/* + * GC privates macros + */ + +#define winGetGCPriv(pGC) ((winPrivGCPtr) \ + dixLookupPrivate(&(pGC)->devPrivates, g_iGCPrivateKey)) + +#define winSetGCPriv(pGC,v) \ + dixSetPrivate(&(pGC)->devPrivates, g_iGCPrivateKey, v) + +#define winGCPriv(pGC) \ + winPrivGCPtr pGCPriv = winGetGCPriv(pGC) + + +/* + * Pixmap privates macros + */ + +#define winGetPixmapPriv(pPixmap) ((winPrivPixmapPtr) \ + dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey)) + +#define winSetPixmapPriv(pPixmap,v) \ + dixLookupPrivate(&(pPixmap)->devPrivates, g_iPixmapPrivateKey, v) + +#define winPixmapPriv(pPixmap) \ + winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap) + + +/* + * Window privates macros + */ + +#define winGetWindowPriv(pWin) ((winPrivWinPtr) \ + dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey)) + +#define winSetWindowPriv(pWin,v) \ + dixLookupPrivate(&(pWin)->devPrivates, g_iWindowPrivateKey, v) + +#define winWindowPriv(pWin) \ + winPrivWinPtr pWinPriv = winGetWindowPriv(pWin) + +/* + * wrapper macros + */ +#define _WIN_WRAP(priv, real, mem, func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define _WIN_UNWRAP(priv, real, mem) {\ + real->mem = priv->mem; \ +} + +#define WIN_WRAP(mem, func) _WIN_WRAP(pScreenPriv, pScreen, mem, func) + +#define WIN_UNWRAP(mem) _WIN_UNWRAP(pScreenPriv, pScreen, mem) + +/* + * BEGIN DDX and DIX Function Prototypes + */ + + +/* + * winallpriv.c + */ + +Bool +winAllocatePrivates (ScreenPtr pScreen); + +Bool +winInitCmapPrivates (ColormapPtr pCmap, int index); + +Bool +winAllocateCmapPrivates (ColormapPtr pCmap); + + +/* + * winauth.c + */ + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) +Bool +winGenerateAuthorization (void); +void winSetAuthorization(void); +#endif + + +/* + * winblock.c + */ + +void +winBlockHandler (int nScreen, + pointer pBlockData, + pointer pTimeout, + pointer pReadMask); + + +#ifdef XWIN_NATIVEGDI +/* + * winclip.c + */ + +RegionPtr +winPixmapToRegionNativeGDI (PixmapPtr pPix); +#endif + + +#ifdef XWIN_CLIPBOARD +/* + * winclipboardinit.c + */ + +Bool +winInitClipboard (void); + +void +winFixClipboardChain (void); +#endif + + +/* + * wincmap.c + */ + +void +winSetColormapFunctions (ScreenPtr pScreen); + +Bool +winCreateDefColormap (ScreenPtr pScreen); + + +/* + * wincreatewnd.c + */ + +Bool +winCreateBoundingWindowFullScreen (ScreenPtr pScreen); + +Bool +winCreateBoundingWindowWindowed (ScreenPtr pScreen); + + +/* + * windialogs.c + */ + +void +winDisplayExitDialog (winPrivScreenPtr pScreenPriv); + +void +winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv); + +void +winDisplayAboutDialog (winPrivScreenPtr pScreenPriv); + + +/* + * winengine.c + */ + +void +winDetectSupportedEngines (void); + +Bool +winSetEngine (ScreenPtr pScreen); + +Bool +winGetDDProcAddresses (void); + +void +winReleaseDDProcAddresses(void); + + +/* + * winerror.c + */ + +#ifdef DDXOSVERRORF +void +OSVenderVErrorF (const char *pszFormat, va_list va_args); +#endif + +void +winMessageBoxF (const char *pszError, UINT uType, ...); + + +#ifdef XWIN_NATIVEGDI +/* + * winfillsp.c + */ + +void +winFillSpansNativeGDI (DrawablePtr pDrawable, + GCPtr pGC, + int nSpans, + DDXPointPtr pPoints, + int *pWidths, + int fSorted); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winfont.c + */ + +Bool +winRealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); + +Bool +winUnrealizeFontNativeGDI (ScreenPtr pScreen, FontPtr pFont); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * wingc.c + */ + +Bool +winCreateGCNativeGDI (GCPtr pGC); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * wingetsp.c + */ + +void +winGetSpansNativeGDI (DrawablePtr pDrawable, + int wMax, + DDXPointPtr pPoints, + int *pWidths, + int nSpans, + char *pDst); +#endif + + +/* + * winglobals.c + */ + +void +winInitializeGlobals (void); + + +/* + * winkeybd.c + */ + +void +winTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode); + +int +winKeybdProc (DeviceIntPtr pDeviceInt, int iState); + +void +winInitializeModeKeyStates (void); + +void +winRestoreModeKeyStates (void); + +Bool +winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam); + +void +winKeybdReleaseKeys (void); + +void +winSendKeyEvent (DWORD dwKey, Bool fDown); + +BOOL +winCheckKeyPressed(WPARAM wParam, LPARAM lParam); + +void +winFixShiftKeys (int iScanCode); + +/* + * winkeyhook.c + */ + +Bool +winInstallKeyboardHookLL (void); + +void +winRemoveKeyboardHookLL (void); + + +/* + * winmisc.c + */ + +#ifdef XWIN_NATIVEGDI +void +winQueryBestSizeNativeGDI (int class, unsigned short *pWidth, + unsigned short *pHeight, ScreenPtr pScreen); +#endif + +CARD8 +winCountBits (DWORD dw); + +Bool +winUpdateFBPointer (ScreenPtr pScreen, void *pbits); + +#ifdef XWIN_NATIVEGDI +BOOL +winPaintBackground (HWND hwnd, COLORREF colorref); +#endif + + +/* + * winmouse.c + */ + +int +winMouseProc (DeviceIntPtr pDeviceInt, int iState); + +int +winMouseWheel (ScreenPtr pScreen, int iDeltaZ); + +void +winMouseButtonsSendEvent (int iEventType, int iButton); + +int +winMouseButtonsHandle (ScreenPtr pScreen, + int iEventType, int iButton, + WPARAM wParam); + +void +winEnqueueMotion(int x, int y); + +#ifdef XWIN_NATIVEGDI +/* + * winnativegdi.c + */ + +HBITMAP +winCreateDIBNativeGDI (int iWidth, int iHeight, int iDepth, + BYTE **ppbBits, BITMAPINFO **ppbmi); + +Bool +winSetEngineFunctionsNativeGDI (ScreenPtr pScreen); +#endif + + +#ifdef XWIN_PRIMARYFB +/* + * winpfbddd.c + */ + +Bool +winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winpixmap.c + */ + +PixmapPtr +winCreatePixmapNativeGDI (ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint); + +Bool +winDestroyPixmapNativeGDI (PixmapPtr pPixmap); + +Bool +winModifyPixmapHeaderNativeGDI (PixmapPtr pPixmap, + int iWidth, int iHeight, + int iDepth, + int iBitsPerPixel, + int devKind, + pointer pPixData); +#endif + +#ifdef XWIN_NATIVEGDI +/* + * winpolyline.c + */ + +void +winPolyLineNativeGDI (DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr ppt); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winpushpxl.c + */ + +void +winPushPixels (GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, + int dx, int dy, int xOrg, int yOrg); +#endif + + +/* + * winscrinit.c + */ + +Bool +winScreenInit (int index, + ScreenPtr pScreen, + int argc, char **argv); + +Bool +winFinishScreenInitFB (int index, + ScreenPtr pScreen, + int argc, char **argv); + +#if defined(XWIN_NATIVEGDI) +Bool +winFinishScreenInitNativeGDI (int index, + ScreenPtr pScreen, + int argc, char **argv); +#endif + + +#ifdef XWIN_NATIVEGDI +/* + * winsetsp.c + */ + +void +winSetSpansNativeGDI (DrawablePtr pDrawable, + GCPtr pGC, + char *pSrc, + DDXPointPtr pPoints, + int *pWidth, + int nSpans, + int fSorted); +#endif + + +/* + * winshaddd.c + */ + +Bool +winSetEngineFunctionsShadowDD (ScreenPtr pScreen); + + +/* + * winshadddnl.c + */ + +Bool +winSetEngineFunctionsShadowDDNL (ScreenPtr pScreen); + + +/* + * winshadgdi.c + */ + +Bool +winSetEngineFunctionsShadowGDI (ScreenPtr pScreen); + + +/* + * winwakeup.c + */ + +void +winWakeupHandler (int nScreen, + pointer pWakeupData, + unsigned long ulResult, + pointer pReadmask); + + +/* + * winwindow.c + */ + +#ifdef XWIN_NATIVEGDI +Bool +winCreateWindowNativeGDI (WindowPtr pWin); + +Bool +winDestroyWindowNativeGDI (WindowPtr pWin); + +Bool +winPositionWindowNativeGDI (WindowPtr pWin, int x, int y); + +void +winCopyWindowNativeGDI (WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc); + +Bool +winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask); + +Bool +winUnmapWindowNativeGDI (WindowPtr pWindow); + +Bool +winMapWindowNativeGDI (WindowPtr pWindow); +#endif + +Bool +winCreateWindowRootless (WindowPtr pWindow); + +Bool +winDestroyWindowRootless (WindowPtr pWindow); + +Bool +winPositionWindowRootless (WindowPtr pWindow, int x, int y); + +Bool +winChangeWindowAttributesRootless (WindowPtr pWindow, unsigned long mask); + +Bool +winUnmapWindowRootless (WindowPtr pWindow); + +Bool +winMapWindowRootless (WindowPtr pWindow); + +void +winSetShapeRootless (WindowPtr pWindow, int kind); + + +/* + * winmultiwindowicons.c - Used by both multi-window and Win32Rootless + */ + +HICON +winXIconToHICON (WindowPtr pWin, int iconSize); + +void +winSelectIcons(WindowPtr pWin, HICON *pIcon, HICON *pSmallIcon); + +#ifdef XWIN_MULTIWINDOW +/* + * winmultiwindowshape.c + */ + +void +winReshapeMultiWindow (WindowPtr pWin); + +void +winSetShapeMultiWindow (WindowPtr pWindow, int kind); + +void +winUpdateRgnMultiWindow (WindowPtr pWindow); +#endif + + +#ifdef XWIN_MULTIWINDOW +/* + * winmultiwindowwindow.c + */ + +Bool +winCreateWindowMultiWindow (WindowPtr pWindow); + +Bool +winDestroyWindowMultiWindow (WindowPtr pWindow); + +Bool +winPositionWindowMultiWindow (WindowPtr pWindow, int x, int y); + +Bool +winChangeWindowAttributesMultiWindow (WindowPtr pWindow, unsigned long mask); + +Bool +winUnmapWindowMultiWindow (WindowPtr pWindow); + +Bool +winMapWindowMultiWindow (WindowPtr pWindow); + +void +winReparentWindowMultiWindow (WindowPtr pWin, WindowPtr pPriorParent); + +void +winRestackWindowMultiWindow (WindowPtr pWin, WindowPtr pOldNextSib); + +void +winReorderWindowsMultiWindow (void); + +void +winResizeWindowMultiWindow (WindowPtr pWin, int x, int y, unsigned int w, + unsigned int h, WindowPtr pSib); +void +winMoveWindowMultiWindow (WindowPtr pWin, int x, int y, + WindowPtr pSib, VTKind kind); + +void +winCopyWindowMultiWindow (WindowPtr pWin, DDXPointRec oldpt, + RegionPtr oldRegion); + +XID +winGetWindowID (WindowPtr pWin); + +int +winAdjustXWindow (WindowPtr pWin, HWND hwnd); +#endif + + +#ifdef XWIN_MULTIWINDOW +/* + * winmultiwindowwndproc.c + */ + +LRESULT CALLBACK +winTopLevelWindowProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); +#endif + + +/* + * wintrayicon.c + */ + +void +winInitNotifyIcon (winPrivScreenPtr pScreenPriv); + +void +winDeleteNotifyIcon (winPrivScreenPtr pScreenPriv); + +LRESULT +winHandleIconMessage (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam, + winPrivScreenPtr pScreenPriv); + + +/* + * winwndproc.c + */ + +LRESULT CALLBACK +winWindowProc (HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); + + +#ifdef XWIN_MULTIWINDOWEXTWM +/* + * winwin32rootless.c + */ + +Bool +winMWExtWMCreateFrame (RootlessWindowPtr pFrame, ScreenPtr pScreen, + int newX, int newY, RegionPtr pShape); + +void +winMWExtWMDestroyFrame (RootlessFrameID wid); + +void +winMWExtWMMoveFrame (RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); + +void +winMWExtWMResizeFrame (RootlessFrameID wid, ScreenPtr pScreen, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int gravity); + +void +winMWExtWMRestackFrame (RootlessFrameID wid, RootlessFrameID nextWid); + +void +winMWExtWMReshapeFrame (RootlessFrameID wid, RegionPtr pShape); + +void +winMWExtWMUnmapFrame (RootlessFrameID wid); + +void +winMWExtWMStartDrawing (RootlessFrameID wid, char **pixelData, int *bytesPerRow); + +void +winMWExtWMStopDrawing (RootlessFrameID wid, Bool flush); + +void +winMWExtWMUpdateRegion (RootlessFrameID wid, RegionPtr pDamage); + +void +winMWExtWMDamageRects (RootlessFrameID wid, int count, const BoxRec *rects, + int shift_x, int shift_y); + +void +winMWExtWMRootlessSwitchWindow (RootlessWindowPtr pFrame, WindowPtr oldWin); + +void +winMWExtWMCopyBytes (unsigned int width, unsigned int height, + const void *src, unsigned int srcRowBytes, + void *dst, unsigned int dstRowBytes); + +void +winMWExtWMCopyWindow (RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, + int dx, int dy); +#endif + + +#ifdef XWIN_MULTIWINDOWEXTWM +/* + * winwin32rootlesswindow.c + */ + +void +winMWExtWMReorderWindows (ScreenPtr pScreen); + +void +winMWExtWMMoveXWindow (WindowPtr pWin, int x, int y); + +void +winMWExtWMResizeXWindow (WindowPtr pWin, int w, int h); + +void +winMWExtWMMoveResizeXWindow (WindowPtr pWin, int x, int y, int w, int h); + +void +winMWExtWMUpdateIcon (Window id); + +void +winMWExtWMUpdateWindowDecoration (win32RootlessWindowPtr pRLWinPriv, + winScreenInfoPtr pScreenInfo); + +wBOOL CALLBACK +winMWExtWMDecorateWindow (HWND hwnd, LPARAM lParam); + +Bool +winIsInternalWMRunning (winScreenInfoPtr pScreenInfo); + +void +winMWExtWMRestackWindows (ScreenPtr pScreen); +#endif + + +#ifdef XWIN_MULTIWINDOWEXTWM +/* + * winwin32rootlesswndproc.c + */ + +LRESULT CALLBACK +winMWExtWMWindowProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); +#endif + + +/* + * winwindowswm.c + */ + +void +winWindowsWMSendEvent (int type, unsigned int mask, int which, int arg, + Window window, int x, int y, int w, int h); + +void +winWindowsWMExtensionInit (void); + +/* + * wincursor.c + */ + +Bool +winInitCursor (ScreenPtr pScreen); + +/* + * winprocarg.c + */ +void +winInitializeScreens(int maxscreens); + +/* + * winrandr.c + */ +Bool +winRandRInit (ScreenPtr pScreen); +void +winDoRandRScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight); + +/* + * END DDX and DIX Function Prototypes + */ + +#endif /* _WIN_H_ */ + diff --git a/xorg-server/hw/xwin/wincreatewnd.c b/xorg-server/hw/xwin/wincreatewnd.c index 0c342e1ae..755373965 100644 --- a/xorg-server/hw/xwin/wincreatewnd.c +++ b/xorg-server/hw/xwin/wincreatewnd.c @@ -192,7 +192,7 @@ winCreateBoundingWindowWindowed (ScreenPtr pScreen) fForceShowWindow = TRUE; } dwWindowStyle |= WS_CAPTION; - if (pScreenInfo->fScrollbars) + if (pScreenInfo->iResizeMode != notAllowed) dwWindowStyle |= WS_THICKFRAME | WS_MAXIMIZEBOX; } else @@ -233,6 +233,22 @@ winCreateBoundingWindowWindowed (ScreenPtr pScreen) iPosY = rcWorkArea.top; } + /* Clean up the scrollbars flag, if necessary */ + if ((!pScreenInfo->fDecoration +#ifdef XWIN_MULTIWINDOWEXTWM + || pScreenInfo->fMWExtWM +#endif + || pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOW + || pScreenInfo->fMultiWindow +#endif + ) + && (pScreenInfo->iResizeMode == resizeWithScrollbars)) + { + /* We cannot have scrollbars if we do not have a window border */ + pScreenInfo->iResizeMode = notAllowed; + } + /* Did the user specify a height and width? */ if (pScreenInfo->fUserGaveHeightAndWidth) { @@ -256,12 +272,12 @@ winCreateBoundingWindowWindowed (ScreenPtr pScreen) #if CYGDEBUG winDebug ("winCreateBoundingWindowWindowed - Window has decoration\n"); #endif - /* Are we using scrollbars? */ - if (pScreenInfo->fScrollbars) + + /* Are we resizable */ + if (pScreenInfo->iResizeMode != notAllowed) { #if CYGDEBUG - winDebug ("winCreateBoundingWindowWindowed - Window has " - "scrollbars\n"); + winDebug ("winCreateBoundingWindowWindowed - Window is resizable\n"); #endif iWidth += 2 * GetSystemMetrics (SM_CXSIZEFRAME); @@ -271,8 +287,7 @@ winCreateBoundingWindowWindowed (ScreenPtr pScreen) else { #if CYGDEBUG - winDebug ("winCreateBoundingWindowWindowed - Window does not have " - "scrollbars\n"); + winDebug ("winCreateBoundingWindowWindowed - Window is not resizable\n"); #endif iWidth += 2 * GetSystemMetrics (SM_CXFIXEDFRAME); @@ -296,22 +311,7 @@ winCreateBoundingWindowWindowed (ScreenPtr pScreen) } } - /* Clean up the scrollbars flag, if necessary */ - if ((!pScreenInfo->fDecoration -#ifdef XWIN_MULTIWINDOWEXTWM - || pScreenInfo->fMWExtWM -#endif - || pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOW - || pScreenInfo->fMultiWindow -#endif - ) - && pScreenInfo->fScrollbars) - { - /* We cannot have scrollbars if we do not have a window border */ - pScreenInfo->fScrollbars = FALSE; - } - + /* Make sure window is no bigger than work area */ if (TRUE #ifdef XWIN_MULTIWINDOWEXTWM && !pScreenInfo->fMWExtWM @@ -396,7 +396,7 @@ winCreateBoundingWindowWindowed (ScreenPtr pScreen) rcClient.bottom, rcClient.top); /* We adjust the visual size if the user did not specify it */ - if (!(pScreenInfo->fScrollbars && pScreenInfo->fUserGaveHeightAndWidth)) + if (!((pScreenInfo->iResizeMode == resizeWithScrollbars) && pScreenInfo->fUserGaveHeightAndWidth)) { /* * User did not give a height and width with scrollbars enabled, diff --git a/xorg-server/hw/xwin/windialogs.c b/xorg-server/hw/xwin/windialogs.c index 8c648e84a..c3a149762 100644 --- a/xorg-server/hw/xwin/windialogs.c +++ b/xorg-server/hw/xwin/windialogs.c @@ -1,774 +1,773 @@ -/* - *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of Harold L Hunt II - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. - * - * Authors: Harold L Hunt II - * Earle F. Philhower III - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" -#ifdef __CYGWIN__ -#include -#endif -#include -#include "winprefs.h" - - -/* - * References to external globals - */ - -#ifdef XWIN_CLIPBOARD -extern Bool g_fClipboardStarted; -#endif -/* - * Local function prototypes - */ - -static wBOOL CALLBACK -winExitDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam); - -static wBOOL CALLBACK -winChangeDepthDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam); - -static wBOOL CALLBACK -winAboutDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam); - - -static void -winDrawURLWindow (LPARAM lParam); - -static LRESULT CALLBACK -winURLWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -static void -winOverrideURLButton (HWND hdlg, int id); - -static void -winUnoverrideURLButton (HWND hdlg, int id); - - -/* - * Owner-draw a button as a URL - */ - -static void -winDrawURLWindow (LPARAM lParam) -{ - DRAWITEMSTRUCT *draw; - char str[256]; - RECT rect; - HFONT font; - COLORREF crText; - - draw = (DRAWITEMSTRUCT *) lParam; - GetWindowText (draw->hwndItem, str, sizeof(str)); - str[255] = 0; - GetClientRect (draw->hwndItem, &rect); - - /* Color the button depending upon its state */ - if (draw->itemState & ODS_SELECTED) - crText = RGB(128+64,0,0); - else if (draw->itemState & ODS_FOCUS) - crText = RGB(0,128+64,0); - else - crText = RGB(0,0,128+64); - SetTextColor (draw->hDC, crText); - - /* Create font 8 high, standard dialog font */ - font = CreateFont (-8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, - 0, 0, 0, 0, 0, "MS Sans Serif"); - if (!font) - { - ErrorF ("winDrawURLWindow: Unable to create URL font, bailing.\n"); - return; - } - /* Draw it */ - SetBkMode (draw->hDC, OPAQUE); - SelectObject (draw->hDC, font); - DrawText (draw->hDC, str, strlen (str),&rect,DT_CENTER | DT_VCENTER); - /* Delete the created font, replace it with stock font */ - DeleteObject (SelectObject (draw->hDC, GetStockObject (ANSI_VAR_FONT))); -} - - -/* - * WndProc for overridden buttons - */ - -static LRESULT CALLBACK -winURLWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC origCB = NULL; - HCURSOR cursor; - - /* If it's a SetCursor message, tell it to the hand */ - if (msg==WM_SETCURSOR) { - cursor = LoadCursor (NULL, IDC_HAND); - if (cursor) - SetCursor (cursor); - return TRUE; - } - origCB = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); - /* Otherwise fall through to original WndProc */ - if (origCB) - return CallWindowProc (origCB, hwnd, msg, wParam, lParam); - else - return FALSE; -} - - -/* - * Register and unregister the custom WndProc - */ - -static void -winOverrideURLButton (HWND hwnd, int id) -{ - WNDPROC origCB; - origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), - GWLP_WNDPROC, (LONG_PTR)winURLWndProc); - SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_USERDATA, (LONG_PTR)origCB); -} - -static void -winUnoverrideURLButton (HWND hwnd, int id) -{ - WNDPROC origCB; - origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), - GWLP_USERDATA, 0); - if (origCB) - SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_WNDPROC, (LONG_PTR)origCB); -} - - -/* - * Center a dialog window in the desktop window - * and set small and large icons to X icons. - */ - -static void -winInitDialog (HWND hwndDlg) -{ - HWND hwndDesk; - RECT rc, rcDlg, rcDesk; - HICON hIcon, hIconSmall; - - hwndDesk = GetParent (hwndDlg); - if (!hwndDesk || IsIconic (hwndDesk)) - hwndDesk = GetDesktopWindow (); - - /* Remove minimize and maximize buttons */ - SetWindowLongPtr(hwndDlg, GWL_STYLE, - GetWindowLongPtr(hwndDlg, GWL_STYLE) - & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); - - /* Set Window not to show in the task bar */ - SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, - GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) & ~WS_EX_APPWINDOW ); - - /* Center dialog window in the screen. Not done for multi-monitor systems, where - * it is likely to end up split across the screens. In that case, it appears - * near the Tray icon. - */ - if (GetSystemMetrics(SM_CMONITORS)>1) { - /* Still need to refresh the frame change. */ - SetWindowPos (hwndDlg, HWND_TOPMOST, 0,0,0,0, - SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); - } else { - GetWindowRect (hwndDesk, &rcDesk); - GetWindowRect (hwndDlg, &rcDlg); - CopyRect (&rc, &rcDesk); - - OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect (&rc, -rc.left, -rc.top); - OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom); - - SetWindowPos (hwndDlg, - HWND_TOPMOST, - rcDesk.left + (rc.right / 2), - rcDesk.top + (rc.bottom / 2), - 0, 0, - SWP_NOSIZE | SWP_FRAMECHANGED); - } - -#ifdef XWIN_MULTIWINDOW - if (g_hIconX) hIcon=g_hIconX; - else -#endif - hIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN)); - -#ifdef XWIN_MULTIWINDOW - if (g_hSmallIconX) hIconSmall=g_hSmallIconX; - else -#endif - hIconSmall = LoadImage (g_hInstance, - MAKEINTRESOURCE(IDI_XWIN), IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_SHARED); - - PostMessage (hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon); - PostMessage (hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); -} - - -/* - * Display the Exit dialog box - */ - -void -winDisplayExitDialog (winPrivScreenPtr pScreenPriv) -{ - int i; - int liveClients = 0; - - /* Count up running clients (clients[0] is serverClient) */ - for (i = 1; i < currentMaxClients; i++) - if (clients[i] != NullClient) - liveClients++; -#if defined(XWIN_MULTIWINDOW) - /* Count down server internal clients */ - if (pScreenPriv->pScreenInfo->fMultiWindow) - liveClients -= 2; /* multiwindow window manager & XMsgProc */ -#endif -#if defined(XWIN_CLIPBOARD) - if (g_fClipboardStarted) - liveClients--; /* clipboard manager */ -#endif - - /* A user reported that this sometimes drops below zero. just eye-candy. */ - if (liveClients < 0) - liveClients = 0; - - /* Don't show the exit confirmation dialog if SilentExit & no clients, - or ForceExit, is enabled */ - if ((pref.fSilentExit && liveClients <= 0) || pref.fForceExit) - { - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - PostMessage (pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); - return; - } - - pScreenPriv->iConnectedClients = liveClients; - - /* Check if dialog already exists */ - if (g_hDlgExit != NULL) - { - /* Dialog box already exists, display it */ - ShowWindow (g_hDlgExit, SW_SHOWDEFAULT); - - /* User has lost the dialog. Show them where it is. */ - SetForegroundWindow (g_hDlgExit); - - return; - } - - /* Create dialog box */ - g_hDlgExit = CreateDialogParam (g_hInstance, - "EXIT_DIALOG", - pScreenPriv->hwndScreen, - winExitDlgProc, - (int) pScreenPriv); - - /* Show the dialog box */ - ShowWindow (g_hDlgExit, SW_SHOW); - - /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ - SetForegroundWindow (g_hDlgExit); - - /* Set focus to the Cancel button */ - PostMessage (g_hDlgExit, WM_NEXTDLGCTL, - (WPARAM)GetDlgItem (g_hDlgExit, IDCANCEL), TRUE); -} - -#define CONNECTED_CLIENTS_FORMAT "There %s currently %d client%s connected." - - -/* - * Exit dialog window procedure - */ - -static wBOOL CALLBACK -winExitDlgProc (HWND hDialog, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - - /* Branch on message type */ - switch (message) - { - case WM_INITDIALOG: - { - char *pszConnectedClients; - - /* Store pointers to private structures for future use */ - s_pScreenPriv = (winPrivScreenPtr) lParam; - - winInitDialog (hDialog); - - /* Format the connected clients string */ - if (asprintf (&pszConnectedClients, CONNECTED_CLIENTS_FORMAT, - (s_pScreenPriv->iConnectedClients == 1) ? "is" : "are", - s_pScreenPriv->iConnectedClients, - (s_pScreenPriv->iConnectedClients == 1) ? "" : "s") == -1) - return TRUE; - - - - /* Set the number of connected clients */ - SetWindowText (GetDlgItem (hDialog, IDC_CLIENTS_CONNECTED), - pszConnectedClients); - free(pszConnectedClients); - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - /* Send message to call the GiveUp function */ - PostMessage (s_pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - - case IDCANCEL: - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - } - break; - - case WM_MOUSEMOVE: - case WM_NCMOUSEMOVE: - /* Show the cursor if it is hidden */ - if (g_fSoftwareCursor && !g_fCursor) - { - g_fCursor = TRUE; - ShowCursor (TRUE); - } - return TRUE; - - case WM_CLOSE: - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - } - - return FALSE; -} - - -/* - * Display the Depth Change dialog box - */ - -void -winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv) -{ - /* Check if dialog already exists */ - if (g_hDlgDepthChange != NULL) - { - /* Dialog box already exists, display it */ - ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); - - /* User has lost the dialog. Show them where it is. */ - SetForegroundWindow (g_hDlgDepthChange); - - return; - } - - /* - * Display a notification to the user that the visual - * will not be displayed until the Windows display depth - * is restored to the original value. - */ - g_hDlgDepthChange = CreateDialogParam (g_hInstance, - "DEPTH_CHANGE_BOX", - pScreenPriv->hwndScreen, - winChangeDepthDlgProc, - (int) pScreenPriv); - /* Show the dialog box */ - ShowWindow (g_hDlgDepthChange, SW_SHOW); - - ErrorF ("winDisplayDepthChangeDialog - DialogBox returned: %d\n", - (int) g_hDlgDepthChange); - ErrorF ("winDisplayDepthChangeDialog - GetLastError: %d\n", - (int) GetLastError ()); - - /* Minimize the display window */ - ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); -} - - -/* - * Process messages for the dialog that is displayed for - * disruptive screen depth changes. - */ - -static wBOOL CALLBACK -winChangeDepthDlgProc (HWND hwndDialog, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - static winScreenInfo *s_pScreenInfo = NULL; - static ScreenPtr s_pScreen = NULL; - -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc\n"); -#endif - - /* Branch on message type */ - switch (message) - { - case WM_INITDIALOG: -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_INITDIALOG\n"); -#endif - - /* Store pointers to private structures for future use */ - s_pScreenPriv = (winPrivScreenPtr) lParam; - s_pScreenInfo = s_pScreenPriv->pScreenInfo; - s_pScreen = s_pScreenInfo->pScreen; - -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - s_pScreenPriv: %08x, " - "s_pScreenInfo: %08x, s_pScreen: %08x\n", - s_pScreenPriv, s_pScreenInfo, s_pScreen); -#endif - -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - orig bpp: %d, " - "last bpp: %d\n", - s_pScreenInfo->dwBPP, - s_pScreenPriv->dwLastWindowsBitsPixel); -#endif - - winInitDialog( hwndDialog ); - - return TRUE; - - case WM_DISPLAYCHANGE: -#if CYGDEBUG - winDebug ("winChangeDepthDlgProc - WM_DISPLAYCHANGE - orig bpp: %d, " - "last bpp: %d, new bpp: %d\n", - s_pScreenInfo->dwBPP, - s_pScreenPriv->dwLastWindowsBitsPixel, - wParam); -#endif - - /* Dismiss the dialog if the display returns to the original depth */ - if (wParam == s_pScreenInfo->dwBPP) - { - ErrorF ("winChangeDelthDlgProc - wParam == s_pScreenInfo->dwBPP\n"); - - /* Depth has been restored, dismiss dialog */ - DestroyWindow (g_hDlgDepthChange); - g_hDlgDepthChange = NULL; - - /* Flag that we have a valid screen depth */ - s_pScreenPriv->fBadDepth = FALSE; - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - case IDCANCEL: - ErrorF ("winChangeDepthDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); - - /* - * User dismissed the dialog, hide it until the - * display mode is restored. - */ - ShowWindow (g_hDlgDepthChange, SW_HIDE); - return TRUE; - } - break; - - case WM_CLOSE: - ErrorF ("winChangeDepthDlgProc - WM_CLOSE\n"); - - DestroyWindow (g_hDlgAbout); - g_hDlgAbout = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - return TRUE; - } - - return FALSE; -} - - -/* - * Display the About dialog box - */ - -void -winDisplayAboutDialog (winPrivScreenPtr pScreenPriv) -{ - /* Check if dialog already exists */ - if (g_hDlgAbout != NULL) - { - /* Dialog box already exists, display it */ - ShowWindow (g_hDlgAbout, SW_SHOWDEFAULT); - - /* User has lost the dialog. Show them where it is. */ - SetForegroundWindow (g_hDlgAbout); - - return; - } - - /* - * Display the about box - */ - g_hDlgAbout = CreateDialogParam (g_hInstance, - "ABOUT_BOX", - pScreenPriv->hwndScreen, - winAboutDlgProc, - (int) pScreenPriv); - - /* Show the dialog box */ - ShowWindow (g_hDlgAbout, SW_SHOW); - - /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ - SetForegroundWindow (g_hDlgAbout); - - /* Set focus to the OK button */ - PostMessage (g_hDlgAbout, WM_NEXTDLGCTL, - (WPARAM)GetDlgItem (g_hDlgAbout, IDOK), TRUE); -} - - -/* - * Process messages for the about dialog. - */ - -static wBOOL CALLBACK -winAboutDlgProc (HWND hwndDialog, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - static winScreenInfo *s_pScreenInfo = NULL; - static ScreenPtr s_pScreen = NULL; - -#if CYGDEBUG - winDebug ("winAboutDlgProc\n"); -#endif - - /* Branch on message type */ - switch (message) - { - case WM_INITDIALOG: -#if CYGDEBUG - winDebug ("winAboutDlgProc - WM_INITDIALOG\n"); -#endif - - /* Store pointers to private structures for future use */ - s_pScreenPriv = (winPrivScreenPtr) lParam; - s_pScreenInfo = s_pScreenPriv->pScreenInfo; - s_pScreen = s_pScreenInfo->pScreen; - - winInitDialog (hwndDialog); - - /* Override the URL buttons */ - winOverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); - winOverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); - winOverrideURLButton (hwndDialog, ID_ABOUT_UG); - winOverrideURLButton (hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - - case WM_DRAWITEM: - /* Draw the URL buttons as needed */ - winDrawURLWindow (lParam); - return TRUE; - - case WM_MOUSEMOVE: - case WM_NCMOUSEMOVE: - /* Show the cursor if it is hidden */ - if (g_fSoftwareCursor && !g_fCursor) - { - g_fCursor = TRUE; - ShowCursor (TRUE); - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - case IDCANCEL: - ErrorF ("winAboutDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); - - DestroyWindow (g_hDlgAbout); - g_hDlgAbout = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - - /* Restore window procedures for URL buttons */ - winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - - case ID_ABOUT_CHANGELOG: - { - int iReturn; -#ifdef __CYGWIN__ - const char * pszCygPath = "/usr/X11R6/share/doc/" - "xorg-x11-xwin/changelog.html"; - char pszWinPath[MAX_PATH + 1]; - - /* Convert the POSIX path to a Win32 path */ - cygwin_conv_to_win32_path (pszCygPath, pszWinPath); -#else - const char * pszWinPath = "http://x.cygwin.com/" - "devel/server/changelog.html"; -#endif - - iReturn = (int)ShellExecute (NULL, - "open", - pszWinPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_CHANGELOG - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - - case ID_ABOUT_WEBSITE: - { - const char * pszPath = __VENDORDWEBSUPPORT__; - int iReturn; - - iReturn = (int)ShellExecute (NULL, - "open", - pszPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_WEBSITE - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - - case ID_ABOUT_UG: - { - const char * pszPath = "http://x.cygwin.com/docs/ug/"; - int iReturn; - - iReturn = (int)ShellExecute (NULL, - "open", - pszPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_UG - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - - case ID_ABOUT_FAQ: - { - const char * pszPath = "http://x.cygwin.com/docs/faq/"; - int iReturn; - - iReturn = (int)ShellExecute (NULL, - "open", - pszPath, - NULL, - NULL, - SW_MAXIMIZE); - if (iReturn < 32) - { - ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_FAQ - " - "ShellExecute failed: %d\n", - iReturn); - } - } - return TRUE; - } - break; - - case WM_CLOSE: - ErrorF ("winAboutDlgProc - WM_CLOSE\n"); - - DestroyWindow (g_hDlgAbout); - g_hDlgAbout = NULL; - - /* Fix to make sure keyboard focus isn't trapped */ - PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); - - /* Restore window procedures for URL buttons */ - winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); - winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); - - return TRUE; - } - - return FALSE; -} +/* + *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + * Earle F. Philhower III + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" +#ifdef __CYGWIN__ +#include +#endif +#include +#include "winprefs.h" + + +/* + * References to external globals + */ + +#ifdef XWIN_CLIPBOARD +extern Bool g_fClipboardStarted; +#endif +/* + * Local function prototypes + */ + +static wBOOL CALLBACK +winExitDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + +static wBOOL CALLBACK +winChangeDepthDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + +static wBOOL CALLBACK +winAboutDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + + +static void +winDrawURLWindow (LPARAM lParam); + +static LRESULT CALLBACK +winURLWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static void +winOverrideURLButton (HWND hdlg, int id); + +static void +winUnoverrideURLButton (HWND hdlg, int id); + + +/* + * Owner-draw a button as a URL + */ + +static void +winDrawURLWindow (LPARAM lParam) +{ + DRAWITEMSTRUCT *draw; + char str[256]; + RECT rect; + HFONT font; + COLORREF crText; + + draw = (DRAWITEMSTRUCT *) lParam; + GetWindowText (draw->hwndItem, str, sizeof(str)); + str[255] = 0; + GetClientRect (draw->hwndItem, &rect); + + /* Color the button depending upon its state */ + if (draw->itemState & ODS_SELECTED) + crText = RGB(128+64,0,0); + else if (draw->itemState & ODS_FOCUS) + crText = RGB(0,128+64,0); + else + crText = RGB(0,0,128+64); + SetTextColor (draw->hDC, crText); + + /* Create font 8 high, standard dialog font */ + font = CreateFont (-8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, + 0, 0, 0, 0, 0, "MS Sans Serif"); + if (!font) + { + ErrorF ("winDrawURLWindow: Unable to create URL font, bailing.\n"); + return; + } + /* Draw it */ + SetBkMode (draw->hDC, OPAQUE); + SelectObject (draw->hDC, font); + DrawText (draw->hDC, str, strlen (str),&rect,DT_CENTER | DT_VCENTER); + /* Delete the created font, replace it with stock font */ + DeleteObject (SelectObject (draw->hDC, GetStockObject (ANSI_VAR_FONT))); +} + + +/* + * WndProc for overridden buttons + */ + +static LRESULT CALLBACK +winURLWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC origCB = NULL; + HCURSOR cursor; + + /* If it's a SetCursor message, tell it to the hand */ + if (msg==WM_SETCURSOR) { + cursor = LoadCursor (NULL, IDC_HAND); + if (cursor) + SetCursor (cursor); + return TRUE; + } + origCB = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + /* Otherwise fall through to original WndProc */ + if (origCB) + return CallWindowProc (origCB, hwnd, msg, wParam, lParam); + else + return FALSE; +} + + +/* + * Register and unregister the custom WndProc + */ + +static void +winOverrideURLButton (HWND hwnd, int id) +{ + WNDPROC origCB; + origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), + GWLP_WNDPROC, (LONG_PTR)winURLWndProc); + SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_USERDATA, (LONG_PTR)origCB); +} + +static void +winUnoverrideURLButton (HWND hwnd, int id) +{ + WNDPROC origCB; + origCB = (WNDPROC)SetWindowLongPtr(GetDlgItem (hwnd, id), + GWLP_USERDATA, 0); + if (origCB) + SetWindowLongPtr(GetDlgItem (hwnd, id), GWLP_WNDPROC, (LONG_PTR)origCB); +} + + +/* + * Center a dialog window in the desktop window + * and set small and large icons to X icons. + */ + +static void +winInitDialog (HWND hwndDlg) +{ + HWND hwndDesk; + RECT rc, rcDlg, rcDesk; + HICON hIcon, hIconSmall; + + hwndDesk = GetParent (hwndDlg); + if (!hwndDesk || IsIconic (hwndDesk)) + hwndDesk = GetDesktopWindow (); + + /* Remove minimize and maximize buttons */ + SetWindowLongPtr(hwndDlg, GWL_STYLE, + GetWindowLongPtr(hwndDlg, GWL_STYLE) + & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); + + /* Set Window not to show in the task bar */ + SetWindowLongPtr(hwndDlg, GWL_EXSTYLE, + GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) & ~WS_EX_APPWINDOW ); + + /* Center dialog window in the screen. Not done for multi-monitor systems, where + * it is likely to end up split across the screens. In that case, it appears + * near the Tray icon. + */ + if (GetSystemMetrics(SM_CMONITORS)>1) { + /* Still need to refresh the frame change. */ + SetWindowPos (hwndDlg, HWND_TOPMOST, 0,0,0,0, + SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + } else { + GetWindowRect (hwndDesk, &rcDesk); + GetWindowRect (hwndDlg, &rcDlg); + CopyRect (&rc, &rcDesk); + + OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top); + OffsetRect (&rc, -rc.left, -rc.top); + OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom); + + SetWindowPos (hwndDlg, + HWND_TOPMOST, + rcDesk.left + (rc.right / 2), + rcDesk.top + (rc.bottom / 2), + 0, 0, + SWP_NOSIZE | SWP_FRAMECHANGED); + } + +#ifdef XWIN_MULTIWINDOW + if (g_hIconX) hIcon=g_hIconX; + else +#endif + hIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN)); + +#ifdef XWIN_MULTIWINDOW + if (g_hSmallIconX) hIconSmall=g_hSmallIconX; + else +#endif + hIconSmall = LoadImage (g_hInstance, + MAKEINTRESOURCE(IDI_XWIN), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_SHARED); + + PostMessage (hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon); + PostMessage (hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); +} + + +/* + * Display the Exit dialog box + */ + +void +winDisplayExitDialog (winPrivScreenPtr pScreenPriv) +{ + int i; + int liveClients = 0; + + /* Count up running clients (clients[0] is serverClient) */ + for (i = 1; i < currentMaxClients; i++) + if (clients[i] != NullClient) + liveClients++; +#if defined(XWIN_MULTIWINDOW) + /* Count down server internal clients */ + if (pScreenPriv->pScreenInfo->fMultiWindow) + liveClients -= 2; /* multiwindow window manager & XMsgProc */ +#endif +#if defined(XWIN_CLIPBOARD) + if (g_fClipboardStarted) + liveClients--; /* clipboard manager */ +#endif + + /* A user reported that this sometimes drops below zero. just eye-candy. */ + if (liveClients < 0) + liveClients = 0; + + /* Don't show the exit confirmation dialog if SilentExit & no clients, + or ForceExit, is enabled */ + if ((pref.fSilentExit && liveClients <= 0) || pref.fForceExit) + { + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + PostMessage (pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); + return; + } + + pScreenPriv->iConnectedClients = liveClients; + + /* Check if dialog already exists */ + if (g_hDlgExit != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgExit, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgExit); + + return; + } + + /* Create dialog box */ + g_hDlgExit = CreateDialogParam (g_hInstance, + "EXIT_DIALOG", + pScreenPriv->hwndScreen, + winExitDlgProc, + (int) pScreenPriv); + + /* Show the dialog box */ + ShowWindow (g_hDlgExit, SW_SHOW); + + /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ + SetForegroundWindow (g_hDlgExit); + + /* Set focus to the Cancel button */ + PostMessage (g_hDlgExit, WM_NEXTDLGCTL, + (WPARAM)GetDlgItem (g_hDlgExit, IDCANCEL), TRUE); +} + +#define CONNECTED_CLIENTS_FORMAT "There %s currently %d client%s connected." + + +/* + * Exit dialog window procedure + */ + +static wBOOL CALLBACK +winExitDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: + { + char *pszConnectedClients; + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + + winInitDialog (hDialog); + + /* Format the connected clients string */ + if (asprintf (&pszConnectedClients, CONNECTED_CLIENTS_FORMAT, + (s_pScreenPriv->iConnectedClients == 1) ? "is" : "are", + s_pScreenPriv->iConnectedClients, + (s_pScreenPriv->iConnectedClients == 1) ? "" : "s") == -1) + return TRUE; + + + + /* Set the number of connected clients */ + SetWindowText (GetDlgItem (hDialog, IDC_CLIENTS_CONNECTED), + pszConnectedClients); + free(pszConnectedClients); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + /* Send message to call the GiveUp function */ + PostMessage (s_pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + + case IDCANCEL: + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + break; + + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + /* Show the cursor if it is hidden */ + if (g_fSoftwareCursor && !g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return TRUE; + + case WM_CLOSE: + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + + return FALSE; +} + + +/* + * Display the Depth Change dialog box + */ + +void +winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv) +{ + /* Check if dialog already exists */ + if (g_hDlgDepthChange != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgDepthChange); + + return; + } + + /* + * Display a notification to the user that the visual + * will not be displayed until the Windows display depth + * is restored to the original value. + */ + g_hDlgDepthChange = CreateDialogParam (g_hInstance, + "DEPTH_CHANGE_BOX", + pScreenPriv->hwndScreen, + winChangeDepthDlgProc, + (int) pScreenPriv); + /* Show the dialog box */ + ShowWindow (g_hDlgDepthChange, SW_SHOW); + + ErrorF ("winDisplayDepthChangeDialog - DialogBox returned: %d\n", + (int) g_hDlgDepthChange); + ErrorF ("winDisplayDepthChangeDialog - GetLastError: %d\n", + (int) GetLastError ()); + + /* Minimize the display window */ + ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); +} + + +/* + * Process messages for the dialog that is displayed for + * disruptive screen depth changes. + */ + +static wBOOL CALLBACK +winChangeDepthDlgProc (HWND hwndDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc\n"); +#endif + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_INITDIALOG\n"); +#endif + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - s_pScreenPriv: %08x, " + "s_pScreenInfo: %08x, s_pScreen: %08x\n", + s_pScreenPriv, s_pScreenInfo, s_pScreen); +#endif + +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_INITDIALOG - orig bpp: %d, " + "current bpp: %d\n", + s_pScreenInfo->dwBPP, + GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL)); +#endif + + winInitDialog( hwndDialog ); + + return TRUE; + + case WM_DISPLAYCHANGE: +#if CYGDEBUG + winDebug ("winChangeDepthDlgProc - WM_DISPLAYCHANGE - orig bpp: %d, " + "new bpp: %d\n", + s_pScreenInfo->dwBPP, + GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL)); +#endif + + /* Dismiss the dialog if the display returns to the original depth */ + if (GetDeviceCaps(s_pScreenPriv->hdcScreen, BITSPIXEL) == s_pScreenInfo->dwBPP) + { + ErrorF ("winChangeDelthDlgProc - wParam == s_pScreenInfo->dwBPP\n"); + + /* Depth has been restored, dismiss dialog */ + DestroyWindow (g_hDlgDepthChange); + g_hDlgDepthChange = NULL; + + /* Flag that we have a valid screen depth */ + s_pScreenPriv->fBadDepth = FALSE; + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + case IDCANCEL: + ErrorF ("winChangeDepthDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); + + /* + * User dismissed the dialog, hide it until the + * display mode is restored. + */ + ShowWindow (g_hDlgDepthChange, SW_HIDE); + return TRUE; + } + break; + + case WM_CLOSE: + ErrorF ("winChangeDepthDlgProc - WM_CLOSE\n"); + + DestroyWindow (g_hDlgAbout); + g_hDlgAbout = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + + return FALSE; +} + + +/* + * Display the About dialog box + */ + +void +winDisplayAboutDialog (winPrivScreenPtr pScreenPriv) +{ + /* Check if dialog already exists */ + if (g_hDlgAbout != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgAbout, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgAbout); + + return; + } + + /* + * Display the about box + */ + g_hDlgAbout = CreateDialogParam (g_hInstance, + "ABOUT_BOX", + pScreenPriv->hwndScreen, + winAboutDlgProc, + (int) pScreenPriv); + + /* Show the dialog box */ + ShowWindow (g_hDlgAbout, SW_SHOW); + + /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ + SetForegroundWindow (g_hDlgAbout); + + /* Set focus to the OK button */ + PostMessage (g_hDlgAbout, WM_NEXTDLGCTL, + (WPARAM)GetDlgItem (g_hDlgAbout, IDOK), TRUE); +} + + +/* + * Process messages for the about dialog. + */ + +static wBOOL CALLBACK +winAboutDlgProc (HWND hwndDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + +#if CYGDEBUG + winDebug ("winAboutDlgProc\n"); +#endif + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: +#if CYGDEBUG + winDebug ("winAboutDlgProc - WM_INITDIALOG\n"); +#endif + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + + winInitDialog (hwndDialog); + + /* Override the URL buttons */ + winOverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); + winOverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); + winOverrideURLButton (hwndDialog, ID_ABOUT_UG); + winOverrideURLButton (hwndDialog, ID_ABOUT_FAQ); + + return TRUE; + + case WM_DRAWITEM: + /* Draw the URL buttons as needed */ + winDrawURLWindow (lParam); + return TRUE; + + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + /* Show the cursor if it is hidden */ + if (g_fSoftwareCursor && !g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + case IDCANCEL: + ErrorF ("winAboutDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); + + DestroyWindow (g_hDlgAbout); + g_hDlgAbout = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + + /* Restore window procedures for URL buttons */ + winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); + + return TRUE; + + case ID_ABOUT_CHANGELOG: + { + int iReturn; +#ifdef __CYGWIN__ + const char * pszCygPath = "/usr/X11R6/share/doc/" + "xorg-x11-xwin/changelog.html"; + char pszWinPath[MAX_PATH + 1]; + + /* Convert the POSIX path to a Win32 path */ + cygwin_conv_to_win32_path (pszCygPath, pszWinPath); +#else + const char * pszWinPath = "http://x.cygwin.com/" + "devel/server/changelog.html"; +#endif + + iReturn = (int)ShellExecute (NULL, + "open", + pszWinPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_CHANGELOG - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + + case ID_ABOUT_WEBSITE: + { + const char * pszPath = __VENDORDWEBSUPPORT__; + int iReturn; + + iReturn = (int)ShellExecute (NULL, + "open", + pszPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_WEBSITE - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + + case ID_ABOUT_UG: + { + const char * pszPath = "http://x.cygwin.com/docs/ug/"; + int iReturn; + + iReturn = (int)ShellExecute (NULL, + "open", + pszPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_UG - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + + case ID_ABOUT_FAQ: + { + const char * pszPath = "http://x.cygwin.com/docs/faq/"; + int iReturn; + + iReturn = (int)ShellExecute (NULL, + "open", + pszPath, + NULL, + NULL, + SW_MAXIMIZE); + if (iReturn < 32) + { + ErrorF ("winAboutDlgProc - WM_COMMAND - ID_ABOUT_FAQ - " + "ShellExecute failed: %d\n", + iReturn); + } + } + return TRUE; + } + break; + + case WM_CLOSE: + ErrorF ("winAboutDlgProc - WM_CLOSE\n"); + + DestroyWindow (g_hDlgAbout); + g_hDlgAbout = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + + /* Restore window procedures for URL buttons */ + winUnoverrideURLButton (hwndDialog, ID_ABOUT_CHANGELOG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_WEBSITE); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_UG); + winUnoverrideURLButton (hwndDialog, ID_ABOUT_FAQ); + + return TRUE; + } + + return FALSE; +} diff --git a/xorg-server/hw/xwin/winmonitors.c b/xorg-server/hw/xwin/winmonitors.c new file mode 100644 index 000000000..63af803d0 --- /dev/null +++ b/xorg-server/hw/xwin/winmonitors.c @@ -0,0 +1,92 @@ +/* + +Copyright 1993, 1998 The Open Group +Copyright (C) Colin Harrison 2005-2008 + +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. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + + +#include "win.h" +#include "winmonitors.h" + +/* + * getMonitorInfo - callback function used to return information from the enumeration of monitors attached + */ + +static +wBOOL CALLBACK getMonitorInfo(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM _data) +{ + struct GetMonitorInfoData* data = (struct GetMonitorInfoData*)_data; + // only get data for monitor number specified in + data->monitorNum++; + if (data->monitorNum == data->requestedMonitor) + { + data->bMonitorSpecifiedExists = TRUE; + data->monitorOffsetX = rect->left; + data->monitorOffsetY = rect->top; + data->monitorHeight = rect->bottom - rect->top; + data->monitorWidth = rect->right - rect->left; + return FALSE; + } + return TRUE; +} + +typedef wBOOL (*ENUMDISPLAYMONITORSPROC)(HDC,LPCRECT,MONITORENUMPROC,LPARAM); +ENUMDISPLAYMONITORSPROC _EnumDisplayMonitors; + +wBOOL CALLBACK getMonitorInfo(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM _data); + +Bool QueryMonitor(int index, struct GetMonitorInfoData *data) +{ + /* Load EnumDisplayMonitors from DLL */ + HMODULE user32; + FARPROC func; + user32 = LoadLibrary("user32.dll"); + if (user32 == NULL) + { + winW32Error(2, "Could not open user32.dll"); + return FALSE; + } + func = GetProcAddress(user32, "EnumDisplayMonitors"); + if (func == NULL) + { + winW32Error(2, "Could not resolve EnumDisplayMonitors: "); + return FALSE; + } + _EnumDisplayMonitors = (ENUMDISPLAYMONITORSPROC)func; + + /* prepare data */ + if (data == NULL) + return FALSE; + memset(data, 0, sizeof(*data)); + data->requestedMonitor = index; + + /* query information */ + _EnumDisplayMonitors(NULL, NULL, getMonitorInfo, (LPARAM) data); + + /* cleanup */ + FreeLibrary(user32); + return TRUE; +} diff --git a/xorg-server/hw/xwin/winmonitors.h b/xorg-server/hw/xwin/winmonitors.h new file mode 100644 index 000000000..180566b00 --- /dev/null +++ b/xorg-server/hw/xwin/winmonitors.h @@ -0,0 +1,14 @@ + +/* data returned for monitor information */ +struct GetMonitorInfoData { + int requestedMonitor; + int monitorNum; + Bool bUserSpecifiedMonitor; + Bool bMonitorSpecifiedExists; + int monitorOffsetX; + int monitorOffsetY; + int monitorHeight; + int monitorWidth; +}; + +Bool QueryMonitor(int index, struct GetMonitorInfoData *data); diff --git a/xorg-server/hw/xwin/winnativegdi.c b/xorg-server/hw/xwin/winnativegdi.c index 1a41bb484..4d7afe898 100644 --- a/xorg-server/hw/xwin/winnativegdi.c +++ b/xorg-server/hw/xwin/winnativegdi.c @@ -1,539 +1,534 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" - - -/* - * Local function prototypes - */ - -static Bool -winAllocateFBNativeGDI (ScreenPtr pScreen); - -static void -winShadowUpdateNativeGDI (ScreenPtr pScreen, - shadowBufPtr pBuf); - -static Bool -winCloseScreenNativeGDI (int nIndex, ScreenPtr pScreen); - -static Bool -winInitVisualsNativeGDI (ScreenPtr pScreen); - -static Bool -winAdjustVideoModeNativeGDI (ScreenPtr pScreen); - -#if 0 -static Bool -winBltExposedRegionsNativeGDI (ScreenPtr pScreen); -#endif - -static Bool -winActivateAppNativeGDI (ScreenPtr pScreen); - -static Bool -winRedrawScreenNativeGDI (ScreenPtr pScreen); - -static Bool -winRealizeInstalledPaletteNativeGDI (ScreenPtr pScreen); - -static Bool -winInstallColormapNativeGDI (ColormapPtr pColormap); - -static Bool -winStoreColorsNativeGDI (ColormapPtr pmap, - int ndef, - xColorItem *pdefs); - -static Bool -winCreateColormapNativeGDI (ColormapPtr pColormap); - -static Bool -winDestroyColormapNativeGDI (ColormapPtr pColormap); - - - -static Bool -winAllocateFBNativeGDI (ScreenPtr pScreen) -{ - FatalError ("winAllocateFBNativeGDI\n"); - - return TRUE; -} - - -/* - * We wrap whatever CloseScreen procedure was specified by fb; - * a pointer to said procedure is stored in our privates. - */ - -static Bool -winCloseScreenNativeGDI (int nIndex, ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - ErrorF ("winCloseScreenNativeGDI - Freeing screen resources\n"); - - /* Flag that the screen is closed */ - pScreenPriv->fClosed = TRUE; - pScreenPriv->fActive = FALSE; - - /* - * NOTE: mi doesn't use a CloseScreen procedure, so we do not - * need to call a wrapped procedure here. - */ - - /* Delete the window property */ - RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); - - ErrorF ("winCloseScreenNativeGDI - Destroying window\n"); - - /* Delete tray icon, if we have one */ - if (!pScreenInfo->fNoTrayIcon) - winDeleteNotifyIcon (pScreenPriv); - - /* Free the exit confirmation dialog box, if it exists */ - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - - /* Kill our window */ - if (pScreenPriv->hwndScreen) - { - DestroyWindow (pScreenPriv->hwndScreen); - pScreenPriv->hwndScreen = NULL; - } - - /* Invalidate our screeninfo's pointer to the screen */ - pScreenInfo->pScreen = NULL; - - /* Free the screen privates for this screen */ - free (pScreenPriv); - - ErrorF ("winCloseScreenNativeGDI - Returning\n"); - - return TRUE; -} - - -static void -winShadowUpdateNativeGDI (ScreenPtr pScreen, - shadowBufPtr pBuf) -{ - FatalError ("winShadowUpdateNativeGDI\n"); - return; -} - - -static Bool -winInitVisualsNativeGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Set the bitsPerRGB and bit masks */ - switch (pScreenInfo->dwDepth) - { - case 24: - pScreenPriv->dwBitsPerRGB = 8; - pScreenPriv->dwRedMask = 0x00FF0000; - pScreenPriv->dwGreenMask = 0x0000FF00; - pScreenPriv->dwBlueMask = 0x000000FF; - break; - - case 16: - pScreenPriv->dwBitsPerRGB = 6; - pScreenPriv->dwRedMask = 0xF800; - pScreenPriv->dwGreenMask = 0x07E0; - pScreenPriv->dwBlueMask = 0x001F; - break; - - case 15: - pScreenPriv->dwBitsPerRGB = 5; - pScreenPriv->dwRedMask = 0x7C00; - pScreenPriv->dwGreenMask = 0x03E0; - pScreenPriv->dwBlueMask = 0x001F; - break; - - case 8: - pScreenPriv->dwBitsPerRGB = 8; - pScreenPriv->dwRedMask = 0; - pScreenPriv->dwGreenMask = 0; - pScreenPriv->dwBlueMask = 0; - break; - - default: - ErrorF ("winInitVisualsNativeGDI - Unknown screen depth\n"); - return FALSE; - break; - } - - /* Tell the user how many bits per RGB we are using */ - ErrorF ("winInitVisualsNativeGDI - Using dwBitsPerRGB: %d\n", - (int) pScreenPriv->dwBitsPerRGB); - - /* Create a single visual according to the Windows screen depth */ - switch (pScreenInfo->dwDepth) - { - case 24: - case 16: - case 15: - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - TrueColorMask, - pScreenPriv->dwBitsPerRGB, - TrueColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisuals - miSetVisualTypesAndMasks failed\n"); - return FALSE; - } - break; - - case 8: - ErrorF ("winInitVisuals - Calling miSetVisualTypesAndMasks\n"); - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - StaticColorMask, - pScreenPriv->dwBitsPerRGB, - StaticColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisuals - miSetVisualTypesAndMasks failed\n"); - return FALSE; - } - break; - - default: - ErrorF ("winInitVisualsNativeGDI - Unknown screen depth\n"); - return FALSE; - } - -#if 1 - ErrorF ("winInitVisualsNativeGDI - Returning\n"); -#endif - - return TRUE; -} - - -/* Adjust the video mode */ -static Bool -winAdjustVideoModeNativeGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HDC hdc = NULL; - DWORD dwBPP; - - hdc = GetDC (NULL); - - /* We're in serious trouble if we can't get a DC */ - if (hdc == NULL) - { - ErrorF ("winAdjustVideoModeNativeGDI - GetDC () failed\n"); - return FALSE; - } - - /* Query GDI for current display depth */ - dwBPP = GetDeviceCaps (hdc, BITSPIXEL); - pScreenInfo->dwDepth = GetDeviceCaps (hdc, PLANES); - - switch (pScreenInfo->dwDepth) { - case 24: - case 16: - case 15: - case 8: - break; - default: - if (dwBPP == 32) - pScreenInfo->dwDepth = 24; - else - pScreenInfo->dwDepth = dwBPP; - break; - } - - /* GDI cannot change the screen depth */ - if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP) - { - /* No -depth parameter passed, let the user know the depth being used */ - ErrorF ("winAdjustVideoModeNativeGDI - Using Windows display " - "depth of %d bits per pixel, %d depth\n", - (int) dwBPP, (int) pScreenInfo->dwDepth); - - /* Use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - else if (dwBPP != pScreenInfo->dwBPP) - { - /* Warn user if GDI depth is different than -depth parameter */ - ErrorF ("winAdjustVideoModeNativeGDI - Command line bpp: %d, "\ - "using bpp: %d\n", - (int) pScreenInfo->dwBPP, (int) dwBPP); - - /* We'll use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - - return TRUE; -} - - -static Bool -winActivateAppNativeGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* - * Are we active? - * Are we fullscreen? - */ - if (pScreenPriv != NULL - && pScreenPriv->fActive - && pScreenInfo->fFullScreen) - { - /* - * Activating, attempt to bring our window - * to the top of the display - */ - ShowWindow (pScreenPriv->hwndScreen, SW_RESTORE); - } - - /* - * Are we inactive? - * Are we fullscreen? - */ - if (pScreenPriv != NULL - && !pScreenPriv->fActive - && pScreenInfo->fFullScreen) - { - /* - * Deactivating, stuff our window onto the - * task bar. - */ - ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); - } - - return TRUE; -} - - -HBITMAP -winCreateDIBNativeGDI (int iWidth, int iHeight, int iDepth, - BYTE **ppbBits, BITMAPINFO **ppbmi) -{ - BITMAPINFOHEADER *pbmih = NULL; - HBITMAP hBitmap = NULL; - BITMAPINFO *pbmi = NULL; - - /* Don't create an invalid bitmap */ - if (iWidth == 0 - || iHeight == 0 - || iDepth == 0) - { - ErrorF ("\nwinCreateDIBNativeGDI - Invalid specs w %d h %d d %d\n\n", - iWidth, iHeight, iDepth); - return NULL; - } - - /* Allocate bitmap info header */ - pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER) - + 256 * sizeof (RGBQUAD)); - if (pbmih == NULL) - { - ErrorF ("winCreateDIBNativeGDI - malloc () failed\n"); - return FALSE; - } - ZeroMemory (pbmih, sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD)); - - /* Describe bitmap to be created */ - pbmih->biSize = sizeof (BITMAPINFOHEADER); - pbmih->biWidth = iWidth; - pbmih->biHeight = -iHeight; - pbmih->biPlanes = 1; - pbmih->biBitCount = iDepth; - pbmih->biCompression = BI_RGB; - pbmih->biSizeImage = 0; - pbmih->biXPelsPerMeter = 0; - pbmih->biYPelsPerMeter = 0; - pbmih->biClrUsed = 0; - pbmih->biClrImportant = 0; - - /* Setup color table for mono DIBs */ - if (iDepth == 1) - { - pbmi = (BITMAPINFO*) pbmih; - pbmi->bmiColors[1].rgbBlue = 255; - pbmi->bmiColors[1].rgbGreen = 255; - pbmi->bmiColors[1].rgbRed = 255; - } - - /* Create a DIB with a bit pointer */ - hBitmap = CreateDIBSection (NULL, - (BITMAPINFO *) pbmih, - DIB_RGB_COLORS, - (void **) ppbBits, - NULL, - 0); - if (hBitmap == NULL) - { - ErrorF ("winCreateDIBNativeGDI - CreateDIBSection () failed\n"); - return NULL; - } - - /* Free the bitmap info header memory */ - if (ppbmi != NULL) - { - /* Store the address of the BMIH in the ppbmih parameter */ - *ppbmi = (BITMAPINFO *) pbmih; - } - else - { - free (pbmih); - pbmih = NULL; - } - - return hBitmap; -} - - -#if 0 -static Bool -winBltExposedRegionsNativeGDI (ScreenPtr pScreen) -{ - - return TRUE; -} -#endif - - -static Bool -winRedrawScreenNativeGDI (ScreenPtr pScreen) -{ - FatalError ("winRedrawScreenNativeGDI\n"); - return TRUE; -} - - -static Bool -winRealizeInstalledPaletteNativeGDI (ScreenPtr pScreen) -{ - FatalError ("winRealizeInstalledPaletteNativeGDI\n"); - return TRUE; -} - - -static Bool -winInstallColormapNativeGDI (ColormapPtr pColormap) -{ - FatalError ("winInstallColormapNativeGDI\n"); - return TRUE; -} - - -static Bool -winStoreColorsNativeGDI (ColormapPtr pmap, - int ndef, - xColorItem *pdefs) -{ - FatalError ("winStoreColorsNativeGDI\n"); - return TRUE; -} - - -static Bool -winCreateColormapNativeGDI (ColormapPtr pColormap) -{ - FatalError ("winCreateColormapNativeGDI\n"); - return TRUE; -} - - -static Bool -winDestroyColormapNativeGDI (ColormapPtr pColormap) -{ - FatalError ("winDestroyColormapNativeGDI\n"); - return TRUE; -} - - -/* Set engine specific funtions */ -Bool -winSetEngineFunctionsNativeGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Set our pointers */ - pScreenPriv->pwinAllocateFB = winAllocateFBNativeGDI; - pScreenPriv->pwinShadowUpdate = winShadowUpdateNativeGDI; - pScreenPriv->pwinCloseScreen = winCloseScreenNativeGDI; - pScreenPriv->pwinInitVisuals = winInitVisualsNativeGDI; - pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeNativeGDI; - if (pScreenInfo->fFullScreen) - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; - else - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; - pScreenPriv->pwinFinishScreenInit = winFinishScreenInitNativeGDI; - /* - * WARNING: Do not set the BltExposedRegions procedure pointer to anything - * other than NULL until a working painting procedure is in place. - * Else, winWindowProc will get stuck in an infinite loop because - * Windows expects the BeginPaint and EndPaint functions to be called - * before a WM_PAINT message can be removed from the queue. We are - * using NULL here as a signal for winWindowProc that it should - * not signal that the WM_PAINT message has been processed. - */ - pScreenPriv->pwinBltExposedRegions = NULL; - pScreenPriv->pwinActivateApp = winActivateAppNativeGDI; - pScreenPriv->pwinRedrawScreen = winRedrawScreenNativeGDI; - pScreenPriv->pwinRealizeInstalledPalette = - winRealizeInstalledPaletteNativeGDI; - pScreenPriv->pwinInstallColormap = winInstallColormapNativeGDI; - pScreenPriv->pwinStoreColors = winStoreColorsNativeGDI; - pScreenPriv->pwinCreateColormap = winCreateColormapNativeGDI; - pScreenPriv->pwinDestroyColormap = winDestroyColormapNativeGDI; - pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; - - return TRUE; -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" + + +/* + * Local function prototypes + */ + +static Bool +winAllocateFBNativeGDI (ScreenPtr pScreen); + +static void +winShadowUpdateNativeGDI (ScreenPtr pScreen, + shadowBufPtr pBuf); + +static Bool +winCloseScreenNativeGDI (int nIndex, ScreenPtr pScreen); + +static Bool +winInitVisualsNativeGDI (ScreenPtr pScreen); + +static Bool +winAdjustVideoModeNativeGDI (ScreenPtr pScreen); + +#if 0 +static Bool +winBltExposedRegionsNativeGDI (ScreenPtr pScreen); +#endif + +static Bool +winActivateAppNativeGDI (ScreenPtr pScreen); + +static Bool +winRedrawScreenNativeGDI (ScreenPtr pScreen); + +static Bool +winRealizeInstalledPaletteNativeGDI (ScreenPtr pScreen); + +static Bool +winInstallColormapNativeGDI (ColormapPtr pColormap); + +static Bool +winStoreColorsNativeGDI (ColormapPtr pmap, + int ndef, + xColorItem *pdefs); + +static Bool +winCreateColormapNativeGDI (ColormapPtr pColormap); + +static Bool +winDestroyColormapNativeGDI (ColormapPtr pColormap); + + + +static Bool +winAllocateFBNativeGDI (ScreenPtr pScreen) +{ + FatalError ("winAllocateFBNativeGDI\n"); + + return TRUE; +} + +static void +winFreeFBNativeGDI (ScreenPtr pScreen) +{ + FatalError ("winFreeFBNativeGDI\n"); +} + + +static Bool +winInitScreenNativeGDI(ScreenPtr pScreen) +{ + FatalError ("winInitScreenNativeGDI\n"); +} + +/* + * We wrap whatever CloseScreen procedure was specified by fb; + * a pointer to said procedure is stored in our privates. + */ + +static Bool +winCloseScreenNativeGDI (int nIndex, ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + ErrorF ("winCloseScreenNativeGDI - Freeing screen resources\n"); + + /* Flag that the screen is closed */ + pScreenPriv->fClosed = TRUE; + pScreenPriv->fActive = FALSE; + + /* + * NOTE: mi doesn't use a CloseScreen procedure, so we do not + * need to call a wrapped procedure here. + */ + + /* Delete the window property */ + RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); + + ErrorF ("winCloseScreenNativeGDI - Destroying window\n"); + + /* Delete tray icon, if we have one */ + if (!pScreenInfo->fNoTrayIcon) + winDeleteNotifyIcon (pScreenPriv); + + /* Free the exit confirmation dialog box, if it exists */ + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + + /* Kill our window */ + if (pScreenPriv->hwndScreen) + { + DestroyWindow (pScreenPriv->hwndScreen); + pScreenPriv->hwndScreen = NULL; + } + + /* Invalidate our screeninfo's pointer to the screen */ + pScreenInfo->pScreen = NULL; + + /* Free the screen privates for this screen */ + free (pScreenPriv); + + ErrorF ("winCloseScreenNativeGDI - Returning\n"); + + return TRUE; +} + + +static void +winShadowUpdateNativeGDI (ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + FatalError ("winShadowUpdateNativeGDI\n"); + return; +} + + +static Bool +winInitVisualsNativeGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Set the bitsPerRGB and bit masks */ + switch (pScreenInfo->dwDepth) + { + case 24: + pScreenPriv->dwBitsPerRGB = 8; + pScreenPriv->dwRedMask = 0x00FF0000; + pScreenPriv->dwGreenMask = 0x0000FF00; + pScreenPriv->dwBlueMask = 0x000000FF; + break; + + case 16: + pScreenPriv->dwBitsPerRGB = 6; + pScreenPriv->dwRedMask = 0xF800; + pScreenPriv->dwGreenMask = 0x07E0; + pScreenPriv->dwBlueMask = 0x001F; + break; + + case 15: + pScreenPriv->dwBitsPerRGB = 5; + pScreenPriv->dwRedMask = 0x7C00; + pScreenPriv->dwGreenMask = 0x03E0; + pScreenPriv->dwBlueMask = 0x001F; + break; + + case 8: + pScreenPriv->dwBitsPerRGB = 8; + pScreenPriv->dwRedMask = 0; + pScreenPriv->dwGreenMask = 0; + pScreenPriv->dwBlueMask = 0; + break; + + default: + ErrorF ("winInitVisualsNativeGDI - Unknown screen depth\n"); + return FALSE; + break; + } + + /* Tell the user how many bits per RGB we are using */ + ErrorF ("winInitVisualsNativeGDI - Using dwBitsPerRGB: %d\n", + (int) pScreenPriv->dwBitsPerRGB); + + /* Create a single visual according to the Windows screen depth */ + switch (pScreenInfo->dwDepth) + { + case 24: + case 16: + case 15: + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + TrueColorMask, + pScreenPriv->dwBitsPerRGB, + TrueColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisuals - miSetVisualTypesAndMasks failed\n"); + return FALSE; + } + break; + + case 8: + ErrorF ("winInitVisuals - Calling miSetVisualTypesAndMasks\n"); + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + StaticColorMask, + pScreenPriv->dwBitsPerRGB, + StaticColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisuals - miSetVisualTypesAndMasks failed\n"); + return FALSE; + } + break; + + default: + ErrorF ("winInitVisualsNativeGDI - Unknown screen depth\n"); + return FALSE; + } + +#if 1 + ErrorF ("winInitVisualsNativeGDI - Returning\n"); +#endif + + return TRUE; +} + + +/* Adjust the video mode */ +static Bool +winAdjustVideoModeNativeGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HDC hdc = NULL; + DWORD dwBPP; + + hdc = GetDC (NULL); + + /* We're in serious trouble if we can't get a DC */ + if (hdc == NULL) + { + ErrorF ("winAdjustVideoModeNativeGDI - GetDC () failed\n"); + return FALSE; + } + + /* Query GDI for current display depth */ + dwBPP = GetDeviceCaps (hdc, BITSPIXEL); + pScreenInfo->dwDepth = GetDeviceCaps (hdc, PLANES); + + switch (pScreenInfo->dwDepth) { + case 24: + case 16: + case 15: + case 8: + break; + default: + if (dwBPP == 32) + pScreenInfo->dwDepth = 24; + else + pScreenInfo->dwDepth = dwBPP; + break; + } + + /* GDI cannot change the screen depth, so we'll use GDI's depth */ + pScreenInfo->dwBPP = dwBPP; + + /* Release our DC */ + ReleaseDC (NULL, hdc); + + return TRUE; +} + + +static Bool +winActivateAppNativeGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* + * Are we active? + * Are we fullscreen? + */ + if (pScreenPriv != NULL + && pScreenPriv->fActive + && pScreenInfo->fFullScreen) + { + /* + * Activating, attempt to bring our window + * to the top of the display + */ + ShowWindow (pScreenPriv->hwndScreen, SW_RESTORE); + } + + /* + * Are we inactive? + * Are we fullscreen? + */ + if (pScreenPriv != NULL + && !pScreenPriv->fActive + && pScreenInfo->fFullScreen) + { + /* + * Deactivating, stuff our window onto the + * task bar. + */ + ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); + } + + return TRUE; +} + + +HBITMAP +winCreateDIBNativeGDI (int iWidth, int iHeight, int iDepth, + BYTE **ppbBits, BITMAPINFO **ppbmi) +{ + BITMAPINFOHEADER *pbmih = NULL; + HBITMAP hBitmap = NULL; + BITMAPINFO *pbmi = NULL; + + /* Don't create an invalid bitmap */ + if (iWidth == 0 + || iHeight == 0 + || iDepth == 0) + { + ErrorF ("\nwinCreateDIBNativeGDI - Invalid specs w %d h %d d %d\n\n", + iWidth, iHeight, iDepth); + return NULL; + } + + /* Allocate bitmap info header */ + pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER) + + 256 * sizeof (RGBQUAD)); + if (pbmih == NULL) + { + ErrorF ("winCreateDIBNativeGDI - malloc () failed\n"); + return FALSE; + } + ZeroMemory (pbmih, sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD)); + + /* Describe bitmap to be created */ + pbmih->biSize = sizeof (BITMAPINFOHEADER); + pbmih->biWidth = iWidth; + pbmih->biHeight = -iHeight; + pbmih->biPlanes = 1; + pbmih->biBitCount = iDepth; + pbmih->biCompression = BI_RGB; + pbmih->biSizeImage = 0; + pbmih->biXPelsPerMeter = 0; + pbmih->biYPelsPerMeter = 0; + pbmih->biClrUsed = 0; + pbmih->biClrImportant = 0; + + /* Setup color table for mono DIBs */ + if (iDepth == 1) + { + pbmi = (BITMAPINFO*) pbmih; + pbmi->bmiColors[1].rgbBlue = 255; + pbmi->bmiColors[1].rgbGreen = 255; + pbmi->bmiColors[1].rgbRed = 255; + } + + /* Create a DIB with a bit pointer */ + hBitmap = CreateDIBSection (NULL, + (BITMAPINFO *) pbmih, + DIB_RGB_COLORS, + (void **) ppbBits, + NULL, + 0); + if (hBitmap == NULL) + { + ErrorF ("winCreateDIBNativeGDI - CreateDIBSection () failed\n"); + return NULL; + } + + /* Free the bitmap info header memory */ + if (ppbmi != NULL) + { + /* Store the address of the BMIH in the ppbmih parameter */ + *ppbmi = (BITMAPINFO *) pbmih; + } + else + { + free (pbmih); + pbmih = NULL; + } + + return hBitmap; +} + + +#if 0 +static Bool +winBltExposedRegionsNativeGDI (ScreenPtr pScreen) +{ + + return TRUE; +} +#endif + + +static Bool +winRedrawScreenNativeGDI (ScreenPtr pScreen) +{ + FatalError ("winRedrawScreenNativeGDI\n"); + return TRUE; +} + + +static Bool +winRealizeInstalledPaletteNativeGDI (ScreenPtr pScreen) +{ + FatalError ("winRealizeInstalledPaletteNativeGDI\n"); + return TRUE; +} + + +static Bool +winInstallColormapNativeGDI (ColormapPtr pColormap) +{ + FatalError ("winInstallColormapNativeGDI\n"); + return TRUE; +} + + +static Bool +winStoreColorsNativeGDI (ColormapPtr pmap, + int ndef, + xColorItem *pdefs) +{ + FatalError ("winStoreColorsNativeGDI\n"); + return TRUE; +} + + +static Bool +winCreateColormapNativeGDI (ColormapPtr pColormap) +{ + FatalError ("winCreateColormapNativeGDI\n"); + return TRUE; +} + + +static Bool +winDestroyColormapNativeGDI (ColormapPtr pColormap) +{ + FatalError ("winDestroyColormapNativeGDI\n"); + return TRUE; +} + + +/* Set engine specific funtions */ +Bool +winSetEngineFunctionsNativeGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Set our pointers */ + pScreenPriv->pwinAllocateFB = winAllocateFBNativeGDI; + pScreenPriv->pwinFreeFB = winFreeFBNativeGDI; + pScreenPriv->pwinShadowUpdate = winShadowUpdateNativeGDI; + pScreenPriv->pwinInitScreen = winInitScreenNativeGDI; + pScreenPriv->pwinCloseScreen = winCloseScreenNativeGDI; + pScreenPriv->pwinInitVisuals = winInitVisualsNativeGDI; + pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeNativeGDI; + if (pScreenInfo->fFullScreen) + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; + else + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; + pScreenPriv->pwinFinishScreenInit = winFinishScreenInitNativeGDI; + /* + * WARNING: Do not set the BltExposedRegions procedure pointer to anything + * other than NULL until a working painting procedure is in place. + * Else, winWindowProc will get stuck in an infinite loop because + * Windows expects the BeginPaint and EndPaint functions to be called + * before a WM_PAINT message can be removed from the queue. We are + * using NULL here as a signal for winWindowProc that it should + * not signal that the WM_PAINT message has been processed. + */ + pScreenPriv->pwinBltExposedRegions = NULL; + pScreenPriv->pwinActivateApp = winActivateAppNativeGDI; + pScreenPriv->pwinRedrawScreen = winRedrawScreenNativeGDI; + pScreenPriv->pwinRealizeInstalledPalette = + winRealizeInstalledPaletteNativeGDI; + pScreenPriv->pwinInstallColormap = winInstallColormapNativeGDI; + pScreenPriv->pwinStoreColors = winStoreColorsNativeGDI; + pScreenPriv->pwinCreateColormap = winCreateColormapNativeGDI; + pScreenPriv->pwinDestroyColormap = winDestroyColormapNativeGDI; + pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winpfbdd.c b/xorg-server/hw/xwin/winpfbdd.c index 840a839f0..c0bca71e3 100644 --- a/xorg-server/hw/xwin/winpfbdd.c +++ b/xorg-server/hw/xwin/winpfbdd.c @@ -1,676 +1,678 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" - - -/* - * Local function prototypes - */ - -static Bool -winAllocateFBPrimaryDD (ScreenPtr pScreen); - -static Bool -winCloseScreenPrimaryDD (int nIndex, ScreenPtr pScreen); - -static Bool -winInitVisualsPrimaryDD (ScreenPtr pScreen); - -static Bool -winAdjustVideoModePrimaryDD (ScreenPtr pScreen); - -static Bool -winActivateAppPrimaryDD (ScreenPtr pScreen); - -static Bool -winHotKeyAltTabPrimaryDD (ScreenPtr pScreen); - - -/* - * Create a DirectDraw primary surface - */ - -static Bool -winAllocateFBPrimaryDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HRESULT ddrval = DD_OK; - DDSURFACEDESC ddsd; - DDSURFACEDESC *pddsdPrimary = NULL; - DDSURFACEDESC *pddsdOffscreen = NULL; - RECT rcClient; - - ErrorF ("winAllocateFBPrimaryDD\n"); - - /* Get client area location in screen coords */ - GetClientRect (pScreenPriv->hwndScreen, &rcClient); - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&rcClient, 2); - - /* Create a DirectDraw object, store the address at lpdd */ - ddrval = (*g_fpDirectDrawCreate) (NULL, &pScreenPriv->pdd, NULL); - if (ddrval != DD_OK) - FatalError ("winAllocateFBPrimaryDD - Could not start DirectDraw\n"); - - /* Get a DirectDraw2 interface pointer */ - ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, - &IID_IDirectDraw2, - (LPVOID*) &pScreenPriv->pdd2); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Failed DD2 query: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - - - ErrorF ("winAllocateFBPrimaryDD - Created and initialized DD\n"); - - /* Are we windowed or fullscreen? */ - if (pScreenInfo->fFullScreen) - { - /* Full screen mode */ - ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, - pScreenPriv->hwndScreen, - DDSCL_FULLSCREEN - | DDSCL_EXCLUSIVE); - if (FAILED (ddrval)) - FatalError ("winAllocateFBPrimaryDD - Could not set " - "cooperative level\n"); - - /* Change the video mode to the mode requested */ - ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, - pScreenInfo->dwWidth, - pScreenInfo->dwHeight, - pScreenInfo->dwBPP, - pScreenInfo->dwRefreshRate, - 0); - if (FAILED (ddrval)) - FatalError ("winAllocateFBPrimaryDD - Could not set " - "full screen display mode\n"); - } - else - { - /* Windowed mode */ - ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, - pScreenPriv->hwndScreen, - DDSCL_NORMAL); - if (FAILED (ddrval)) - FatalError ("winAllocateFBPrimaryDD - Could not set " - "cooperative level\n"); - } - - /* Describe the primary surface */ - ZeroMemory (&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - /* Create the primary surface */ - ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, - &ddsd, - &pScreenPriv->pddsPrimary, - NULL); - if (FAILED (ddrval)) - FatalError ("winAllocateFBPrimaryDD - Could not create primary " - "surface %08x\n", (unsigned int) ddrval); - - ErrorF ("winAllocateFBPrimaryDD - Created primary\n"); - - /* Allocate a DD surface description for our screen privates */ - pddsdPrimary = pScreenPriv->pddsdPrimary - = malloc (sizeof (DDSURFACEDESC)); - if (pddsdPrimary == NULL) - FatalError ("winAllocateFBPrimaryDD - Could not allocate surface " - "description memory\n"); - ZeroMemory (pddsdPrimary, sizeof (*pddsdPrimary)); - pddsdPrimary->dwSize = sizeof (*pddsdPrimary); - - /* Describe the offscreen surface to be created */ - /* - * NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, - * as drawing, locking, and unlocking take forever - * with video memory surfaces. In addition, - * video memory is a somewhat scarce resource, - * so you shouldn't be allocating video memory when - * you have the option of using system memory instead. - */ - ZeroMemory (&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - ddsd.dwHeight = pScreenInfo->dwHeight; - ddsd.dwWidth = pScreenInfo->dwWidth; - - /* Create the shadow surface */ - ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, - &ddsd, - &pScreenPriv->pddsOffscreen, - NULL); - if (ddrval != DD_OK) - FatalError ("winAllocateFBPrimaryDD - Could not create shadow " - "surface\n"); - - ErrorF ("winAllocateFBPrimaryDD - Created offscreen\n"); - - /* Allocate a DD surface description for our screen privates */ - pddsdOffscreen = pScreenPriv->pddsdOffscreen - = malloc (sizeof (DDSURFACEDESC)); - if (pddsdOffscreen == NULL) - FatalError ("winAllocateFBPrimaryDD - Could not allocate surface " - "description memory\n"); - ZeroMemory (pddsdOffscreen, sizeof (*pddsdOffscreen)); - pddsdOffscreen->dwSize = sizeof (*pddsdOffscreen); - - ErrorF ("winAllocateFBPrimaryDD - Locking primary\n"); - - /* Lock the primary surface */ - ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsPrimary, - pScreenInfo->fFullScreen ? NULL:&rcClient, - pddsdPrimary, - DDLOCK_WAIT, - NULL); - if (ddrval != DD_OK || pddsdPrimary->lpSurface == NULL) - FatalError ("winAllocateFBPrimaryDD - Could not lock " - "primary surface\n"); - - ErrorF ("winAllocateFBPrimaryDD - Locked primary\n"); - - /* We don't know how to deal with anything other than RGB */ - if (!(pddsdPrimary->ddpfPixelFormat.dwFlags & DDPF_RGB)) - FatalError ("winAllocateFBPrimaryDD - Color format other than RGB\n"); - - /* Grab the pitch from the surface desc */ - pScreenInfo->dwStride = (pddsdPrimary->u1.lPitch * 8) - / pScreenInfo->dwBPP; - - /* Save the pointer to our surface memory */ - pScreenInfo->pfb = pddsdPrimary->lpSurface; - - /* Grab the color depth and masks from the surface description */ - pScreenPriv->dwRedMask = pddsdPrimary->ddpfPixelFormat.u2.dwRBitMask; - pScreenPriv->dwGreenMask = pddsdPrimary->ddpfPixelFormat.u3.dwGBitMask; - pScreenPriv->dwBlueMask = pddsdPrimary->ddpfPixelFormat.u4.dwBBitMask; - - ErrorF ("winAllocateFBPrimaryDD - Returning\n"); - - return TRUE; -} - - -/* - * Call the wrapped CloseScreen function. - * - * Free our resources and private structures. - */ - -static Bool -winCloseScreenPrimaryDD (int nIndex, ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - Bool fReturn; - - ErrorF ("winCloseScreenPrimaryDD - Freeing screen resources\n"); - - /* Flag that the screen is closed */ - pScreenPriv->fClosed = TRUE; - pScreenPriv->fActive = FALSE; - - /* Call the wrapped CloseScreen procedure */ - WIN_UNWRAP(CloseScreen); - fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); - - /* Delete the window property */ - RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); - - /* Free the offscreen surface, if there is one */ - if (pScreenPriv->pddsOffscreen) - { - IDirectDrawSurface2_Unlock (pScreenPriv->pddsOffscreen, NULL); - IDirectDrawSurface2_Release (pScreenPriv->pddsOffscreen); - pScreenPriv->pddsOffscreen = NULL; - } - - /* Release the primary surface, if there is one */ - if (pScreenPriv->pddsPrimary) - { - IDirectDrawSurface2_Unlock (pScreenPriv->pddsPrimary, NULL); - IDirectDrawSurface2_Release (pScreenPriv->pddsPrimary); - pScreenPriv->pddsPrimary = NULL; - } - - /* Free the DirectDraw object, if there is one */ - if (pScreenPriv->pdd) - { - IDirectDraw2_RestoreDisplayMode (pScreenPriv->pdd); - IDirectDraw2_Release (pScreenPriv->pdd); - pScreenPriv->pdd = NULL; - } - - /* Delete tray icon, if we have one */ - if (!pScreenInfo->fNoTrayIcon) - winDeleteNotifyIcon (pScreenPriv); - - /* Free the exit confirmation dialog box, if it exists */ - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - - /* Kill our window */ - if (pScreenPriv->hwndScreen) - { - DestroyWindow (pScreenPriv->hwndScreen); - pScreenPriv->hwndScreen = NULL; - } - - /* Kill our screeninfo's pointer to the screen */ - pScreenInfo->pScreen = NULL; - - /* Invalidate the ScreenInfo's fb pointer */ - pScreenInfo->pfb = NULL; - - /* Free the screen privates for this screen */ - free ((pointer) pScreenPriv); - - return fReturn; -} - - -/* - * Tell mi what sort of visuals we need. - * - * Generally we only need one visual, as our screen can only - * handle one format at a time, I believe. You may want - * to verify that last sentence. - */ - -static Bool -winInitVisualsPrimaryDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - DWORD dwRedBits, dwGreenBits, dwBlueBits; - - /* Count the number of ones in each color mask */ - dwRedBits = winCountBits (pScreenPriv->dwRedMask); - dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); - dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); - - /* Store the maximum number of ones in a color mask as the bitsPerRGB */ - if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwRedBits; - else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwGreenBits; - else - pScreenPriv->dwBitsPerRGB = dwBlueBits; - - ErrorF ("winInitVisualsPrimaryDD - Masks: %08x %08x %08x bpRGB: %d\n", - (unsigned int) pScreenPriv->dwRedMask, - (unsigned int) pScreenPriv->dwGreenMask, - (unsigned int) pScreenPriv->dwBlueMask, - (int) pScreenPriv->dwBitsPerRGB); - - /* Create a single visual according to the Windows screen depth */ - switch (pScreenInfo->dwDepth) - { - case 24: - case 16: - case 15: - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - TrueColorMask, - pScreenPriv->dwBitsPerRGB, - TrueColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsPrimaryDD - " - "miSetVisualTypesAndMasks failed\n"); - return FALSE; - } - break; - - case 8: -#if CYGDEBUG - winDebug ("winInitVisuals - Calling miSetVisualTypesAndMasks\n"); -#endif /* CYGDEBUG */ - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - PseudoColorMask, - pScreenPriv->dwBitsPerRGB, - PseudoColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsPrimaryDD - " - "miSetVisualTypesAndMasks failed\n"); - return FALSE; - } -#if CYGDEBUG - winDebug ("winInitVisualsPrimaryDD - Returned from " - "miSetVisualTypesAndMasks\n"); -#endif /* CYGDEBUG */ - break; - - default: - ErrorF ("winInitVisualsPrimaryDD - Unknown screen depth\n"); - return FALSE; - } - - ErrorF ("winInitVisualsPrimaryDD - Returning\n"); - - return TRUE; -} - - -static Bool -winAdjustVideoModePrimaryDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HDC hdc = NULL; - DWORD dwBPP; - - /* We're in serious trouble if we can't get a DC */ - hdc = GetDC (NULL); - if (hdc == NULL) - { - ErrorF ("winAdjustVideoModePrimaryDD - GetDC failed\n"); - return FALSE; - } - - /* Query GDI for current display depth */ - dwBPP = GetDeviceCaps (hdc, BITSPIXEL); - - /* DirectDraw can only change the depth in fullscreen mode */ - if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP) - { - /* No -depth parameter passed, let the user know the depth being used */ - ErrorF ("winAdjustVideoModePrimaryDD - Using Windows display " - "depth of %d bits per pixel\n", (int) dwBPP); - - /* Use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - else if (pScreenInfo->fFullScreen - && pScreenInfo->dwBPP != dwBPP) - { - /* FullScreen, and GDI depth differs from -depth parameter */ - ErrorF ("winAdjustVideoModePrimaryDD - FullScreen, using command " - "line depth: %d\n", (int) pScreenInfo->dwBPP); - } - else if (dwBPP != pScreenInfo->dwBPP) - { - /* Windowed, and GDI depth differs from -depth parameter */ - ErrorF ("winAdjustVideoModePrimaryDD - Windowed, command line " - "depth: %d, using depth: %d\n", - (int) pScreenInfo->dwBPP, (int) dwBPP); - - /* We'll use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - - return TRUE; -} - - -/* - * We need to blit our offscreen fb to - * the screen when we are activated, and we need to point - * the fb code back to the primary surface memory. - */ - -static Bool -winActivateAppPrimaryDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RECT rcSrc, rcClient; - HRESULT ddrval = DD_OK; - - /* Check for errors */ - if (pScreenPriv == NULL - || pScreenPriv->pddsPrimary == NULL - || pScreenPriv->pddsOffscreen == NULL) - return FALSE; - - /* Check for do-nothing */ - if (!pScreenPriv->fActive) - return TRUE; - - /* We are activating */ - ddrval = IDirectDrawSurface2_IsLost (pScreenPriv->pddsOffscreen); - if (ddrval == DD_OK) - { - IDirectDrawSurface2_Unlock (pScreenPriv->pddsOffscreen, - NULL); - /* - * We don't check for an error from Unlock, because it - * doesn't matter if the Unlock failed. - */ - } - - /* Restore both surfaces, just cause I like it that way */ - IDirectDrawSurface2_Restore (pScreenPriv->pddsOffscreen); - IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); - - /* Get client area in screen coords */ - GetClientRect (pScreenPriv->hwndScreen, &rcClient); - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&rcClient, 2); - - /* Setup a source rectangle */ - rcSrc.left = 0; - rcSrc.top = 0; - rcSrc.right = pScreenInfo->dwWidth; - rcSrc.bottom = pScreenInfo->dwHeight; - - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, - &rcClient, - pScreenPriv->pddsOffscreen, - &rcSrc, - DDBLT_WAIT, - NULL); - if (ddrval != DD_OK) - FatalError ("winActivateAppPrimaryDD () - Failed blitting offscreen " - "surface to primary surface %08x\n", (unsigned int) ddrval); - - /* Lock the primary surface */ - ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsPrimary, - &rcClient, - pScreenPriv->pddsdPrimary, - DDLOCK_WAIT, - NULL); - if (ddrval != DD_OK - || pScreenPriv->pddsdPrimary->lpSurface == NULL) - FatalError ("winActivateAppPrimaryDD () - Could not lock " - "primary surface\n"); - - /* Notify FB of the new memory pointer */ - winUpdateFBPointer (pScreen, - pScreenPriv->pddsdPrimary->lpSurface); - - /* - * Register the Alt-Tab combo as a hotkey so we can copy - * the primary framebuffer before the display mode changes - */ - RegisterHotKey (pScreenPriv->hwndScreen, 1, MOD_ALT, 9); - - return TRUE; -} - - -/* - * Handle the Alt+Tab hotkey. - * - * We need to save the primary fb to an offscreen fb when - * we get deactivated, and point the fb code at the offscreen - * fb for the duration of the deactivation. - */ - -static Bool -winHotKeyAltTabPrimaryDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RECT rcClient, rcSrc; - HRESULT ddrval = DD_OK; - - ErrorF ("\nwinHotKeyAltTabPrimaryDD\n\n"); - - /* Alt+Tab was pressed, we will lose focus very soon */ - pScreenPriv->fActive = FALSE; - - /* Check for error conditions */ - if (pScreenPriv->pddsPrimary == NULL - || pScreenPriv->pddsOffscreen == NULL) - return FALSE; - - /* Get client area in screen coords */ - GetClientRect (pScreenPriv->hwndScreen, &rcClient); - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&rcClient, 2); - - /* Did we loose the primary surface? */ - ddrval = IDirectDrawSurface2_IsLost (pScreenPriv->pddsPrimary); - if (ddrval == DD_OK) - { - ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsPrimary, - NULL); - if (FAILED (ddrval)) - FatalError ("winHotKeyAltTabPrimaryDD - Failed unlocking primary " - "surface\n"); - } - - /* Setup a source rectangle */ - rcSrc.left = 0; - rcSrc.top = 0; - rcSrc.right = pScreenInfo->dwWidth; - rcSrc.bottom = pScreenInfo->dwHeight; - - /* Blit the primary surface to the offscreen surface */ - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsOffscreen, - NULL, /* should be rcDest */ - pScreenPriv->pddsPrimary, - NULL, - DDBLT_WAIT, - NULL); - if (ddrval == DDERR_SURFACELOST) - { - IDirectDrawSurface2_Restore (pScreenPriv->pddsOffscreen); - IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); - - /* Blit the primary surface to the offscreen surface */ - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsOffscreen, - NULL, - pScreenPriv->pddsPrimary, - NULL, - DDBLT_WAIT, - NULL); - if (FAILED (ddrval)) - FatalError ("winHotKeyAltTabPrimaryDD - Failed blitting primary " - "surface to offscreen surface: %08x\n", - (unsigned int) ddrval); - } - else - { - FatalError ("winHotKeyAltTabPrimaryDD - Unknown error from " - "Blt: %08dx\n", (unsigned int) ddrval); - } - - /* Lock the offscreen surface */ - ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsOffscreen, - NULL, - pScreenPriv->pddsdOffscreen, - DDLOCK_WAIT, - NULL); - if (ddrval != DD_OK - || pScreenPriv->pddsdPrimary->lpSurface == NULL) - FatalError ("winHotKeyAltTabPrimaryDD - Could not lock " - "offscreen surface\n"); - - /* Notify FB of the new memory pointer */ - winUpdateFBPointer (pScreen, - pScreenPriv->pddsdOffscreen->lpSurface); - - /* Unregister our hotkey */ - UnregisterHotKey (pScreenPriv->hwndScreen, 1); - - return TRUE; -} - - -/* Set engine specific functions */ -Bool -winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Set our pointers */ - pScreenPriv->pwinAllocateFB = winAllocateFBPrimaryDD; - pScreenPriv->pwinShadowUpdate - = (winShadowUpdateProcPtr) (void (*)(void))NoopDDA; - pScreenPriv->pwinCloseScreen = winCloseScreenPrimaryDD; - pScreenPriv->pwinInitVisuals = winInitVisualsPrimaryDD; - pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModePrimaryDD; - if (pScreenInfo->fFullScreen) - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; - else - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; - pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; - pScreenPriv->pwinBltExposedRegions - = (winBltExposedRegionsProcPtr) (void (*)(void))NoopDDA; - pScreenPriv->pwinActivateApp = winActivateAppPrimaryDD; - pScreenPriv->pwinHotKeyAltTab = winHotKeyAltTabPrimaryDD; -#ifdef XWIN_MULTIWINDOW - pScreenPriv->pwinFinishCreateWindowsWindow = - (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA; -#endif - - return TRUE; -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" + + +/* + * Local function prototypes + */ + +static Bool +winAllocateFBPrimaryDD (ScreenPtr pScreen); + +static Bool +winCloseScreenPrimaryDD (int nIndex, ScreenPtr pScreen); + +static Bool +winInitVisualsPrimaryDD (ScreenPtr pScreen); + +static Bool +winAdjustVideoModePrimaryDD (ScreenPtr pScreen); + +static Bool +winActivateAppPrimaryDD (ScreenPtr pScreen); + +static Bool +winHotKeyAltTabPrimaryDD (ScreenPtr pScreen); + + +/* + * Create a DirectDraw primary surface + */ + +static Bool +winAllocateFBPrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HRESULT ddrval = DD_OK; + DDSURFACEDESC ddsd; + DDSURFACEDESC *pddsdPrimary = NULL; + DDSURFACEDESC *pddsdOffscreen = NULL; + RECT rcClient; + + ErrorF ("winAllocateFBPrimaryDD\n"); + + /* Get client area location in screen coords */ + GetClientRect (pScreenPriv->hwndScreen, &rcClient); + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&rcClient, 2); + + /* Create a DirectDraw object, store the address at lpdd */ + ddrval = (*g_fpDirectDrawCreate) (NULL, &pScreenPriv->pdd, NULL); + if (ddrval != DD_OK) + FatalError ("winAllocateFBPrimaryDD - Could not start DirectDraw\n"); + + /* Get a DirectDraw2 interface pointer */ + ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, + &IID_IDirectDraw2, + (LPVOID*) &pScreenPriv->pdd2); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Failed DD2 query: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + + + ErrorF ("winAllocateFBPrimaryDD - Created and initialized DD\n"); + + /* Are we windowed or fullscreen? */ + if (pScreenInfo->fFullScreen) + { + /* Full screen mode */ + ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, + pScreenPriv->hwndScreen, + DDSCL_FULLSCREEN + | DDSCL_EXCLUSIVE); + if (FAILED (ddrval)) + FatalError ("winAllocateFBPrimaryDD - Could not set " + "cooperative level\n"); + + /* Change the video mode to the mode requested */ + ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, + pScreenInfo->dwWidth, + pScreenInfo->dwHeight, + pScreenInfo->dwBPP, + pScreenInfo->dwRefreshRate, + 0); + if (FAILED (ddrval)) + FatalError ("winAllocateFBPrimaryDD - Could not set " + "full screen display mode\n"); + } + else + { + /* Windowed mode */ + ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, + pScreenPriv->hwndScreen, + DDSCL_NORMAL); + if (FAILED (ddrval)) + FatalError ("winAllocateFBPrimaryDD - Could not set " + "cooperative level\n"); + } + + /* Describe the primary surface */ + ZeroMemory (&ddsd, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + /* Create the primary surface */ + ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, + &ddsd, + &pScreenPriv->pddsPrimary, + NULL); + if (FAILED (ddrval)) + FatalError ("winAllocateFBPrimaryDD - Could not create primary " + "surface %08x\n", (unsigned int) ddrval); + + ErrorF ("winAllocateFBPrimaryDD - Created primary\n"); + + /* Allocate a DD surface description for our screen privates */ + pddsdPrimary = pScreenPriv->pddsdPrimary + = malloc (sizeof (DDSURFACEDESC)); + if (pddsdPrimary == NULL) + FatalError ("winAllocateFBPrimaryDD - Could not allocate surface " + "description memory\n"); + ZeroMemory (pddsdPrimary, sizeof (*pddsdPrimary)); + pddsdPrimary->dwSize = sizeof (*pddsdPrimary); + + /* Describe the offscreen surface to be created */ + /* + * NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, + * as drawing, locking, and unlocking take forever + * with video memory surfaces. In addition, + * video memory is a somewhat scarce resource, + * so you shouldn't be allocating video memory when + * you have the option of using system memory instead. + */ + ZeroMemory (&ddsd, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.dwHeight = pScreenInfo->dwHeight; + ddsd.dwWidth = pScreenInfo->dwWidth; + + /* Create the shadow surface */ + ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, + &ddsd, + &pScreenPriv->pddsOffscreen, + NULL); + if (ddrval != DD_OK) + FatalError ("winAllocateFBPrimaryDD - Could not create shadow " + "surface\n"); + + ErrorF ("winAllocateFBPrimaryDD - Created offscreen\n"); + + /* Allocate a DD surface description for our screen privates */ + pddsdOffscreen = pScreenPriv->pddsdOffscreen + = malloc (sizeof (DDSURFACEDESC)); + if (pddsdOffscreen == NULL) + FatalError ("winAllocateFBPrimaryDD - Could not allocate surface " + "description memory\n"); + ZeroMemory (pddsdOffscreen, sizeof (*pddsdOffscreen)); + pddsdOffscreen->dwSize = sizeof (*pddsdOffscreen); + + ErrorF ("winAllocateFBPrimaryDD - Locking primary\n"); + + /* Lock the primary surface */ + ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsPrimary, + pScreenInfo->fFullScreen ? NULL:&rcClient, + pddsdPrimary, + DDLOCK_WAIT, + NULL); + if (ddrval != DD_OK || pddsdPrimary->lpSurface == NULL) + FatalError ("winAllocateFBPrimaryDD - Could not lock " + "primary surface\n"); + + ErrorF ("winAllocateFBPrimaryDD - Locked primary\n"); + + /* We don't know how to deal with anything other than RGB */ + if (!(pddsdPrimary->ddpfPixelFormat.dwFlags & DDPF_RGB)) + FatalError ("winAllocateFBPrimaryDD - Color format other than RGB\n"); + + /* Grab the pitch from the surface desc */ + pScreenInfo->dwStride = (pddsdPrimary->u1.lPitch * 8) + / pScreenInfo->dwBPP; + + /* Save the pointer to our surface memory */ + pScreenInfo->pfb = pddsdPrimary->lpSurface; + + /* Grab the color depth and masks from the surface description */ + pScreenPriv->dwRedMask = pddsdPrimary->ddpfPixelFormat.u2.dwRBitMask; + pScreenPriv->dwGreenMask = pddsdPrimary->ddpfPixelFormat.u3.dwGBitMask; + pScreenPriv->dwBlueMask = pddsdPrimary->ddpfPixelFormat.u4.dwBBitMask; + + ErrorF ("winAllocateFBPrimaryDD - Returning\n"); + + return TRUE; +} + +static void +winFreeFBPrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Free the offscreen surface, if there is one */ + if (pScreenPriv->pddsOffscreen) + { + IDirectDrawSurface2_Unlock (pScreenPriv->pddsOffscreen, NULL); + IDirectDrawSurface2_Release (pScreenPriv->pddsOffscreen); + pScreenPriv->pddsOffscreen = NULL; + } + + /* Release the primary surface, if there is one */ + if (pScreenPriv->pddsPrimary) + { + IDirectDrawSurface2_Unlock (pScreenPriv->pddsPrimary, NULL); + IDirectDrawSurface2_Release (pScreenPriv->pddsPrimary); + pScreenPriv->pddsPrimary = NULL; + } + + /* Free the DirectDraw object, if there is one */ + if (pScreenPriv->pdd) + { + IDirectDraw2_RestoreDisplayMode (pScreenPriv->pdd); + IDirectDraw2_Release (pScreenPriv->pdd); + pScreenPriv->pdd = NULL; + } + + /* Invalidate the ScreenInfo's fb pointer */ + pScreenInfo->pfb = NULL; +} + +static Bool +winInitScreenPrimaryDD(ScreenPtr pScreen) +{ + return winAllocateFBPrimaryDD(pScreen); +} + +/* + * Call the wrapped CloseScreen function. + * + * Free our resources and private structures. + */ + +static Bool +winCloseScreenPrimaryDD (int nIndex, ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + Bool fReturn; + + ErrorF ("winCloseScreenPrimaryDD - Freeing screen resources\n"); + + /* Flag that the screen is closed */ + pScreenPriv->fClosed = TRUE; + pScreenPriv->fActive = FALSE; + + /* Call the wrapped CloseScreen procedure */ + WIN_UNWRAP(CloseScreen); + fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); + + /* Delete the window property */ + RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); + + winFreeFBPrimaryDD(pScreen); + + /* Delete tray icon, if we have one */ + if (!pScreenInfo->fNoTrayIcon) + winDeleteNotifyIcon (pScreenPriv); + + /* Free the exit confirmation dialog box, if it exists */ + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + + /* Kill our window */ + if (pScreenPriv->hwndScreen) + { + DestroyWindow (pScreenPriv->hwndScreen); + pScreenPriv->hwndScreen = NULL; + } + + /* Kill our screeninfo's pointer to the screen */ + pScreenInfo->pScreen = NULL; + + /* Free the screen privates for this screen */ + free ((pointer) pScreenPriv); + + return fReturn; +} + + +/* + * Tell mi what sort of visuals we need. + * + * Generally we only need one visual, as our screen can only + * handle one format at a time, I believe. You may want + * to verify that last sentence. + */ + +static Bool +winInitVisualsPrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + DWORD dwRedBits, dwGreenBits, dwBlueBits; + + /* Count the number of ones in each color mask */ + dwRedBits = winCountBits (pScreenPriv->dwRedMask); + dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); + dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); + + /* Store the maximum number of ones in a color mask as the bitsPerRGB */ + if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwRedBits; + else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwGreenBits; + else + pScreenPriv->dwBitsPerRGB = dwBlueBits; + + ErrorF ("winInitVisualsPrimaryDD - Masks: %08x %08x %08x bpRGB: %d\n", + (unsigned int) pScreenPriv->dwRedMask, + (unsigned int) pScreenPriv->dwGreenMask, + (unsigned int) pScreenPriv->dwBlueMask, + (int) pScreenPriv->dwBitsPerRGB); + + /* Create a single visual according to the Windows screen depth */ + switch (pScreenInfo->dwDepth) + { + case 24: + case 16: + case 15: + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + TrueColorMask, + pScreenPriv->dwBitsPerRGB, + TrueColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsPrimaryDD - " + "miSetVisualTypesAndMasks failed\n"); + return FALSE; + } + break; + + case 8: +#if CYGDEBUG + winDebug ("winInitVisuals - Calling miSetVisualTypesAndMasks\n"); +#endif /* CYGDEBUG */ + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + PseudoColorMask, + pScreenPriv->dwBitsPerRGB, + PseudoColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsPrimaryDD - " + "miSetVisualTypesAndMasks failed\n"); + return FALSE; + } +#if CYGDEBUG + winDebug ("winInitVisualsPrimaryDD - Returned from " + "miSetVisualTypesAndMasks\n"); +#endif /* CYGDEBUG */ + break; + + default: + ErrorF ("winInitVisualsPrimaryDD - Unknown screen depth\n"); + return FALSE; + } + + ErrorF ("winInitVisualsPrimaryDD - Returning\n"); + + return TRUE; +} + + +static Bool +winAdjustVideoModePrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HDC hdc = NULL; + DWORD dwBPP; + + /* We're in serious trouble if we can't get a DC */ + hdc = GetDC (NULL); + if (hdc == NULL) + { + ErrorF ("winAdjustVideoModePrimaryDD - GetDC failed\n"); + return FALSE; + } + + /* Query GDI for current display depth */ + dwBPP = GetDeviceCaps (hdc, BITSPIXEL); + + /* DirectDraw can only change the depth in fullscreen mode */ + if (!(pScreenInfo->fFullScreen && + (pScreenInfo->dwBPP != WIN_DEFAULT_BPP))) + { + /* Otherwise, We'll use GDI's depth */ + pScreenInfo->dwBPP = dwBPP; + } + + /* Release our DC */ + ReleaseDC (NULL, hdc); + + return TRUE; +} + + +/* + * We need to blit our offscreen fb to + * the screen when we are activated, and we need to point + * the fb code back to the primary surface memory. + */ + +static Bool +winActivateAppPrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RECT rcSrc, rcClient; + HRESULT ddrval = DD_OK; + + /* Check for errors */ + if (pScreenPriv == NULL + || pScreenPriv->pddsPrimary == NULL + || pScreenPriv->pddsOffscreen == NULL) + return FALSE; + + /* Check for do-nothing */ + if (!pScreenPriv->fActive) + return TRUE; + + /* We are activating */ + ddrval = IDirectDrawSurface2_IsLost (pScreenPriv->pddsOffscreen); + if (ddrval == DD_OK) + { + IDirectDrawSurface2_Unlock (pScreenPriv->pddsOffscreen, + NULL); + /* + * We don't check for an error from Unlock, because it + * doesn't matter if the Unlock failed. + */ + } + + /* Restore both surfaces, just cause I like it that way */ + IDirectDrawSurface2_Restore (pScreenPriv->pddsOffscreen); + IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); + + /* Get client area in screen coords */ + GetClientRect (pScreenPriv->hwndScreen, &rcClient); + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&rcClient, 2); + + /* Setup a source rectangle */ + rcSrc.left = 0; + rcSrc.top = 0; + rcSrc.right = pScreenInfo->dwWidth; + rcSrc.bottom = pScreenInfo->dwHeight; + + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, + &rcClient, + pScreenPriv->pddsOffscreen, + &rcSrc, + DDBLT_WAIT, + NULL); + if (ddrval != DD_OK) + FatalError ("winActivateAppPrimaryDD () - Failed blitting offscreen " + "surface to primary surface %08x\n", (unsigned int) ddrval); + + /* Lock the primary surface */ + ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsPrimary, + &rcClient, + pScreenPriv->pddsdPrimary, + DDLOCK_WAIT, + NULL); + if (ddrval != DD_OK + || pScreenPriv->pddsdPrimary->lpSurface == NULL) + FatalError ("winActivateAppPrimaryDD () - Could not lock " + "primary surface\n"); + + /* Notify FB of the new memory pointer */ + winUpdateFBPointer (pScreen, + pScreenPriv->pddsdPrimary->lpSurface); + + /* + * Register the Alt-Tab combo as a hotkey so we can copy + * the primary framebuffer before the display mode changes + */ + RegisterHotKey (pScreenPriv->hwndScreen, 1, MOD_ALT, 9); + + return TRUE; +} + + +/* + * Handle the Alt+Tab hotkey. + * + * We need to save the primary fb to an offscreen fb when + * we get deactivated, and point the fb code at the offscreen + * fb for the duration of the deactivation. + */ + +static Bool +winHotKeyAltTabPrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RECT rcClient, rcSrc; + HRESULT ddrval = DD_OK; + + ErrorF ("\nwinHotKeyAltTabPrimaryDD\n\n"); + + /* Alt+Tab was pressed, we will lose focus very soon */ + pScreenPriv->fActive = FALSE; + + /* Check for error conditions */ + if (pScreenPriv->pddsPrimary == NULL + || pScreenPriv->pddsOffscreen == NULL) + return FALSE; + + /* Get client area in screen coords */ + GetClientRect (pScreenPriv->hwndScreen, &rcClient); + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&rcClient, 2); + + /* Did we loose the primary surface? */ + ddrval = IDirectDrawSurface2_IsLost (pScreenPriv->pddsPrimary); + if (ddrval == DD_OK) + { + ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsPrimary, + NULL); + if (FAILED (ddrval)) + FatalError ("winHotKeyAltTabPrimaryDD - Failed unlocking primary " + "surface\n"); + } + + /* Setup a source rectangle */ + rcSrc.left = 0; + rcSrc.top = 0; + rcSrc.right = pScreenInfo->dwWidth; + rcSrc.bottom = pScreenInfo->dwHeight; + + /* Blit the primary surface to the offscreen surface */ + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsOffscreen, + NULL, /* should be rcDest */ + pScreenPriv->pddsPrimary, + NULL, + DDBLT_WAIT, + NULL); + if (ddrval == DDERR_SURFACELOST) + { + IDirectDrawSurface2_Restore (pScreenPriv->pddsOffscreen); + IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); + + /* Blit the primary surface to the offscreen surface */ + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsOffscreen, + NULL, + pScreenPriv->pddsPrimary, + NULL, + DDBLT_WAIT, + NULL); + if (FAILED (ddrval)) + FatalError ("winHotKeyAltTabPrimaryDD - Failed blitting primary " + "surface to offscreen surface: %08x\n", + (unsigned int) ddrval); + } + else + { + FatalError ("winHotKeyAltTabPrimaryDD - Unknown error from " + "Blt: %08dx\n", (unsigned int) ddrval); + } + + /* Lock the offscreen surface */ + ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsOffscreen, + NULL, + pScreenPriv->pddsdOffscreen, + DDLOCK_WAIT, + NULL); + if (ddrval != DD_OK + || pScreenPriv->pddsdPrimary->lpSurface == NULL) + FatalError ("winHotKeyAltTabPrimaryDD - Could not lock " + "offscreen surface\n"); + + /* Notify FB of the new memory pointer */ + winUpdateFBPointer (pScreen, + pScreenPriv->pddsdOffscreen->lpSurface); + + /* Unregister our hotkey */ + UnregisterHotKey (pScreenPriv->hwndScreen, 1); + + return TRUE; +} + + +/* Set engine specific functions */ +Bool +winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Set our pointers */ + pScreenPriv->pwinAllocateFB = winAllocateFBPrimaryDD; + pScreenPriv->pwinFreeFB = winFreeFBPrimaryDD; + pScreenPriv->pwinShadowUpdate = (winShadowUpdateProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinInitScreen = winInitScreenPrimaryDD; + pScreenPriv->pwinCloseScreen = winCloseScreenPrimaryDD; + pScreenPriv->pwinInitVisuals = winInitVisualsPrimaryDD; + pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModePrimaryDD; + if (pScreenInfo->fFullScreen) + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; + else + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; + pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; + pScreenPriv->pwinBltExposedRegions = (winBltExposedRegionsProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinActivateApp = winActivateAppPrimaryDD; + pScreenPriv->pwinRedrawScreen = NULL; + pScreenPriv->pwinRealizeInstalledPalette = NULL; + pScreenPriv->pwinInstallColormap = NULL; + pScreenPriv->pwinStoreColors = NULL; + pScreenPriv->pwinCreateColormap = NULL; + pScreenPriv->pwinDestroyColormap = NULL; + pScreenPriv->pwinHotKeyAltTab = winHotKeyAltTabPrimaryDD; + pScreenPriv->pwinCreatePrimarySurface = (winCreatePrimarySurfaceProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinReleasePrimarySurface = (winReleasePrimarySurfaceProcPtr) (void (*)(void))NoopDDA; +#ifdef XWIN_MULTIWINDOW + pScreenPriv->pwinFinishCreateWindowsWindow = + (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA; +#endif + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winprocarg.c b/xorg-server/hw/xwin/winprocarg.c index 39f0ee3e5..ddfe1f5b7 100644 --- a/xorg-server/hw/xwin/winprocarg.c +++ b/xorg-server/hw/xwin/winprocarg.c @@ -1,1256 +1,1217 @@ -/* - -Copyright 1993, 1998 The Open Group -Copyright (C) Colin Harrison 2005-2008 - -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. - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall -not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization -from The Open Group. - -*/ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif - -#include <../xfree86/common/xorgVersion.h> -#include "win.h" -#include "winconfig.h" -#include "winmsg.h" - -/* - * References to external symbols - */ - -#ifdef XWIN_CLIPBOARD -extern Bool g_fUnicodeClipboard; -extern Bool g_fClipboard; -#endif -/* globals required by callback function for monitor information */ -struct GetMonitorInfoData { - int requestedMonitor; - int monitorNum; - Bool bUserSpecifiedMonitor; - Bool bMonitorSpecifiedExists; - int monitorOffsetX; - int monitorOffsetY; - int monitorHeight; - int monitorWidth; -}; - -typedef wBOOL (*ENUMDISPLAYMONITORSPROC)(HDC,LPCRECT,MONITORENUMPROC,LPARAM); -ENUMDISPLAYMONITORSPROC _EnumDisplayMonitors; - -wBOOL CALLBACK getMonitorInfo(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM _data); - -static Bool QueryMonitor(int index, struct GetMonitorInfoData *data) -{ - /* Load EnumDisplayMonitors from DLL */ - HMODULE user32; - FARPROC func; - user32 = LoadLibrary("user32.dll"); - if (user32 == NULL) - { - winW32Error(2, "Could not open user32.dll"); - return FALSE; - } - func = GetProcAddress(user32, "EnumDisplayMonitors"); - if (func == NULL) - { - winW32Error(2, "Could not resolve EnumDisplayMonitors: "); - return FALSE; - } - _EnumDisplayMonitors = (ENUMDISPLAYMONITORSPROC)func; - - /* prepare data */ - if (data == NULL) - return FALSE; - memset(data, 0, sizeof(*data)); - data->requestedMonitor = index; - - /* query information */ - _EnumDisplayMonitors(NULL, NULL, getMonitorInfo, (LPARAM) data); - - /* cleanup */ - FreeLibrary(user32); - return TRUE; -} - -/* - * Function prototypes - */ - -void -winLogCommandLine (int argc, char *argv[]); - -void -winLogVersionInfo (void); - -#ifdef DDXOSVERRORF -void OsVendorVErrorF (const char *pszFormat, va_list va_args); -#endif - -/* - * Process arguments on the command line - */ - -static int iLastScreen = -1; -static winScreenInfo defaultScreenInfo; - -static void -winInitializeScreenDefaults(void) -{ - DWORD dwWidth, dwHeight; - static Bool fInitializedScreenDefaults = FALSE; - - /* Bail out early if default screen has already been initialized */ - if (fInitializedScreenDefaults) - return; - - /* Zero the memory used for storing the screen info */ - memset(&defaultScreenInfo, 0, sizeof(winScreenInfo)); - - /* Get default width and height */ - /* - * NOTE: These defaults will cause the window to cover only - * the primary monitor in the case that we have multiple monitors. - */ - dwWidth = GetSystemMetrics (SM_CXSCREEN); - dwHeight = GetSystemMetrics (SM_CYSCREEN); - - winErrorFVerb (2, "winInitializeScreenDefaults - w %d h %d\n", - (int) dwWidth, (int) dwHeight); - - /* Set a default DPI, if no parameter was passed */ - if (monitorResolution == 0) - monitorResolution = WIN_DEFAULT_DPI; - - defaultScreenInfo.dwWidth = dwWidth; - defaultScreenInfo.dwHeight = dwHeight; - defaultScreenInfo.dwUserWidth = dwWidth; - defaultScreenInfo.dwUserHeight = dwHeight; - defaultScreenInfo.fUserGaveHeightAndWidth = WIN_DEFAULT_USER_GAVE_HEIGHT_AND_WIDTH; - defaultScreenInfo.fUserGavePosition = FALSE; - defaultScreenInfo.dwBPP = WIN_DEFAULT_BPP; - defaultScreenInfo.dwClipUpdatesNBoxes = WIN_DEFAULT_CLIP_UPDATES_NBOXES; -#ifdef XWIN_EMULATEPSEUDO - defaultScreenInfo.fEmulatePseudo = WIN_DEFAULT_EMULATE_PSEUDO; -#endif - defaultScreenInfo.dwRefreshRate = WIN_DEFAULT_REFRESH; - defaultScreenInfo.pfb = NULL; - defaultScreenInfo.fFullScreen = FALSE; - defaultScreenInfo.fDecoration = TRUE; -#ifdef XWIN_MULTIWINDOWEXTWM - defaultScreenInfo.fMWExtWM = FALSE; - defaultScreenInfo.fInternalWM = FALSE; -#endif - defaultScreenInfo.fRootless = FALSE; -#ifdef XWIN_MULTIWINDOW - defaultScreenInfo.fMultiWindow = FALSE; -#endif -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - defaultScreenInfo.fMultiMonitorOverride = FALSE; -#endif - defaultScreenInfo.fMultipleMonitors = FALSE; - defaultScreenInfo.fLessPointer = FALSE; - defaultScreenInfo.fScrollbars = FALSE; - defaultScreenInfo.fNoTrayIcon = FALSE; - defaultScreenInfo.iE3BTimeout = WIN_E3B_OFF; - defaultScreenInfo.dwWidth_mm = (dwWidth / WIN_DEFAULT_DPI) * 25.4; - defaultScreenInfo.dwHeight_mm = (dwHeight / WIN_DEFAULT_DPI) * 25.4; - defaultScreenInfo.fUseWinKillKey = WIN_DEFAULT_WIN_KILL; - defaultScreenInfo.fUseUnixKillKey = WIN_DEFAULT_UNIX_KILL; - defaultScreenInfo.fIgnoreInput = FALSE; - defaultScreenInfo.fExplicitScreen = FALSE; - - /* Note that the default screen has been initialized */ - fInitializedScreenDefaults = TRUE; -} - -static void -winInitializeScreen(int i) -{ - winErrorFVerb (2, "winInitializeScreen - %d\n",i); - - /* Initialize default screen values, if needed */ - winInitializeScreenDefaults(); - - /* Copy the default screen info */ - g_ScreenInfo[i] = defaultScreenInfo; - - /* Set the screen number */ - g_ScreenInfo[i].dwScreen = i; -} - -void -winInitializeScreens(int maxscreens) -{ - int i; - winErrorFVerb (2, "winInitializeScreens - %i\n", maxscreens); - - if (maxscreens > g_iNumScreens) - { - /* Reallocate the memory for DDX-specific screen info */ - g_ScreenInfo = realloc(g_ScreenInfo, maxscreens * sizeof (winScreenInfo)); - - /* Set default values for any new screens */ - for (i = g_iNumScreens; i < maxscreens ; i++) - winInitializeScreen(i); - - /* Keep a count of the number of screens */ - g_iNumScreens = maxscreens; - } -} - -/* See Porting Layer Definition - p. 57 */ -/* - * INPUT - * argv: pointer to an array of null-terminated strings, one for - * each token in the X Server command line; the first token - * is 'XWin.exe', or similar. - * argc: a count of the number of tokens stored in argv. - * i: a zero-based index into argv indicating the current token being - * processed. - * - * OUTPUT - * return: return the number of tokens processed correctly. - * - * NOTE - * When looking for n tokens, check that i + n is less than argc. Or, - * you may check if i is greater than or equal to argc, in which case - * you should display the UseMsg () and return 0. - */ - -/* Check if enough arguments are given for the option */ -#define CHECK_ARGS(count) if (i + count >= argc) { UseMsg (); return 0; } - -/* Compare the current option with the string. */ -#define IS_OPTION(name) (strcmp (argv[i], name) == 0) - -int -ddxProcessArgument (int argc, char *argv[], int i) -{ - static Bool s_fBeenHere = FALSE; - winScreenInfo *screenInfoPtr = NULL; - - /* Initialize once */ - if (!s_fBeenHere) - { -#ifdef DDXOSVERRORF - /* - * This initialises our hook into VErrorF () for catching log messages - * that are generated before OsInit () is called. - */ - OsVendorVErrorFProc = OsVendorVErrorF; -#endif - - s_fBeenHere = TRUE; - - /* Initialize only if option is not -help */ - if (!IS_OPTION("-help") && !IS_OPTION("-h") && !IS_OPTION("--help") && - !IS_OPTION("-version") && !IS_OPTION("--version")) - { - - /* Log the version information */ - winLogVersionInfo (); - - /* Log the command line */ - winLogCommandLine (argc, argv); - - /* - * Initialize default screen settings. We have to do this before - * OsVendorInit () gets called, otherwise we will overwrite - * settings changed by parameters such as -fullscreen, etc. - */ - winErrorFVerb (2, "ddxProcessArgument - Initializing default " - "screens\n"); - winInitializeScreenDefaults(); - } - } - -#if CYGDEBUG - winDebug ("ddxProcessArgument - arg: %s\n", argv[i]); -#endif - - /* - * Look for the '-help' and similar options - */ - if (IS_OPTION ("-help") || IS_OPTION("-h") || IS_OPTION("--help")) - { - /* Reset logfile. We don't need that helpmessage in the logfile */ - g_pszLogFile = NULL; - g_fNoHelpMessageBox = TRUE; - UseMsg(); - exit (0); - return 1; - } - - if (IS_OPTION ("-version") || IS_OPTION("--version")) - { - /* Reset logfile. We don't need that versioninfo in the logfile */ - g_pszLogFile = NULL; - winLogVersionInfo (); - exit (0); - return 1; - } - - /* - * Look for the '-screen scr_num [width height]' argument - */ - if (IS_OPTION ("-screen")) - { - int iArgsProcessed = 1; - int nScreenNum; - int iWidth, iHeight, iX, iY; - int iMonitor; - -#if CYGDEBUG - winDebug ("ddxProcessArgument - screen - argc: %d i: %d\n", - argc, i); -#endif - - /* Display the usage message if the argument is malformed */ - if (i + 1 >= argc) - { - return 0; - } - - /* Grab screen number */ - nScreenNum = atoi (argv[i + 1]); - - /* Validate the specified screen number */ - if (nScreenNum < 0) - { - ErrorF ("ddxProcessArgument - screen - Invalid screen number %d\n", - nScreenNum); - UseMsg (); - return 0; - } - - /* - Initialize default values for any new screens - - Note that default values can't change after a -screen option is - seen, so it's safe to do this for each screen as it is introduced - */ - winInitializeScreens(nScreenNum+1); - - /* look for @m where m is monitor number */ - if (i + 2 < argc - && 1 == sscanf(argv[i + 2], "@%d", (int *) &iMonitor)) - { - struct GetMonitorInfoData data; - if (!QueryMonitor(iMonitor, &data)) - { - ErrorF ("ddxProcessArgument - screen - " - "Querying monitors is not supported on NT4 and Win95\n"); - } else if (data.bMonitorSpecifiedExists == TRUE) - { - winErrorFVerb(2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); - iArgsProcessed = 3; - g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE; - g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; - g_ScreenInfo[nScreenNum].dwWidth = data.monitorWidth; - g_ScreenInfo[nScreenNum].dwHeight = data.monitorHeight; - g_ScreenInfo[nScreenNum].dwUserWidth = data.monitorWidth; - g_ScreenInfo[nScreenNum].dwUserHeight = data.monitorHeight; - g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX; - g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY; - } - else - { - /* monitor does not exist, error out */ - ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", - iMonitor); - UseMsg (); - exit (0); - return 0; - } - } - - /* Look for 'WxD' or 'W D' */ - else if (i + 2 < argc - && 2 == sscanf (argv[i + 2], "%dx%d", - (int *) &iWidth, - (int *) &iHeight)) - { - winErrorFVerb (2, "ddxProcessArgument - screen - Found ``WxD'' arg\n"); - iArgsProcessed = 3; - g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = TRUE; - g_ScreenInfo[nScreenNum].dwWidth = iWidth; - g_ScreenInfo[nScreenNum].dwHeight = iHeight; - g_ScreenInfo[nScreenNum].dwUserWidth = iWidth; - g_ScreenInfo[nScreenNum].dwUserHeight = iHeight; - /* Look for WxD+X+Y */ - if (2 == sscanf (argv[i + 2], "%*dx%*d+%d+%d", - (int *) &iX, - (int *) &iY)) - { - winErrorFVerb (2, "ddxProcessArgument - screen - Found ``X+Y'' arg\n"); - g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; - g_ScreenInfo[nScreenNum].dwInitialX = iX; - g_ScreenInfo[nScreenNum].dwInitialY = iY; - - /* look for WxD+X+Y@m where m is monitor number. take X,Y to be offsets from monitor's root position */ - if (1 == sscanf (argv[i + 2], "%*dx%*d+%*d+%*d@%d", - (int *) &iMonitor)) - { - struct GetMonitorInfoData data; - if (!QueryMonitor(iMonitor, &data)) - { - ErrorF ("ddxProcessArgument - screen - " - "Querying monitors is not supported on NT4 and Win95\n"); - } else if (data.bMonitorSpecifiedExists == TRUE) - { - g_ScreenInfo[nScreenNum].dwInitialX += data.monitorOffsetX; - g_ScreenInfo[nScreenNum].dwInitialY += data.monitorOffsetY; - } - else - { - /* monitor does not exist, error out */ - ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", - iMonitor); - UseMsg (); - exit (0); - return 0; - } - - } - } - - /* look for WxD@m where m is monitor number */ - else if (1 == sscanf(argv[i + 2], "%*dx%*d@%d", - (int *) &iMonitor)) - { - struct GetMonitorInfoData data; - if (!QueryMonitor(iMonitor, &data)) - { - ErrorF ("ddxProcessArgument - screen - " - "Querying monitors is not supported on NT4 and Win95\n"); - } else if (data.bMonitorSpecifiedExists == TRUE) - { - winErrorFVerb (2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); - g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; - g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX; - g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY; - } - else - { - /* monitor does not exist, error out */ - ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", - iMonitor); - UseMsg (); - exit (0); - return 0; - } - - } - } - else if (i + 3 < argc - && 1 == sscanf (argv[i + 2], "%d", - (int *) &iWidth) - && 1 == sscanf (argv[i + 3], "%d", - (int *) &iHeight)) - { - winErrorFVerb (2, "ddxProcessArgument - screen - Found ``W D'' arg\n"); - iArgsProcessed = 4; - g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = TRUE; - g_ScreenInfo[nScreenNum].dwWidth = iWidth; - g_ScreenInfo[nScreenNum].dwHeight = iHeight; - g_ScreenInfo[nScreenNum].dwUserWidth = iWidth; - g_ScreenInfo[nScreenNum].dwUserHeight = iHeight; - if (i + 5 < argc - && 1 == sscanf (argv[i + 4], "%d", - (int *) &iX) - && 1 == sscanf (argv[i + 5], "%d", - (int *) &iY)) - { - winErrorFVerb (2, "ddxProcessArgument - screen - Found ``X Y'' arg\n"); - iArgsProcessed = 6; - g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; - g_ScreenInfo[nScreenNum].dwInitialX = iX; - g_ScreenInfo[nScreenNum].dwInitialY = iY; - } - } - else - { - winErrorFVerb (2, "ddxProcessArgument - screen - Did not find size arg. " - "dwWidth: %d dwHeight: %d\n", - (int) g_ScreenInfo[nScreenNum].dwWidth, - (int) g_ScreenInfo[nScreenNum].dwHeight); - iArgsProcessed = 2; - g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE; - } - - /* Calculate the screen width and height in millimeters */ - if (g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth) - { - g_ScreenInfo[nScreenNum].dwWidth_mm - = (g_ScreenInfo[nScreenNum].dwWidth - / monitorResolution) * 25.4; - g_ScreenInfo[nScreenNum].dwHeight_mm - = (g_ScreenInfo[nScreenNum].dwHeight - / monitorResolution) * 25.4; - } - - /* Flag that this screen was explicity specified by the user */ - g_ScreenInfo[nScreenNum].fExplicitScreen = TRUE; - - /* - * Keep track of the last screen number seen, as parameters seen - * before a screen number apply to all screens, whereas parameters - * seen after a screen number apply to that screen number only. - */ - iLastScreen = nScreenNum; - - return iArgsProcessed; - } - - - /* - * Is this parameter attached to a screen or global? - * - * If the parameter is for all screens (appears before - * any -screen option), store it in the default screen - * info - * - * If the parameter is for a single screen (appears - * after a -screen option), store it in the screen info - * for that screen - * - */ - if (iLastScreen == -1) - { - screenInfoPtr = &defaultScreenInfo; - } - else - { - screenInfoPtr = &(g_ScreenInfo[iLastScreen]); - } - - /* - * Look for the '-engine n' argument - */ - if (IS_OPTION ("-engine")) - { - DWORD dwEngine = 0; - CARD8 c8OnBits = 0; - - /* Display the usage message if the argument is malformed */ - if (++i >= argc) - { - UseMsg (); - return 0; - } - - /* Grab the argument */ - dwEngine = atoi (argv[i]); - - /* Count the one bits in the engine argument */ - c8OnBits = winCountBits (dwEngine); - - /* Argument should only have a single bit on */ - if (c8OnBits != 1) - { - UseMsg (); - return 0; - } - - screenInfoPtr->dwEnginePreferred = dwEngine; - - /* Indicate that we have processed the argument */ - return 2; - } - - /* - * Look for the '-fullscreen' argument - */ - if (IS_OPTION ("-fullscreen")) - { -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = FALSE; -#endif - screenInfoPtr->fFullScreen = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-lesspointer' argument - */ - if (IS_OPTION ("-lesspointer")) - { - screenInfoPtr->fLessPointer = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-nodecoration' argument - */ - if (IS_OPTION ("-nodecoration")) - { -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = FALSE; -#endif - screenInfoPtr->fDecoration = FALSE; - - /* Indicate that we have processed this argument */ - return 1; - } - -#ifdef XWIN_MULTIWINDOWEXTWM - /* - * Look for the '-mwextwm' argument - */ - if (IS_OPTION ("-mwextwm")) - { - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = TRUE; - screenInfoPtr->fMWExtWM = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - /* - * Look for the '-internalwm' argument - */ - if (IS_OPTION ("-internalwm")) - { - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = TRUE; - screenInfoPtr->fMWExtWM = TRUE; - screenInfoPtr->fInternalWM = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } -#endif - - /* - * Look for the '-rootless' argument - */ - if (IS_OPTION ("-rootless")) - { -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = FALSE; -#endif - screenInfoPtr->fRootless = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - -#ifdef XWIN_MULTIWINDOW - /* - * Look for the '-multiwindow' argument - */ - if (IS_OPTION ("-multiwindow")) - { -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - if (!screenInfoPtr->fMultiMonitorOverride) - screenInfoPtr->fMultipleMonitors = TRUE; -#endif - screenInfoPtr->fMultiWindow = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } -#endif - - /* - * Look for the '-multiplemonitors' argument - */ - if (IS_OPTION ("-multiplemonitors") - || IS_OPTION ("-multimonitors")) - { -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - screenInfoPtr->fMultiMonitorOverride = TRUE; -#endif - screenInfoPtr->fMultipleMonitors = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-nomultiplemonitors' argument - */ - if (IS_OPTION ("-nomultiplemonitors") - || IS_OPTION ("-nomultimonitors")) - { -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - screenInfoPtr->fMultiMonitorOverride = TRUE; -#endif - screenInfoPtr->fMultipleMonitors = FALSE; - - /* Indicate that we have processed this argument */ - return 1; - } - - - /* - * Look for the '-scrollbars' argument - */ - if (IS_OPTION ("-scrollbars")) - { - screenInfoPtr->fScrollbars = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - -#ifdef XWIN_CLIPBOARD - /* - * Look for the '-clipboard' argument - */ - if (IS_OPTION ("-clipboard")) - { - /* Now the default, we still accept the arg for backwards compatibility */ - g_fClipboard = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-noclipboard' argument - */ - if (IS_OPTION ("-noclipboard")) - { - g_fClipboard = FALSE; - - /* Indicate that we have processed this argument */ - return 1; - } -#endif - - - /* - * Look for the '-ignoreinput' argument - */ - if (IS_OPTION ("-ignoreinput")) - { - screenInfoPtr->fIgnoreInput = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-emulate3buttons' argument - */ - if (IS_OPTION ("-emulate3buttons")) - { - int iArgsProcessed = 1; - int iE3BTimeout = WIN_DEFAULT_E3B_TIME; - - /* Grab the optional timeout value */ - if (i + 1 < argc - && 1 == sscanf (argv[i + 1], "%d", - &iE3BTimeout)) - { - /* Indicate that we have processed the next argument */ - iArgsProcessed++; - } - else - { - /* - * sscanf () won't modify iE3BTimeout if it doesn't find - * the specified format; however, I want to be explicit - * about setting the default timeout in such cases to - * prevent some programs (me) from getting confused. - */ - iE3BTimeout = WIN_DEFAULT_E3B_TIME; - } - - screenInfoPtr->iE3BTimeout = iE3BTimeout; - - /* Indicate that we have processed this argument */ - return iArgsProcessed; - } - - /* - * Look for the '-depth n' argument - */ - if (IS_OPTION ("-depth")) - { - DWORD dwBPP = 0; - - /* Display the usage message if the argument is malformed */ - if (++i >= argc) - { - UseMsg (); - return 0; - } - - /* Grab the argument */ - dwBPP = atoi (argv[i]); - - screenInfoPtr->dwBPP = dwBPP; - - /* Indicate that we have processed the argument */ - return 2; - } - - /* - * Look for the '-refresh n' argument - */ - if (IS_OPTION ("-refresh")) - { - DWORD dwRefreshRate = 0; - - /* Display the usage message if the argument is malformed */ - if (++i >= argc) - { - UseMsg (); - return 0; - } - - /* Grab the argument */ - dwRefreshRate = atoi (argv[i]); - - screenInfoPtr->dwRefreshRate = dwRefreshRate; - - /* Indicate that we have processed the argument */ - return 2; - } - - /* - * Look for the '-clipupdates num_boxes' argument - */ - if (IS_OPTION ("-clipupdates")) - { - DWORD dwNumBoxes = 0; - - /* Display the usage message if the argument is malformed */ - if (++i >= argc) - { - UseMsg (); - return 0; - } - - /* Grab the argument */ - dwNumBoxes = atoi (argv[i]); - - screenInfoPtr->dwClipUpdatesNBoxes = dwNumBoxes; - - /* Indicate that we have processed the argument */ - return 2; - } - -#ifdef XWIN_EMULATEPSEUDO - /* - * Look for the '-emulatepseudo' argument - */ - if (IS_OPTION ("-emulatepseudo")) - { - screenInfoPtr->fEmulatePseudo = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } -#endif - - /* - * Look for the '-nowinkill' argument - */ - if (IS_OPTION ("-nowinkill")) - { - screenInfoPtr->fUseWinKillKey = FALSE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-winkill' argument - */ - if (IS_OPTION ("-winkill")) - { - screenInfoPtr->fUseWinKillKey = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-nounixkill' argument - */ - if (IS_OPTION ("-nounixkill")) - { - screenInfoPtr->fUseUnixKillKey = FALSE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-unixkill' argument - */ - if (IS_OPTION ("-unixkill")) - { - screenInfoPtr->fUseUnixKillKey = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-notrayicon' argument - */ - if (IS_OPTION ("-notrayicon")) - { - screenInfoPtr->fNoTrayIcon = TRUE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-trayicon' argument - */ - if (IS_OPTION ("-trayicon")) - { - screenInfoPtr->fNoTrayIcon = FALSE; - - /* Indicate that we have processed this argument */ - return 1; - } - - /* - * Look for the '-fp' argument - */ - if (IS_OPTION ("-fp")) - { - CHECK_ARGS (1); - g_cmdline.fontPath = argv[++i]; - return 0; /* Let DIX parse this again */ - } - - /* - * Look for the '-query' argument - */ - if (IS_OPTION ("-query")) - { - CHECK_ARGS (1); - g_fXdmcpEnabled = TRUE; - g_pszQueryHost = argv[++i]; - return 0; /* Let DIX parse this again */ - } - - /* - * Look for the '-auth' argument - */ - if (IS_OPTION ("-auth")) - { - g_fAuthEnabled = TRUE; - return 0; /* Let DIX parse this again */ - } - - /* - * Look for the '-indirect' or '-broadcast' arguments - */ - if (IS_OPTION ("-indirect") - || IS_OPTION ("-broadcast")) - { - g_fXdmcpEnabled = TRUE; - return 0; /* Let DIX parse this again */ - } - - /* - * Look for the '-config' argument - */ - if (IS_OPTION ("-config") - || IS_OPTION ("-xf86config")) - { - CHECK_ARGS (1); -#ifdef XWIN_XF86CONFIG - g_cmdline.configFile = argv[++i]; -#else - winMessageBoxF ("The %s option is not supported in this " - "release.\n" - "Ignoring this option and continuing.\n", - MB_ICONINFORMATION, - argv[i]); -#endif - return 2; - } - - /* - * Look for the '-configdir' argument - */ - if (IS_OPTION ("-configdir")) - { - CHECK_ARGS (1); -#ifdef XWIN_XF86CONFIG - g_cmdline.configDir = argv[++i]; -#else - winMessageBoxF ("The %s option is not supported in this " - "release.\n" - "Ignoring this option and continuing.\n", - MB_ICONINFORMATION, - argv[i]); -#endif - return 2; - } - - /* - * Look for the '-keyboard' argument - */ - if (IS_OPTION ("-keyboard")) - { -#ifdef XWIN_XF86CONFIG - CHECK_ARGS (1); - g_cmdline.keyboard = argv[++i]; -#else - winMessageBoxF ("The -keyboard option is not supported in this " - "release.\n" - "Ignoring this option and continuing.\n", - MB_ICONINFORMATION); -#endif - return 2; - } - - /* - * Look for the '-logfile' argument - */ - if (IS_OPTION ("-logfile")) - { - CHECK_ARGS (1); - g_pszLogFile = argv[++i]; -#ifdef RELOCATE_PROJECTROOT - g_fLogFileChanged = TRUE; -#endif - return 2; - } - - /* - * Look for the '-logverbose' argument - */ - if (IS_OPTION ("-logverbose")) - { - CHECK_ARGS (1); - g_iLogVerbose = atoi(argv[++i]); - return 2; - } - -#ifdef XWIN_CLIPBOARD - /* - * Look for the '-nounicodeclipboard' argument - */ - if (IS_OPTION ("-nounicodeclipboard")) - { - g_fUnicodeClipboard = FALSE; - /* Indicate that we have processed the argument */ - return 1; - } -#endif - - if (IS_OPTION ("-xkbrules")) - { - CHECK_ARGS (1); - g_cmdline.xkbRules = argv[++i]; - return 2; - } - if (IS_OPTION ("-xkbmodel")) - { - CHECK_ARGS (1); - g_cmdline.xkbModel = argv[++i]; - return 2; - } - if (IS_OPTION ("-xkblayout")) - { - CHECK_ARGS (1); - g_cmdline.xkbLayout = argv[++i]; - return 2; - } - if (IS_OPTION ("-xkbvariant")) - { - CHECK_ARGS (1); - g_cmdline.xkbVariant = argv[++i]; - return 2; - } - if (IS_OPTION ("-xkboptions")) - { - CHECK_ARGS (1); - g_cmdline.xkbOptions = argv[++i]; - return 2; - } - - if (IS_OPTION ("-keyhook")) - { - g_fKeyboardHookLL = TRUE; - return 1; - } - - if (IS_OPTION ("-nokeyhook")) - { - g_fKeyboardHookLL = FALSE; - return 1; - } - - if (IS_OPTION ("-swcursor")) - { - g_fSoftwareCursor = TRUE; - return 1; - } - - if (IS_OPTION ("-silent-dup-error")) - { - g_fSilentDupError = TRUE; - return 1; - } - - if (IS_OPTION("-wgl")) - { - g_fNativeGl = TRUE; - return 1; - } - - if (IS_OPTION("-nowgl")) - { - g_fNativeGl = FALSE; - return 1; - } - - return 0; -} - - -/* - * winLogCommandLine - Write entire command line to the log file - */ - -void -winLogCommandLine (int argc, char *argv[]) -{ - int i; - int iSize = 0; - int iCurrLen = 0; - -#define CHARS_PER_LINE 60 - - /* Bail if command line has already been logged */ - if (g_pszCommandLine) - return; - - /* Count how much memory is needed for concatenated command line */ - for (i = 0, iCurrLen = 0; i < argc; ++i) - if (argv[i]) - { - /* Adds two characters for lines that overflow */ - if ((strlen (argv[i]) < CHARS_PER_LINE - && iCurrLen + strlen (argv[i]) > CHARS_PER_LINE) - || strlen (argv[i]) > CHARS_PER_LINE) - { - iCurrLen = 0; - iSize += 2; - } - - /* Add space for item and trailing space */ - iSize += strlen (argv[i]) + 1; - - /* Update current line length */ - iCurrLen += strlen (argv[i]); - } - - /* Allocate memory for concatenated command line */ - g_pszCommandLine = malloc (iSize + 1); - if (!g_pszCommandLine) - FatalError ("winLogCommandLine - Could not allocate memory for " - "command line string. Exiting.\n"); - - /* Set first character to concatenated command line to null */ - g_pszCommandLine[0] = '\0'; - - /* Loop through all args */ - for (i = 0, iCurrLen = 0; i < argc; ++i) - { - /* Add a character for lines that overflow */ - if ((strlen (argv[i]) < CHARS_PER_LINE - && iCurrLen + strlen (argv[i]) > CHARS_PER_LINE) - || strlen (argv[i]) > CHARS_PER_LINE) - { - iCurrLen = 0; - - /* Add line break if it fits */ - strncat (g_pszCommandLine, "\n ", iSize - strlen (g_pszCommandLine)); - } - - strncat (g_pszCommandLine, argv[i], iSize - strlen (g_pszCommandLine)); - strncat (g_pszCommandLine, " ", iSize - strlen (g_pszCommandLine)); - - /* Save new line length */ - iCurrLen += strlen (argv[i]); - } - - ErrorF ("XWin was started with the following command line:\n\n" - "%s\n\n", g_pszCommandLine); -} - - -/* - * winLogVersionInfo - Log Cygwin/X version information - */ - -void -winLogVersionInfo (void) -{ - static Bool s_fBeenHere = FALSE; - - if (s_fBeenHere) - return; - s_fBeenHere = TRUE; - - ErrorF ("Welcome to the XWin X Server\n"); - ErrorF ("Vendor: %s\n", XVENDORNAME); - ErrorF ("Release: %d.%d.%d.%d (%d)\n", XORG_VERSION_MAJOR, XORG_VERSION_MINOR, XORG_VERSION_PATCH, XORG_VERSION_SNAP, XORG_VERSION_CURRENT); - ErrorF ("%s\n\n", BUILDERSTRING); - ErrorF ("Contact: %s\n", BUILDERADDR); -} - -/* - * getMonitorInfo - callback function used to return information from the enumeration of monitors attached - */ - -wBOOL CALLBACK getMonitorInfo(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM _data) -{ - struct GetMonitorInfoData* data = (struct GetMonitorInfoData*)_data; - // only get data for monitor number specified in - data->monitorNum++; - if (data->monitorNum == data->requestedMonitor) - { - data->bMonitorSpecifiedExists = TRUE; - data->monitorOffsetX = rect->left; - data->monitorOffsetY = rect->top; - data->monitorHeight = rect->bottom - rect->top; - data->monitorWidth = rect->right - rect->left; - return FALSE; - } - return TRUE; -} +/* + +Copyright 1993, 1998 The Open Group +Copyright (C) Colin Harrison 2005-2008 + +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. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif + +#include <../xfree86/common/xorgVersion.h> +#include "win.h" +#include "winconfig.h" +#include "winmsg.h" +#include "winmonitors.h" + +/* + * References to external symbols + */ + +#ifdef XWIN_CLIPBOARD +extern Bool g_fUnicodeClipboard; +extern Bool g_fClipboard; +#endif + +/* + * Function prototypes + */ + +void +winLogCommandLine (int argc, char *argv[]); + +void +winLogVersionInfo (void); + +#ifdef DDXOSVERRORF +void OsVendorVErrorF (const char *pszFormat, va_list va_args); +#endif + +/* + * Process arguments on the command line + */ + +static int iLastScreen = -1; +static winScreenInfo defaultScreenInfo; + +static void +winInitializeScreenDefaults(void) +{ + DWORD dwWidth, dwHeight; + static Bool fInitializedScreenDefaults = FALSE; + + /* Bail out early if default screen has already been initialized */ + if (fInitializedScreenDefaults) + return; + + /* Zero the memory used for storing the screen info */ + memset(&defaultScreenInfo, 0, sizeof(winScreenInfo)); + + /* Get default width and height */ + /* + * NOTE: These defaults will cause the window to cover only + * the primary monitor in the case that we have multiple monitors. + */ + dwWidth = GetSystemMetrics (SM_CXSCREEN); + dwHeight = GetSystemMetrics (SM_CYSCREEN); + + winErrorFVerb (2, "winInitializeScreenDefaults - w %d h %d\n", + (int) dwWidth, (int) dwHeight); + + /* Set a default DPI, if no parameter was passed */ + if (monitorResolution == 0) + monitorResolution = WIN_DEFAULT_DPI; + + defaultScreenInfo.iMonitor = 1; + defaultScreenInfo.dwWidth = dwWidth; + defaultScreenInfo.dwHeight = dwHeight; + defaultScreenInfo.dwUserWidth = dwWidth; + defaultScreenInfo.dwUserHeight = dwHeight; + defaultScreenInfo.fUserGaveHeightAndWidth = WIN_DEFAULT_USER_GAVE_HEIGHT_AND_WIDTH; + defaultScreenInfo.fUserGavePosition = FALSE; + defaultScreenInfo.dwBPP = WIN_DEFAULT_BPP; + defaultScreenInfo.dwClipUpdatesNBoxes = WIN_DEFAULT_CLIP_UPDATES_NBOXES; +#ifdef XWIN_EMULATEPSEUDO + defaultScreenInfo.fEmulatePseudo = WIN_DEFAULT_EMULATE_PSEUDO; +#endif + defaultScreenInfo.dwRefreshRate = WIN_DEFAULT_REFRESH; + defaultScreenInfo.pfb = NULL; + defaultScreenInfo.fFullScreen = FALSE; + defaultScreenInfo.fDecoration = TRUE; +#ifdef XWIN_MULTIWINDOWEXTWM + defaultScreenInfo.fMWExtWM = FALSE; + defaultScreenInfo.fInternalWM = FALSE; +#endif + defaultScreenInfo.fRootless = FALSE; +#ifdef XWIN_MULTIWINDOW + defaultScreenInfo.fMultiWindow = FALSE; +#endif +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + defaultScreenInfo.fMultiMonitorOverride = FALSE; +#endif + defaultScreenInfo.fMultipleMonitors = FALSE; + defaultScreenInfo.fLessPointer = FALSE; + defaultScreenInfo.iResizeMode = notAllowed; + defaultScreenInfo.fNoTrayIcon = FALSE; + defaultScreenInfo.iE3BTimeout = WIN_E3B_OFF; + defaultScreenInfo.fUseWinKillKey = WIN_DEFAULT_WIN_KILL; + defaultScreenInfo.fUseUnixKillKey = WIN_DEFAULT_UNIX_KILL; + defaultScreenInfo.fIgnoreInput = FALSE; + defaultScreenInfo.fExplicitScreen = FALSE; + + /* Note that the default screen has been initialized */ + fInitializedScreenDefaults = TRUE; +} + +static void +winInitializeScreen(int i) +{ + winErrorFVerb (2, "winInitializeScreen - %d\n",i); + + /* Initialize default screen values, if needed */ + winInitializeScreenDefaults(); + + /* Copy the default screen info */ + g_ScreenInfo[i] = defaultScreenInfo; + + /* Set the screen number */ + g_ScreenInfo[i].dwScreen = i; +} + +void +winInitializeScreens(int maxscreens) +{ + int i; + winErrorFVerb (2, "winInitializeScreens - %i\n", maxscreens); + + if (maxscreens > g_iNumScreens) + { + /* Reallocate the memory for DDX-specific screen info */ + g_ScreenInfo = realloc(g_ScreenInfo, maxscreens * sizeof (winScreenInfo)); + + /* Set default values for any new screens */ + for (i = g_iNumScreens; i < maxscreens ; i++) + winInitializeScreen(i); + + /* Keep a count of the number of screens */ + g_iNumScreens = maxscreens; + } +} + +/* See Porting Layer Definition - p. 57 */ +/* + * INPUT + * argv: pointer to an array of null-terminated strings, one for + * each token in the X Server command line; the first token + * is 'XWin.exe', or similar. + * argc: a count of the number of tokens stored in argv. + * i: a zero-based index into argv indicating the current token being + * processed. + * + * OUTPUT + * return: return the number of tokens processed correctly. + * + * NOTE + * When looking for n tokens, check that i + n is less than argc. Or, + * you may check if i is greater than or equal to argc, in which case + * you should display the UseMsg () and return 0. + */ + +/* Check if enough arguments are given for the option */ +#define CHECK_ARGS(count) if (i + count >= argc) { UseMsg (); return 0; } + +/* Compare the current option with the string. */ +#define IS_OPTION(name) (strcmp (argv[i], name) == 0) + +int +ddxProcessArgument (int argc, char *argv[], int i) +{ + static Bool s_fBeenHere = FALSE; + winScreenInfo *screenInfoPtr = NULL; + + /* Initialize once */ + if (!s_fBeenHere) + { +#ifdef DDXOSVERRORF + /* + * This initialises our hook into VErrorF () for catching log messages + * that are generated before OsInit () is called. + */ + OsVendorVErrorFProc = OsVendorVErrorF; +#endif + + s_fBeenHere = TRUE; + + /* Initialize only if option is not -help */ + if (!IS_OPTION("-help") && !IS_OPTION("-h") && !IS_OPTION("--help") && + !IS_OPTION("-version") && !IS_OPTION("--version")) + { + + /* Log the version information */ + winLogVersionInfo (); + + /* Log the command line */ + winLogCommandLine (argc, argv); + + /* + * Initialize default screen settings. We have to do this before + * OsVendorInit () gets called, otherwise we will overwrite + * settings changed by parameters such as -fullscreen, etc. + */ + winErrorFVerb (2, "ddxProcessArgument - Initializing default " + "screens\n"); + winInitializeScreenDefaults(); + } + } + +#if CYGDEBUG + winDebug ("ddxProcessArgument - arg: %s\n", argv[i]); +#endif + + /* + * Look for the '-help' and similar options + */ + if (IS_OPTION ("-help") || IS_OPTION("-h") || IS_OPTION("--help")) + { + /* Reset logfile. We don't need that helpmessage in the logfile */ + g_pszLogFile = NULL; + g_fNoHelpMessageBox = TRUE; + UseMsg(); + exit (0); + return 1; + } + + if (IS_OPTION ("-version") || IS_OPTION("--version")) + { + /* Reset logfile. We don't need that versioninfo in the logfile */ + g_pszLogFile = NULL; + winLogVersionInfo (); + exit (0); + return 1; + } + + /* + * Look for the '-screen scr_num [width height]' argument + */ + if (IS_OPTION ("-screen")) + { + int iArgsProcessed = 1; + int nScreenNum; + int iWidth, iHeight, iX, iY; + int iMonitor; + +#if CYGDEBUG + winDebug ("ddxProcessArgument - screen - argc: %d i: %d\n", + argc, i); +#endif + + /* Display the usage message if the argument is malformed */ + if (i + 1 >= argc) + { + return 0; + } + + /* Grab screen number */ + nScreenNum = atoi (argv[i + 1]); + + /* Validate the specified screen number */ + if (nScreenNum < 0) + { + ErrorF ("ddxProcessArgument - screen - Invalid screen number %d\n", + nScreenNum); + UseMsg (); + return 0; + } + + /* + Initialize default values for any new screens + + Note that default values can't change after a -screen option is + seen, so it's safe to do this for each screen as it is introduced + */ + winInitializeScreens(nScreenNum+1); + + /* look for @m where m is monitor number */ + if (i + 2 < argc + && 1 == sscanf(argv[i + 2], "@%d", (int *) &iMonitor)) + { + struct GetMonitorInfoData data; + if (!QueryMonitor(iMonitor, &data)) + { + ErrorF ("ddxProcessArgument - screen - " + "Querying monitors is not supported on NT4 and Win95\n"); + } else if (data.bMonitorSpecifiedExists == TRUE) + { + winErrorFVerb(2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); + iArgsProcessed = 3; + g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE; + g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; + g_ScreenInfo[nScreenNum].iMonitor = iMonitor; + g_ScreenInfo[nScreenNum].dwWidth = data.monitorWidth; + g_ScreenInfo[nScreenNum].dwHeight = data.monitorHeight; + g_ScreenInfo[nScreenNum].dwUserWidth = data.monitorWidth; + g_ScreenInfo[nScreenNum].dwUserHeight = data.monitorHeight; + g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX; + g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY; + } + else + { + /* monitor does not exist, error out */ + ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", + iMonitor); + UseMsg (); + exit (0); + return 0; + } + } + + /* Look for 'WxD' or 'W D' */ + else if (i + 2 < argc + && 2 == sscanf (argv[i + 2], "%dx%d", + (int *) &iWidth, + (int *) &iHeight)) + { + winErrorFVerb (2, "ddxProcessArgument - screen - Found ``WxD'' arg\n"); + iArgsProcessed = 3; + g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = TRUE; + g_ScreenInfo[nScreenNum].dwWidth = iWidth; + g_ScreenInfo[nScreenNum].dwHeight = iHeight; + g_ScreenInfo[nScreenNum].dwUserWidth = iWidth; + g_ScreenInfo[nScreenNum].dwUserHeight = iHeight; + /* Look for WxD+X+Y */ + if (2 == sscanf (argv[i + 2], "%*dx%*d+%d+%d", + (int *) &iX, + (int *) &iY)) + { + winErrorFVerb (2, "ddxProcessArgument - screen - Found ``X+Y'' arg\n"); + g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; + g_ScreenInfo[nScreenNum].dwInitialX = iX; + g_ScreenInfo[nScreenNum].dwInitialY = iY; + + /* look for WxD+X+Y@m where m is monitor number. take X,Y to be offsets from monitor's root position */ + if (1 == sscanf (argv[i + 2], "%*dx%*d+%*d+%*d@%d", + (int *) &iMonitor)) + { + struct GetMonitorInfoData data; + if (!QueryMonitor(iMonitor, &data)) + { + ErrorF ("ddxProcessArgument - screen - " + "Querying monitors is not supported on NT4 and Win95\n"); + } else if (data.bMonitorSpecifiedExists == TRUE) + { + g_ScreenInfo[nScreenNum].iMonitor = iMonitor; + g_ScreenInfo[nScreenNum].dwInitialX += data.monitorOffsetX; + g_ScreenInfo[nScreenNum].dwInitialY += data.monitorOffsetY; + } + else + { + /* monitor does not exist, error out */ + ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", + iMonitor); + UseMsg (); + exit (0); + return 0; + } + + } + } + + /* look for WxD@m where m is monitor number */ + else if (1 == sscanf(argv[i + 2], "%*dx%*d@%d", + (int *) &iMonitor)) + { + struct GetMonitorInfoData data; + if (!QueryMonitor(iMonitor, &data)) + { + ErrorF ("ddxProcessArgument - screen - " + "Querying monitors is not supported on NT4 and Win95\n"); + } else if (data.bMonitorSpecifiedExists == TRUE) + { + winErrorFVerb (2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); + g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; + g_ScreenInfo[nScreenNum].iMonitor = iMonitor; + g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX; + g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY; + } + else + { + /* monitor does not exist, error out */ + ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", + iMonitor); + UseMsg (); + exit (0); + return 0; + } + + } + } + else if (i + 3 < argc + && 1 == sscanf (argv[i + 2], "%d", + (int *) &iWidth) + && 1 == sscanf (argv[i + 3], "%d", + (int *) &iHeight)) + { + winErrorFVerb (2, "ddxProcessArgument - screen - Found ``W D'' arg\n"); + iArgsProcessed = 4; + g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = TRUE; + g_ScreenInfo[nScreenNum].dwWidth = iWidth; + g_ScreenInfo[nScreenNum].dwHeight = iHeight; + g_ScreenInfo[nScreenNum].dwUserWidth = iWidth; + g_ScreenInfo[nScreenNum].dwUserHeight = iHeight; + if (i + 5 < argc + && 1 == sscanf (argv[i + 4], "%d", + (int *) &iX) + && 1 == sscanf (argv[i + 5], "%d", + (int *) &iY)) + { + winErrorFVerb (2, "ddxProcessArgument - screen - Found ``X Y'' arg\n"); + iArgsProcessed = 6; + g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; + g_ScreenInfo[nScreenNum].dwInitialX = iX; + g_ScreenInfo[nScreenNum].dwInitialY = iY; + } + } + else + { + winErrorFVerb (2, "ddxProcessArgument - screen - Did not find size arg. " + "dwWidth: %d dwHeight: %d\n", + (int) g_ScreenInfo[nScreenNum].dwWidth, + (int) g_ScreenInfo[nScreenNum].dwHeight); + iArgsProcessed = 2; + g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE; + } + + /* Flag that this screen was explicity specified by the user */ + g_ScreenInfo[nScreenNum].fExplicitScreen = TRUE; + + /* + * Keep track of the last screen number seen, as parameters seen + * before a screen number apply to all screens, whereas parameters + * seen after a screen number apply to that screen number only. + */ + iLastScreen = nScreenNum; + + return iArgsProcessed; + } + + + /* + * Is this parameter attached to a screen or global? + * + * If the parameter is for all screens (appears before + * any -screen option), store it in the default screen + * info + * + * If the parameter is for a single screen (appears + * after a -screen option), store it in the screen info + * for that screen + * + */ + if (iLastScreen == -1) + { + screenInfoPtr = &defaultScreenInfo; + } + else + { + screenInfoPtr = &(g_ScreenInfo[iLastScreen]); + } + + /* + * Look for the '-engine n' argument + */ + if (IS_OPTION ("-engine")) + { + DWORD dwEngine = 0; + CARD8 c8OnBits = 0; + + /* Display the usage message if the argument is malformed */ + if (++i >= argc) + { + UseMsg (); + return 0; + } + + /* Grab the argument */ + dwEngine = atoi (argv[i]); + + /* Count the one bits in the engine argument */ + c8OnBits = winCountBits (dwEngine); + + /* Argument should only have a single bit on */ + if (c8OnBits != 1) + { + UseMsg (); + return 0; + } + + screenInfoPtr->dwEnginePreferred = dwEngine; + + /* Indicate that we have processed the argument */ + return 2; + } + + /* + * Look for the '-fullscreen' argument + */ + if (IS_OPTION ("-fullscreen")) + { +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + if (!screenInfoPtr->fMultiMonitorOverride) + screenInfoPtr->fMultipleMonitors = FALSE; +#endif + screenInfoPtr->fFullScreen = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-lesspointer' argument + */ + if (IS_OPTION ("-lesspointer")) + { + screenInfoPtr->fLessPointer = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-nodecoration' argument + */ + if (IS_OPTION ("-nodecoration")) + { +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + if (!screenInfoPtr->fMultiMonitorOverride) + screenInfoPtr->fMultipleMonitors = FALSE; +#endif + screenInfoPtr->fDecoration = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + +#ifdef XWIN_MULTIWINDOWEXTWM + /* + * Look for the '-mwextwm' argument + */ + if (IS_OPTION ("-mwextwm")) + { + if (!screenInfoPtr->fMultiMonitorOverride) + screenInfoPtr->fMultipleMonitors = TRUE; + screenInfoPtr->fMWExtWM = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + /* + * Look for the '-internalwm' argument + */ + if (IS_OPTION ("-internalwm")) + { + if (!screenInfoPtr->fMultiMonitorOverride) + screenInfoPtr->fMultipleMonitors = TRUE; + screenInfoPtr->fMWExtWM = TRUE; + screenInfoPtr->fInternalWM = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } +#endif + + /* + * Look for the '-rootless' argument + */ + if (IS_OPTION ("-rootless")) + { +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + if (!screenInfoPtr->fMultiMonitorOverride) + screenInfoPtr->fMultipleMonitors = FALSE; +#endif + screenInfoPtr->fRootless = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + +#ifdef XWIN_MULTIWINDOW + /* + * Look for the '-multiwindow' argument + */ + if (IS_OPTION ("-multiwindow")) + { +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + if (!screenInfoPtr->fMultiMonitorOverride) + screenInfoPtr->fMultipleMonitors = TRUE; +#endif + screenInfoPtr->fMultiWindow = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } +#endif + + /* + * Look for the '-multiplemonitors' argument + */ + if (IS_OPTION ("-multiplemonitors") + || IS_OPTION ("-multimonitors")) + { +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + screenInfoPtr->fMultiMonitorOverride = TRUE; +#endif + screenInfoPtr->fMultipleMonitors = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-nomultiplemonitors' argument + */ + if (IS_OPTION ("-nomultiplemonitors") + || IS_OPTION ("-nomultimonitors")) + { +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + screenInfoPtr->fMultiMonitorOverride = TRUE; +#endif + screenInfoPtr->fMultipleMonitors = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + + + /* + * Look for the '-scrollbars' argument + */ + if (IS_OPTION ("-scrollbars")) + { + + screenInfoPtr->iResizeMode = resizeWithScrollbars; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-resize' argument + */ + if (IS_OPTION ("-resize") || IS_OPTION ("-noresize") || + (strncmp(argv[i], "-resize=",strlen("-resize=")) == 0)) + { + winResizeMode mode; + + if (IS_OPTION ("-resize")) + mode = resizeWithRandr; + else if (IS_OPTION ("-noresize")) + mode = notAllowed; + else if (strncmp(argv[i], "-resize=",strlen("-resize=")) == 0) + { + char *option = argv[i] + strlen("-resize="); + if (strcmp(option, "randr") == 0) + mode = resizeWithRandr; + else if (strcmp(option, "scrollbars") == 0) + mode = resizeWithScrollbars; + else if (strcmp(option, "none") == 0) + mode = notAllowed; + else + { + ErrorF ("ddxProcessArgument - resize - Invalid resize mode %s\n", option); + return 0; + } + } + else + { + ErrorF ("ddxProcessArgument - resize - Invalid resize option %s\n", argv[i]); + return 0; + } + + screenInfoPtr->iResizeMode = mode; + + /* Indicate that we have processed this argument */ + return 1; + } + +#ifdef XWIN_CLIPBOARD + /* + * Look for the '-clipboard' argument + */ + if (IS_OPTION ("-clipboard")) + { + /* Now the default, we still accept the arg for backwards compatibility */ + g_fClipboard = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-noclipboard' argument + */ + if (IS_OPTION ("-noclipboard")) + { + g_fClipboard = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } +#endif + + + /* + * Look for the '-ignoreinput' argument + */ + if (IS_OPTION ("-ignoreinput")) + { + screenInfoPtr->fIgnoreInput = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-emulate3buttons' argument + */ + if (IS_OPTION ("-emulate3buttons")) + { + int iArgsProcessed = 1; + int iE3BTimeout = WIN_DEFAULT_E3B_TIME; + + /* Grab the optional timeout value */ + if (i + 1 < argc + && 1 == sscanf (argv[i + 1], "%d", + &iE3BTimeout)) + { + /* Indicate that we have processed the next argument */ + iArgsProcessed++; + } + else + { + /* + * sscanf () won't modify iE3BTimeout if it doesn't find + * the specified format; however, I want to be explicit + * about setting the default timeout in such cases to + * prevent some programs (me) from getting confused. + */ + iE3BTimeout = WIN_DEFAULT_E3B_TIME; + } + + screenInfoPtr->iE3BTimeout = iE3BTimeout; + + /* Indicate that we have processed this argument */ + return iArgsProcessed; + } + + /* + * Look for the '-depth n' argument + */ + if (IS_OPTION ("-depth")) + { + DWORD dwBPP = 0; + + /* Display the usage message if the argument is malformed */ + if (++i >= argc) + { + UseMsg (); + return 0; + } + + /* Grab the argument */ + dwBPP = atoi (argv[i]); + + screenInfoPtr->dwBPP = dwBPP; + + /* Indicate that we have processed the argument */ + return 2; + } + + /* + * Look for the '-refresh n' argument + */ + if (IS_OPTION ("-refresh")) + { + DWORD dwRefreshRate = 0; + + /* Display the usage message if the argument is malformed */ + if (++i >= argc) + { + UseMsg (); + return 0; + } + + /* Grab the argument */ + dwRefreshRate = atoi (argv[i]); + + screenInfoPtr->dwRefreshRate = dwRefreshRate; + + /* Indicate that we have processed the argument */ + return 2; + } + + /* + * Look for the '-clipupdates num_boxes' argument + */ + if (IS_OPTION ("-clipupdates")) + { + DWORD dwNumBoxes = 0; + + /* Display the usage message if the argument is malformed */ + if (++i >= argc) + { + UseMsg (); + return 0; + } + + /* Grab the argument */ + dwNumBoxes = atoi (argv[i]); + + screenInfoPtr->dwClipUpdatesNBoxes = dwNumBoxes; + + /* Indicate that we have processed the argument */ + return 2; + } + +#ifdef XWIN_EMULATEPSEUDO + /* + * Look for the '-emulatepseudo' argument + */ + if (IS_OPTION ("-emulatepseudo")) + { + screenInfoPtr->fEmulatePseudo = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } +#endif + + /* + * Look for the '-nowinkill' argument + */ + if (IS_OPTION ("-nowinkill")) + { + screenInfoPtr->fUseWinKillKey = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-winkill' argument + */ + if (IS_OPTION ("-winkill")) + { + screenInfoPtr->fUseWinKillKey = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-nounixkill' argument + */ + if (IS_OPTION ("-nounixkill")) + { + screenInfoPtr->fUseUnixKillKey = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-unixkill' argument + */ + if (IS_OPTION ("-unixkill")) + { + screenInfoPtr->fUseUnixKillKey = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-notrayicon' argument + */ + if (IS_OPTION ("-notrayicon")) + { + screenInfoPtr->fNoTrayIcon = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-trayicon' argument + */ + if (IS_OPTION ("-trayicon")) + { + screenInfoPtr->fNoTrayIcon = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + + /* + * Look for the '-fp' argument + */ + if (IS_OPTION ("-fp")) + { + CHECK_ARGS (1); + g_cmdline.fontPath = argv[++i]; + return 0; /* Let DIX parse this again */ + } + + /* + * Look for the '-query' argument + */ + if (IS_OPTION ("-query")) + { + CHECK_ARGS (1); + g_fXdmcpEnabled = TRUE; + g_pszQueryHost = argv[++i]; + return 0; /* Let DIX parse this again */ + } + + /* + * Look for the '-auth' argument + */ + if (IS_OPTION ("-auth")) + { + g_fAuthEnabled = TRUE; + return 0; /* Let DIX parse this again */ + } + + /* + * Look for the '-indirect' or '-broadcast' arguments + */ + if (IS_OPTION ("-indirect") + || IS_OPTION ("-broadcast")) + { + g_fXdmcpEnabled = TRUE; + return 0; /* Let DIX parse this again */ + } + + /* + * Look for the '-config' argument + */ + if (IS_OPTION ("-config") + || IS_OPTION ("-xf86config")) + { + CHECK_ARGS (1); +#ifdef XWIN_XF86CONFIG + g_cmdline.configFile = argv[++i]; +#else + winMessageBoxF ("The %s option is not supported in this " + "release.\n" + "Ignoring this option and continuing.\n", + MB_ICONINFORMATION, + argv[i]); +#endif + return 2; + } + + /* + * Look for the '-configdir' argument + */ + if (IS_OPTION ("-configdir")) + { + CHECK_ARGS (1); +#ifdef XWIN_XF86CONFIG + g_cmdline.configDir = argv[++i]; +#else + winMessageBoxF ("The %s option is not supported in this " + "release.\n" + "Ignoring this option and continuing.\n", + MB_ICONINFORMATION, + argv[i]); +#endif + return 2; + } + + /* + * Look for the '-keyboard' argument + */ + if (IS_OPTION ("-keyboard")) + { +#ifdef XWIN_XF86CONFIG + CHECK_ARGS (1); + g_cmdline.keyboard = argv[++i]; +#else + winMessageBoxF ("The -keyboard option is not supported in this " + "release.\n" + "Ignoring this option and continuing.\n", + MB_ICONINFORMATION); +#endif + return 2; + } + + /* + * Look for the '-logfile' argument + */ + if (IS_OPTION ("-logfile")) + { + CHECK_ARGS (1); + g_pszLogFile = argv[++i]; +#ifdef RELOCATE_PROJECTROOT + g_fLogFileChanged = TRUE; +#endif + return 2; + } + + /* + * Look for the '-logverbose' argument + */ + if (IS_OPTION ("-logverbose")) + { + CHECK_ARGS (1); + g_iLogVerbose = atoi(argv[++i]); + return 2; + } + +#ifdef XWIN_CLIPBOARD + /* + * Look for the '-nounicodeclipboard' argument + */ + if (IS_OPTION ("-nounicodeclipboard")) + { + g_fUnicodeClipboard = FALSE; + /* Indicate that we have processed the argument */ + return 1; + } +#endif + + if (IS_OPTION ("-xkbrules")) + { + CHECK_ARGS (1); + g_cmdline.xkbRules = argv[++i]; + return 2; + } + if (IS_OPTION ("-xkbmodel")) + { + CHECK_ARGS (1); + g_cmdline.xkbModel = argv[++i]; + return 2; + } + if (IS_OPTION ("-xkblayout")) + { + CHECK_ARGS (1); + g_cmdline.xkbLayout = argv[++i]; + return 2; + } + if (IS_OPTION ("-xkbvariant")) + { + CHECK_ARGS (1); + g_cmdline.xkbVariant = argv[++i]; + return 2; + } + if (IS_OPTION ("-xkboptions")) + { + CHECK_ARGS (1); + g_cmdline.xkbOptions = argv[++i]; + return 2; + } + + if (IS_OPTION ("-keyhook")) + { + g_fKeyboardHookLL = TRUE; + return 1; + } + + if (IS_OPTION ("-nokeyhook")) + { + g_fKeyboardHookLL = FALSE; + return 1; + } + + if (IS_OPTION ("-swcursor")) + { + g_fSoftwareCursor = TRUE; + return 1; + } + + if (IS_OPTION ("-silent-dup-error")) + { + g_fSilentDupError = TRUE; + return 1; + } + + if (IS_OPTION("-wgl")) + { + g_fNativeGl = TRUE; + return 1; + } + + if (IS_OPTION("-nowgl")) + { + g_fNativeGl = FALSE; + return 1; + } + + return 0; +} + + +/* + * winLogCommandLine - Write entire command line to the log file + */ + +void +winLogCommandLine (int argc, char *argv[]) +{ + int i; + int iSize = 0; + int iCurrLen = 0; + +#define CHARS_PER_LINE 60 + + /* Bail if command line has already been logged */ + if (g_pszCommandLine) + return; + + /* Count how much memory is needed for concatenated command line */ + for (i = 0, iCurrLen = 0; i < argc; ++i) + if (argv[i]) + { + /* Adds two characters for lines that overflow */ + if ((strlen (argv[i]) < CHARS_PER_LINE + && iCurrLen + strlen (argv[i]) > CHARS_PER_LINE) + || strlen (argv[i]) > CHARS_PER_LINE) + { + iCurrLen = 0; + iSize += 2; + } + + /* Add space for item and trailing space */ + iSize += strlen (argv[i]) + 1; + + /* Update current line length */ + iCurrLen += strlen (argv[i]); + } + + /* Allocate memory for concatenated command line */ + g_pszCommandLine = malloc (iSize + 1); + if (!g_pszCommandLine) + FatalError ("winLogCommandLine - Could not allocate memory for " + "command line string. Exiting.\n"); + + /* Set first character to concatenated command line to null */ + g_pszCommandLine[0] = '\0'; + + /* Loop through all args */ + for (i = 0, iCurrLen = 0; i < argc; ++i) + { + /* Add a character for lines that overflow */ + if ((strlen (argv[i]) < CHARS_PER_LINE + && iCurrLen + strlen (argv[i]) > CHARS_PER_LINE) + || strlen (argv[i]) > CHARS_PER_LINE) + { + iCurrLen = 0; + + /* Add line break if it fits */ + strncat (g_pszCommandLine, "\n ", iSize - strlen (g_pszCommandLine)); + } + + strncat (g_pszCommandLine, argv[i], iSize - strlen (g_pszCommandLine)); + strncat (g_pszCommandLine, " ", iSize - strlen (g_pszCommandLine)); + + /* Save new line length */ + iCurrLen += strlen (argv[i]); + } + + ErrorF ("XWin was started with the following command line:\n\n" + "%s\n\n", g_pszCommandLine); +} + + +/* + * winLogVersionInfo - Log Cygwin/X version information + */ + +void +winLogVersionInfo (void) +{ + static Bool s_fBeenHere = FALSE; + + if (s_fBeenHere) + return; + s_fBeenHere = TRUE; + + ErrorF ("Welcome to the XWin X Server\n"); + ErrorF ("Vendor: %s\n", XVENDORNAME); + ErrorF ("Release: %d.%d.%d.%d (%d)\n", XORG_VERSION_MAJOR, XORG_VERSION_MINOR, XORG_VERSION_PATCH, XORG_VERSION_SNAP, XORG_VERSION_CURRENT); + ErrorF ("%s\n\n", BUILDERSTRING); + ErrorF ("Contact: %s\n", BUILDERADDR); +} diff --git a/xorg-server/hw/xwin/winrandr.c b/xorg-server/hw/xwin/winrandr.c index 7b5b1359c..248404800 100644 --- a/xorg-server/hw/xwin/winrandr.c +++ b/xorg-server/hw/xwin/winrandr.c @@ -1,8 +1,9 @@ /* *Copyright (C) 2001-2004 Harold L Hunt II All Rights Reserved. + *Copyright (C) 2009-2010 Jon TURNEY * *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the + *a copy of this software and associated documentation files (the *"Software"), to deal in the Software without restriction, including *without limitation the rights to use, copy, modify, merge, publish, *distribute, sublicense, and/or sell copies of the Software, and to @@ -20,101 +21,280 @@ *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - *Except as contained in this notice, the name of Harold L Hunt II + *Except as contained in this notice, the name of the author(s) *shall not be used in advertising or otherwise to promote the sale, use *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. + *from the author(s) * * Authors: Harold L Hunt II + * Jon TURNEY */ #ifdef HAVE_XWIN_CONFIG_H #include #endif #include "win.h" +#include "mivalidate.h" // for union _Validate used by windowstr.h + +#ifndef RANDR_12_INTERFACE +#error X server must have RandR 1.2 interface +#endif /* - * Local prototypes + * Answer queries about the RandR features supported. */ static Bool -winRandRGetInfo (ScreenPtr pScreen, Rotation *pRotations); +winRandRGetInfo (ScreenPtr pScreen, Rotation *pRotations) +{ + winDebug ("winRandRGetInfo ()\n"); -static Bool -winRandRSetConfig (ScreenPtr pScreen, - Rotation rotateKind, - int rate, - RRScreenSizePtr pSize); + /* Don't support rotations */ + *pRotations = RR_Rotate_0; -Bool -winRandRInit (ScreenPtr pScreen); + /* + The screen doesn't have to be limited to the actual + monitor size (we can have scrollbars :-), so what is + the upper limit? + */ + RRScreenSetSizeRange(pScreen, 0, 0, 4096, 4096); + + return TRUE; +} /* - * Answer queries about the RandR features supported. + Copied from the xfree86 DDX + + Why can't this be in DIX? + Does union _Validate vary depending on DDX?? */ +static void +xf86SetRootClip (ScreenPtr pScreen, Bool enable) +{ + WindowPtr pWin = pScreen->root; + WindowPtr pChild; + Bool WasViewable = (Bool)(pWin->viewable); + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + BoxRec box; -static Bool -winRandRGetInfo (ScreenPtr pScreen, Rotation *pRotations) + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + /* + * Use REGION_BREAK to avoid optimizations in ValidateTree + * that assume the root borderClip can't change well, normally + * it doesn't...) + */ + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_INIT (pScreen, &pWin->winSize, &box, 1); + REGION_INIT (pScreen, &pWin->borderSize, &box, 1); + if (WasViewable) + REGION_RESET(pScreen, &pWin->borderClip, &box); + pWin->drawable.width = pScreen->width; + pWin->drawable.height = pScreen->height; + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + else + { + REGION_EMPTY(pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + FlushAllOutput (); +} + +/* + +*/ +void +winDoRandRScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) { winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - int n; - Rotation rotateKind; - RRScreenSizePtr pSize; + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + WindowPtr pRoot = pScreen->root; - winDebug ("winRandRGetInfo ()\n"); + // Prevent screen updates while we change things around + xf86SetRootClip(pScreen, FALSE); - /* Don't support rotations, yet */ - *pRotations = RR_Rotate_0; + /* Update the screen size as requested */ + pScreenInfo->dwWidth = width; + pScreenInfo->dwHeight = height; - /* Bail if no depth has a visual associated with it */ - for (n = 0; n < pScreen->numDepths; n++) - if (pScreen->allowedDepths[n].numVids) - break; - if (n == pScreen->numDepths) - return FALSE; + /* Reallocate the framebuffer used by the drawing engine */ + (*pScreenPriv->pwinFreeFB)(pScreen); + if (!(*pScreenPriv->pwinAllocateFB)(pScreen)) + { + ErrorF ("winDoRandRScreenSetSize - Could not reallocate framebuffer\n"); + } - /* Only one allowed rotation for now */ - rotateKind = RR_Rotate_0; + pScreen->width = width; + pScreen->height = height; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; - /* - * Register supported sizes. This can be called many times, but - * we only support one size for now. - */ - pSize = RRRegisterSize (pScreen, - pScreenInfo->dwWidth, - pScreenInfo->dwHeight, - pScreenInfo->dwWidth_mm, - pScreenInfo->dwHeight_mm); - - /* Tell RandR what the current config is */ - RRSetCurrentConfig (pScreen, - rotateKind, - 0, /* refresh rate, not needed */ - pSize); - - return TRUE; -} + /* Update the screen pixmap to point to the new framebuffer */ + winUpdateFBPointer(pScreen, pScreenInfo->pfb); + + // pScreen->devPrivate == pScreen->GetScreenPixmap(screen) ? + // resize the root window + //pScreen->ResizeWindow(pRoot, 0, 0, width, height, NULL); + // does this emit a ConfigureNotify?? + // Restore the ability to update screen, now with new dimensions + xf86SetRootClip(pScreen, TRUE); + + // and arrange for it to be repainted + miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); + + /* Indicate that a screen size change took place */ + RRScreenSizeNotify(pScreen); +} /* - * Respond to resize/rotate request from either X Server or X client app + * Respond to resize request */ - -static Bool -winRandRSetConfig (ScreenPtr pScreen, - Rotation rotateKind, - int rate, - RRScreenSizePtr pSize) +static +Bool +winRandRScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD16 pixWidth, + CARD16 pixHeight, + CARD32 mmWidth, + CARD32 mmHeight) { - winDebug ("winRandRSetConfig ()\n"); + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + winDebug ("winRandRScreenSetSize ()\n"); + + /* + It doesn't currently make sense to allow resize in fullscreen mode + (we'd actually have to list the supported resolutions) + */ + if (pScreenInfo->fFullScreen) + { + ErrorF ("winRandRScreenSetSize - resize not supported in fullscreen mode\n"); + return FALSE; + } + + /* + Client resize requests aren't allowed in rootless modes, even if + the X screen is monitor or virtual desktop size, we'd need to + resize the native display size + */ + if (FALSE +#ifdef XWIN_MULTIWINDOWEXTWM + || pScreenInfo->fMWExtWM +#endif + || pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOW + || pScreenInfo->fMultiWindow +#endif + ) + { + ErrorF ("winRandRScreenSetSize - resize not supported in rootless modes\n"); + return FALSE; + } + + winDoRandRScreenSetSize(pScreen, width, height, mmWidth, mmHeight); + + /* Cause the native window for the screen to resize itself */ + { + DWORD dwStyle, dwExStyle; + RECT rcClient; + + rcClient.left = 0; + rcClient.top = 0; + rcClient.right = width; + rcClient.bottom = height; + + ErrorF ("winRandRScreenSetSize new client area w: %d h: %d\n", width, height); + + /* Get the Windows window style and extended style */ + dwExStyle = GetWindowLongPtr(pScreenPriv->hwndScreen, GWL_EXSTYLE); + dwStyle = GetWindowLongPtr(pScreenPriv->hwndScreen, GWL_STYLE); + + /* + * Calculate the window size needed for the given client area + * adjusting for any decorations it will have + */ + AdjustWindowRectEx(&rcClient, dwStyle, FALSE, dwExStyle); + + ErrorF ("winRandRScreenSetSize new window area w: %ld h: %ld\n", rcClient.right-rcClient.left, rcClient.bottom-rcClient.top); + + SetWindowPos(pScreenPriv->hwndScreen, NULL, + 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, + SWP_NOZORDER | SWP_NOMOVE); + } return TRUE; } - /* * Initialize the RandR layer. */ @@ -122,8 +302,7 @@ winRandRSetConfig (ScreenPtr pScreen, Bool winRandRInit (ScreenPtr pScreen) { - rrScrPrivPtr pRRScrPriv; - + rrScrPrivPtr pRRScrPriv; winDebug ("winRandRInit ()\n"); if (!RRScreenInit (pScreen)) @@ -135,7 +314,10 @@ winRandRInit (ScreenPtr pScreen) /* Set some RandR function pointers */ pRRScrPriv = rrGetScrPriv (pScreen); pRRScrPriv->rrGetInfo = winRandRGetInfo; - pRRScrPriv->rrSetConfig = winRandRSetConfig; + pRRScrPriv->rrSetConfig = NULL; + pRRScrPriv->rrScreenSetSize = winRandRScreenSetSize; + pRRScrPriv->rrCrtcSet = NULL; + pRRScrPriv->rrCrtcSetGamma = NULL; return TRUE; } diff --git a/xorg-server/hw/xwin/winscrinit.c b/xorg-server/hw/xwin/winscrinit.c index f067fde6a..691237e6f 100644 --- a/xorg-server/hw/xwin/winscrinit.c +++ b/xorg-server/hw/xwin/winscrinit.c @@ -1,767 +1,769 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - * Kensuke Matsuzaki - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" -#include "winmsg.h" - - -#ifdef XWIN_MULTIWINDOWEXTWM -static RootlessFrameProcsRec -winMWExtWMProcs = { - winMWExtWMCreateFrame, - winMWExtWMDestroyFrame, - - winMWExtWMMoveFrame, - winMWExtWMResizeFrame, - winMWExtWMRestackFrame, - winMWExtWMReshapeFrame, - winMWExtWMUnmapFrame, - - winMWExtWMStartDrawing, - winMWExtWMStopDrawing, - winMWExtWMUpdateRegion, - winMWExtWMDamageRects, - winMWExtWMRootlessSwitchWindow, - NULL,//winMWExtWMDoReorderWindow, - NULL,//winMWExtWMHideWindow, - NULL,//winMWExtWMUpdateColorMap, - - NULL,//winMWExtWMCopyBytes, - winMWExtWMCopyWindow -}; -#endif - -/* - * Prototypes - */ - -Bool -winRandRInit (ScreenPtr pScreen); - - -/* - * Local functions - */ - -static Bool -winSaveScreen (ScreenPtr pScreen, int on); - - -/* - * Determine what type of screen we are initializing - * and call the appropriate procedure to intiailize - * that type of screen. - */ - -Bool -winScreenInit (int index, - ScreenPtr pScreen, - int argc, char **argv) -{ - winScreenInfoPtr pScreenInfo = &g_ScreenInfo[index]; - winPrivScreenPtr pScreenPriv; - HDC hdc; - -#if CYGDEBUG || YES - winDebug ("winScreenInit - dwWidth: %ld dwHeight: %ld\n", - pScreenInfo->dwWidth, pScreenInfo->dwHeight); -#endif - - /* Allocate privates for this screen */ - if (!winAllocatePrivates (pScreen)) - { - ErrorF ("winScreenInit - Couldn't allocate screen privates\n"); - return FALSE; - } - - /* Get a pointer to the privates structure that was allocated */ - pScreenPriv = winGetScreenPriv (pScreen); - - /* Save a pointer to this screen in the screen info structure */ - pScreenInfo->pScreen = pScreen; - - /* Save a pointer to the screen info in the screen privates structure */ - /* This allows us to get back to the screen info from a screen pointer */ - pScreenPriv->pScreenInfo = pScreenInfo; - - /* - * Determine which engine to use. - * - * NOTE: This is done once per screen because each screen possibly has - * a preferred engine specified on the command line. - */ - if (!winSetEngine (pScreen)) - { - ErrorF ("winScreenInit - winSetEngine () failed\n"); - return FALSE; - } - - /* Adjust the video mode for our engine type */ - if (!(*pScreenPriv->pwinAdjustVideoMode) (pScreen)) - { - ErrorF ("winScreenInit - winAdjustVideoMode () failed\n"); - return FALSE; - } - - /* Check for supported display depth */ - if (!(WIN_SUPPORTED_BPPS & (1 << (pScreenInfo->dwBPP - 1)))) - { - ErrorF ("winScreenInit - Unsupported display depth: %d\n" \ - "Change your Windows display depth to 15, 16, 24, or 32 bits " - "per pixel.\n", - (int) pScreenInfo->dwBPP); - ErrorF ("winScreenInit - Supported depths: %08x\n", - WIN_SUPPORTED_BPPS); -#if WIN_CHECK_DEPTH - return FALSE; -#endif - } - - /* - * Check that all monitors have the same display depth if we are using - * multiple monitors - */ - if (pScreenInfo->fMultipleMonitors - && !GetSystemMetrics (SM_SAMEDISPLAYFORMAT)) - { - ErrorF ("winScreenInit - Monitors do not all have same pixel format / " - "display depth.\n" - "Using primary display only.\n"); - pScreenInfo->fMultipleMonitors = FALSE; - } - - /* Create display window */ - if (!(*pScreenPriv->pwinCreateBoundingWindow) (pScreen)) - { - ErrorF ("winScreenInit - pwinCreateBoundingWindow () " - "failed\n"); - return FALSE; - } - - /* Get a device context */ - hdc = GetDC (pScreenPriv->hwndScreen); - - /* Store the initial height, width, and depth of the display */ - /* Are we using multiple monitors? */ - if (pScreenInfo->fMultipleMonitors) - { - pScreenPriv->dwLastWindowsWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN); - pScreenPriv->dwLastWindowsHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN); - - /* - * In this case, some of the defaults set in - * winInitializeScreenDefaults() are not correct ... - */ - if (!pScreenInfo->fUserGaveHeightAndWidth) - { - pScreenInfo->dwWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN); - pScreenInfo->dwHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN); - pScreenInfo->dwWidth_mm = (pScreenInfo->dwWidth / - WIN_DEFAULT_DPI) * 25.4; - pScreenInfo->dwHeight_mm = (pScreenInfo->dwHeight / - WIN_DEFAULT_DPI) * 25.4; - } - } - else - { - pScreenPriv->dwLastWindowsWidth = GetSystemMetrics (SM_CXSCREEN); - pScreenPriv->dwLastWindowsHeight = GetSystemMetrics (SM_CYSCREEN); - } - - /* Save the original bits per pixel */ - pScreenPriv->dwLastWindowsBitsPixel = GetDeviceCaps (hdc, BITSPIXEL); - - /* Release the device context */ - ReleaseDC (pScreenPriv->hwndScreen, hdc); - - /* Clear the visuals list */ - miClearVisualTypes (); - - /* Set the padded screen width */ - pScreenInfo->dwPaddedWidth = PixmapBytePad (pScreenInfo->dwWidth, - pScreenInfo->dwBPP); - - /* Call the engine dependent screen initialization procedure */ - if (!((*pScreenPriv->pwinFinishScreenInit) (index, pScreen, argc, argv))) - { - ErrorF ("winScreenInit - winFinishScreenInit () failed\n"); - return FALSE; - } - - if (!g_fSoftwareCursor) - winInitCursor(pScreen); - else - winErrorFVerb(2, "winScreenInit - Using software cursor\n"); - - /* - Note the screen origin in a normalized coordinate space where (0,0) is at the top left - of the native virtual desktop area - */ - pScreen->x = pScreenInfo->dwInitialX - GetSystemMetrics(SM_XVIRTUALSCREEN); - pScreen->y = pScreenInfo->dwInitialY - GetSystemMetrics(SM_YVIRTUALSCREEN); - - ErrorF("Screen %d added at virtual desktop coordinate (%d,%d).\n", - index, pScreen->x, pScreen->y); - -#if CYGDEBUG || YES - winDebug ("winScreenInit - returning\n"); -#endif - - return TRUE; -} - -static Bool -winCreateScreenResources(ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - Bool result; - - result = pScreenPriv->pwinCreateScreenResources(pScreen); - - /* Now the screen bitmap has been wrapped in a pixmap, - add that to the Shadow framebuffer */ - if (!shadowAdd(pScreen, pScreen->devPrivate, - pScreenPriv->pwinShadowUpdate, NULL, 0, 0)) - { - ErrorF ("winCreateScreenResources - shadowAdd () failed\n"); - return FALSE; - } - - return result; -} - -/* See Porting Layer Definition - p. 20 */ -Bool -winFinishScreenInitFB (int index, - ScreenPtr pScreen, - int argc, char **argv) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - VisualPtr pVisual = NULL; - char *pbits = NULL; -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - int iReturn; -#endif - - /* Create framebuffer */ - if (!(*pScreenPriv->pwinAllocateFB) (pScreen)) - { - ErrorF ("winFinishScreenInitFB - Could not allocate framebuffer\n"); - return FALSE; - } - - /* - * Grab the number of bits that are used to represent color in each pixel. - */ - if (pScreenInfo->dwBPP == 8) - pScreenInfo->dwDepth = 8; - else - pScreenInfo->dwDepth = winCountBits (pScreenPriv->dwRedMask) - + winCountBits (pScreenPriv->dwGreenMask) - + winCountBits (pScreenPriv->dwBlueMask); - - winErrorFVerb (2, "winFinishScreenInitFB - Masks: %08x %08x %08x\n", - (unsigned int) pScreenPriv->dwRedMask, - (unsigned int) pScreenPriv->dwGreenMask, - (unsigned int) pScreenPriv->dwBlueMask); - - /* Init visuals */ - if (!(*pScreenPriv->pwinInitVisuals) (pScreen)) - { - ErrorF ("winFinishScreenInitFB - winInitVisuals failed\n"); - return FALSE; - } - - /* Setup a local variable to point to the framebuffer */ - pbits = pScreenInfo->pfb; - - /* Apparently we need this for the render extension */ - miSetPixmapDepths (); - - /* Start fb initialization */ - if (!fbSetupScreen (pScreen, - pScreenInfo->pfb, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - monitorResolution, monitorResolution, - pScreenInfo->dwStride, - pScreenInfo->dwBPP)) - { - ErrorF ("winFinishScreenInitFB - fbSetupScreen failed\n"); - return FALSE; - } - - /* Override default colormap routines if visual class is dynamic */ - if (pScreenInfo->dwDepth == 8 - && (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI - || (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL - && pScreenInfo->fFullScreen) - || (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD - && pScreenInfo->fFullScreen))) - { - winSetColormapFunctions (pScreen); - - /* - * NOTE: Setting whitePixel to 255 causes Magic 7.1 to allocate its - * own colormap, as it cannot allocate 7 planes in the default - * colormap. Setting whitePixel to 1 allows Magic to get 7 - * planes in the default colormap, so it doesn't create its - * own colormap. This latter situation is highly desireable, - * as it keeps the Magic window viewable when switching to - * other X clients that use the default colormap. - */ - pScreen->blackPixel = 0; - pScreen->whitePixel = 1; - } - - /* Place our save screen function */ - pScreen->SaveScreen = winSaveScreen; - - /* Finish fb initialization */ - if (!fbFinishScreenInit (pScreen, - pScreenInfo->pfb, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - monitorResolution, monitorResolution, - pScreenInfo->dwStride, - pScreenInfo->dwBPP)) - { - ErrorF ("winFinishScreenInitFB - fbFinishScreenInit failed\n"); - return FALSE; - } - - /* Save a pointer to the root visual */ - for (pVisual = pScreen->visuals; - pVisual->vid != pScreen->rootVisual; - pVisual++); - pScreenPriv->pRootVisual = pVisual; - - /* - * Setup points to the block and wakeup handlers. Pass a pointer - * to the current screen as pWakeupdata. - */ - pScreen->BlockHandler = winBlockHandler; - pScreen->WakeupHandler = winWakeupHandler; - pScreen->blockData = pScreen; - pScreen->wakeupData = pScreen; - - /* Render extension initialization, calls miPictureInit */ - if (!fbPictureInit (pScreen, NULL, 0)) - { - ErrorF ("winFinishScreenInitFB - fbPictureInit () failed\n"); - return FALSE; - } - -#ifdef RANDR - /* Initialize resize and rotate support */ - if (!winRandRInit (pScreen)) - { - ErrorF ("winFinishScreenInitFB - winRandRInit () failed\n"); - return FALSE; - } -#endif - - /* Setup the cursor routines */ -#if CYGDEBUG - winDebug ("winFinishScreenInitFB - Calling miDCInitialize ()\n"); -#endif - miDCInitialize (pScreen, &g_winPointerCursorFuncs); - - /* KDrive does winCreateDefColormap right after miDCInitialize */ - /* Create a default colormap */ -#if CYGDEBUG - winDebug ("winFinishScreenInitFB - Calling winCreateDefColormap ()\n"); -#endif - if (!winCreateDefColormap (pScreen)) - { - ErrorF ("winFinishScreenInitFB - Could not create colormap\n"); - return FALSE; - } - - /* Initialize the shadow framebuffer layer */ - if ((pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI - || pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD - || pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL) -#ifdef XWIN_MULTIWINDOWEXTWM - && !pScreenInfo->fMWExtWM -#endif - ) - { -#if CYGDEBUG - winDebug ("winFinishScreenInitFB - Calling shadowSetup ()\n"); -#endif - if (!shadowSetup(pScreen)) - { - ErrorF ("winFinishScreenInitFB - shadowSetup () failed\n"); - return FALSE; - } - - /* Wrap CreateScreenResources so we can add the screen pixmap - to the Shadow framebuffer after it's been created */ - pScreenPriv->pwinCreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = winCreateScreenResources; - } - -#ifdef XWIN_MULTIWINDOWEXTWM - /* Handle multi-window external window manager mode */ - if (pScreenInfo->fMWExtWM) - { - winDebug ("winScreenInit - MultiWindowExtWM - Calling RootlessInit\n"); - - RootlessInit(pScreen, &winMWExtWMProcs); - - winDebug ("winScreenInit - MultiWindowExtWM - RootlessInit returned\n"); - - rootless_CopyBytes_threshold = 0; - /* FIXME: How many? Profiling needed? */ - rootless_CopyWindow_threshold = 1; - - winWindowsWMExtensionInit (); - } -#endif - - /* Handle rootless mode */ - if (pScreenInfo->fRootless) - { - /* Define the WRAP macro temporarily for local use */ -#define WRAP(a) \ - if (pScreen->a) { \ - pScreenPriv->a = pScreen->a; \ - } else { \ - ErrorF("null screen fn " #a "\n"); \ - pScreenPriv->a = NULL; \ - } - - /* Save a pointer to each lower-level window procedure */ - WRAP(CreateWindow); - WRAP(DestroyWindow); - WRAP(RealizeWindow); - WRAP(UnrealizeWindow); - WRAP(PositionWindow); - WRAP(ChangeWindowAttributes); - WRAP(SetShape); - - /* Assign rootless window procedures to be top level procedures */ - pScreen->CreateWindow = winCreateWindowRootless; - pScreen->DestroyWindow = winDestroyWindowRootless; - pScreen->PositionWindow = winPositionWindowRootless; - /*pScreen->ChangeWindowAttributes = winChangeWindowAttributesRootless;*/ - pScreen->RealizeWindow = winMapWindowRootless; - pScreen->UnrealizeWindow = winUnmapWindowRootless; - pScreen->SetShape = winSetShapeRootless; - - /* Undefine the WRAP macro, as it is not needed elsewhere */ -#undef WRAP - } - - -#ifdef XWIN_MULTIWINDOW - /* Handle multi window mode */ - else if (pScreenInfo->fMultiWindow) - { - /* Define the WRAP macro temporarily for local use */ -#define WRAP(a) \ - if (pScreen->a) { \ - pScreenPriv->a = pScreen->a; \ - } else { \ - ErrorF("null screen fn " #a "\n"); \ - pScreenPriv->a = NULL; \ - } - - /* Save a pointer to each lower-level window procedure */ - WRAP(CreateWindow); - WRAP(DestroyWindow); - WRAP(RealizeWindow); - WRAP(UnrealizeWindow); - WRAP(PositionWindow); - WRAP(ChangeWindowAttributes); - WRAP(ReparentWindow); - WRAP(RestackWindow); - WRAP(ResizeWindow); - WRAP(MoveWindow); - WRAP(CopyWindow); - WRAP(SetShape); - - /* Assign multi-window window procedures to be top level procedures */ - pScreen->CreateWindow = winCreateWindowMultiWindow; - pScreen->DestroyWindow = winDestroyWindowMultiWindow; - pScreen->PositionWindow = winPositionWindowMultiWindow; - /*pScreen->ChangeWindowAttributes = winChangeWindowAttributesMultiWindow;*/ - pScreen->RealizeWindow = winMapWindowMultiWindow; - pScreen->UnrealizeWindow = winUnmapWindowMultiWindow; - pScreen->ReparentWindow = winReparentWindowMultiWindow; - pScreen->RestackWindow = winRestackWindowMultiWindow; - pScreen->ResizeWindow = winResizeWindowMultiWindow; - pScreen->MoveWindow = winMoveWindowMultiWindow; - pScreen->CopyWindow = winCopyWindowMultiWindow; - pScreen->SetShape = winSetShapeMultiWindow; - - /* Undefine the WRAP macro, as it is not needed elsewhere */ -#undef WRAP - } -#endif - - /* Wrap either fb's or shadow's CloseScreen with our CloseScreen */ - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = pScreenPriv->pwinCloseScreen; - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - /* Create a mutex for modules in separate threads to wait for */ - iReturn = pthread_mutex_init (&pScreenPriv->pmServerStarted, NULL); - if (iReturn != 0) - { - ErrorF ("winFinishScreenInitFB - pthread_mutex_init () failed: %d\n", - iReturn); - return FALSE; - } - - /* Own the mutex for modules in separate threads */ - iReturn = pthread_mutex_lock (&pScreenPriv->pmServerStarted); - if (iReturn != 0) - { - ErrorF ("winFinishScreenInitFB - pthread_mutex_lock () failed: %d\n", - iReturn); - return FALSE; - } - - /* Set the ServerStarted flag to false */ - pScreenPriv->fServerStarted = FALSE; -#endif - -#ifdef XWIN_MULTIWINDOWEXTWM - pScreenPriv->fRestacking = FALSE; -#endif - -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) - if (FALSE -#ifdef XWIN_MULTIWINDOW - || pScreenInfo->fMultiWindow -#endif -#ifdef XWIN_MULTIWINDOWEXTWM - || pScreenInfo->fInternalWM -#endif - ) - { -#if CYGDEBUG || YES - winDebug ("winFinishScreenInitFB - Calling winInitWM.\n"); -#endif - - /* Initialize multi window mode */ - if (!winInitWM (&pScreenPriv->pWMInfo, - &pScreenPriv->ptWMProc, - &pScreenPriv->ptXMsgProc, - &pScreenPriv->pmServerStarted, - pScreenInfo->dwScreen, - (HWND)&pScreenPriv->hwndScreen, -#ifdef XWIN_MULTIWINDOWEXTWM - pScreenInfo->fInternalWM || -#endif - FALSE)) - { - ErrorF ("winFinishScreenInitFB - winInitWM () failed.\n"); - return FALSE; - } - } -#endif - - /* Tell the server that we are enabled */ - pScreenPriv->fEnabled = TRUE; - - /* Tell the server that we have a valid depth */ - pScreenPriv->fBadDepth = FALSE; - -#if CYGDEBUG || YES - winDebug ("winFinishScreenInitFB - returning\n"); -#endif - - return TRUE; -} - -#ifdef XWIN_NATIVEGDI -/* See Porting Layer Definition - p. 20 */ - -Bool -winFinishScreenInitNativeGDI (int index, - ScreenPtr pScreen, - int argc, char **argv) -{ - winScreenPriv(pScreen); - winScreenInfoPtr pScreenInfo = &g_ScreenInfo[index]; - VisualPtr pVisuals = NULL; - DepthPtr pDepths = NULL; - VisualID rootVisual = 0; - int nVisuals = 0, nDepths = 0, nRootDepth = 0; - - /* Ignore user input (mouse, keyboard) */ - pScreenInfo->fIgnoreInput = FALSE; - - /* Get device contexts for the screen and shadow bitmap */ - pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); - if (pScreenPriv->hdcScreen == NULL) - FatalError ("winFinishScreenInitNativeGDI - Couldn't get a DC\n"); - - /* Init visuals */ - if (!(*pScreenPriv->pwinInitVisuals) (pScreen)) - { - ErrorF ("winFinishScreenInitNativeGDI - pwinInitVisuals failed\n"); - return FALSE; - } - - /* Initialize the mi visuals */ - if (!miInitVisuals (&pVisuals, &pDepths, &nVisuals, &nDepths, &nRootDepth, - &rootVisual, - ((unsigned long)1 << (pScreenInfo->dwDepth - 1)), 8, - TrueColor)) - { - ErrorF ("winFinishScreenInitNativeGDI - miInitVisuals () failed\n"); - return FALSE; - } - - /* Initialize the CloseScreen procedure pointer */ - pScreen->CloseScreen = NULL; - - /* Initialize the mi code */ - if (!miScreenInit (pScreen, - NULL, /* No framebuffer */ - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - monitorResolution, monitorResolution, - pScreenInfo->dwStride, - nRootDepth, nDepths, pDepths, rootVisual, - nVisuals, pVisuals)) - { - ErrorF ("winFinishScreenInitNativeGDI - miScreenInit failed\n"); - return FALSE; - } - - pScreen->defColormap = FakeClientID(0); - - /* - * Register our block and wakeup handlers; these procedures - * process messages in our Windows message queue; specifically, - * they process mouse and keyboard input. - */ - pScreen->BlockHandler = winBlockHandler; - pScreen->WakeupHandler = winWakeupHandler; - pScreen->blockData = pScreen; - pScreen->wakeupData = pScreen; - - /* Place our save screen function */ - pScreen->SaveScreen = winSaveScreen; - - /* Pixmaps */ - pScreen->CreatePixmap = winCreatePixmapNativeGDI; - pScreen->DestroyPixmap = winDestroyPixmapNativeGDI; - - /* Other Screen Routines */ - pScreen->QueryBestSize = winQueryBestSizeNativeGDI; - pScreen->SaveScreen = winSaveScreen; - pScreen->GetImage = miGetImage; - pScreen->GetSpans = winGetSpansNativeGDI; - - /* Window Procedures */ - pScreen->CreateWindow = winCreateWindowNativeGDI; - pScreen->DestroyWindow = winDestroyWindowNativeGDI; - pScreen->PositionWindow = winPositionWindowNativeGDI; - /*pScreen->ChangeWindowAttributes = winChangeWindowAttributesNativeGDI;*/ - pScreen->RealizeWindow = winMapWindowNativeGDI; - pScreen->UnrealizeWindow = winUnmapWindowNativeGDI; - - /* Paint window */ - pScreen->CopyWindow = winCopyWindowNativeGDI; - - /* Fonts */ - pScreen->RealizeFont = winRealizeFontNativeGDI; - pScreen->UnrealizeFont = winUnrealizeFontNativeGDI; - - /* GC */ - pScreen->CreateGC = winCreateGCNativeGDI; - - /* Colormap Routines */ - pScreen->CreateColormap = miInitializeColormap; - pScreen->DestroyColormap = (DestroyColormapProcPtr) (void (*)(void)) NoopDDA; - pScreen->InstallColormap = miInstallColormap; - pScreen->UninstallColormap = miUninstallColormap; - pScreen->ListInstalledColormaps = miListInstalledColormaps; - pScreen->StoreColors = (StoreColorsProcPtr) (void (*)(void)) NoopDDA; - pScreen->ResolveColor = miResolveColor; - - /* Bitmap */ - pScreen->BitmapToRegion = winPixmapToRegionNativeGDI; - - ErrorF ("winFinishScreenInitNativeGDI - calling miDCInitialize\n"); - - /* Set the default white and black pixel positions */ - pScreen->whitePixel = pScreen->blackPixel = (Pixel) 0; - - /* Initialize the cursor */ - if (!miDCInitialize (pScreen, &g_winPointerCursorFuncs)) - { - ErrorF ("winFinishScreenInitNativeGDI - miDCInitialize failed\n"); - return FALSE; - } - - /* Create a default colormap */ - if (!miCreateDefColormap (pScreen)) - { - ErrorF ("winFinishScreenInitNativeGDI - miCreateDefColormap () " - "failed\n"); - return FALSE; - } - - ErrorF ("winFinishScreenInitNativeGDI - miCreateDefColormap () " - "returned\n"); - - /* mi doesn't use a CloseScreen procedure, so no need to wrap */ - pScreen->CloseScreen = pScreenPriv->pwinCloseScreen; - - /* Tell the server that we are enabled */ - pScreenPriv->fEnabled = TRUE; - - ErrorF ("winFinishScreenInitNativeGDI - Successful addition of " - "screen %08x\n", - (unsigned int) pScreen); - - return TRUE; -} -#endif - - -/* See Porting Layer Definition - p. 33 */ -static Bool -winSaveScreen (ScreenPtr pScreen, int on) -{ - return TRUE; -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + * Kensuke Matsuzaki + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" +#include "winmsg.h" + + +#ifdef XWIN_MULTIWINDOWEXTWM +static RootlessFrameProcsRec +winMWExtWMProcs = { + winMWExtWMCreateFrame, + winMWExtWMDestroyFrame, + + winMWExtWMMoveFrame, + winMWExtWMResizeFrame, + winMWExtWMRestackFrame, + winMWExtWMReshapeFrame, + winMWExtWMUnmapFrame, + + winMWExtWMStartDrawing, + winMWExtWMStopDrawing, + winMWExtWMUpdateRegion, + winMWExtWMDamageRects, + winMWExtWMRootlessSwitchWindow, + NULL,//winMWExtWMDoReorderWindow, + NULL,//winMWExtWMHideWindow, + NULL,//winMWExtWMUpdateColorMap, + + NULL,//winMWExtWMCopyBytes, + winMWExtWMCopyWindow +}; +#endif + +/* + * Prototypes + */ + +/* + * Local functions + */ + +static Bool +winSaveScreen (ScreenPtr pScreen, int on); + + +/* + * Determine what type of screen we are initializing + * and call the appropriate procedure to intiailize + * that type of screen. + */ + +Bool +winScreenInit (int index, + ScreenPtr pScreen, + int argc, char **argv) +{ + winScreenInfoPtr pScreenInfo = &g_ScreenInfo[index]; + winPrivScreenPtr pScreenPriv; + HDC hdc; + DWORD dwInitialBPP; + +#if CYGDEBUG || YES + winDebug ("winScreenInit - dwWidth: %ld dwHeight: %ld\n", + pScreenInfo->dwWidth, pScreenInfo->dwHeight); +#endif + + /* Allocate privates for this screen */ + if (!winAllocatePrivates (pScreen)) + { + ErrorF ("winScreenInit - Couldn't allocate screen privates\n"); + return FALSE; + } + + /* Get a pointer to the privates structure that was allocated */ + pScreenPriv = winGetScreenPriv (pScreen); + + /* Save a pointer to this screen in the screen info structure */ + pScreenInfo->pScreen = pScreen; + + /* Save a pointer to the screen info in the screen privates structure */ + /* This allows us to get back to the screen info from a screen pointer */ + pScreenPriv->pScreenInfo = pScreenInfo; + + /* + * Determine which engine to use. + * + * NOTE: This is done once per screen because each screen possibly has + * a preferred engine specified on the command line. + */ + if (!winSetEngine (pScreen)) + { + ErrorF ("winScreenInit - winSetEngine () failed\n"); + return FALSE; + } + + /* Horribly misnamed function: Allow engine to adjust BPP for screen */ + dwInitialBPP = pScreenInfo->dwBPP; + + if (!(*pScreenPriv->pwinAdjustVideoMode) (pScreen)) + { + ErrorF ("winScreenInit - winAdjustVideoMode () failed\n"); + return FALSE; + } + + if (dwInitialBPP == WIN_DEFAULT_BPP) + { + /* No -depth parameter was passed, let the user know the depth being used */ + ErrorF ("winScreenInit - Using Windows display depth of %d bits per pixel\n", (int) pScreenInfo->dwBPP); + } + else if (dwInitialBPP != pScreenInfo->dwBPP) + { + /* Warn user if engine forced a depth different to -depth parameter */ + ErrorF ("winScreenInit - Command line depth of %d bpp overidden by engine, using %d bpp\n", (int) dwInitialBPP, (int) pScreenInfo->dwBPP); + } + else + { + ErrorF ("winScreenInit - Using command line depth of %d bpp\n", (int) pScreenInfo->dwBPP); + } + + /* Check for supported display depth */ + if (!(WIN_SUPPORTED_BPPS & (1 << (pScreenInfo->dwBPP - 1)))) + { + ErrorF ("winScreenInit - Unsupported display depth: %d\n" \ + "Change your Windows display depth to 15, 16, 24, or 32 bits " + "per pixel.\n", + (int) pScreenInfo->dwBPP); + ErrorF ("winScreenInit - Supported depths: %08x\n", + WIN_SUPPORTED_BPPS); +#if WIN_CHECK_DEPTH + return FALSE; +#endif + } + + /* + * Check that all monitors have the same display depth if we are using + * multiple monitors + */ + if (pScreenInfo->fMultipleMonitors + && !GetSystemMetrics (SM_SAMEDISPLAYFORMAT)) + { + ErrorF ("winScreenInit - Monitors do not all have same pixel format / " + "display depth.\n"); + if (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI) + { + ErrorF ("winScreenInit - Performance may suffer off primary display.\n"); + } + else + { + ErrorF ("winScreenInit - Using primary display only.\n"); + pScreenInfo->fMultipleMonitors = FALSE; + } + } + + /* Create display window */ + if (!(*pScreenPriv->pwinCreateBoundingWindow) (pScreen)) + { + ErrorF ("winScreenInit - pwinCreateBoundingWindow () " + "failed\n"); + return FALSE; + } + + /* Get a device context */ + hdc = GetDC (pScreenPriv->hwndScreen); + + /* Are we using multiple monitors? */ + if (pScreenInfo->fMultipleMonitors) + { + /* + * In this case, some of the defaults set in + * winInitializeScreenDefaults() are not correct ... + */ + if (!pScreenInfo->fUserGaveHeightAndWidth) + { + pScreenInfo->dwWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN); + pScreenInfo->dwHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN); + } + } + + /* Release the device context */ + ReleaseDC (pScreenPriv->hwndScreen, hdc); + + /* Clear the visuals list */ + miClearVisualTypes (); + + /* Call the engine dependent screen initialization procedure */ + if (!((*pScreenPriv->pwinFinishScreenInit) (index, pScreen, argc, argv))) + { + ErrorF ("winScreenInit - winFinishScreenInit () failed\n"); + return FALSE; + } + + if (!g_fSoftwareCursor) + winInitCursor(pScreen); + else + winErrorFVerb(2, "winScreenInit - Using software cursor\n"); + + /* + Note the screen origin in a normalized coordinate space where (0,0) is at the top left + of the native virtual desktop area + */ + pScreen->x = pScreenInfo->dwInitialX - GetSystemMetrics(SM_XVIRTUALSCREEN); + pScreen->y = pScreenInfo->dwInitialY - GetSystemMetrics(SM_YVIRTUALSCREEN); + + ErrorF("Screen %d added at virtual desktop coordinate (%d,%d).\n", + index, pScreen->x, pScreen->y); + +#if CYGDEBUG || YES + winDebug ("winScreenInit - returning\n"); +#endif + + return TRUE; +} + +static Bool +winCreateScreenResources(ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + Bool result; + + result = pScreenPriv->pwinCreateScreenResources(pScreen); + + /* Now the screen bitmap has been wrapped in a pixmap, + add that to the Shadow framebuffer */ + if (!shadowAdd(pScreen, pScreen->devPrivate, + pScreenPriv->pwinShadowUpdate, NULL, 0, 0)) + { + ErrorF ("winCreateScreenResources - shadowAdd () failed\n"); + return FALSE; + } + + return result; +} + +/* See Porting Layer Definition - p. 20 */ +Bool +winFinishScreenInitFB (int index, + ScreenPtr pScreen, + int argc, char **argv) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + VisualPtr pVisual = NULL; + char *pbits = NULL; +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + int iReturn; +#endif + + /* Create framebuffer */ + if (!(*pScreenPriv->pwinInitScreen) (pScreen)) + { + ErrorF ("winFinishScreenInitFB - Could not allocate framebuffer\n"); + return FALSE; + } + + /* + * Calculate the number of bits that are used to represent color in each pixel, + * the color depth for the screen + */ + if (pScreenInfo->dwBPP == 8) + pScreenInfo->dwDepth = 8; + else + pScreenInfo->dwDepth = winCountBits (pScreenPriv->dwRedMask) + + winCountBits (pScreenPriv->dwGreenMask) + + winCountBits (pScreenPriv->dwBlueMask); + + winErrorFVerb (2, "winFinishScreenInitFB - Masks: %08x %08x %08x\n", + (unsigned int) pScreenPriv->dwRedMask, + (unsigned int) pScreenPriv->dwGreenMask, + (unsigned int) pScreenPriv->dwBlueMask); + + /* Init visuals */ + if (!(*pScreenPriv->pwinInitVisuals) (pScreen)) + { + ErrorF ("winFinishScreenInitFB - winInitVisuals failed\n"); + return FALSE; + } + + /* Setup a local variable to point to the framebuffer */ + pbits = pScreenInfo->pfb; + + /* Apparently we need this for the render extension */ + miSetPixmapDepths (); + + /* Start fb initialization */ + if (!fbSetupScreen (pScreen, + pScreenInfo->pfb, + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + monitorResolution, monitorResolution, + pScreenInfo->dwStride, + pScreenInfo->dwBPP)) + { + ErrorF ("winFinishScreenInitFB - fbSetupScreen failed\n"); + return FALSE; + } + + /* Override default colormap routines if visual class is dynamic */ + if (pScreenInfo->dwDepth == 8 + && (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI + || (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL + && pScreenInfo->fFullScreen) + || (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD + && pScreenInfo->fFullScreen))) + { + winSetColormapFunctions (pScreen); + + /* + * NOTE: Setting whitePixel to 255 causes Magic 7.1 to allocate its + * own colormap, as it cannot allocate 7 planes in the default + * colormap. Setting whitePixel to 1 allows Magic to get 7 + * planes in the default colormap, so it doesn't create its + * own colormap. This latter situation is highly desireable, + * as it keeps the Magic window viewable when switching to + * other X clients that use the default colormap. + */ + pScreen->blackPixel = 0; + pScreen->whitePixel = 1; + } + + /* Place our save screen function */ + pScreen->SaveScreen = winSaveScreen; + + /* Finish fb initialization */ + if (!fbFinishScreenInit (pScreen, + pScreenInfo->pfb, + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + monitorResolution, monitorResolution, + pScreenInfo->dwStride, + pScreenInfo->dwBPP)) + { + ErrorF ("winFinishScreenInitFB - fbFinishScreenInit failed\n"); + return FALSE; + } + + /* Save a pointer to the root visual */ + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++); + pScreenPriv->pRootVisual = pVisual; + + /* + * Setup points to the block and wakeup handlers. Pass a pointer + * to the current screen as pWakeupdata. + */ + pScreen->BlockHandler = winBlockHandler; + pScreen->WakeupHandler = winWakeupHandler; + pScreen->blockData = pScreen; + pScreen->wakeupData = pScreen; + + /* Render extension initialization, calls miPictureInit */ + if (!fbPictureInit (pScreen, NULL, 0)) + { + ErrorF ("winFinishScreenInitFB - fbPictureInit () failed\n"); + return FALSE; + } + +#ifdef RANDR + /* Initialize resize and rotate support */ + if (!winRandRInit (pScreen)) + { + ErrorF ("winFinishScreenInitFB - winRandRInit () failed\n"); + return FALSE; + } +#endif + + /* Setup the cursor routines */ +#if CYGDEBUG + winDebug ("winFinishScreenInitFB - Calling miDCInitialize ()\n"); +#endif + miDCInitialize (pScreen, &g_winPointerCursorFuncs); + + /* KDrive does winCreateDefColormap right after miDCInitialize */ + /* Create a default colormap */ +#if CYGDEBUG + winDebug ("winFinishScreenInitFB - Calling winCreateDefColormap ()\n"); +#endif + if (!winCreateDefColormap (pScreen)) + { + ErrorF ("winFinishScreenInitFB - Could not create colormap\n"); + return FALSE; + } + + /* Initialize the shadow framebuffer layer */ + if ((pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI + || pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD + || pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL) +#ifdef XWIN_MULTIWINDOWEXTWM + && !pScreenInfo->fMWExtWM +#endif + ) + { +#if CYGDEBUG + winDebug ("winFinishScreenInitFB - Calling shadowSetup ()\n"); +#endif + if (!shadowSetup(pScreen)) + { + ErrorF ("winFinishScreenInitFB - shadowSetup () failed\n"); + return FALSE; + } + + /* Wrap CreateScreenResources so we can add the screen pixmap + to the Shadow framebuffer after it's been created */ + pScreenPriv->pwinCreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = winCreateScreenResources; + } + +#ifdef XWIN_MULTIWINDOWEXTWM + /* Handle multi-window external window manager mode */ + if (pScreenInfo->fMWExtWM) + { + winDebug ("winScreenInit - MultiWindowExtWM - Calling RootlessInit\n"); + + RootlessInit(pScreen, &winMWExtWMProcs); + + winDebug ("winScreenInit - MultiWindowExtWM - RootlessInit returned\n"); + + rootless_CopyBytes_threshold = 0; + /* FIXME: How many? Profiling needed? */ + rootless_CopyWindow_threshold = 1; + + winWindowsWMExtensionInit (); + } +#endif + + /* Handle rootless mode */ + if (pScreenInfo->fRootless) + { + /* Define the WRAP macro temporarily for local use */ +#define WRAP(a) \ + if (pScreen->a) { \ + pScreenPriv->a = pScreen->a; \ + } else { \ + ErrorF("null screen fn " #a "\n"); \ + pScreenPriv->a = NULL; \ + } + + /* Save a pointer to each lower-level window procedure */ + WRAP(CreateWindow); + WRAP(DestroyWindow); + WRAP(RealizeWindow); + WRAP(UnrealizeWindow); + WRAP(PositionWindow); + WRAP(ChangeWindowAttributes); + WRAP(SetShape); + + /* Assign rootless window procedures to be top level procedures */ + pScreen->CreateWindow = winCreateWindowRootless; + pScreen->DestroyWindow = winDestroyWindowRootless; + pScreen->PositionWindow = winPositionWindowRootless; + /*pScreen->ChangeWindowAttributes = winChangeWindowAttributesRootless;*/ + pScreen->RealizeWindow = winMapWindowRootless; + pScreen->UnrealizeWindow = winUnmapWindowRootless; + pScreen->SetShape = winSetShapeRootless; + + /* Undefine the WRAP macro, as it is not needed elsewhere */ +#undef WRAP + } + + +#ifdef XWIN_MULTIWINDOW + /* Handle multi window mode */ + else if (pScreenInfo->fMultiWindow) + { + /* Define the WRAP macro temporarily for local use */ +#define WRAP(a) \ + if (pScreen->a) { \ + pScreenPriv->a = pScreen->a; \ + } else { \ + ErrorF("null screen fn " #a "\n"); \ + pScreenPriv->a = NULL; \ + } + + /* Save a pointer to each lower-level window procedure */ + WRAP(CreateWindow); + WRAP(DestroyWindow); + WRAP(RealizeWindow); + WRAP(UnrealizeWindow); + WRAP(PositionWindow); + WRAP(ChangeWindowAttributes); + WRAP(ReparentWindow); + WRAP(RestackWindow); + WRAP(ResizeWindow); + WRAP(MoveWindow); + WRAP(CopyWindow); + WRAP(SetShape); + + /* Assign multi-window window procedures to be top level procedures */ + pScreen->CreateWindow = winCreateWindowMultiWindow; + pScreen->DestroyWindow = winDestroyWindowMultiWindow; + pScreen->PositionWindow = winPositionWindowMultiWindow; + /*pScreen->ChangeWindowAttributes = winChangeWindowAttributesMultiWindow;*/ + pScreen->RealizeWindow = winMapWindowMultiWindow; + pScreen->UnrealizeWindow = winUnmapWindowMultiWindow; + pScreen->ReparentWindow = winReparentWindowMultiWindow; + pScreen->RestackWindow = winRestackWindowMultiWindow; + pScreen->ResizeWindow = winResizeWindowMultiWindow; + pScreen->MoveWindow = winMoveWindowMultiWindow; + pScreen->CopyWindow = winCopyWindowMultiWindow; + pScreen->SetShape = winSetShapeMultiWindow; + + /* Undefine the WRAP macro, as it is not needed elsewhere */ +#undef WRAP + } +#endif + + /* Wrap either fb's or shadow's CloseScreen with our CloseScreen */ + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = pScreenPriv->pwinCloseScreen; + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + /* Create a mutex for modules in separate threads to wait for */ + iReturn = pthread_mutex_init (&pScreenPriv->pmServerStarted, NULL); + if (iReturn != 0) + { + ErrorF ("winFinishScreenInitFB - pthread_mutex_init () failed: %d\n", + iReturn); + return FALSE; + } + + /* Own the mutex for modules in separate threads */ + iReturn = pthread_mutex_lock (&pScreenPriv->pmServerStarted); + if (iReturn != 0) + { + ErrorF ("winFinishScreenInitFB - pthread_mutex_lock () failed: %d\n", + iReturn); + return FALSE; + } + + /* Set the ServerStarted flag to false */ + pScreenPriv->fServerStarted = FALSE; +#endif + +#ifdef XWIN_MULTIWINDOWEXTWM + pScreenPriv->fRestacking = FALSE; +#endif + +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) + if (FALSE +#ifdef XWIN_MULTIWINDOW + || pScreenInfo->fMultiWindow +#endif +#ifdef XWIN_MULTIWINDOWEXTWM + || pScreenInfo->fInternalWM +#endif + ) + { +#if CYGDEBUG || YES + winDebug ("winFinishScreenInitFB - Calling winInitWM.\n"); +#endif + + /* Initialize multi window mode */ + if (!winInitWM (&pScreenPriv->pWMInfo, + &pScreenPriv->ptWMProc, + &pScreenPriv->ptXMsgProc, + &pScreenPriv->pmServerStarted, + pScreenInfo->dwScreen, + (HWND)&pScreenPriv->hwndScreen, +#ifdef XWIN_MULTIWINDOWEXTWM + pScreenInfo->fInternalWM || +#endif + FALSE)) + { + ErrorF ("winFinishScreenInitFB - winInitWM () failed.\n"); + return FALSE; + } + } +#endif + + /* Tell the server that we are enabled */ + pScreenPriv->fEnabled = TRUE; + + /* Tell the server that we have a valid depth */ + pScreenPriv->fBadDepth = FALSE; + +#if CYGDEBUG || YES + winDebug ("winFinishScreenInitFB - returning\n"); +#endif + + return TRUE; +} + +#ifdef XWIN_NATIVEGDI +/* See Porting Layer Definition - p. 20 */ + +Bool +winFinishScreenInitNativeGDI (int index, + ScreenPtr pScreen, + int argc, char **argv) +{ + winScreenPriv(pScreen); + winScreenInfoPtr pScreenInfo = &g_ScreenInfo[index]; + VisualPtr pVisuals = NULL; + DepthPtr pDepths = NULL; + VisualID rootVisual = 0; + int nVisuals = 0, nDepths = 0, nRootDepth = 0; + + /* Ignore user input (mouse, keyboard) */ + pScreenInfo->fIgnoreInput = FALSE; + + /* Get device contexts for the screen and shadow bitmap */ + pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); + if (pScreenPriv->hdcScreen == NULL) + FatalError ("winFinishScreenInitNativeGDI - Couldn't get a DC\n"); + + /* Init visuals */ + if (!(*pScreenPriv->pwinInitVisuals) (pScreen)) + { + ErrorF ("winFinishScreenInitNativeGDI - pwinInitVisuals failed\n"); + return FALSE; + } + + /* Initialize the mi visuals */ + if (!miInitVisuals (&pVisuals, &pDepths, &nVisuals, &nDepths, &nRootDepth, + &rootVisual, + ((unsigned long)1 << (pScreenInfo->dwDepth - 1)), 8, + TrueColor)) + { + ErrorF ("winFinishScreenInitNativeGDI - miInitVisuals () failed\n"); + return FALSE; + } + + /* Initialize the CloseScreen procedure pointer */ + pScreen->CloseScreen = NULL; + + /* Initialize the mi code */ + if (!miScreenInit (pScreen, + NULL, /* No framebuffer */ + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + monitorResolution, monitorResolution, + pScreenInfo->dwStride, + nRootDepth, nDepths, pDepths, rootVisual, + nVisuals, pVisuals)) + { + ErrorF ("winFinishScreenInitNativeGDI - miScreenInit failed\n"); + return FALSE; + } + + pScreen->defColormap = FakeClientID(0); + + /* + * Register our block and wakeup handlers; these procedures + * process messages in our Windows message queue; specifically, + * they process mouse and keyboard input. + */ + pScreen->BlockHandler = winBlockHandler; + pScreen->WakeupHandler = winWakeupHandler; + pScreen->blockData = pScreen; + pScreen->wakeupData = pScreen; + + /* Place our save screen function */ + pScreen->SaveScreen = winSaveScreen; + + /* Pixmaps */ + pScreen->CreatePixmap = winCreatePixmapNativeGDI; + pScreen->DestroyPixmap = winDestroyPixmapNativeGDI; + + /* Other Screen Routines */ + pScreen->QueryBestSize = winQueryBestSizeNativeGDI; + pScreen->SaveScreen = winSaveScreen; + pScreen->GetImage = miGetImage; + pScreen->GetSpans = winGetSpansNativeGDI; + + /* Window Procedures */ + pScreen->CreateWindow = winCreateWindowNativeGDI; + pScreen->DestroyWindow = winDestroyWindowNativeGDI; + pScreen->PositionWindow = winPositionWindowNativeGDI; + /*pScreen->ChangeWindowAttributes = winChangeWindowAttributesNativeGDI;*/ + pScreen->RealizeWindow = winMapWindowNativeGDI; + pScreen->UnrealizeWindow = winUnmapWindowNativeGDI; + + /* Paint window */ + pScreen->CopyWindow = winCopyWindowNativeGDI; + + /* Fonts */ + pScreen->RealizeFont = winRealizeFontNativeGDI; + pScreen->UnrealizeFont = winUnrealizeFontNativeGDI; + + /* GC */ + pScreen->CreateGC = winCreateGCNativeGDI; + + /* Colormap Routines */ + pScreen->CreateColormap = miInitializeColormap; + pScreen->DestroyColormap = (DestroyColormapProcPtr) (void (*)(void)) NoopDDA; + pScreen->InstallColormap = miInstallColormap; + pScreen->UninstallColormap = miUninstallColormap; + pScreen->ListInstalledColormaps = miListInstalledColormaps; + pScreen->StoreColors = (StoreColorsProcPtr) (void (*)(void)) NoopDDA; + pScreen->ResolveColor = miResolveColor; + + /* Bitmap */ + pScreen->BitmapToRegion = winPixmapToRegionNativeGDI; + + ErrorF ("winFinishScreenInitNativeGDI - calling miDCInitialize\n"); + + /* Set the default white and black pixel positions */ + pScreen->whitePixel = pScreen->blackPixel = (Pixel) 0; + + /* Initialize the cursor */ + if (!miDCInitialize (pScreen, &g_winPointerCursorFuncs)) + { + ErrorF ("winFinishScreenInitNativeGDI - miDCInitialize failed\n"); + return FALSE; + } + + /* Create a default colormap */ + if (!miCreateDefColormap (pScreen)) + { + ErrorF ("winFinishScreenInitNativeGDI - miCreateDefColormap () " + "failed\n"); + return FALSE; + } + + ErrorF ("winFinishScreenInitNativeGDI - miCreateDefColormap () " + "returned\n"); + + /* mi doesn't use a CloseScreen procedure, so no need to wrap */ + pScreen->CloseScreen = pScreenPriv->pwinCloseScreen; + + /* Tell the server that we are enabled */ + pScreenPriv->fEnabled = TRUE; + + ErrorF ("winFinishScreenInitNativeGDI - Successful addition of " + "screen %08x\n", + (unsigned int) pScreen); + + return TRUE; +} +#endif + + +/* See Porting Layer Definition - p. 33 */ +static Bool +winSaveScreen (ScreenPtr pScreen, int on) +{ + return TRUE; +} diff --git a/xorg-server/hw/xwin/winshaddd.c b/xorg-server/hw/xwin/winshaddd.c index ae49d5a3d..00d7a379f 100644 --- a/xorg-server/hw/xwin/winshaddd.c +++ b/xorg-server/hw/xwin/winshaddd.c @@ -1,1400 +1,1366 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" - - -/* - * FIXME: Headers are broken, DEFINE_GUID doesn't work correctly, - * so we have to redefine it here. - */ -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} -#endif /* DEFINE_GUID */ - - -/* - * FIXME: Headers are broken, IID_IDirectDraw2 has to be defined - * here manually. Should be handled by ddraw.h - */ -#ifndef IID_IDirectDraw2 -DEFINE_GUID( IID_IDirectDraw2,0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 ); -#endif /* IID_IDirectDraw2 */ - - -/* - * Local prototypes - */ - -static Bool -winAllocateFBShadowDD (ScreenPtr pScreen); - -static void -winShadowUpdateDD (ScreenPtr pScreen, - shadowBufPtr pBuf); - -static Bool -winCloseScreenShadowDD (int nIndex, ScreenPtr pScreen); - -static Bool -winInitVisualsShadowDD (ScreenPtr pScreen); - -static Bool -winAdjustVideoModeShadowDD (ScreenPtr pScreen); - -static Bool -winBltExposedRegionsShadowDD (ScreenPtr pScreen); - -static Bool -winActivateAppShadowDD (ScreenPtr pScreen); - -static Bool -winRedrawScreenShadowDD (ScreenPtr pScreen); - -static Bool -winRealizeInstalledPaletteShadowDD (ScreenPtr pScreen); - -static Bool -winInstallColormapShadowDD (ColormapPtr pColormap); - -static Bool -winStoreColorsShadowDD (ColormapPtr pmap, - int ndef, - xColorItem *pdefs); - -static Bool -winCreateColormapShadowDD (ColormapPtr pColormap); - -static Bool -winDestroyColormapShadowDD (ColormapPtr pColormap); - -static Bool -winCreatePrimarySurfaceShadowDD (ScreenPtr pScreen); - -static Bool -winReleasePrimarySurfaceShadowDD (ScreenPtr pScreen); - - -/* - * Create the primary surface and attach the clipper. - * Used for both the initial surface creation and during - * WM_DISPLAYCHANGE messages. - */ - -static Bool -winCreatePrimarySurfaceShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - HRESULT ddrval = DD_OK; - DDSURFACEDESC ddsd; - - /* Describe the primary surface */ - ZeroMemory (&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - /* Create the primary surface */ - ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, - &ddsd, - &pScreenPriv->pddsPrimary, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winCreatePrimarySurfaceShadowDD - Could not create primary " - "surface: %08x\n", (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winCreatePrimarySurfaceShadowDD - Created primary surface\n"); -#endif - - /* - * Attach a clipper to the primary surface that will clip our blits to our - * display window. - */ - ddrval = IDirectDrawSurface2_SetClipper (pScreenPriv->pddsPrimary, - pScreenPriv->pddcPrimary); - if (FAILED (ddrval)) - { - ErrorF ("winCreatePrimarySurfaceShadowDD - Primary attach clipper " - "failed: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winCreatePrimarySurfaceShadowDD - Attached clipper to " - "primary surface\n"); -#endif - - /* Everything was correct */ - return TRUE; -} - - -/* - * Detach the clipper and release the primary surface. - * Called from WM_DISPLAYCHANGE. - */ - -static Bool -winReleasePrimarySurfaceShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - - ErrorF ("winReleasePrimarySurfaceShadowDD - Hello\n"); - - /* Release the primary surface and clipper, if they exist */ - if (pScreenPriv->pddsPrimary) - { - /* - * Detach the clipper from the primary surface. - * NOTE: We do this explicity for clarity. The Clipper is not released. - */ - IDirectDrawSurface2_SetClipper (pScreenPriv->pddsPrimary, - NULL); - - ErrorF ("winReleasePrimarySurfaceShadowDD - Detached clipper\n"); - - /* Release the primary surface */ - IDirectDrawSurface2_Release (pScreenPriv->pddsPrimary); - pScreenPriv->pddsPrimary = NULL; - } - - ErrorF ("winReleasePrimarySurfaceShadowDD - Released primary surface\n"); - - return TRUE; -} - - -/* - * Create a DirectDraw surface for the shadow framebuffer; also create - * a primary surface object so we can blit to the display. - * - * Install a DirectDraw clipper on our primary surface object - * that clips our blits to the unobscured client area of our display window. - */ - -static Bool -winAllocateFBShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HRESULT ddrval = DD_OK; - DDSURFACEDESC ddsd; - DDSURFACEDESC *pddsdShadow = NULL; - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD\n"); -#endif - - /* Create a clipper */ - ddrval = (*g_fpDirectDrawCreateClipper) (0, - &pScreenPriv->pddcPrimary, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not create clipper: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD - Created a clipper\n"); -#endif - - /* Get a device context for the screen */ - pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); - - /* Attach the clipper to our display window */ - ddrval = IDirectDrawClipper_SetHWnd (pScreenPriv->pddcPrimary, - 0, - pScreenPriv->hwndScreen); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Clipper not attached to " - "window: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD - Attached clipper to window\n"); -#endif - - /* Create a DirectDraw object, store the address at lpdd */ - ddrval = (*g_fpDirectDrawCreate) (NULL, &pScreenPriv->pdd, NULL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not start DirectDraw: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD () - Created and initialized DD\n"); -#endif - - /* Get a DirectDraw2 interface pointer */ - ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, - &IID_IDirectDraw2, - (LPVOID*) &pScreenPriv->pdd2); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Failed DD2 query: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - - /* Are we full screen? */ - if (pScreenInfo->fFullScreen) - { - DDSURFACEDESC ddsdCurrent; - DWORD dwRefreshRateCurrent = 0; - HDC hdc = NULL; - - /* Set the cooperative level to full screen */ - ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, - pScreenPriv->hwndScreen, - DDSCL_EXCLUSIVE - | DDSCL_FULLSCREEN); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not set " - "cooperative level: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - - /* - * We only need to get the current refresh rate for comparison - * if a refresh rate has been passed on the command line. - */ - if (pScreenInfo->dwRefreshRate != 0) - { - ZeroMemory (&ddsdCurrent, sizeof (ddsdCurrent)); - ddsdCurrent.dwSize = sizeof (ddsdCurrent); - - /* Get information about current display settings */ - ddrval = IDirectDraw2_GetDisplayMode (pScreenPriv->pdd2, - &ddsdCurrent); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not get current " - "refresh rate: %08x. Continuing.\n", - (unsigned int) ddrval); - dwRefreshRateCurrent = 0; - } - else - { - /* Grab the current refresh rate */ - dwRefreshRateCurrent = ddsdCurrent.u2.dwRefreshRate; - } - } - - /* Clean up the refresh rate */ - if (dwRefreshRateCurrent == pScreenInfo->dwRefreshRate) - { - /* - * Refresh rate is non-specified or equal to current. - */ - pScreenInfo->dwRefreshRate = 0; - } - - /* Grab a device context for the screen */ - hdc = GetDC (NULL); - if (hdc == NULL) - { - ErrorF ("winAllocateFBShadowDD - GetDC () failed\n"); - return FALSE; - } - - /* Only change the video mode when different than current mode */ - if (!pScreenInfo->fMultipleMonitors - && (pScreenInfo->dwWidth != GetSystemMetrics (SM_CXSCREEN) - || pScreenInfo->dwHeight != GetSystemMetrics (SM_CYSCREEN) - || pScreenInfo->dwBPP != GetDeviceCaps (hdc, BITSPIXEL) - || pScreenInfo->dwRefreshRate != 0)) - { - ErrorF ("winAllocateFBShadowDD - Changing video mode\n"); - - /* Change the video mode to the mode requested, and use the driver default refresh rate on failure */ - ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, - pScreenInfo->dwWidth, - pScreenInfo->dwHeight, - pScreenInfo->dwBPP, - pScreenInfo->dwRefreshRate, - 0); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not set "\ - "full screen display mode: %08x\n", - (unsigned int) ddrval); - ErrorF ("winAllocateFBShadowDD - Using default driver refresh rate\n"); - ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, - pScreenInfo->dwWidth, - pScreenInfo->dwHeight, - pScreenInfo->dwBPP, - 0, - 0); - if (FAILED(ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not set default refresh rate " - "full screen display mode: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - } - } - else - { - ErrorF ("winAllocateFBShadowDD - Not changing video mode\n"); - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - hdc = NULL; - } - else - { - /* Set the cooperative level for windowed mode */ - ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, - pScreenPriv->hwndScreen, - DDSCL_NORMAL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not set "\ - "cooperative level: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - } - - /* Create the primary surface */ - if (!winCreatePrimarySurfaceShadowDD (pScreen)) - { - ErrorF ("winAllocateFBShadowDD - winCreatePrimarySurfaceShadowDD " - "failed\n"); - return FALSE; - } - - /* Describe the shadow surface to be created */ - /* NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, - * as drawing, locking, and unlocking take forever - * with video memory surfaces. In addition, - * video memory is a somewhat scarce resource, - * so you shouldn't be allocating video memory when - * you have the option of using system memory instead. - */ - ZeroMemory (&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - ddsd.dwHeight = pScreenInfo->dwHeight; - ddsd.dwWidth = pScreenInfo->dwWidth; - - /* Create the shadow surface */ - ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, - &ddsd, - &pScreenPriv->pddsShadow, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDD - Could not create shadow "\ - "surface: %08x\n", (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD - Created shadow\n"); -#endif - - /* Allocate a DD surface description for our screen privates */ - pddsdShadow = pScreenPriv->pddsdShadow = malloc (sizeof (DDSURFACEDESC)); - if (pddsdShadow == NULL) - { - ErrorF ("winAllocateFBShadowDD - Could not allocate surface "\ - "description memory\n"); - return FALSE; - } - ZeroMemory (pddsdShadow, sizeof (*pddsdShadow)); - pddsdShadow->dwSize = sizeof (*pddsdShadow); - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD - Locking shadow\n"); -#endif - - /* Lock the shadow surface */ - ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, - NULL, - pddsdShadow, - DDLOCK_WAIT, - NULL); - if (FAILED (ddrval) || pddsdShadow->lpSurface == NULL) - { - ErrorF ("winAllocateFBShadowDD - Could not lock shadow "\ - "surface: %08x\n", (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD - Locked shadow\n"); -#endif - - /* We don't know how to deal with anything other than RGB */ - if (!(pddsdShadow->ddpfPixelFormat.dwFlags & DDPF_RGB)) - { - ErrorF ("winAllocateFBShadowDD - Color format other than RGB\n"); - return FALSE; - } - - /* Grab the pitch from the surface desc */ - pScreenInfo->dwStride = (pddsdShadow->u1.lPitch * 8) - / pScreenInfo->dwBPP; - - /* Save the pointer to our surface memory */ - pScreenInfo->pfb = pddsdShadow->lpSurface; - - /* Grab the color depth and masks from the surface description */ - pScreenPriv->dwRedMask = pddsdShadow->ddpfPixelFormat.u2.dwRBitMask; - pScreenPriv->dwGreenMask = pddsdShadow->ddpfPixelFormat.u3.dwGBitMask; - pScreenPriv->dwBlueMask = pddsdShadow->ddpfPixelFormat.u4.dwBBitMask; - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDD - Returning\n"); -#endif - - return TRUE; -} - - -/* - * Transfer the damaged regions of the shadow framebuffer to the display. - */ - -static void -winShadowUpdateDD (ScreenPtr pScreen, - shadowBufPtr pBuf) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RegionPtr damage = shadowDamage(pBuf); - HRESULT ddrval = DD_OK; - RECT rcDest, rcSrc; - POINT ptOrigin; - DWORD dwBox = RegionNumRects (damage); - BoxPtr pBox = RegionRects (damage); - HRGN hrgnTemp = NULL, hrgnCombined = NULL; - - /* - * Return immediately if the app is not active - * and we are fullscreen, or if we have a bad display depth - */ - if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen) - || pScreenPriv->fBadDepth) return; - - /* Get the origin of the window in the screen coords */ - ptOrigin.x = pScreenInfo->dwXOffset; - ptOrigin.y = pScreenInfo->dwYOffset; - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&ptOrigin, 1); - - /* Unlock the shadow surface, so we can blit */ - ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsShadow, NULL); - if (FAILED (ddrval)) - { - ErrorF ("winShadowUpdateDD - Unlock failed\n"); - return; - } - - /* - * Handle small regions with multiple blits, - * handle large regions by creating a clipping region and - * doing a single blit constrained to that clipping region. - */ - if (pScreenInfo->dwClipUpdatesNBoxes == 0 - || dwBox < pScreenInfo->dwClipUpdatesNBoxes) - { - /* Loop through all boxes in the damaged region */ - while (dwBox--) - { - /* Assign damage box to source rectangle */ - rcSrc.left = pBox->x1; - rcSrc.top = pBox->y1; - rcSrc.right = pBox->x2; - rcSrc.bottom = pBox->y2; - - /* Calculate destination rectange */ - rcDest.left = ptOrigin.x + rcSrc.left; - rcDest.top = ptOrigin.y + rcSrc.top; - rcDest.right = ptOrigin.x + rcSrc.right; - rcDest.bottom = ptOrigin.y + rcSrc.bottom; - - /* Blit the damaged areas */ - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, - &rcDest, - pScreenPriv->pddsShadow, - &rcSrc, - DDBLT_WAIT, - NULL); - - /* Get a pointer to the next box */ - ++pBox; - } - } - else - { - BoxPtr pBoxExtents = RegionExtents(damage); - - /* Compute a GDI region from the damaged region */ - hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); - dwBox--; - pBox++; - while (dwBox--) - { - hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); - CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR); - DeleteObject (hrgnTemp); - pBox++; - } - - /* Install the GDI region as a clipping region */ - SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined); - DeleteObject (hrgnCombined); - hrgnCombined = NULL; - - /* Calculating a bounding box for the source is easy */ - rcSrc.left = pBoxExtents->x1; - rcSrc.top = pBoxExtents->y1; - rcSrc.right = pBoxExtents->x2; - rcSrc.bottom = pBoxExtents->y2; - - /* Calculating a bounding box for the destination is trickier */ - rcDest.left = ptOrigin.x + rcSrc.left; - rcDest.top = ptOrigin.y + rcSrc.top; - rcDest.right = ptOrigin.x + rcSrc.right; - rcDest.bottom = ptOrigin.y + rcSrc.bottom; - - /* Our Blt should be clipped to the invalidated region */ - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, - &rcDest, - pScreenPriv->pddsShadow, - &rcSrc, - DDBLT_WAIT, - NULL); - - /* Reset the clip region */ - SelectClipRgn (pScreenPriv->hdcScreen, NULL); - } - - /* Relock the shadow surface */ - ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, - NULL, - pScreenPriv->pddsdShadow, - DDLOCK_WAIT, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winShadowUpdateDD - Lock failed\n"); - return; - } - - /* Has our memory pointer changed? */ - if (pScreenInfo->pfb != pScreenPriv->pddsdShadow->lpSurface) - { - ErrorF ("winShadowUpdateDD - Memory location of the shadow " - "surface has changed, trying to update the root window " - "pixmap header to point to the new address. If you get " - "this message and "PROJECT_NAME" freezes or crashes " - "after this message then send a problem report and your " - "%s file to " BUILDERADDR "\n", g_pszLogFile); - - /* Location of shadow framebuffer has changed */ - pScreenInfo->pfb = pScreenPriv->pddsdShadow->lpSurface; - - /* Update the screen pixmap */ - if (!(*pScreen->ModifyPixmapHeader)(pScreen->devPrivate, - pScreen->width, - pScreen->height, - pScreen->rootDepth, - BitsPerPixel (pScreen->rootDepth), - PixmapBytePad (pScreenInfo->dwStride, - pScreenInfo->dwBPP), - pScreenInfo->pfb)) - { - ErrorF ("winShadowUpdateDD - Bits changed, could not " - "notify fb.\n"); - return; - } - } -} - - -/* - * Call the wrapped CloseScreen function. - * - * Free our resources and private structures. - */ - -static Bool -winCloseScreenShadowDD (int nIndex, ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - Bool fReturn; - -#if CYGDEBUG - winDebug ("winCloseScreenShadowDD - Freeing screen resources\n"); -#endif - - /* Flag that the screen is closed */ - pScreenPriv->fClosed = TRUE; - pScreenPriv->fActive = FALSE; - - /* Call the wrapped CloseScreen procedure */ - WIN_UNWRAP(CloseScreen); - fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); - - /* Free the screen DC */ - ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen); - - /* Delete the window property */ - RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); - - /* Free the shadow surface, if there is one */ - if (pScreenPriv->pddsShadow) - { - IDirectDrawSurface2_Unlock (pScreenPriv->pddsShadow, NULL); - IDirectDrawSurface2_Release (pScreenPriv->pddsShadow); - pScreenPriv->pddsShadow = NULL; - } - - /* Detach the clipper from the primary surface and release the clipper. */ - if (pScreenPriv->pddcPrimary) - { - /* Detach the clipper */ - IDirectDrawSurface2_SetClipper (pScreenPriv->pddsPrimary, - NULL); - - /* Release the clipper object */ - IDirectDrawClipper_Release (pScreenPriv->pddcPrimary); - pScreenPriv->pddcPrimary = NULL; - } - - /* Release the primary surface, if there is one */ - if (pScreenPriv->pddsPrimary) - { - IDirectDrawSurface2_Release (pScreenPriv->pddsPrimary); - pScreenPriv->pddsPrimary = NULL; - } - - /* Free the DirectDraw2 object, if there is one */ - if (pScreenPriv->pdd2) - { - IDirectDraw2_RestoreDisplayMode (pScreenPriv->pdd2); - IDirectDraw2_Release (pScreenPriv->pdd2); - pScreenPriv->pdd2 = NULL; - } - - /* Free the DirectDraw object, if there is one */ - if (pScreenPriv->pdd) - { - IDirectDraw_Release (pScreenPriv->pdd); - pScreenPriv->pdd = NULL; - } - - /* Delete tray icon, if we have one */ - if (!pScreenInfo->fNoTrayIcon) - winDeleteNotifyIcon (pScreenPriv); - - /* Free the exit confirmation dialog box, if it exists */ - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - - /* Kill our window */ - if (pScreenPriv->hwndScreen) - { - DestroyWindow (pScreenPriv->hwndScreen); - pScreenPriv->hwndScreen = NULL; - } - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - /* Destroy the thread startup mutex */ - pthread_mutex_destroy (&pScreenPriv->pmServerStarted); -#endif - - /* Kill our screeninfo's pointer to the screen */ - pScreenInfo->pScreen = NULL; - - /* Invalidate the ScreenInfo's fb pointer */ - pScreenInfo->pfb = NULL; - - /* Free the screen privates for this screen */ - free ((pointer) pScreenPriv); - - return fReturn; -} - - -/* - * Tell mi what sort of visuals we need. - * - * Generally we only need one visual, as our screen can only - * handle one format at a time, I believe. You may want - * to verify that last sentence. - */ - -static Bool -winInitVisualsShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - DWORD dwRedBits, dwGreenBits, dwBlueBits; - - /* Count the number of ones in each color mask */ - dwRedBits = winCountBits (pScreenPriv->dwRedMask); - dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); - dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); - - /* Store the maximum number of ones in a color mask as the bitsPerRGB */ - if (dwRedBits == 0 || dwGreenBits == 0 || dwBlueBits == 0) - pScreenPriv->dwBitsPerRGB = 8; - else if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwRedBits; - else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwGreenBits; - else - pScreenPriv->dwBitsPerRGB = dwBlueBits; - - ErrorF ("winInitVisualsShadowDD - Masks %08x %08x %08x BPRGB %d d %d " - "bpp %d\n", - (unsigned int) pScreenPriv->dwRedMask, - (unsigned int) pScreenPriv->dwGreenMask, - (unsigned int) pScreenPriv->dwBlueMask, - (int) pScreenPriv->dwBitsPerRGB, - (int) pScreenInfo->dwDepth, - (int) pScreenInfo->dwBPP); - - /* Create a single visual according to the Windows screen depth */ - switch (pScreenInfo->dwDepth) - { - case 24: - case 16: - case 15: - /* Create the real visual */ - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - TrueColorMask, - pScreenPriv->dwBitsPerRGB, - TrueColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsShadowDD - miSetVisualTypesAndMasks " - "failed for TrueColor\n"); - return FALSE; - } - -#ifdef XWIN_EMULATEPSEUDO - if (!pScreenInfo->fEmulatePseudo) - break; - - /* Setup a pseudocolor visual */ - if (!miSetVisualTypesAndMasks (8, - PseudoColorMask, - 8, - -1, - 0, - 0, - 0)) - { - ErrorF ("winInitVisualsShadowDD - miSetVisualTypesAndMasks " - "failed for PseudoColor\n"); - return FALSE; - } -#endif - break; - - case 8: - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - pScreenInfo->fFullScreen - ? PseudoColorMask : StaticColorMask, - pScreenPriv->dwBitsPerRGB, - pScreenInfo->fFullScreen - ? PseudoColor : StaticColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsShadowDD - miSetVisualTypesAndMasks " - "failed\n"); - return FALSE; - } - break; - - default: - ErrorF ("winInitVisualsShadowDD - Unknown screen depth\n"); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winInitVisualsShadowDD - Returning\n"); -#endif - - return TRUE; -} - - -/* - * Adjust the user proposed video mode - */ - -static Bool -winAdjustVideoModeShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HDC hdc = NULL; - DWORD dwBPP; - - /* We're in serious trouble if we can't get a DC */ - hdc = GetDC (NULL); - if (hdc == NULL) - { - ErrorF ("winAdjustVideoModeShadowDD - GetDC () failed\n"); - return FALSE; - } - - /* Query GDI for current display depth */ - dwBPP = GetDeviceCaps (hdc, BITSPIXEL); - - /* DirectDraw can only change the depth in fullscreen mode */ - if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP) - { - /* No -depth parameter passed, let the user know the depth being used */ - ErrorF ("winAdjustVideoModeShadowDD - Using Windows display " - "depth of %d bits per pixel\n", (int) dwBPP); - - /* Use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - else if (pScreenInfo->fFullScreen - && pScreenInfo->dwBPP != dwBPP) - { - /* FullScreen, and GDI depth differs from -depth parameter */ - ErrorF ("winAdjustVideoModeShadowDD - FullScreen, using command line " - "bpp: %d\n", (int) pScreenInfo->dwBPP); - } - else if (dwBPP != pScreenInfo->dwBPP) - { - /* Windowed, and GDI depth differs from -depth parameter */ - ErrorF ("winAdjustVideoModeShadowDD - Windowed, command line bpp: " - "%d, using bpp: %d\n", (int) pScreenInfo->dwBPP, (int) dwBPP); - - /* We'll use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - - /* See if the shadow bitmap will be larger than the DIB size limit */ - if (pScreenInfo->dwWidth * pScreenInfo->dwHeight * pScreenInfo->dwBPP - >= WIN_DIB_MAXIMUM_SIZE) - { - ErrorF ("winAdjustVideoModeShadowDD - Requested DirectDraw surface " - "will be larger than %d MB. The surface may fail to be " - "allocated on Windows 95, 98, or Me, due to a %d MB limit in " - "DIB size. This limit does not apply to Windows NT/2000, and " - "this message may be ignored on those platforms.\n", - WIN_DIB_MAXIMUM_SIZE_MB, WIN_DIB_MAXIMUM_SIZE_MB); - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - return TRUE; -} - - -/* - * Blt exposed regions to the screen - */ - -static Bool -winBltExposedRegionsShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RECT rcSrc, rcDest; - POINT ptOrigin; - HDC hdcUpdate = NULL; - PAINTSTRUCT ps; - HRESULT ddrval = DD_OK; - Bool fReturn = TRUE; - Bool fLocked = TRUE; - int i; - - /* BeginPaint gives us an hdc that clips to the invalidated region */ - hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps); - if (hdcUpdate == NULL) - { - ErrorF ("winBltExposedRegionsShadowDD - BeginPaint () returned " - "a NULL device context handle. Aborting blit attempt.\n"); - return FALSE; - } - - /* Unlock the shadow surface, so we can blit */ - ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsShadow, NULL); - if (FAILED (ddrval)) - { - fReturn = FALSE; - goto winBltExposedRegionsShadowDD_Exit; - } - else - { - /* Flag that we have unlocked the shadow surface */ - fLocked = FALSE; - } - - /* Get the origin of the window in the screen coords */ - ptOrigin.x = pScreenInfo->dwXOffset; - ptOrigin.y = pScreenInfo->dwYOffset; - - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&ptOrigin, 1); - rcDest.left = ptOrigin.x; - rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; - rcDest.top = ptOrigin.y; - rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; - - /* Source can be enter shadow surface, as Blt should clip */ - rcSrc.left = 0; - rcSrc.top = 0; - rcSrc.right = pScreenInfo->dwWidth; - rcSrc.bottom = pScreenInfo->dwHeight; - - /* Try to regain the primary surface and blit again if we've lost it */ - for (i = 0; i <= WIN_REGAIN_SURFACE_RETRIES; ++i) - { - /* Our Blt should be clipped to the invalidated region */ - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, - &rcDest, - pScreenPriv->pddsShadow, - &rcSrc, - DDBLT_WAIT, - NULL); - if (ddrval == DDERR_SURFACELOST) - { - /* Surface was lost */ - ErrorF ("winBltExposedRegionsShadowDD - IDirectDrawSurface2_Blt " - "reported that the primary surface was lost, " - "trying to restore, retry: %d\n", i + 1); - - /* Try to restore the surface, once */ - ddrval = IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); - ErrorF ("winBltExposedRegionsShadowDD - " - "IDirectDrawSurface2_Restore returned: "); - if (ddrval == DD_OK) - ErrorF ("DD_OK\n"); - else if (ddrval == DDERR_WRONGMODE) - ErrorF ("DDERR_WRONGMODE\n"); - else if (ddrval == DDERR_INCOMPATIBLEPRIMARY) - ErrorF ("DDERR_INCOMPATIBLEPRIMARY\n"); - else if (ddrval == DDERR_UNSUPPORTED) - ErrorF ("DDERR_UNSUPPORTED\n"); - else if (ddrval == DDERR_INVALIDPARAMS) - ErrorF ("DDERR_INVALIDPARAMS\n"); - else if (ddrval == DDERR_INVALIDOBJECT) - ErrorF ("DDERR_INVALIDOBJECT\n"); - else - ErrorF ("unknown error: %08x\n", (unsigned int) ddrval); - - /* Loop around to try the blit one more time */ - continue; - } - else if (FAILED (ddrval)) - { - fReturn = FALSE; - ErrorF ("winBltExposedRegionsShadowDD - IDirectDrawSurface2_Blt " - "failed, but surface not lost: %08x %d\n", - (unsigned int) ddrval, (int) ddrval); - goto winBltExposedRegionsShadowDD_Exit; - } - else - { - /* Success, stop looping */ - break; - } - } - - /* Relock the shadow surface */ - ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, - NULL, - pScreenPriv->pddsdShadow, - DDLOCK_WAIT, - NULL); - if (FAILED (ddrval)) - { - fReturn = FALSE; - ErrorF ("winBltExposedRegionsShadowDD - IDirectDrawSurface2_Lock " - "failed\n"); - goto winBltExposedRegionsShadowDD_Exit; - } - else - { - /* Indicate that we have relocked the shadow surface */ - fLocked = TRUE; - } - - /* Has our memory pointer changed? */ - if (pScreenInfo->pfb != pScreenPriv->pddsdShadow->lpSurface) - winUpdateFBPointer (pScreen, - pScreenPriv->pddsdShadow->lpSurface); - - winBltExposedRegionsShadowDD_Exit: - /* EndPaint frees the DC */ - if (hdcUpdate != NULL) - EndPaint (pScreenPriv->hwndScreen, &ps); - - /* - * Relock the surface if it is not locked. We don't care if locking fails, - * as it will cause the server to shutdown within a few more operations. - */ - if (!fLocked) - { - IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, - NULL, - pScreenPriv->pddsdShadow, - DDLOCK_WAIT, - NULL); - - /* Has our memory pointer changed? */ - if (pScreenInfo->pfb != pScreenPriv->pddsdShadow->lpSurface) - winUpdateFBPointer (pScreen, - pScreenPriv->pddsdShadow->lpSurface); - - fLocked = TRUE; - } - return fReturn; -} - - -/* - * Do any engine-specific appliation-activation processing - */ - -static Bool -winActivateAppShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - - /* - * Do we have a surface? - * Are we active? - * Are we fullscreen? - */ - if (pScreenPriv != NULL - && pScreenPriv->pddsPrimary != NULL - && pScreenPriv->fActive) - { - /* Primary surface was lost, restore it */ - IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); - } - - return TRUE; -} - - -/* - * Reblit the shadow framebuffer to the screen. - */ - -static Bool -winRedrawScreenShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HRESULT ddrval = DD_OK; - RECT rcSrc, rcDest; - POINT ptOrigin; - - /* Get the origin of the window in the screen coords */ - ptOrigin.x = pScreenInfo->dwXOffset; - ptOrigin.y = pScreenInfo->dwYOffset; - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&ptOrigin, 1); - rcDest.left = ptOrigin.x; - rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; - rcDest.top = ptOrigin.y; - rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; - - /* Source can be entire shadow surface, as Blt should clip for us */ - rcSrc.left = 0; - rcSrc.top = 0; - rcSrc.right = pScreenInfo->dwWidth; - rcSrc.bottom = pScreenInfo->dwHeight; - - /* Redraw the whole window, to take account for the new colors */ - ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, - &rcDest, - pScreenPriv->pddsShadow, - &rcSrc, - DDBLT_WAIT, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winRedrawScreenShadowDD - IDirectDrawSurface_Blt () " - "failed: %08x\n", - (unsigned int) ddrval); - } - - return TRUE; -} - - -/* - * Realize the currently installed colormap - */ - -static Bool -winRealizeInstalledPaletteShadowDD (ScreenPtr pScreen) -{ - return TRUE; -} - - -/* - * Install the specified colormap - */ - -static Bool -winInstallColormapShadowDD (ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - HRESULT ddrval = DD_OK; - - /* Install the DirectDraw palette on the primary surface */ - ddrval = IDirectDrawSurface2_SetPalette (pScreenPriv->pddsPrimary, - pCmapPriv->lpDDPalette); - if (FAILED (ddrval)) - { - ErrorF ("winInstallColormapShadowDD - Failed installing the " - "DirectDraw palette.\n"); - return FALSE; - } - - /* Save a pointer to the newly installed colormap */ - pScreenPriv->pcmapInstalled = pColormap; - - return TRUE; -} - - -/* - * Store the specified colors in the specified colormap - */ - -static Bool -winStoreColorsShadowDD (ColormapPtr pColormap, - int ndef, - xColorItem *pdefs) -{ - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - ColormapPtr curpmap = pScreenPriv->pcmapInstalled; - HRESULT ddrval = DD_OK; - - /* Put the X colormap entries into the Windows logical palette */ - ddrval = IDirectDrawPalette_SetEntries (pCmapPriv->lpDDPalette, - 0, - pdefs[0].pixel, - ndef, - pCmapPriv->peColors - + pdefs[0].pixel); - if (FAILED (ddrval)) - { - ErrorF ("winStoreColorsShadowDD - SetEntries () failed\n"); - return FALSE; - } - - /* Don't install the DirectDraw palette if the colormap is not installed */ - if (pColormap != curpmap) - { - return TRUE; - } - - if (!winInstallColormapShadowDD (pColormap)) - { - ErrorF ("winStoreColorsShadowDD - Failed installing colormap\n"); - return FALSE; - } - - return TRUE; -} - - -/* - * Colormap initialization procedure - */ - -static Bool -winCreateColormapShadowDD (ColormapPtr pColormap) -{ - HRESULT ddrval = DD_OK; - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - - /* Create a DirectDraw palette */ - ddrval = IDirectDraw2_CreatePalette (pScreenPriv->pdd, - DDPCAPS_8BIT | DDPCAPS_ALLOW256, - pCmapPriv->peColors, - &pCmapPriv->lpDDPalette, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winCreateColormapShadowDD - CreatePalette failed\n"); - return FALSE; - } - - return TRUE; -} - - -/* - * Colormap destruction procedure - */ - -static Bool -winDestroyColormapShadowDD (ColormapPtr pColormap) -{ - winScreenPriv(pColormap->pScreen); - winCmapPriv(pColormap); - HRESULT ddrval = DD_OK; - - /* - * Is colormap to be destroyed the default? - * - * Non-default colormaps should have had winUninstallColormap - * called on them before we get here. The default colormap - * will not have had winUninstallColormap called on it. Thus, - * we need to handle the default colormap in a special way. - */ - if (pColormap->flags & IsDefault) - { -#if CYGDEBUG - winDebug ("winDestroyColormapShadowDD - Destroying default " - "colormap\n"); -#endif - - /* - * FIXME: Walk the list of all screens, popping the default - * palette out of each screen device context. - */ - - /* Pop the palette out of the primary surface */ - ddrval = IDirectDrawSurface2_SetPalette (pScreenPriv->pddsPrimary, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winDestroyColormapShadowDD - Failed freeing the " - "default colormap DirectDraw palette.\n"); - return FALSE; - } - - /* Clear our private installed colormap pointer */ - pScreenPriv->pcmapInstalled = NULL; - } - - /* Release the palette */ - IDirectDrawPalette_Release (pCmapPriv->lpDDPalette); - - /* Invalidate the colormap privates */ - pCmapPriv->lpDDPalette = NULL; - - return TRUE; -} - - -/* - * Set engine specific functions - */ - -Bool -winSetEngineFunctionsShadowDD (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Set our pointers */ - pScreenPriv->pwinAllocateFB = winAllocateFBShadowDD; - pScreenPriv->pwinShadowUpdate = winShadowUpdateDD; - pScreenPriv->pwinCloseScreen = winCloseScreenShadowDD; - pScreenPriv->pwinInitVisuals = winInitVisualsShadowDD; - pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowDD; - if (pScreenInfo->fFullScreen) - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; - else - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; - pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; - pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDD; - pScreenPriv->pwinActivateApp = winActivateAppShadowDD; - pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDD; - pScreenPriv->pwinRealizeInstalledPalette - = winRealizeInstalledPaletteShadowDD; - pScreenPriv->pwinInstallColormap = winInstallColormapShadowDD; - pScreenPriv->pwinStoreColors = winStoreColorsShadowDD; - pScreenPriv->pwinCreateColormap = winCreateColormapShadowDD; - pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowDD; - pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; - pScreenPriv->pwinCreatePrimarySurface = winCreatePrimarySurfaceShadowDD; - pScreenPriv->pwinReleasePrimarySurface = winReleasePrimarySurfaceShadowDD; -#ifdef XWIN_MULTIWINDOW - pScreenPriv->pwinFinishCreateWindowsWindow = - (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA; -#endif - - return TRUE; -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" + + +/* + * FIXME: Headers are broken, DEFINE_GUID doesn't work correctly, + * so we have to redefine it here. + */ +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#endif /* DEFINE_GUID */ + + +/* + * FIXME: Headers are broken, IID_IDirectDraw2 has to be defined + * here manually. Should be handled by ddraw.h + */ +#ifndef IID_IDirectDraw2 +DEFINE_GUID( IID_IDirectDraw2,0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +#endif /* IID_IDirectDraw2 */ + + +/* + * Local prototypes + */ + +static Bool +winAllocateFBShadowDD (ScreenPtr pScreen); + +static void +winShadowUpdateDD (ScreenPtr pScreen, + shadowBufPtr pBuf); + +static Bool +winCloseScreenShadowDD (int nIndex, ScreenPtr pScreen); + +static Bool +winInitVisualsShadowDD (ScreenPtr pScreen); + +static Bool +winAdjustVideoModeShadowDD (ScreenPtr pScreen); + +static Bool +winBltExposedRegionsShadowDD (ScreenPtr pScreen); + +static Bool +winActivateAppShadowDD (ScreenPtr pScreen); + +static Bool +winRedrawScreenShadowDD (ScreenPtr pScreen); + +static Bool +winRealizeInstalledPaletteShadowDD (ScreenPtr pScreen); + +static Bool +winInstallColormapShadowDD (ColormapPtr pColormap); + +static Bool +winStoreColorsShadowDD (ColormapPtr pmap, + int ndef, + xColorItem *pdefs); + +static Bool +winCreateColormapShadowDD (ColormapPtr pColormap); + +static Bool +winDestroyColormapShadowDD (ColormapPtr pColormap); + +static Bool +winCreatePrimarySurfaceShadowDD (ScreenPtr pScreen); + +static Bool +winReleasePrimarySurfaceShadowDD (ScreenPtr pScreen); + + +/* + * Create the primary surface and attach the clipper. + * Used for both the initial surface creation and during + * WM_DISPLAYCHANGE messages. + */ + +static Bool +winCreatePrimarySurfaceShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + HRESULT ddrval = DD_OK; + DDSURFACEDESC ddsd; + + /* Describe the primary surface */ + ZeroMemory (&ddsd, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + /* Create the primary surface */ + ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, + &ddsd, + &pScreenPriv->pddsPrimary, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winCreatePrimarySurfaceShadowDD - Could not create primary " + "surface: %08x\n", (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winCreatePrimarySurfaceShadowDD - Created primary surface\n"); +#endif + + /* + * Attach a clipper to the primary surface that will clip our blits to our + * display window. + */ + ddrval = IDirectDrawSurface2_SetClipper (pScreenPriv->pddsPrimary, + pScreenPriv->pddcPrimary); + if (FAILED (ddrval)) + { + ErrorF ("winCreatePrimarySurfaceShadowDD - Primary attach clipper " + "failed: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winCreatePrimarySurfaceShadowDD - Attached clipper to " + "primary surface\n"); +#endif + + /* Everything was correct */ + return TRUE; +} + + +/* + * Detach the clipper and release the primary surface. + * Called from WM_DISPLAYCHANGE. + */ + +static Bool +winReleasePrimarySurfaceShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + ErrorF ("winReleasePrimarySurfaceShadowDD - Hello\n"); + + /* Release the primary surface and clipper, if they exist */ + if (pScreenPriv->pddsPrimary) + { + /* + * Detach the clipper from the primary surface. + * NOTE: We do this explicity for clarity. The Clipper is not released. + */ + IDirectDrawSurface2_SetClipper (pScreenPriv->pddsPrimary, + NULL); + + ErrorF ("winReleasePrimarySurfaceShadowDD - Detached clipper\n"); + + /* Release the primary surface */ + IDirectDrawSurface2_Release (pScreenPriv->pddsPrimary); + pScreenPriv->pddsPrimary = NULL; + } + + ErrorF ("winReleasePrimarySurfaceShadowDD - Released primary surface\n"); + + return TRUE; +} + + +/* + * Create a DirectDraw surface for the shadow framebuffer; also create + * a primary surface object so we can blit to the display. + * + * Install a DirectDraw clipper on our primary surface object + * that clips our blits to the unobscured client area of our display window. + */ + +static Bool +winAllocateFBShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HRESULT ddrval = DD_OK; + DDSURFACEDESC ddsd; + DDSURFACEDESC *pddsdShadow = NULL; + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD\n"); +#endif + + /* Create a clipper */ + ddrval = (*g_fpDirectDrawCreateClipper) (0, + &pScreenPriv->pddcPrimary, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not create clipper: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD - Created a clipper\n"); +#endif + + /* Attach the clipper to our display window */ + ddrval = IDirectDrawClipper_SetHWnd (pScreenPriv->pddcPrimary, + 0, + pScreenPriv->hwndScreen); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Clipper not attached to " + "window: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD - Attached clipper to window\n"); +#endif + + /* Create a DirectDraw object, store the address at lpdd */ + ddrval = (*g_fpDirectDrawCreate) (NULL, &pScreenPriv->pdd, NULL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not start DirectDraw: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD () - Created and initialized DD\n"); +#endif + + /* Get a DirectDraw2 interface pointer */ + ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, + &IID_IDirectDraw2, + (LPVOID*) &pScreenPriv->pdd2); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Failed DD2 query: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + + /* Are we full screen? */ + if (pScreenInfo->fFullScreen) + { + DDSURFACEDESC ddsdCurrent; + DWORD dwRefreshRateCurrent = 0; + HDC hdc = NULL; + + /* Set the cooperative level to full screen */ + ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, + pScreenPriv->hwndScreen, + DDSCL_EXCLUSIVE + | DDSCL_FULLSCREEN); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not set " + "cooperative level: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + + /* + * We only need to get the current refresh rate for comparison + * if a refresh rate has been passed on the command line. + */ + if (pScreenInfo->dwRefreshRate != 0) + { + ZeroMemory (&ddsdCurrent, sizeof (ddsdCurrent)); + ddsdCurrent.dwSize = sizeof (ddsdCurrent); + + /* Get information about current display settings */ + ddrval = IDirectDraw2_GetDisplayMode (pScreenPriv->pdd2, + &ddsdCurrent); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not get current " + "refresh rate: %08x. Continuing.\n", + (unsigned int) ddrval); + dwRefreshRateCurrent = 0; + } + else + { + /* Grab the current refresh rate */ + dwRefreshRateCurrent = ddsdCurrent.u2.dwRefreshRate; + } + } + + /* Clean up the refresh rate */ + if (dwRefreshRateCurrent == pScreenInfo->dwRefreshRate) + { + /* + * Refresh rate is non-specified or equal to current. + */ + pScreenInfo->dwRefreshRate = 0; + } + + /* Grab a device context for the screen */ + hdc = GetDC (NULL); + if (hdc == NULL) + { + ErrorF ("winAllocateFBShadowDD - GetDC () failed\n"); + return FALSE; + } + + /* Only change the video mode when different than current mode */ + if (!pScreenInfo->fMultipleMonitors + && (pScreenInfo->dwWidth != GetSystemMetrics (SM_CXSCREEN) + || pScreenInfo->dwHeight != GetSystemMetrics (SM_CYSCREEN) + || pScreenInfo->dwBPP != GetDeviceCaps (hdc, BITSPIXEL) + || pScreenInfo->dwRefreshRate != 0)) + { + ErrorF ("winAllocateFBShadowDD - Changing video mode\n"); + + /* Change the video mode to the mode requested, and use the driver default refresh rate on failure */ + ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, + pScreenInfo->dwWidth, + pScreenInfo->dwHeight, + pScreenInfo->dwBPP, + pScreenInfo->dwRefreshRate, + 0); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not set "\ + "full screen display mode: %08x\n", + (unsigned int) ddrval); + ErrorF ("winAllocateFBShadowDD - Using default driver refresh rate\n"); + ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, + pScreenInfo->dwWidth, + pScreenInfo->dwHeight, + pScreenInfo->dwBPP, + 0, + 0); + if (FAILED(ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not set default refresh rate " + "full screen display mode: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + } + } + else + { + ErrorF ("winAllocateFBShadowDD - Not changing video mode\n"); + } + + /* Release our DC */ + ReleaseDC (NULL, hdc); + hdc = NULL; + } + else + { + /* Set the cooperative level for windowed mode */ + ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, + pScreenPriv->hwndScreen, + DDSCL_NORMAL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not set "\ + "cooperative level: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + } + + /* Create the primary surface */ + if (!winCreatePrimarySurfaceShadowDD (pScreen)) + { + ErrorF ("winAllocateFBShadowDD - winCreatePrimarySurfaceShadowDD " + "failed\n"); + return FALSE; + } + + /* Describe the shadow surface to be created */ + /* NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, + * as drawing, locking, and unlocking take forever + * with video memory surfaces. In addition, + * video memory is a somewhat scarce resource, + * so you shouldn't be allocating video memory when + * you have the option of using system memory instead. + */ + ZeroMemory (&ddsd, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsd.dwHeight = pScreenInfo->dwHeight; + ddsd.dwWidth = pScreenInfo->dwWidth; + + /* Create the shadow surface */ + ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, + &ddsd, + &pScreenPriv->pddsShadow, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDD - Could not create shadow "\ + "surface: %08x\n", (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD - Created shadow\n"); +#endif + + /* Allocate a DD surface description for our screen privates */ + pddsdShadow = pScreenPriv->pddsdShadow = malloc (sizeof (DDSURFACEDESC)); + if (pddsdShadow == NULL) + { + ErrorF ("winAllocateFBShadowDD - Could not allocate surface "\ + "description memory\n"); + return FALSE; + } + ZeroMemory (pddsdShadow, sizeof (*pddsdShadow)); + pddsdShadow->dwSize = sizeof (*pddsdShadow); + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD - Locking shadow\n"); +#endif + + /* Lock the shadow surface */ + ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, + NULL, + pddsdShadow, + DDLOCK_WAIT, + NULL); + if (FAILED (ddrval) || pddsdShadow->lpSurface == NULL) + { + ErrorF ("winAllocateFBShadowDD - Could not lock shadow "\ + "surface: %08x\n", (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD - Locked shadow\n"); +#endif + + /* We don't know how to deal with anything other than RGB */ + if (!(pddsdShadow->ddpfPixelFormat.dwFlags & DDPF_RGB)) + { + ErrorF ("winAllocateFBShadowDD - Color format other than RGB\n"); + return FALSE; + } + + /* Grab the pitch from the surface desc */ + pScreenInfo->dwStride = (pddsdShadow->u1.lPitch * 8) + / pScreenInfo->dwBPP; + + /* Save the pointer to our surface memory */ + pScreenInfo->pfb = pddsdShadow->lpSurface; + + /* Grab the color depth and masks from the surface description */ + pScreenPriv->dwRedMask = pddsdShadow->ddpfPixelFormat.u2.dwRBitMask; + pScreenPriv->dwGreenMask = pddsdShadow->ddpfPixelFormat.u3.dwGBitMask; + pScreenPriv->dwBlueMask = pddsdShadow->ddpfPixelFormat.u4.dwBBitMask; + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDD - Returning\n"); +#endif + + return TRUE; +} + +static void +winFreeFBShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Free the shadow surface, if there is one */ + if (pScreenPriv->pddsShadow) + { + IDirectDrawSurface2_Unlock (pScreenPriv->pddsShadow, NULL); + IDirectDrawSurface2_Release (pScreenPriv->pddsShadow); + pScreenPriv->pddsShadow = NULL; + } + + /* Detach the clipper from the primary surface and release the primary surface, if there is one */ + winReleasePrimarySurfaceShadowDD(pScreen); + + /* Release the clipper object */ + if (pScreenPriv->pddcPrimary) + { + IDirectDrawClipper_Release (pScreenPriv->pddcPrimary); + pScreenPriv->pddcPrimary = NULL; + } + + /* Free the DirectDraw2 object, if there is one */ + if (pScreenPriv->pdd2) + { + IDirectDraw2_RestoreDisplayMode (pScreenPriv->pdd2); + IDirectDraw2_Release (pScreenPriv->pdd2); + pScreenPriv->pdd2 = NULL; + } + + /* Free the DirectDraw object, if there is one */ + if (pScreenPriv->pdd) + { + IDirectDraw_Release (pScreenPriv->pdd); + pScreenPriv->pdd = NULL; + } + + /* Invalidate the ScreenInfo's fb pointer */ + pScreenInfo->pfb = NULL; +} + +/* + * Transfer the damaged regions of the shadow framebuffer to the display. + */ + +static void +winShadowUpdateDD (ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RegionPtr damage = shadowDamage(pBuf); + HRESULT ddrval = DD_OK; + RECT rcDest, rcSrc; + POINT ptOrigin; + DWORD dwBox = RegionNumRects (damage); + BoxPtr pBox = RegionRects (damage); + HRGN hrgnTemp = NULL, hrgnCombined = NULL; + + /* + * Return immediately if the app is not active + * and we are fullscreen, or if we have a bad display depth + */ + if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen) + || pScreenPriv->fBadDepth) return; + + /* Return immediately if we didn't get needed surfaces */ + if (!pScreenPriv->pddsPrimary || !pScreenPriv->pddsShadow) + return; + + /* Get the origin of the window in the screen coords */ + ptOrigin.x = pScreenInfo->dwXOffset; + ptOrigin.y = pScreenInfo->dwYOffset; + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&ptOrigin, 1); + + /* Unlock the shadow surface, so we can blit */ + ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsShadow, NULL); + if (FAILED (ddrval)) + { + ErrorF ("winShadowUpdateDD - Unlock failed\n"); + return; + } + + /* + * Handle small regions with multiple blits, + * handle large regions by creating a clipping region and + * doing a single blit constrained to that clipping region. + */ + if (pScreenInfo->dwClipUpdatesNBoxes == 0 + || dwBox < pScreenInfo->dwClipUpdatesNBoxes) + { + /* Loop through all boxes in the damaged region */ + while (dwBox--) + { + /* Assign damage box to source rectangle */ + rcSrc.left = pBox->x1; + rcSrc.top = pBox->y1; + rcSrc.right = pBox->x2; + rcSrc.bottom = pBox->y2; + + /* Calculate destination rectange */ + rcDest.left = ptOrigin.x + rcSrc.left; + rcDest.top = ptOrigin.y + rcSrc.top; + rcDest.right = ptOrigin.x + rcSrc.right; + rcDest.bottom = ptOrigin.y + rcSrc.bottom; + + /* Blit the damaged areas */ + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, + &rcDest, + pScreenPriv->pddsShadow, + &rcSrc, + DDBLT_WAIT, + NULL); + + /* Get a pointer to the next box */ + ++pBox; + } + } + else + { + BoxPtr pBoxExtents = RegionExtents(damage); + + /* Compute a GDI region from the damaged region */ + hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); + dwBox--; + pBox++; + while (dwBox--) + { + hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); + CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR); + DeleteObject (hrgnTemp); + pBox++; + } + + /* Install the GDI region as a clipping region */ + SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined); + DeleteObject (hrgnCombined); + hrgnCombined = NULL; + + /* Calculating a bounding box for the source is easy */ + rcSrc.left = pBoxExtents->x1; + rcSrc.top = pBoxExtents->y1; + rcSrc.right = pBoxExtents->x2; + rcSrc.bottom = pBoxExtents->y2; + + /* Calculating a bounding box for the destination is trickier */ + rcDest.left = ptOrigin.x + rcSrc.left; + rcDest.top = ptOrigin.y + rcSrc.top; + rcDest.right = ptOrigin.x + rcSrc.right; + rcDest.bottom = ptOrigin.y + rcSrc.bottom; + + /* Our Blt should be clipped to the invalidated region */ + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, + &rcDest, + pScreenPriv->pddsShadow, + &rcSrc, + DDBLT_WAIT, + NULL); + + /* Reset the clip region */ + SelectClipRgn (pScreenPriv->hdcScreen, NULL); + } + + /* Relock the shadow surface */ + ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, + NULL, + pScreenPriv->pddsdShadow, + DDLOCK_WAIT, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winShadowUpdateDD - Lock failed\n"); + return; + } + + /* Has our memory pointer changed? */ + if (pScreenInfo->pfb != pScreenPriv->pddsdShadow->lpSurface) + { + ErrorF ("winShadowUpdateDD - Memory location of the shadow " + "surface has changed, trying to update the root window " + "pixmap header to point to the new address. If you get " + "this message and "PROJECT_NAME" freezes or crashes " + "after this message then send a problem report and your " + "%s file to " BUILDERADDR "\n", g_pszLogFile); + + /* Location of shadow framebuffer has changed */ + winUpdateFBPointer(pScreen, pScreenPriv->pddsdShadow->lpSurface); + } +} + +static Bool +winInitScreenShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + /* Get a device context for the screen */ + pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); + + return winAllocateFBShadowDD(pScreen); +} + +/* + * Call the wrapped CloseScreen function. + * + * Free our resources and private structures. + */ + +static Bool +winCloseScreenShadowDD (int nIndex, ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + Bool fReturn; + +#if CYGDEBUG + winDebug ("winCloseScreenShadowDD - Freeing screen resources\n"); +#endif + + /* Flag that the screen is closed */ + pScreenPriv->fClosed = TRUE; + pScreenPriv->fActive = FALSE; + + /* Call the wrapped CloseScreen procedure */ + WIN_UNWRAP(CloseScreen); + fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); + + winFreeFBShadowDD(pScreen); + + /* Free the screen DC */ + ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen); + + /* Delete the window property */ + RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); + + /* Delete tray icon, if we have one */ + if (!pScreenInfo->fNoTrayIcon) + winDeleteNotifyIcon (pScreenPriv); + + /* Free the exit confirmation dialog box, if it exists */ + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + + /* Kill our window */ + if (pScreenPriv->hwndScreen) + { + DestroyWindow (pScreenPriv->hwndScreen); + pScreenPriv->hwndScreen = NULL; + } + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + /* Destroy the thread startup mutex */ + pthread_mutex_destroy (&pScreenPriv->pmServerStarted); +#endif + + /* Kill our screeninfo's pointer to the screen */ + pScreenInfo->pScreen = NULL; + + /* Free the screen privates for this screen */ + free ((pointer) pScreenPriv); + + return fReturn; +} + + +/* + * Tell mi what sort of visuals we need. + * + * Generally we only need one visual, as our screen can only + * handle one format at a time, I believe. You may want + * to verify that last sentence. + */ + +static Bool +winInitVisualsShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + DWORD dwRedBits, dwGreenBits, dwBlueBits; + + /* Count the number of ones in each color mask */ + dwRedBits = winCountBits (pScreenPriv->dwRedMask); + dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); + dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); + + /* Store the maximum number of ones in a color mask as the bitsPerRGB */ + if (dwRedBits == 0 || dwGreenBits == 0 || dwBlueBits == 0) + pScreenPriv->dwBitsPerRGB = 8; + else if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwRedBits; + else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwGreenBits; + else + pScreenPriv->dwBitsPerRGB = dwBlueBits; + + ErrorF ("winInitVisualsShadowDD - Masks %08x %08x %08x BPRGB %d d %d " + "bpp %d\n", + (unsigned int) pScreenPriv->dwRedMask, + (unsigned int) pScreenPriv->dwGreenMask, + (unsigned int) pScreenPriv->dwBlueMask, + (int) pScreenPriv->dwBitsPerRGB, + (int) pScreenInfo->dwDepth, + (int) pScreenInfo->dwBPP); + + /* Create a single visual according to the Windows screen depth */ + switch (pScreenInfo->dwDepth) + { + case 24: + case 16: + case 15: + /* Create the real visual */ + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + TrueColorMask, + pScreenPriv->dwBitsPerRGB, + TrueColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsShadowDD - miSetVisualTypesAndMasks " + "failed for TrueColor\n"); + return FALSE; + } + +#ifdef XWIN_EMULATEPSEUDO + if (!pScreenInfo->fEmulatePseudo) + break; + + /* Setup a pseudocolor visual */ + if (!miSetVisualTypesAndMasks (8, + PseudoColorMask, + 8, + -1, + 0, + 0, + 0)) + { + ErrorF ("winInitVisualsShadowDD - miSetVisualTypesAndMasks " + "failed for PseudoColor\n"); + return FALSE; + } +#endif + break; + + case 8: + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + pScreenInfo->fFullScreen + ? PseudoColorMask : StaticColorMask, + pScreenPriv->dwBitsPerRGB, + pScreenInfo->fFullScreen + ? PseudoColor : StaticColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsShadowDD - miSetVisualTypesAndMasks " + "failed\n"); + return FALSE; + } + break; + + default: + ErrorF ("winInitVisualsShadowDD - Unknown screen depth\n"); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winInitVisualsShadowDD - Returning\n"); +#endif + + return TRUE; +} + + +/* + * Adjust the user proposed video mode + */ + +static Bool +winAdjustVideoModeShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HDC hdc = NULL; + DWORD dwBPP; + + /* We're in serious trouble if we can't get a DC */ + hdc = GetDC (NULL); + if (hdc == NULL) + { + ErrorF ("winAdjustVideoModeShadowDD - GetDC () failed\n"); + return FALSE; + } + + /* Query GDI for current display depth */ + dwBPP = GetDeviceCaps (hdc, BITSPIXEL); + + /* DirectDraw can only change the depth in fullscreen mode */ + if (!(pScreenInfo->fFullScreen && + (pScreenInfo->dwBPP != WIN_DEFAULT_BPP))) + { + /* Otherwise, We'll use GDI's depth */ + pScreenInfo->dwBPP = dwBPP; + } + + /* Release our DC */ + ReleaseDC (NULL, hdc); + return TRUE; +} + + +/* + * Blt exposed regions to the screen + */ + +static Bool +winBltExposedRegionsShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RECT rcSrc, rcDest; + POINT ptOrigin; + HDC hdcUpdate = NULL; + PAINTSTRUCT ps; + HRESULT ddrval = DD_OK; + Bool fReturn = TRUE; + Bool fLocked = TRUE; + int i; + + /* BeginPaint gives us an hdc that clips to the invalidated region */ + hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps); + if (hdcUpdate == NULL) + { + ErrorF ("winBltExposedRegionsShadowDD - BeginPaint () returned " + "a NULL device context handle. Aborting blit attempt.\n"); + return FALSE; + } + + /* Unlock the shadow surface, so we can blit */ + ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsShadow, NULL); + if (FAILED (ddrval)) + { + fReturn = FALSE; + goto winBltExposedRegionsShadowDD_Exit; + } + else + { + /* Flag that we have unlocked the shadow surface */ + fLocked = FALSE; + } + + /* Get the origin of the window in the screen coords */ + ptOrigin.x = pScreenInfo->dwXOffset; + ptOrigin.y = pScreenInfo->dwYOffset; + + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&ptOrigin, 1); + rcDest.left = ptOrigin.x; + rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; + rcDest.top = ptOrigin.y; + rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; + + /* Source can be enter shadow surface, as Blt should clip */ + rcSrc.left = 0; + rcSrc.top = 0; + rcSrc.right = pScreenInfo->dwWidth; + rcSrc.bottom = pScreenInfo->dwHeight; + + /* Try to regain the primary surface and blit again if we've lost it */ + for (i = 0; i <= WIN_REGAIN_SURFACE_RETRIES; ++i) + { + /* Our Blt should be clipped to the invalidated region */ + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, + &rcDest, + pScreenPriv->pddsShadow, + &rcSrc, + DDBLT_WAIT, + NULL); + if (ddrval == DDERR_SURFACELOST) + { + /* Surface was lost */ + ErrorF ("winBltExposedRegionsShadowDD - IDirectDrawSurface2_Blt " + "reported that the primary surface was lost, " + "trying to restore, retry: %d\n", i + 1); + + /* Try to restore the surface, once */ + ddrval = IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); + ErrorF ("winBltExposedRegionsShadowDD - " + "IDirectDrawSurface2_Restore returned: "); + if (ddrval == DD_OK) + ErrorF ("DD_OK\n"); + else if (ddrval == DDERR_WRONGMODE) + ErrorF ("DDERR_WRONGMODE\n"); + else if (ddrval == DDERR_INCOMPATIBLEPRIMARY) + ErrorF ("DDERR_INCOMPATIBLEPRIMARY\n"); + else if (ddrval == DDERR_UNSUPPORTED) + ErrorF ("DDERR_UNSUPPORTED\n"); + else if (ddrval == DDERR_INVALIDPARAMS) + ErrorF ("DDERR_INVALIDPARAMS\n"); + else if (ddrval == DDERR_INVALIDOBJECT) + ErrorF ("DDERR_INVALIDOBJECT\n"); + else + ErrorF ("unknown error: %08x\n", (unsigned int) ddrval); + + /* Loop around to try the blit one more time */ + continue; + } + else if (FAILED (ddrval)) + { + fReturn = FALSE; + ErrorF ("winBltExposedRegionsShadowDD - IDirectDrawSurface2_Blt " + "failed, but surface not lost: %08x %d\n", + (unsigned int) ddrval, (int) ddrval); + goto winBltExposedRegionsShadowDD_Exit; + } + else + { + /* Success, stop looping */ + break; + } + } + + /* Relock the shadow surface */ + ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, + NULL, + pScreenPriv->pddsdShadow, + DDLOCK_WAIT, + NULL); + if (FAILED (ddrval)) + { + fReturn = FALSE; + ErrorF ("winBltExposedRegionsShadowDD - IDirectDrawSurface2_Lock " + "failed\n"); + goto winBltExposedRegionsShadowDD_Exit; + } + else + { + /* Indicate that we have relocked the shadow surface */ + fLocked = TRUE; + } + + /* Has our memory pointer changed? */ + if (pScreenInfo->pfb != pScreenPriv->pddsdShadow->lpSurface) + winUpdateFBPointer (pScreen, + pScreenPriv->pddsdShadow->lpSurface); + + winBltExposedRegionsShadowDD_Exit: + /* EndPaint frees the DC */ + if (hdcUpdate != NULL) + EndPaint (pScreenPriv->hwndScreen, &ps); + + /* + * Relock the surface if it is not locked. We don't care if locking fails, + * as it will cause the server to shutdown within a few more operations. + */ + if (!fLocked) + { + IDirectDrawSurface2_Lock (pScreenPriv->pddsShadow, + NULL, + pScreenPriv->pddsdShadow, + DDLOCK_WAIT, + NULL); + + /* Has our memory pointer changed? */ + if (pScreenInfo->pfb != pScreenPriv->pddsdShadow->lpSurface) + winUpdateFBPointer (pScreen, + pScreenPriv->pddsdShadow->lpSurface); + + fLocked = TRUE; + } + return fReturn; +} + + +/* + * Do any engine-specific appliation-activation processing + */ + +static Bool +winActivateAppShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + /* + * Do we have a surface? + * Are we active? + * Are we fullscreen? + */ + if (pScreenPriv != NULL + && pScreenPriv->pddsPrimary != NULL + && pScreenPriv->fActive) + { + /* Primary surface was lost, restore it */ + IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); + } + + return TRUE; +} + + +/* + * Reblit the shadow framebuffer to the screen. + */ + +static Bool +winRedrawScreenShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HRESULT ddrval = DD_OK; + RECT rcSrc, rcDest; + POINT ptOrigin; + + /* Get the origin of the window in the screen coords */ + ptOrigin.x = pScreenInfo->dwXOffset; + ptOrigin.y = pScreenInfo->dwYOffset; + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&ptOrigin, 1); + rcDest.left = ptOrigin.x; + rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; + rcDest.top = ptOrigin.y; + rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; + + /* Source can be entire shadow surface, as Blt should clip for us */ + rcSrc.left = 0; + rcSrc.top = 0; + rcSrc.right = pScreenInfo->dwWidth; + rcSrc.bottom = pScreenInfo->dwHeight; + + /* Redraw the whole window, to take account for the new colors */ + ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, + &rcDest, + pScreenPriv->pddsShadow, + &rcSrc, + DDBLT_WAIT, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winRedrawScreenShadowDD - IDirectDrawSurface_Blt () " + "failed: %08x\n", + (unsigned int) ddrval); + } + + return TRUE; +} + + +/* + * Realize the currently installed colormap + */ + +static Bool +winRealizeInstalledPaletteShadowDD (ScreenPtr pScreen) +{ + return TRUE; +} + + +/* + * Install the specified colormap + */ + +static Bool +winInstallColormapShadowDD (ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + HRESULT ddrval = DD_OK; + + /* Install the DirectDraw palette on the primary surface */ + ddrval = IDirectDrawSurface2_SetPalette (pScreenPriv->pddsPrimary, + pCmapPriv->lpDDPalette); + if (FAILED (ddrval)) + { + ErrorF ("winInstallColormapShadowDD - Failed installing the " + "DirectDraw palette.\n"); + return FALSE; + } + + /* Save a pointer to the newly installed colormap */ + pScreenPriv->pcmapInstalled = pColormap; + + return TRUE; +} + + +/* + * Store the specified colors in the specified colormap + */ + +static Bool +winStoreColorsShadowDD (ColormapPtr pColormap, + int ndef, + xColorItem *pdefs) +{ + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + ColormapPtr curpmap = pScreenPriv->pcmapInstalled; + HRESULT ddrval = DD_OK; + + /* Put the X colormap entries into the Windows logical palette */ + ddrval = IDirectDrawPalette_SetEntries (pCmapPriv->lpDDPalette, + 0, + pdefs[0].pixel, + ndef, + pCmapPriv->peColors + + pdefs[0].pixel); + if (FAILED (ddrval)) + { + ErrorF ("winStoreColorsShadowDD - SetEntries () failed\n"); + return FALSE; + } + + /* Don't install the DirectDraw palette if the colormap is not installed */ + if (pColormap != curpmap) + { + return TRUE; + } + + if (!winInstallColormapShadowDD (pColormap)) + { + ErrorF ("winStoreColorsShadowDD - Failed installing colormap\n"); + return FALSE; + } + + return TRUE; +} + + +/* + * Colormap initialization procedure + */ + +static Bool +winCreateColormapShadowDD (ColormapPtr pColormap) +{ + HRESULT ddrval = DD_OK; + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + + /* Create a DirectDraw palette */ + ddrval = IDirectDraw2_CreatePalette (pScreenPriv->pdd, + DDPCAPS_8BIT | DDPCAPS_ALLOW256, + pCmapPriv->peColors, + &pCmapPriv->lpDDPalette, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winCreateColormapShadowDD - CreatePalette failed\n"); + return FALSE; + } + + return TRUE; +} + + +/* + * Colormap destruction procedure + */ + +static Bool +winDestroyColormapShadowDD (ColormapPtr pColormap) +{ + winScreenPriv(pColormap->pScreen); + winCmapPriv(pColormap); + HRESULT ddrval = DD_OK; + + /* + * Is colormap to be destroyed the default? + * + * Non-default colormaps should have had winUninstallColormap + * called on them before we get here. The default colormap + * will not have had winUninstallColormap called on it. Thus, + * we need to handle the default colormap in a special way. + */ + if (pColormap->flags & IsDefault) + { +#if CYGDEBUG + winDebug ("winDestroyColormapShadowDD - Destroying default " + "colormap\n"); +#endif + + /* + * FIXME: Walk the list of all screens, popping the default + * palette out of each screen device context. + */ + + /* Pop the palette out of the primary surface */ + ddrval = IDirectDrawSurface2_SetPalette (pScreenPriv->pddsPrimary, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winDestroyColormapShadowDD - Failed freeing the " + "default colormap DirectDraw palette.\n"); + return FALSE; + } + + /* Clear our private installed colormap pointer */ + pScreenPriv->pcmapInstalled = NULL; + } + + /* Release the palette */ + IDirectDrawPalette_Release (pCmapPriv->lpDDPalette); + + /* Invalidate the colormap privates */ + pCmapPriv->lpDDPalette = NULL; + + return TRUE; +} + + +/* + * Set engine specific functions + */ + +Bool +winSetEngineFunctionsShadowDD (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Set our pointers */ + pScreenPriv->pwinAllocateFB = winAllocateFBShadowDD; + pScreenPriv->pwinFreeFB = winFreeFBShadowDD; + pScreenPriv->pwinShadowUpdate = winShadowUpdateDD; + pScreenPriv->pwinInitScreen = winInitScreenShadowDD; + pScreenPriv->pwinCloseScreen = winCloseScreenShadowDD; + pScreenPriv->pwinInitVisuals = winInitVisualsShadowDD; + pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowDD; + if (pScreenInfo->fFullScreen) + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; + else + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; + pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; + pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDD; + pScreenPriv->pwinActivateApp = winActivateAppShadowDD; + pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDD; + pScreenPriv->pwinRealizeInstalledPalette + = winRealizeInstalledPaletteShadowDD; + pScreenPriv->pwinInstallColormap = winInstallColormapShadowDD; + pScreenPriv->pwinStoreColors = winStoreColorsShadowDD; + pScreenPriv->pwinCreateColormap = winCreateColormapShadowDD; + pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowDD; + pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinCreatePrimarySurface = winCreatePrimarySurfaceShadowDD; + pScreenPriv->pwinReleasePrimarySurface = winReleasePrimarySurfaceShadowDD; +#ifdef XWIN_MULTIWINDOW + pScreenPriv->pwinFinishCreateWindowsWindow = + (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA; +#endif + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winshadddnl.c b/xorg-server/hw/xwin/winshadddnl.c index 0ce5d8d85..0a0b4ae13 100644 --- a/xorg-server/hw/xwin/winshadddnl.c +++ b/xorg-server/hw/xwin/winshadddnl.c @@ -1,1412 +1,1396 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" - - -/* - * FIXME: Headers are broken, DEFINE_GUID doesn't work correctly, - * so we have to redefine it here. - */ -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} -#endif /* DEFINE_GUID */ - -/* - * FIXME: Headers are broken, IID_IDirectDraw4 has to be defined - * here manually. Should be handled by ddraw.h - */ -#ifndef IID_IDirectDraw4 -DEFINE_GUID( IID_IDirectDraw4, 0x9c59509a,0x39bd,0x11d1,0x8c,0x4a,0x00,0xc0,0x4f,0xd9,0x30,0xc5 ); -#endif /* IID_IDirectDraw4 */ - -#define FAIL_MSG_MAX_BLT 10 - - -/* - * Local prototypes - */ - -static Bool -winAllocateFBShadowDDNL (ScreenPtr pScreen); - -static void -winShadowUpdateDDNL (ScreenPtr pScreen, - shadowBufPtr pBuf); - -static Bool -winCloseScreenShadowDDNL (int nIndex, ScreenPtr pScreen); - -static Bool -winInitVisualsShadowDDNL (ScreenPtr pScreen); - -static Bool -winAdjustVideoModeShadowDDNL (ScreenPtr pScreen); - -static Bool -winBltExposedRegionsShadowDDNL (ScreenPtr pScreen); - -static Bool -winActivateAppShadowDDNL (ScreenPtr pScreen); - -static Bool -winRedrawScreenShadowDDNL (ScreenPtr pScreen); - -static Bool -winRealizeInstalledPaletteShadowDDNL (ScreenPtr pScreen); - -static Bool -winInstallColormapShadowDDNL (ColormapPtr pColormap); - -static Bool -winStoreColorsShadowDDNL (ColormapPtr pmap, - int ndef, - xColorItem *pdefs); - -static Bool -winCreateColormapShadowDDNL (ColormapPtr pColormap); - -static Bool -winDestroyColormapShadowDDNL (ColormapPtr pColormap); - -static Bool -winCreatePrimarySurfaceShadowDDNL (ScreenPtr pScreen); - -static Bool -winReleasePrimarySurfaceShadowDDNL (ScreenPtr pScreen); - - -/* - * Create the primary surface and attach the clipper. - * Used for both the initial surface creation and during - * WM_DISPLAYCHANGE messages. - */ - -static Bool -winCreatePrimarySurfaceShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - HRESULT ddrval = DD_OK; - DDSURFACEDESC2 ddsd; - - winDebug ("winCreatePrimarySurfaceShadowDDNL - Creating primary surface\n"); - - /* Describe the primary surface */ - ZeroMemory (&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - /* Create the primary surface */ - ddrval = IDirectDraw4_CreateSurface (pScreenPriv->pdd4, - &ddsd, - &pScreenPriv->pddsPrimary4, - NULL); - pScreenPriv->fRetryCreateSurface = FALSE; - if (FAILED (ddrval)) - { - if (ddrval == DDERR_NOEXCLUSIVEMODE) - { - /* Recreating the surface failed. Mark screen to retry later */ - pScreenPriv->fRetryCreateSurface = TRUE; - winDebug ("winCreatePrimarySurfaceShadowDDNL - Could not create " - "primary surface: DDERR_NOEXCLUSIVEMODE\n"); - } - else - { - ErrorF ("winCreatePrimarySurfaceShadowDDNL - Could not create " - "primary surface: %08x\n", (unsigned int) ddrval); - } - return FALSE; - } - -#if 1 - winDebug ("winCreatePrimarySurfaceShadowDDNL - Created primary surface\n"); -#endif - - /* Attach our clipper to our primary surface handle */ - ddrval = IDirectDrawSurface4_SetClipper (pScreenPriv->pddsPrimary4, - pScreenPriv->pddcPrimary); - if (FAILED (ddrval)) - { - ErrorF ("winCreatePrimarySurfaceShadowDDNL - Primary attach clipper " - "failed: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if 1 - winDebug ("winCreatePrimarySurfaceShadowDDNL - Attached clipper to primary " - "surface\n"); -#endif - - /* Everything was correct */ - return TRUE; -} - - -/* - * Detach the clipper and release the primary surface. - * Called from WM_DISPLAYCHANGE. - */ - -static Bool -winReleasePrimarySurfaceShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - - winDebug ("winReleasePrimarySurfaceShadowDDNL - Hello\n"); - - /* Release the primary surface and clipper, if they exist */ - if (pScreenPriv->pddsPrimary4) - { - /* - * Detach the clipper from the primary surface. - * NOTE: We do this explicity for clarity. The Clipper is not released. - */ - IDirectDrawSurface4_SetClipper (pScreenPriv->pddsPrimary4, - NULL); - - winDebug ("winReleasePrimarySurfaceShadowDDNL - Detached clipper\n"); - - /* Release the primary surface */ - IDirectDrawSurface4_Release (pScreenPriv->pddsPrimary4); - pScreenPriv->pddsPrimary4 = NULL; - } - - winDebug ("winReleasePrimarySurfaceShadowDDNL - Released primary surface\n"); - - return TRUE; -} - - -/* - * Create a DirectDraw surface for the shadow framebuffer; also create - * a primary surface object so we can blit to the display. - * - * Install a DirectDraw clipper on our primary surface object - * that clips our blits to the unobscured client area of our display window. - */ - -Bool -winAllocateFBShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HRESULT ddrval = DD_OK; - DDSURFACEDESC2 ddsdShadow; - char *lpSurface = NULL; - DDPIXELFORMAT ddpfPrimary; - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDDNL - w %d h %d d %d\n", - pScreenInfo->dwWidth, pScreenInfo->dwHeight, pScreenInfo->dwDepth); -#endif - - /* Allocate memory for our shadow surface */ - lpSurface = malloc (pScreenInfo->dwPaddedWidth * pScreenInfo->dwHeight); - if (lpSurface == NULL) - { - ErrorF ("winAllocateFBShadowDDNL - Could not allocate bits\n"); - return FALSE; - } - - /* - * Initialize the framebuffer memory so we don't get a - * strange display at startup - */ - ZeroMemory (lpSurface, pScreenInfo->dwPaddedWidth * pScreenInfo->dwHeight); - - /* Create a clipper */ - ddrval = (*g_fpDirectDrawCreateClipper) (0, - &pScreenPriv->pddcPrimary, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not attach clipper: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDDNL - Created a clipper\n"); -#endif - - /* Get a device context for the screen */ - pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); - - /* Attach the clipper to our display window */ - ddrval = IDirectDrawClipper_SetHWnd (pScreenPriv->pddcPrimary, - 0, - pScreenPriv->hwndScreen); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Clipper not attached " - "to window: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDDNL - Attached clipper to window\n"); -#endif - - /* Create a DirectDraw object, store the address at lpdd */ - ddrval = (*g_fpDirectDrawCreate) (NULL, - (LPDIRECTDRAW*) &pScreenPriv->pdd, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not start " - "DirectDraw: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDDNL - Created and initialized DD\n"); -#endif - - /* Get a DirectDraw4 interface pointer */ - ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, - &IID_IDirectDraw4, - (LPVOID*) &pScreenPriv->pdd4); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Failed DD4 query: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - - /* Are we full screen? */ - if (pScreenInfo->fFullScreen) - { - DDSURFACEDESC2 ddsdCurrent; - DWORD dwRefreshRateCurrent = 0; - HDC hdc = NULL; - - /* Set the cooperative level to full screen */ - ddrval = IDirectDraw4_SetCooperativeLevel (pScreenPriv->pdd4, - pScreenPriv->hwndScreen, - DDSCL_EXCLUSIVE - | DDSCL_FULLSCREEN); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not set " - "cooperative level: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - - /* - * We only need to get the current refresh rate for comparison - * if a refresh rate has been passed on the command line. - */ - if (pScreenInfo->dwRefreshRate != 0) - { - ZeroMemory (&ddsdCurrent, sizeof (ddsdCurrent)); - ddsdCurrent.dwSize = sizeof (ddsdCurrent); - - /* Get information about current display settings */ - ddrval = IDirectDraw4_GetDisplayMode (pScreenPriv->pdd4, - &ddsdCurrent); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not get current " - "refresh rate: %08x. Continuing.\n", - (unsigned int) ddrval); - dwRefreshRateCurrent = 0; - } - else - { - /* Grab the current refresh rate */ - dwRefreshRateCurrent = ddsdCurrent.u2.dwRefreshRate; - } - } - - /* Clean up the refresh rate */ - if (dwRefreshRateCurrent == pScreenInfo->dwRefreshRate) - { - /* - * Refresh rate is non-specified or equal to current. - */ - pScreenInfo->dwRefreshRate = 0; - } - - /* Grab a device context for the screen */ - hdc = GetDC (NULL); - if (hdc == NULL) - { - ErrorF ("winAllocateFBShadowDDNL - GetDC () failed\n"); - return FALSE; - } - - /* Only change the video mode when different than current mode */ - if (!pScreenInfo->fMultipleMonitors - && (pScreenInfo->dwWidth != GetSystemMetrics (SM_CXSCREEN) - || pScreenInfo->dwHeight != GetSystemMetrics (SM_CYSCREEN) - || pScreenInfo->dwBPP != GetDeviceCaps (hdc, BITSPIXEL) - || pScreenInfo->dwRefreshRate != 0)) - { - winDebug ("winAllocateFBShadowDDNL - Changing video mode\n"); - - /* Change the video mode to the mode requested, and use the driver default refresh rate on failure */ - ddrval = IDirectDraw4_SetDisplayMode (pScreenPriv->pdd4, - pScreenInfo->dwWidth, - pScreenInfo->dwHeight, - pScreenInfo->dwBPP, - pScreenInfo->dwRefreshRate, - 0); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not set " - "full screen display mode: %08x\n", - (unsigned int) ddrval); - ErrorF ("winAllocateFBShadowDDNL - Using default driver refresh rate\n"); - ddrval = IDirectDraw4_SetDisplayMode (pScreenPriv->pdd4, - pScreenInfo->dwWidth, - pScreenInfo->dwHeight, - pScreenInfo->dwBPP, - 0, - 0); - if (FAILED(ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not set default refresh rate " - "full screen display mode: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - } - } - else - { - winDebug ("winAllocateFBShadowDDNL - Not changing video mode\n"); - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - hdc = NULL; - } - else - { - /* Set the cooperative level for windowed mode */ - ddrval = IDirectDraw4_SetCooperativeLevel (pScreenPriv->pdd4, - pScreenPriv->hwndScreen, - DDSCL_NORMAL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not set " - "cooperative level: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - } - - /* Create the primary surface */ - if (!winCreatePrimarySurfaceShadowDDNL (pScreen)) - { - ErrorF ("winAllocateFBShadowDDNL - winCreatePrimarySurfaceShadowDDNL " - "failed\n"); - return FALSE; - } - - /* Get primary surface's pixel format */ - ZeroMemory (&ddpfPrimary, sizeof (ddpfPrimary)); - ddpfPrimary.dwSize = sizeof (ddpfPrimary); - ddrval = IDirectDrawSurface4_GetPixelFormat (pScreenPriv->pddsPrimary4, - &ddpfPrimary); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not get primary " - "pixformat: %08x\n", - (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDDNL - Primary masks: %08x %08x %08x " - "dwRGBBitCount: %d\n", - ddpfPrimary.u2.dwRBitMask, - ddpfPrimary.u3.dwGBitMask, - ddpfPrimary.u4.dwBBitMask, - ddpfPrimary.u1.dwRGBBitCount); -#endif - - /* Describe the shadow surface to be created */ - /* - * NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, - * as drawing, locking, and unlocking take forever - * with video memory surfaces. In addition, - * video memory is a somewhat scarce resource, - * so you shouldn't be allocating video memory when - * you have the option of using system memory instead. - */ - ZeroMemory (&ddsdShadow, sizeof (ddsdShadow)); - ddsdShadow.dwSize = sizeof (ddsdShadow); - ddsdShadow.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH - | DDSD_LPSURFACE | DDSD_PITCH | DDSD_PIXELFORMAT; - ddsdShadow.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - ddsdShadow.dwHeight = pScreenInfo->dwHeight; - ddsdShadow.dwWidth = pScreenInfo->dwWidth; - ddsdShadow.u1.lPitch = pScreenInfo->dwPaddedWidth; - ddsdShadow.lpSurface = lpSurface; - ddsdShadow.u4.ddpfPixelFormat = ddpfPrimary; - - winDebug ("winAllocateFBShadowDDNL - lPitch: %d\n", - (int) pScreenInfo->dwPaddedWidth); - - /* Create the shadow surface */ - ddrval = IDirectDraw4_CreateSurface (pScreenPriv->pdd4, - &ddsdShadow, - &pScreenPriv->pddsShadow4, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winAllocateFBShadowDDNL - Could not create shadow " - "surface: %08x\n", (unsigned int) ddrval); - return FALSE; - } - -#if CYGDEBUG || YES - winDebug ("winAllocateFBShadowDDNL - Created shadow pitch: %d\n", - (int) ddsdShadow.u1.lPitch); -#endif - - /* Grab the pitch from the surface desc */ - pScreenInfo->dwStride = (ddsdShadow.u1.lPitch * 8) - / pScreenInfo->dwBPP; - -#if CYGDEBUG || YES - winDebug ("winAllocateFBShadowDDNL - Created shadow stride: %d\n", - (int) pScreenInfo->dwStride); -#endif - - /* Save the pointer to our surface memory */ - pScreenInfo->pfb = lpSurface; - - /* Grab the masks from the surface description */ - pScreenPriv->dwRedMask = ddsdShadow.u4.ddpfPixelFormat.u2.dwRBitMask; - pScreenPriv->dwGreenMask = ddsdShadow.u4.ddpfPixelFormat.u3.dwGBitMask; - pScreenPriv->dwBlueMask = ddsdShadow.u4.ddpfPixelFormat.u4.dwBBitMask; - -#if CYGDEBUG - winDebug ("winAllocateFBShadowDDNL - Returning\n"); -#endif - - return TRUE; -} - - -#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) -/* - * Create a DirectDraw surface for the new multi-window window - */ - -static -Bool -winFinishCreateWindowsWindowDDNL (WindowPtr pWin) -{ - winWindowPriv(pWin); - winPrivScreenPtr pScreenPriv = pWinPriv->pScreenPriv; - HRESULT ddrval = DD_OK; - DDSURFACEDESC2 ddsd; - int iWidth, iHeight; - int iX, iY; - - winDebug ("winFinishCreateWindowsWindowDDNL!\n\n"); - - iX = pWin->drawable.x + GetSystemMetrics (SM_XVIRTUALSCREEN); - iY = pWin->drawable.y + GetSystemMetrics (SM_YVIRTUALSCREEN); - - iWidth = pWin->drawable.width; - iHeight = pWin->drawable.height; - - /* Describe the primary surface */ - ZeroMemory (&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - ddsd.dwHeight = iHeight; - ddsd.dwWidth = iWidth; - - /* Create the primary surface */ - ddrval = IDirectDraw4_CreateSurface (pScreenPriv->pdd4, - &ddsd, - &pWinPriv->pddsPrimary4, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winFinishCreateWindowsWindowDDNL - Could not create primary " - "surface: %08x\n", - (unsigned int)ddrval); - return FALSE; - } - return TRUE; -} -#endif - - -/* - * Transfer the damaged regions of the shadow framebuffer to the display. - */ - -static void -winShadowUpdateDDNL (ScreenPtr pScreen, - shadowBufPtr pBuf) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RegionPtr damage = shadowDamage(pBuf); - HRESULT ddrval = DD_OK; - RECT rcDest, rcSrc; - POINT ptOrigin; - DWORD dwBox = RegionNumRects (damage); - BoxPtr pBox = RegionRects (damage); - HRGN hrgnTemp = NULL, hrgnCombined = NULL; - - /* - * Return immediately if the app is not active - * and we are fullscreen, or if we have a bad display depth - */ - if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen) - || pScreenPriv->fBadDepth) return; - - /* Get the origin of the window in the screen coords */ - ptOrigin.x = pScreenInfo->dwXOffset; - ptOrigin.y = pScreenInfo->dwYOffset; - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&ptOrigin, 1); - - /* - * Handle small regions with multiple blits, - * handle large regions by creating a clipping region and - * doing a single blit constrained to that clipping region. - */ - if (pScreenInfo->dwClipUpdatesNBoxes == 0 - || dwBox < pScreenInfo->dwClipUpdatesNBoxes) - { - /* Loop through all boxes in the damaged region */ - while (dwBox--) - { - /* Assign damage box to source rectangle */ - rcSrc.left = pBox->x1; - rcSrc.top = pBox->y1; - rcSrc.right = pBox->x2; - rcSrc.bottom = pBox->y2; - - /* Calculate destination rectangle */ - rcDest.left = ptOrigin.x + rcSrc.left; - rcDest.top = ptOrigin.y + rcSrc.top; - rcDest.right = ptOrigin.x + rcSrc.right; - rcDest.bottom = ptOrigin.y + rcSrc.bottom; - - /* Blit the damaged areas */ - ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, - &rcDest, - pScreenPriv->pddsShadow4, - &rcSrc, - DDBLT_WAIT, - NULL); - if (FAILED (ddrval)) - { - static int s_iFailCount = 0; - - if (s_iFailCount < FAIL_MSG_MAX_BLT) - { - ErrorF ("winShadowUpdateDDNL - IDirectDrawSurface4_Blt () " - "failed: %08x\n", - (unsigned int) ddrval); - - ++s_iFailCount; - - if (s_iFailCount == FAIL_MSG_MAX_BLT) - { - ErrorF ("winShadowUpdateDDNL - IDirectDrawSurface4_Blt " - "failure message maximum (%d) reached. No " - "more failure messages will be printed.\n", - FAIL_MSG_MAX_BLT); - } - } - } - - /* Get a pointer to the next box */ - ++pBox; - } - } - else - { - BoxPtr pBoxExtents = RegionExtents(damage); - - /* Compute a GDI region from the damaged region */ - hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); - dwBox--; - pBox++; - while (dwBox--) - { - hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); - CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR); - DeleteObject (hrgnTemp); - pBox++; - } - - /* Install the GDI region as a clipping region */ - SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined); - DeleteObject (hrgnCombined); - hrgnCombined = NULL; - -#if CYGDEBUG - winDebug ("winShadowUpdateDDNL - be x1 %d y1 %d x2 %d y2 %d\n", - pBoxExtents->x1, pBoxExtents->y1, - pBoxExtents->x2, pBoxExtents->y2); -#endif - - /* Calculating a bounding box for the source is easy */ - rcSrc.left = pBoxExtents->x1; - rcSrc.top = pBoxExtents->y1; - rcSrc.right = pBoxExtents->x2; - rcSrc.bottom = pBoxExtents->y2; - - /* Calculating a bounding box for the destination is trickier */ - rcDest.left = ptOrigin.x + rcSrc.left; - rcDest.top = ptOrigin.y + rcSrc.top; - rcDest.right = ptOrigin.x + rcSrc.right; - rcDest.bottom = ptOrigin.y + rcSrc.bottom; - - /* Our Blt should be clipped to the invalidated region */ - ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, - &rcDest, - pScreenPriv->pddsShadow4, - &rcSrc, - DDBLT_WAIT, - NULL); - - /* Reset the clip region */ - SelectClipRgn (pScreenPriv->hdcScreen, NULL); - } -} - - -/* - * Call the wrapped CloseScreen function. - * - * Free our resources and private structures. - */ - -static Bool -winCloseScreenShadowDDNL (int nIndex, ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - Bool fReturn; - -#if CYGDEBUG - winDebug ("winCloseScreenShadowDDNL - Freeing screen resources\n"); -#endif - - /* Flag that the screen is closed */ - pScreenPriv->fClosed = TRUE; - pScreenPriv->fActive = FALSE; - - /* Call the wrapped CloseScreen procedure */ - WIN_UNWRAP(CloseScreen); - fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); - - /* Free the screen DC */ - ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen); - - /* Delete the window property */ - RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); - - /* Free the shadow surface, if there is one */ - if (pScreenPriv->pddsShadow4) - { - IDirectDrawSurface4_Release (pScreenPriv->pddsShadow4); - free (pScreenInfo->pfb); - pScreenInfo->pfb = NULL; - pScreenPriv->pddsShadow4 = NULL; - } - - /* Detach the clipper from the primary surface and release the clipper. */ - if (pScreenPriv->pddcPrimary) - { - /* Detach the clipper */ - IDirectDrawSurface4_SetClipper (pScreenPriv->pddsPrimary4, - NULL); - - /* Release the clipper object */ - IDirectDrawClipper_Release (pScreenPriv->pddcPrimary); - pScreenPriv->pddcPrimary = NULL; - } - - /* Release the primary surface, if there is one */ - if (pScreenPriv->pddsPrimary4) - { - IDirectDrawSurface4_Release (pScreenPriv->pddsPrimary4); - pScreenPriv->pddsPrimary4 = NULL; - } - - /* Free the DirectDraw4 object, if there is one */ - if (pScreenPriv->pdd4) - { - IDirectDraw4_RestoreDisplayMode (pScreenPriv->pdd4); - IDirectDraw4_Release (pScreenPriv->pdd4); - pScreenPriv->pdd4 = NULL; - } - - /* Free the DirectDraw object, if there is one */ - if (pScreenPriv->pdd) - { - IDirectDraw_Release (pScreenPriv->pdd); - pScreenPriv->pdd = NULL; - } - - /* Delete tray icon, if we have one */ - if (!pScreenInfo->fNoTrayIcon) - winDeleteNotifyIcon (pScreenPriv); - - /* Free the exit confirmation dialog box, if it exists */ - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - - /* Kill our window */ - if (pScreenPriv->hwndScreen) - { - DestroyWindow (pScreenPriv->hwndScreen); - pScreenPriv->hwndScreen = NULL; - } - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - /* Destroy the thread startup mutex */ - pthread_mutex_destroy (&pScreenPriv->pmServerStarted); -#endif - - /* Kill our screeninfo's pointer to the screen */ - pScreenInfo->pScreen = NULL; - - /* Invalidate the ScreenInfo's fb pointer */ - pScreenInfo->pfb = NULL; - - /* Free the screen privates for this screen */ - free ((pointer) pScreenPriv); - - return fReturn; -} - - -/* - * Tell mi what sort of visuals we need. - * - * Generally we only need one visual, as our screen can only - * handle one format at a time, I believe. You may want - * to verify that last sentence. - */ - -static Bool -winInitVisualsShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - DWORD dwRedBits, dwGreenBits, dwBlueBits; - - /* Count the number of ones in each color mask */ - dwRedBits = winCountBits (pScreenPriv->dwRedMask); - dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); - dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); - - /* Store the maximum number of ones in a color mask as the bitsPerRGB */ - if (dwRedBits == 0 || dwGreenBits == 0 || dwBlueBits == 0) - pScreenPriv->dwBitsPerRGB = 8; - else if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwRedBits; - else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwGreenBits; - else - pScreenPriv->dwBitsPerRGB = dwBlueBits; - - winDebug ("winInitVisualsShadowDDNL - Masks %08x %08x %08x BPRGB %d d %d " - "bpp %d\n", - (unsigned int) pScreenPriv->dwRedMask, - (unsigned int) pScreenPriv->dwGreenMask, - (unsigned int) pScreenPriv->dwBlueMask, - (int) pScreenPriv->dwBitsPerRGB, - (int) pScreenInfo->dwDepth, - (int) pScreenInfo->dwBPP); - - /* Create a single visual according to the Windows screen depth */ - switch (pScreenInfo->dwDepth) - { - case 24: - case 16: - case 15: - /* Setup the real visual */ - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - TrueColorMask, - pScreenPriv->dwBitsPerRGB, - -1, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsShadowDDNL - miSetVisualTypesAndMasks " - "failed for TrueColor\n"); - return FALSE; - } - -#ifdef XWIN_EMULATEPSEUDO - if (!pScreenInfo->fEmulatePseudo) - break; - - /* Setup a pseudocolor visual */ - if (!miSetVisualTypesAndMasks (8, - PseudoColorMask, - 8, - -1, - 0, - 0, - 0)) - { - ErrorF ("winInitVisualsShadowDDNL - miSetVisualTypesAndMasks " - "failed for PseudoColor\n"); - return FALSE; - } -#endif - break; - - case 8: - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - pScreenInfo->fFullScreen - ? PseudoColorMask : StaticColorMask, - pScreenPriv->dwBitsPerRGB, - pScreenInfo->fFullScreen - ? PseudoColor : StaticColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsShadowDDNL - miSetVisualTypesAndMasks " - "failed\n"); - return FALSE; - } - break; - - default: - ErrorF ("winInitVisualsShadowDDNL - Unknown screen depth\n"); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winInitVisualsShadowDDNL - Returning\n"); -#endif - - return TRUE; -} - - -/* - * Adjust the user proposed video mode - */ - -static Bool -winAdjustVideoModeShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HDC hdc = NULL; - DWORD dwBPP; - - /* We're in serious trouble if we can't get a DC */ - hdc = GetDC (NULL); - if (hdc == NULL) - { - ErrorF ("winAdjustVideoModeShadowDDNL - GetDC () failed\n"); - return FALSE; - } - - /* Query GDI for current display depth */ - dwBPP = GetDeviceCaps (hdc, BITSPIXEL); - - /* DirectDraw can only change the depth in fullscreen mode */ - if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP) - { - /* No -depth parameter passed, let the user know the depth being used */ - winErrorFVerb (2, "winAdjustVideoModeShadowDDNL - Using Windows display " - "depth of %d bits per pixel\n", (int) dwBPP); - - /* Use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - else if (pScreenInfo->fFullScreen - && pScreenInfo->dwBPP != dwBPP) - { - /* FullScreen, and GDI depth differs from -depth parameter */ - winErrorFVerb (2, "winAdjustVideoModeShadowDDNL - FullScreen, using command " - "line bpp: %d\n", (int) pScreenInfo->dwBPP); - } - else if (dwBPP != pScreenInfo->dwBPP) - { - /* Windowed, and GDI depth differs from -depth parameter */ - winErrorFVerb (2, "winAdjustVideoModeShadowDDNL - Windowed, command line " - "bpp: %d, using bpp: %d\n", - (int) pScreenInfo->dwBPP, (int) dwBPP); - - /* We'll use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - - /* See if the shadow bitmap will be larger than the DIB size limit */ - if (pScreenInfo->dwWidth * pScreenInfo->dwHeight * pScreenInfo->dwBPP - >= WIN_DIB_MAXIMUM_SIZE) - { - winErrorFVerb (1, "winAdjustVideoModeShadowDDNL - Requested DirectDraw surface " - "will be larger than %d MB. The surface may fail to be " - "allocated on Windows 95, 98, or Me, due to a %d MB limit in " - "DIB size. This limit does not apply to Windows NT/2000, and " - "this message may be ignored on those platforms.\n", - WIN_DIB_MAXIMUM_SIZE_MB, WIN_DIB_MAXIMUM_SIZE_MB); - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - - return TRUE; -} - - -/* - * Blt exposed regions to the screen - */ - -static Bool -winBltExposedRegionsShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RECT rcSrc, rcDest; - POINT ptOrigin; - HDC hdcUpdate; - PAINTSTRUCT ps; - HRESULT ddrval = DD_OK; - Bool fReturn = TRUE; - int i; - - /* Quite common case. The primary surface was lost (maybe because of depth - * change). Try to create a new primary surface. Bail out if this fails */ - if (pScreenPriv->pddsPrimary4 == NULL && pScreenPriv->fRetryCreateSurface && - !winCreatePrimarySurfaceShadowDDNL(pScreen)) - { - Sleep(100); - return FALSE; - } - if (pScreenPriv->pddsPrimary4 == NULL) - return FALSE; - - /* BeginPaint gives us an hdc that clips to the invalidated region */ - hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps); - if (hdcUpdate == NULL) - { - fReturn = FALSE; - ErrorF ("winBltExposedRegionsShadowDDNL - BeginPaint () returned " - "a NULL device context handle. Aborting blit attempt.\n"); - goto winBltExposedRegionsShadowDDNL_Exit; - } - - /* Get the origin of the window in the screen coords */ - ptOrigin.x = pScreenInfo->dwXOffset; - ptOrigin.y = pScreenInfo->dwYOffset; - - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&ptOrigin, 1); - rcDest.left = ptOrigin.x; - rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; - rcDest.top = ptOrigin.y; - rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; - - /* Source can be entire shadow surface, as Blt should clip for us */ - rcSrc.left = 0; - rcSrc.top = 0; - rcSrc.right = pScreenInfo->dwWidth; - rcSrc.bottom = pScreenInfo->dwHeight; - - /* Try to regain the primary surface and blit again if we've lost it */ - for (i = 0; i <= WIN_REGAIN_SURFACE_RETRIES; ++i) - { - /* Our Blt should be clipped to the invalidated region */ - ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, - &rcDest, - pScreenPriv->pddsShadow4, - &rcSrc, - DDBLT_WAIT, - NULL); - if (ddrval == DDERR_SURFACELOST) - { - /* Surface was lost */ - winErrorFVerb (1, "winBltExposedRegionsShadowDDNL - " - "IDirectDrawSurface4_Blt reported that the primary " - "surface was lost, trying to restore, retry: %d\n", i + 1); - - /* Try to restore the surface, once */ - - ddrval = IDirectDrawSurface4_Restore (pScreenPriv->pddsPrimary4); - winDebug ("winBltExposedRegionsShadowDDNL - " - "IDirectDrawSurface4_Restore returned: "); - if (ddrval == DD_OK) - winDebug ("DD_OK\n"); - else if (ddrval == DDERR_WRONGMODE) - winDebug ("DDERR_WRONGMODE\n"); - else if (ddrval == DDERR_INCOMPATIBLEPRIMARY) - winDebug ("DDERR_INCOMPATIBLEPRIMARY\n"); - else if (ddrval == DDERR_UNSUPPORTED) - winDebug ("DDERR_UNSUPPORTED\n"); - else if (ddrval == DDERR_INVALIDPARAMS) - winDebug ("DDERR_INVALIDPARAMS\n"); - else if (ddrval == DDERR_INVALIDOBJECT) - winDebug ("DDERR_INVALIDOBJECT\n"); - else - winDebug ("unknown error: %08x\n", (unsigned int) ddrval); - - /* Loop around to try the blit one more time */ - continue; - } - else if (FAILED (ddrval)) - { - fReturn = FALSE; - winErrorFVerb (1, "winBltExposedRegionsShadowDDNL - " - "IDirectDrawSurface4_Blt failed, but surface not " - "lost: %08x %d\n", - (unsigned int) ddrval, (int) ddrval); - goto winBltExposedRegionsShadowDDNL_Exit; - } - else - { - /* Success, stop looping */ - break; - } - } - - winBltExposedRegionsShadowDDNL_Exit: - /* EndPaint frees the DC */ - if (hdcUpdate != NULL) - EndPaint (pScreenPriv->hwndScreen, &ps); - return fReturn; -} - - -/* - * Do any engine-specific application-activation processing - */ - -static Bool -winActivateAppShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - - /* - * Do we have a surface? - * Are we active? - * Are we full screen? - */ - if (pScreenPriv != NULL - && pScreenPriv->pddsPrimary4 != NULL - && pScreenPriv->fActive) - { - /* Primary surface was lost, restore it */ - IDirectDrawSurface4_Restore (pScreenPriv->pddsPrimary4); - } - - return TRUE; -} - - -/* - * Reblit the shadow framebuffer to the screen. - */ - -static Bool -winRedrawScreenShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HRESULT ddrval = DD_OK; - RECT rcSrc, rcDest; - POINT ptOrigin; - - /* Get the origin of the window in the screen coords */ - ptOrigin.x = pScreenInfo->dwXOffset; - ptOrigin.y = pScreenInfo->dwYOffset; - MapWindowPoints (pScreenPriv->hwndScreen, - HWND_DESKTOP, - (LPPOINT)&ptOrigin, 1); - rcDest.left = ptOrigin.x; - rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; - rcDest.top = ptOrigin.y; - rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; - - /* Source can be entire shadow surface, as Blt should clip for us */ - rcSrc.left = 0; - rcSrc.top = 0; - rcSrc.right = pScreenInfo->dwWidth; - rcSrc.bottom = pScreenInfo->dwHeight; - - /* Redraw the whole window, to take account for the new colors */ - ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, - &rcDest, - pScreenPriv->pddsShadow4, - &rcSrc, - DDBLT_WAIT, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winRedrawScreenShadowDDNL - IDirectDrawSurface4_Blt () " - "failed: %08x\n", - (unsigned int) ddrval); - } - - return TRUE; -} - - -/* - * Realize the currently installed colormap - */ - -static Bool -winRealizeInstalledPaletteShadowDDNL (ScreenPtr pScreen) -{ - return TRUE; -} - - -/* - * Install the specified colormap - */ - -static Bool -winInstallColormapShadowDDNL (ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - HRESULT ddrval = DD_OK; - - /* Install the DirectDraw palette on the primary surface */ - ddrval = IDirectDrawSurface4_SetPalette (pScreenPriv->pddsPrimary4, - pCmapPriv->lpDDPalette); - if (FAILED (ddrval)) - { - ErrorF ("winInstallColormapShadowDDNL - Failed installing the " - "DirectDraw palette.\n"); - return FALSE; - } - - /* Save a pointer to the newly installed colormap */ - pScreenPriv->pcmapInstalled = pColormap; - - return TRUE; -} - - -/* - * Store the specified colors in the specified colormap - */ - -static Bool -winStoreColorsShadowDDNL (ColormapPtr pColormap, - int ndef, - xColorItem *pdefs) -{ - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - ColormapPtr curpmap = pScreenPriv->pcmapInstalled; - HRESULT ddrval = DD_OK; - - /* Put the X colormap entries into the Windows logical palette */ - ddrval = IDirectDrawPalette_SetEntries (pCmapPriv->lpDDPalette, - 0, - pdefs[0].pixel, - ndef, - pCmapPriv->peColors - + pdefs[0].pixel); - if (FAILED (ddrval)) - { - ErrorF ("winStoreColorsShadowDDNL - SetEntries () failed: %08x\n", (unsigned int) ddrval); - return FALSE; - } - - /* Don't install the DirectDraw palette if the colormap is not installed */ - if (pColormap != curpmap) - { - return TRUE; - } - - if (!winInstallColormapShadowDDNL (pColormap)) - { - ErrorF ("winStoreColorsShadowDDNL - Failed installing colormap\n"); - return FALSE; - } - - return TRUE; -} - - -/* - * Colormap initialization procedure - */ - -static Bool -winCreateColormapShadowDDNL (ColormapPtr pColormap) -{ - HRESULT ddrval = DD_OK; - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - - /* Create a DirectDraw palette */ - ddrval = IDirectDraw4_CreatePalette (pScreenPriv->pdd4, - DDPCAPS_8BIT | DDPCAPS_ALLOW256, - pCmapPriv->peColors, - &pCmapPriv->lpDDPalette, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winCreateColormapShadowDDNL - CreatePalette failed\n"); - return FALSE; - } - - return TRUE; -} - - -/* - * Colormap destruction procedure - */ - -static Bool -winDestroyColormapShadowDDNL (ColormapPtr pColormap) -{ - winScreenPriv(pColormap->pScreen); - winCmapPriv(pColormap); - HRESULT ddrval = DD_OK; - - /* - * Is colormap to be destroyed the default? - * - * Non-default colormaps should have had winUninstallColormap - * called on them before we get here. The default colormap - * will not have had winUninstallColormap called on it. Thus, - * we need to handle the default colormap in a special way. - */ - if (pColormap->flags & IsDefault) - { -#if CYGDEBUG - winDebug ("winDestroyColormapShadowDDNL - Destroying default colormap\n"); -#endif - - /* - * FIXME: Walk the list of all screens, popping the default - * palette out of each screen device context. - */ - - /* Pop the palette out of the primary surface */ - ddrval = IDirectDrawSurface4_SetPalette (pScreenPriv->pddsPrimary4, - NULL); - if (FAILED (ddrval)) - { - ErrorF ("winDestroyColormapShadowDDNL - Failed freeing the " - "default colormap DirectDraw palette.\n"); - return FALSE; - } - - /* Clear our private installed colormap pointer */ - pScreenPriv->pcmapInstalled = NULL; - } - - /* Release the palette */ - IDirectDrawPalette_Release (pCmapPriv->lpDDPalette); - - /* Invalidate the colormap privates */ - pCmapPriv->lpDDPalette = NULL; - - return TRUE; -} - - -/* - * Set pointers to our engine specific functions - */ - -Bool -winSetEngineFunctionsShadowDDNL (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Set our pointers */ - pScreenPriv->pwinAllocateFB = winAllocateFBShadowDDNL; - pScreenPriv->pwinShadowUpdate = winShadowUpdateDDNL; - pScreenPriv->pwinCloseScreen = winCloseScreenShadowDDNL; - pScreenPriv->pwinInitVisuals = winInitVisualsShadowDDNL; - pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowDDNL; - if (pScreenInfo->fFullScreen) - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; - else - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; - pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; - pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDDNL; - pScreenPriv->pwinActivateApp = winActivateAppShadowDDNL; - pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDDNL; - pScreenPriv->pwinRealizeInstalledPalette - = winRealizeInstalledPaletteShadowDDNL; - pScreenPriv->pwinInstallColormap = winInstallColormapShadowDDNL; - pScreenPriv->pwinStoreColors = winStoreColorsShadowDDNL; - pScreenPriv->pwinCreateColormap = winCreateColormapShadowDDNL; - pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowDDNL; - pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; - pScreenPriv->pwinCreatePrimarySurface = winCreatePrimarySurfaceShadowDDNL; - pScreenPriv->pwinReleasePrimarySurface = winReleasePrimarySurfaceShadowDDNL; -#ifdef XWIN_MULTIWINDOW - pScreenPriv->pwinFinishCreateWindowsWindow - = winFinishCreateWindowsWindowDDNL; -#endif - - return TRUE; -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" + + +/* + * FIXME: Headers are broken, DEFINE_GUID doesn't work correctly, + * so we have to redefine it here. + */ +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#endif /* DEFINE_GUID */ + +/* + * FIXME: Headers are broken, IID_IDirectDraw4 has to be defined + * here manually. Should be handled by ddraw.h + */ +#ifndef IID_IDirectDraw4 +DEFINE_GUID( IID_IDirectDraw4, 0x9c59509a,0x39bd,0x11d1,0x8c,0x4a,0x00,0xc0,0x4f,0xd9,0x30,0xc5 ); +#endif /* IID_IDirectDraw4 */ + +#define FAIL_MSG_MAX_BLT 10 + + +/* + * Local prototypes + */ + +static Bool +winAllocateFBShadowDDNL (ScreenPtr pScreen); + +static void +winShadowUpdateDDNL (ScreenPtr pScreen, + shadowBufPtr pBuf); + +static Bool +winCloseScreenShadowDDNL (int nIndex, ScreenPtr pScreen); + +static Bool +winInitVisualsShadowDDNL (ScreenPtr pScreen); + +static Bool +winAdjustVideoModeShadowDDNL (ScreenPtr pScreen); + +static Bool +winBltExposedRegionsShadowDDNL (ScreenPtr pScreen); + +static Bool +winActivateAppShadowDDNL (ScreenPtr pScreen); + +static Bool +winRedrawScreenShadowDDNL (ScreenPtr pScreen); + +static Bool +winRealizeInstalledPaletteShadowDDNL (ScreenPtr pScreen); + +static Bool +winInstallColormapShadowDDNL (ColormapPtr pColormap); + +static Bool +winStoreColorsShadowDDNL (ColormapPtr pmap, + int ndef, + xColorItem *pdefs); + +static Bool +winCreateColormapShadowDDNL (ColormapPtr pColormap); + +static Bool +winDestroyColormapShadowDDNL (ColormapPtr pColormap); + +static Bool +winCreatePrimarySurfaceShadowDDNL (ScreenPtr pScreen); + +static Bool +winReleasePrimarySurfaceShadowDDNL (ScreenPtr pScreen); + + +/* + * Create the primary surface and attach the clipper. + * Used for both the initial surface creation and during + * WM_DISPLAYCHANGE messages. + */ + +static Bool +winCreatePrimarySurfaceShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + HRESULT ddrval = DD_OK; + DDSURFACEDESC2 ddsd; + + winDebug ("winCreatePrimarySurfaceShadowDDNL - Creating primary surface\n"); + + /* Describe the primary surface */ + ZeroMemory (&ddsd, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + /* Create the primary surface */ + ddrval = IDirectDraw4_CreateSurface (pScreenPriv->pdd4, + &ddsd, + &pScreenPriv->pddsPrimary4, + NULL); + pScreenPriv->fRetryCreateSurface = FALSE; + if (FAILED (ddrval)) + { + if (ddrval == DDERR_NOEXCLUSIVEMODE) + { + /* Recreating the surface failed. Mark screen to retry later */ + pScreenPriv->fRetryCreateSurface = TRUE; + winDebug ("winCreatePrimarySurfaceShadowDDNL - Could not create " + "primary surface: DDERR_NOEXCLUSIVEMODE\n"); + } + else + { + ErrorF ("winCreatePrimarySurfaceShadowDDNL - Could not create " + "primary surface: %08x\n", (unsigned int) ddrval); + } + return FALSE; + } + +#if 1 + winDebug ("winCreatePrimarySurfaceShadowDDNL - Created primary surface\n"); +#endif + + /* Attach our clipper to our primary surface handle */ + ddrval = IDirectDrawSurface4_SetClipper (pScreenPriv->pddsPrimary4, + pScreenPriv->pddcPrimary); + if (FAILED (ddrval)) + { + ErrorF ("winCreatePrimarySurfaceShadowDDNL - Primary attach clipper " + "failed: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if 1 + winDebug ("winCreatePrimarySurfaceShadowDDNL - Attached clipper to primary " + "surface\n"); +#endif + + /* Everything was correct */ + return TRUE; +} + + +/* + * Detach the clipper and release the primary surface. + * Called from WM_DISPLAYCHANGE. + */ + +static Bool +winReleasePrimarySurfaceShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + winDebug ("winReleasePrimarySurfaceShadowDDNL - Hello\n"); + + /* Release the primary surface and clipper, if they exist */ + if (pScreenPriv->pddsPrimary4) + { + /* + * Detach the clipper from the primary surface. + * NOTE: We do this explicity for clarity. The Clipper is not released. + */ + IDirectDrawSurface4_SetClipper (pScreenPriv->pddsPrimary4, + NULL); + + winDebug ("winReleasePrimarySurfaceShadowDDNL - Detached clipper\n"); + + /* Release the primary surface */ + IDirectDrawSurface4_Release (pScreenPriv->pddsPrimary4); + pScreenPriv->pddsPrimary4 = NULL; + } + + winDebug ("winReleasePrimarySurfaceShadowDDNL - Released primary surface\n"); + + return TRUE; +} + + +/* + * Create a DirectDraw surface for the shadow framebuffer; also create + * a primary surface object so we can blit to the display. + * + * Install a DirectDraw clipper on our primary surface object + * that clips our blits to the unobscured client area of our display window. + */ + +Bool +winAllocateFBShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HRESULT ddrval = DD_OK; + DDSURFACEDESC2 ddsdShadow; + char *lpSurface = NULL; + DDPIXELFORMAT ddpfPrimary; + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDDNL - w %d h %d d %d\n", + pScreenInfo->dwWidth, pScreenInfo->dwHeight, pScreenInfo->dwDepth); +#endif + + /* Set the padded screen width */ + pScreenInfo->dwPaddedWidth = PixmapBytePad (pScreenInfo->dwWidth, + pScreenInfo->dwBPP); + + /* Allocate memory for our shadow surface */ + lpSurface = malloc (pScreenInfo->dwPaddedWidth * pScreenInfo->dwHeight); + if (lpSurface == NULL) + { + ErrorF ("winAllocateFBShadowDDNL - Could not allocate bits\n"); + return FALSE; + } + + /* + * Initialize the framebuffer memory so we don't get a + * strange display at startup + */ + ZeroMemory (lpSurface, pScreenInfo->dwPaddedWidth * pScreenInfo->dwHeight); + + /* Create a clipper */ + ddrval = (*g_fpDirectDrawCreateClipper) (0, + &pScreenPriv->pddcPrimary, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not attach clipper: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDDNL - Created a clipper\n"); +#endif + + /* Attach the clipper to our display window */ + ddrval = IDirectDrawClipper_SetHWnd (pScreenPriv->pddcPrimary, + 0, + pScreenPriv->hwndScreen); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Clipper not attached " + "to window: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDDNL - Attached clipper to window\n"); +#endif + + /* Create a DirectDraw object, store the address at lpdd */ + ddrval = (*g_fpDirectDrawCreate) (NULL, + (LPDIRECTDRAW*) &pScreenPriv->pdd, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not start " + "DirectDraw: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDDNL - Created and initialized DD\n"); +#endif + + /* Get a DirectDraw4 interface pointer */ + ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, + &IID_IDirectDraw4, + (LPVOID*) &pScreenPriv->pdd4); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Failed DD4 query: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + + /* Are we full screen? */ + if (pScreenInfo->fFullScreen) + { + DDSURFACEDESC2 ddsdCurrent; + DWORD dwRefreshRateCurrent = 0; + HDC hdc = NULL; + + /* Set the cooperative level to full screen */ + ddrval = IDirectDraw4_SetCooperativeLevel (pScreenPriv->pdd4, + pScreenPriv->hwndScreen, + DDSCL_EXCLUSIVE + | DDSCL_FULLSCREEN); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not set " + "cooperative level: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + + /* + * We only need to get the current refresh rate for comparison + * if a refresh rate has been passed on the command line. + */ + if (pScreenInfo->dwRefreshRate != 0) + { + ZeroMemory (&ddsdCurrent, sizeof (ddsdCurrent)); + ddsdCurrent.dwSize = sizeof (ddsdCurrent); + + /* Get information about current display settings */ + ddrval = IDirectDraw4_GetDisplayMode (pScreenPriv->pdd4, + &ddsdCurrent); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not get current " + "refresh rate: %08x. Continuing.\n", + (unsigned int) ddrval); + dwRefreshRateCurrent = 0; + } + else + { + /* Grab the current refresh rate */ + dwRefreshRateCurrent = ddsdCurrent.u2.dwRefreshRate; + } + } + + /* Clean up the refresh rate */ + if (dwRefreshRateCurrent == pScreenInfo->dwRefreshRate) + { + /* + * Refresh rate is non-specified or equal to current. + */ + pScreenInfo->dwRefreshRate = 0; + } + + /* Grab a device context for the screen */ + hdc = GetDC (NULL); + if (hdc == NULL) + { + ErrorF ("winAllocateFBShadowDDNL - GetDC () failed\n"); + return FALSE; + } + + /* Only change the video mode when different than current mode */ + if (!pScreenInfo->fMultipleMonitors + && (pScreenInfo->dwWidth != GetSystemMetrics (SM_CXSCREEN) + || pScreenInfo->dwHeight != GetSystemMetrics (SM_CYSCREEN) + || pScreenInfo->dwBPP != GetDeviceCaps (hdc, BITSPIXEL) + || pScreenInfo->dwRefreshRate != 0)) + { + winDebug ("winAllocateFBShadowDDNL - Changing video mode\n"); + + /* Change the video mode to the mode requested, and use the driver default refresh rate on failure */ + ddrval = IDirectDraw4_SetDisplayMode (pScreenPriv->pdd4, + pScreenInfo->dwWidth, + pScreenInfo->dwHeight, + pScreenInfo->dwBPP, + pScreenInfo->dwRefreshRate, + 0); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not set " + "full screen display mode: %08x\n", + (unsigned int) ddrval); + ErrorF ("winAllocateFBShadowDDNL - Using default driver refresh rate\n"); + ddrval = IDirectDraw4_SetDisplayMode (pScreenPriv->pdd4, + pScreenInfo->dwWidth, + pScreenInfo->dwHeight, + pScreenInfo->dwBPP, + 0, + 0); + if (FAILED(ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not set default refresh rate " + "full screen display mode: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + } + } + else + { + winDebug ("winAllocateFBShadowDDNL - Not changing video mode\n"); + } + + /* Release our DC */ + ReleaseDC (NULL, hdc); + hdc = NULL; + } + else + { + /* Set the cooperative level for windowed mode */ + ddrval = IDirectDraw4_SetCooperativeLevel (pScreenPriv->pdd4, + pScreenPriv->hwndScreen, + DDSCL_NORMAL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not set " + "cooperative level: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + } + + /* Create the primary surface */ + if (!winCreatePrimarySurfaceShadowDDNL (pScreen)) + { + ErrorF ("winAllocateFBShadowDDNL - winCreatePrimarySurfaceShadowDDNL " + "failed\n"); + return FALSE; + } + + /* Get primary surface's pixel format */ + ZeroMemory (&ddpfPrimary, sizeof (ddpfPrimary)); + ddpfPrimary.dwSize = sizeof (ddpfPrimary); + ddrval = IDirectDrawSurface4_GetPixelFormat (pScreenPriv->pddsPrimary4, + &ddpfPrimary); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not get primary " + "pixformat: %08x\n", + (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDDNL - Primary masks: %08x %08x %08x " + "dwRGBBitCount: %d\n", + ddpfPrimary.u2.dwRBitMask, + ddpfPrimary.u3.dwGBitMask, + ddpfPrimary.u4.dwBBitMask, + ddpfPrimary.u1.dwRGBBitCount); +#endif + + /* Describe the shadow surface to be created */ + /* + * NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, + * as drawing, locking, and unlocking take forever + * with video memory surfaces. In addition, + * video memory is a somewhat scarce resource, + * so you shouldn't be allocating video memory when + * you have the option of using system memory instead. + */ + ZeroMemory (&ddsdShadow, sizeof (ddsdShadow)); + ddsdShadow.dwSize = sizeof (ddsdShadow); + ddsdShadow.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH + | DDSD_LPSURFACE | DDSD_PITCH | DDSD_PIXELFORMAT; + ddsdShadow.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + ddsdShadow.dwHeight = pScreenInfo->dwHeight; + ddsdShadow.dwWidth = pScreenInfo->dwWidth; + ddsdShadow.u1.lPitch = pScreenInfo->dwPaddedWidth; + ddsdShadow.lpSurface = lpSurface; + ddsdShadow.u4.ddpfPixelFormat = ddpfPrimary; + + winDebug ("winAllocateFBShadowDDNL - lPitch: %d\n", + (int) pScreenInfo->dwPaddedWidth); + + /* Create the shadow surface */ + ddrval = IDirectDraw4_CreateSurface (pScreenPriv->pdd4, + &ddsdShadow, + &pScreenPriv->pddsShadow4, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winAllocateFBShadowDDNL - Could not create shadow " + "surface: %08x\n", (unsigned int) ddrval); + return FALSE; + } + +#if CYGDEBUG || YES + winDebug ("winAllocateFBShadowDDNL - Created shadow pitch: %d\n", + (int) ddsdShadow.u1.lPitch); +#endif + + /* Grab the pitch from the surface desc */ + pScreenInfo->dwStride = (ddsdShadow.u1.lPitch * 8) + / pScreenInfo->dwBPP; + +#if CYGDEBUG || YES + winDebug ("winAllocateFBShadowDDNL - Created shadow stride: %d\n", + (int) pScreenInfo->dwStride); +#endif + + /* Save the pointer to our surface memory */ + pScreenInfo->pfb = lpSurface; + + /* Grab the masks from the surface description */ + pScreenPriv->dwRedMask = ddsdShadow.u4.ddpfPixelFormat.u2.dwRBitMask; + pScreenPriv->dwGreenMask = ddsdShadow.u4.ddpfPixelFormat.u3.dwGBitMask; + pScreenPriv->dwBlueMask = ddsdShadow.u4.ddpfPixelFormat.u4.dwBBitMask; + +#if CYGDEBUG + winDebug ("winAllocateFBShadowDDNL - Returning\n"); +#endif + + return TRUE; +} + +static void +winFreeFBShadowDDNL(ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Free the shadow surface, if there is one */ + if (pScreenPriv->pddsShadow4) + { + IDirectDrawSurface4_Release (pScreenPriv->pddsShadow4); + free (pScreenInfo->pfb); + pScreenInfo->pfb = NULL; + pScreenPriv->pddsShadow4 = NULL; + } + + /* Detach the clipper from the primary surface and release the primary surface, if there is one */ + winReleasePrimarySurfaceShadowDDNL(pScreen); + + /* Release the clipper object */ + if (pScreenPriv->pddcPrimary) + { + IDirectDrawClipper_Release (pScreenPriv->pddcPrimary); + pScreenPriv->pddcPrimary = NULL; + } + + /* Free the DirectDraw4 object, if there is one */ + if (pScreenPriv->pdd4) + { + IDirectDraw4_RestoreDisplayMode (pScreenPriv->pdd4); + IDirectDraw4_Release (pScreenPriv->pdd4); + pScreenPriv->pdd4 = NULL; + } + + /* Free the DirectDraw object, if there is one */ + if (pScreenPriv->pdd) + { + IDirectDraw_Release (pScreenPriv->pdd); + pScreenPriv->pdd = NULL; + } + + /* Invalidate the ScreenInfo's fb pointer */ + pScreenInfo->pfb = NULL; +} + +#if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) +/* + * Create a DirectDraw surface for the new multi-window window + */ + +static +Bool +winFinishCreateWindowsWindowDDNL (WindowPtr pWin) +{ + winWindowPriv(pWin); + winPrivScreenPtr pScreenPriv = pWinPriv->pScreenPriv; + HRESULT ddrval = DD_OK; + DDSURFACEDESC2 ddsd; + int iWidth, iHeight; + int iX, iY; + + winDebug ("winFinishCreateWindowsWindowDDNL!\n\n"); + + iX = pWin->drawable.x + GetSystemMetrics (SM_XVIRTUALSCREEN); + iY = pWin->drawable.y + GetSystemMetrics (SM_YVIRTUALSCREEN); + + iWidth = pWin->drawable.width; + iHeight = pWin->drawable.height; + + /* Describe the primary surface */ + ZeroMemory (&ddsd, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddsd.dwHeight = iHeight; + ddsd.dwWidth = iWidth; + + /* Create the primary surface */ + ddrval = IDirectDraw4_CreateSurface (pScreenPriv->pdd4, + &ddsd, + &pWinPriv->pddsPrimary4, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winFinishCreateWindowsWindowDDNL - Could not create primary " + "surface: %08x\n", + (unsigned int)ddrval); + return FALSE; + } + return TRUE; +} +#endif + + +/* + * Transfer the damaged regions of the shadow framebuffer to the display. + */ + +static void +winShadowUpdateDDNL (ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RegionPtr damage = shadowDamage(pBuf); + HRESULT ddrval = DD_OK; + RECT rcDest, rcSrc; + POINT ptOrigin; + DWORD dwBox = RegionNumRects (damage); + BoxPtr pBox = RegionRects (damage); + HRGN hrgnTemp = NULL, hrgnCombined = NULL; + + /* + * Return immediately if the app is not active + * and we are fullscreen, or if we have a bad display depth + */ + if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen) + || pScreenPriv->fBadDepth) return; + + /* Return immediately if we didn't get needed surfaces */ + if (!pScreenPriv->pddsPrimary4 || !pScreenPriv->pddsShadow4) + return; + + /* Get the origin of the window in the screen coords */ + ptOrigin.x = pScreenInfo->dwXOffset; + ptOrigin.y = pScreenInfo->dwYOffset; + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&ptOrigin, 1); + + /* + * Handle small regions with multiple blits, + * handle large regions by creating a clipping region and + * doing a single blit constrained to that clipping region. + */ + if (pScreenInfo->dwClipUpdatesNBoxes == 0 + || dwBox < pScreenInfo->dwClipUpdatesNBoxes) + { + /* Loop through all boxes in the damaged region */ + while (dwBox--) + { + /* Assign damage box to source rectangle */ + rcSrc.left = pBox->x1; + rcSrc.top = pBox->y1; + rcSrc.right = pBox->x2; + rcSrc.bottom = pBox->y2; + + /* Calculate destination rectangle */ + rcDest.left = ptOrigin.x + rcSrc.left; + rcDest.top = ptOrigin.y + rcSrc.top; + rcDest.right = ptOrigin.x + rcSrc.right; + rcDest.bottom = ptOrigin.y + rcSrc.bottom; + + /* Blit the damaged areas */ + ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, + &rcDest, + pScreenPriv->pddsShadow4, + &rcSrc, + DDBLT_WAIT, + NULL); + if (FAILED (ddrval)) + { + static int s_iFailCount = 0; + + if (s_iFailCount < FAIL_MSG_MAX_BLT) + { + ErrorF ("winShadowUpdateDDNL - IDirectDrawSurface4_Blt () " + "failed: %08x\n", + (unsigned int) ddrval); + + ++s_iFailCount; + + if (s_iFailCount == FAIL_MSG_MAX_BLT) + { + ErrorF ("winShadowUpdateDDNL - IDirectDrawSurface4_Blt " + "failure message maximum (%d) reached. No " + "more failure messages will be printed.\n", + FAIL_MSG_MAX_BLT); + } + } + } + + /* Get a pointer to the next box */ + ++pBox; + } + } + else + { + BoxPtr pBoxExtents = RegionExtents(damage); + + /* Compute a GDI region from the damaged region */ + hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); + dwBox--; + pBox++; + while (dwBox--) + { + hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); + CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR); + DeleteObject (hrgnTemp); + pBox++; + } + + /* Install the GDI region as a clipping region */ + SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined); + DeleteObject (hrgnCombined); + hrgnCombined = NULL; + +#if CYGDEBUG + winDebug ("winShadowUpdateDDNL - be x1 %d y1 %d x2 %d y2 %d\n", + pBoxExtents->x1, pBoxExtents->y1, + pBoxExtents->x2, pBoxExtents->y2); +#endif + + /* Calculating a bounding box for the source is easy */ + rcSrc.left = pBoxExtents->x1; + rcSrc.top = pBoxExtents->y1; + rcSrc.right = pBoxExtents->x2; + rcSrc.bottom = pBoxExtents->y2; + + /* Calculating a bounding box for the destination is trickier */ + rcDest.left = ptOrigin.x + rcSrc.left; + rcDest.top = ptOrigin.y + rcSrc.top; + rcDest.right = ptOrigin.x + rcSrc.right; + rcDest.bottom = ptOrigin.y + rcSrc.bottom; + + /* Our Blt should be clipped to the invalidated region */ + ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, + &rcDest, + pScreenPriv->pddsShadow4, + &rcSrc, + DDBLT_WAIT, + NULL); + + /* Reset the clip region */ + SelectClipRgn (pScreenPriv->hdcScreen, NULL); + } +} + +static Bool +winInitScreenShadowDDNL(ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + /* Get a device context for the screen */ + pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); + + return winAllocateFBShadowDDNL(pScreen); +} + +/* + * Call the wrapped CloseScreen function. + * + * Free our resources and private structures. + */ + +static Bool +winCloseScreenShadowDDNL (int nIndex, ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + Bool fReturn; + +#if CYGDEBUG + winDebug ("winCloseScreenShadowDDNL - Freeing screen resources\n"); +#endif + + /* Flag that the screen is closed */ + pScreenPriv->fClosed = TRUE; + pScreenPriv->fActive = FALSE; + + /* Call the wrapped CloseScreen procedure */ + WIN_UNWRAP(CloseScreen); + fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); + + winFreeFBShadowDDNL(pScreen); + + /* Free the screen DC */ + ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen); + + /* Delete the window property */ + RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); + + /* Delete tray icon, if we have one */ + if (!pScreenInfo->fNoTrayIcon) + winDeleteNotifyIcon (pScreenPriv); + + /* Free the exit confirmation dialog box, if it exists */ + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + + /* Kill our window */ + if (pScreenPriv->hwndScreen) + { + DestroyWindow (pScreenPriv->hwndScreen); + pScreenPriv->hwndScreen = NULL; + } + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + /* Destroy the thread startup mutex */ + pthread_mutex_destroy (&pScreenPriv->pmServerStarted); +#endif + + /* Kill our screeninfo's pointer to the screen */ + pScreenInfo->pScreen = NULL; + + /* Free the screen privates for this screen */ + free ((pointer) pScreenPriv); + + return fReturn; +} + + +/* + * Tell mi what sort of visuals we need. + * + * Generally we only need one visual, as our screen can only + * handle one format at a time, I believe. You may want + * to verify that last sentence. + */ + +static Bool +winInitVisualsShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + DWORD dwRedBits, dwGreenBits, dwBlueBits; + + /* Count the number of ones in each color mask */ + dwRedBits = winCountBits (pScreenPriv->dwRedMask); + dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); + dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); + + /* Store the maximum number of ones in a color mask as the bitsPerRGB */ + if (dwRedBits == 0 || dwGreenBits == 0 || dwBlueBits == 0) + pScreenPriv->dwBitsPerRGB = 8; + else if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwRedBits; + else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwGreenBits; + else + pScreenPriv->dwBitsPerRGB = dwBlueBits; + + winDebug ("winInitVisualsShadowDDNL - Masks %08x %08x %08x BPRGB %d d %d " + "bpp %d\n", + (unsigned int) pScreenPriv->dwRedMask, + (unsigned int) pScreenPriv->dwGreenMask, + (unsigned int) pScreenPriv->dwBlueMask, + (int) pScreenPriv->dwBitsPerRGB, + (int) pScreenInfo->dwDepth, + (int) pScreenInfo->dwBPP); + + /* Create a single visual according to the Windows screen depth */ + switch (pScreenInfo->dwDepth) + { + case 24: + case 16: + case 15: + /* Setup the real visual */ + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + TrueColorMask, + pScreenPriv->dwBitsPerRGB, + -1, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsShadowDDNL - miSetVisualTypesAndMasks " + "failed for TrueColor\n"); + return FALSE; + } + +#ifdef XWIN_EMULATEPSEUDO + if (!pScreenInfo->fEmulatePseudo) + break; + + /* Setup a pseudocolor visual */ + if (!miSetVisualTypesAndMasks (8, + PseudoColorMask, + 8, + -1, + 0, + 0, + 0)) + { + ErrorF ("winInitVisualsShadowDDNL - miSetVisualTypesAndMasks " + "failed for PseudoColor\n"); + return FALSE; + } +#endif + break; + + case 8: + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + pScreenInfo->fFullScreen + ? PseudoColorMask : StaticColorMask, + pScreenPriv->dwBitsPerRGB, + pScreenInfo->fFullScreen + ? PseudoColor : StaticColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsShadowDDNL - miSetVisualTypesAndMasks " + "failed\n"); + return FALSE; + } + break; + + default: + ErrorF ("winInitVisualsShadowDDNL - Unknown screen depth\n"); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winInitVisualsShadowDDNL - Returning\n"); +#endif + + return TRUE; +} + + +/* + * Adjust the user proposed video mode + */ + +static Bool +winAdjustVideoModeShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HDC hdc = NULL; + DWORD dwBPP; + + /* We're in serious trouble if we can't get a DC */ + hdc = GetDC (NULL); + if (hdc == NULL) + { + ErrorF ("winAdjustVideoModeShadowDDNL - GetDC () failed\n"); + return FALSE; + } + + /* Query GDI for current display depth */ + dwBPP = GetDeviceCaps (hdc, BITSPIXEL); + + /* DirectDraw can only change the depth in fullscreen mode */ + if (!(pScreenInfo->fFullScreen && + (pScreenInfo->dwBPP != WIN_DEFAULT_BPP))) + { + /* Otherwise, We'll use GDI's depth */ + pScreenInfo->dwBPP = dwBPP; + } + + /* Release our DC */ + ReleaseDC (NULL, hdc); + + return TRUE; +} + + +/* + * Blt exposed regions to the screen + */ + +static Bool +winBltExposedRegionsShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RECT rcSrc, rcDest; + POINT ptOrigin; + HDC hdcUpdate; + PAINTSTRUCT ps; + HRESULT ddrval = DD_OK; + Bool fReturn = TRUE; + int i; + + /* Quite common case. The primary surface was lost (maybe because of depth + * change). Try to create a new primary surface. Bail out if this fails */ + if (pScreenPriv->pddsPrimary4 == NULL && pScreenPriv->fRetryCreateSurface && + !winCreatePrimarySurfaceShadowDDNL(pScreen)) + { + Sleep(100); + return FALSE; + } + if (pScreenPriv->pddsPrimary4 == NULL) + return FALSE; + + /* BeginPaint gives us an hdc that clips to the invalidated region */ + hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps); + if (hdcUpdate == NULL) + { + fReturn = FALSE; + ErrorF ("winBltExposedRegionsShadowDDNL - BeginPaint () returned " + "a NULL device context handle. Aborting blit attempt.\n"); + goto winBltExposedRegionsShadowDDNL_Exit; + } + + /* Get the origin of the window in the screen coords */ + ptOrigin.x = pScreenInfo->dwXOffset; + ptOrigin.y = pScreenInfo->dwYOffset; + + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&ptOrigin, 1); + rcDest.left = ptOrigin.x; + rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; + rcDest.top = ptOrigin.y; + rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; + + /* Source can be entire shadow surface, as Blt should clip for us */ + rcSrc.left = 0; + rcSrc.top = 0; + rcSrc.right = pScreenInfo->dwWidth; + rcSrc.bottom = pScreenInfo->dwHeight; + + /* Try to regain the primary surface and blit again if we've lost it */ + for (i = 0; i <= WIN_REGAIN_SURFACE_RETRIES; ++i) + { + /* Our Blt should be clipped to the invalidated region */ + ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, + &rcDest, + pScreenPriv->pddsShadow4, + &rcSrc, + DDBLT_WAIT, + NULL); + if (ddrval == DDERR_SURFACELOST) + { + /* Surface was lost */ + winErrorFVerb (1, "winBltExposedRegionsShadowDDNL - " + "IDirectDrawSurface4_Blt reported that the primary " + "surface was lost, trying to restore, retry: %d\n", i + 1); + + /* Try to restore the surface, once */ + + ddrval = IDirectDrawSurface4_Restore (pScreenPriv->pddsPrimary4); + winDebug ("winBltExposedRegionsShadowDDNL - " + "IDirectDrawSurface4_Restore returned: "); + if (ddrval == DD_OK) + winDebug ("DD_OK\n"); + else if (ddrval == DDERR_WRONGMODE) + winDebug ("DDERR_WRONGMODE\n"); + else if (ddrval == DDERR_INCOMPATIBLEPRIMARY) + winDebug ("DDERR_INCOMPATIBLEPRIMARY\n"); + else if (ddrval == DDERR_UNSUPPORTED) + winDebug ("DDERR_UNSUPPORTED\n"); + else if (ddrval == DDERR_INVALIDPARAMS) + winDebug ("DDERR_INVALIDPARAMS\n"); + else if (ddrval == DDERR_INVALIDOBJECT) + winDebug ("DDERR_INVALIDOBJECT\n"); + else + winDebug ("unknown error: %08x\n", (unsigned int) ddrval); + + /* Loop around to try the blit one more time */ + continue; + } + else if (FAILED (ddrval)) + { + fReturn = FALSE; + winErrorFVerb (1, "winBltExposedRegionsShadowDDNL - " + "IDirectDrawSurface4_Blt failed, but surface not " + "lost: %08x %d\n", + (unsigned int) ddrval, (int) ddrval); + goto winBltExposedRegionsShadowDDNL_Exit; + } + else + { + /* Success, stop looping */ + break; + } + } + + winBltExposedRegionsShadowDDNL_Exit: + /* EndPaint frees the DC */ + if (hdcUpdate != NULL) + EndPaint (pScreenPriv->hwndScreen, &ps); + return fReturn; +} + + +/* + * Do any engine-specific application-activation processing + */ + +static Bool +winActivateAppShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + /* + * Do we have a surface? + * Are we active? + * Are we full screen? + */ + if (pScreenPriv != NULL + && pScreenPriv->pddsPrimary4 != NULL + && pScreenPriv->fActive) + { + /* Primary surface was lost, restore it */ + IDirectDrawSurface4_Restore (pScreenPriv->pddsPrimary4); + } + + return TRUE; +} + + +/* + * Reblit the shadow framebuffer to the screen. + */ + +static Bool +winRedrawScreenShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HRESULT ddrval = DD_OK; + RECT rcSrc, rcDest; + POINT ptOrigin; + + /* Get the origin of the window in the screen coords */ + ptOrigin.x = pScreenInfo->dwXOffset; + ptOrigin.y = pScreenInfo->dwYOffset; + MapWindowPoints (pScreenPriv->hwndScreen, + HWND_DESKTOP, + (LPPOINT)&ptOrigin, 1); + rcDest.left = ptOrigin.x; + rcDest.right = ptOrigin.x + pScreenInfo->dwWidth; + rcDest.top = ptOrigin.y; + rcDest.bottom = ptOrigin.y + pScreenInfo->dwHeight; + + /* Source can be entire shadow surface, as Blt should clip for us */ + rcSrc.left = 0; + rcSrc.top = 0; + rcSrc.right = pScreenInfo->dwWidth; + rcSrc.bottom = pScreenInfo->dwHeight; + + /* Redraw the whole window, to take account for the new colors */ + ddrval = IDirectDrawSurface4_Blt (pScreenPriv->pddsPrimary4, + &rcDest, + pScreenPriv->pddsShadow4, + &rcSrc, + DDBLT_WAIT, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winRedrawScreenShadowDDNL - IDirectDrawSurface4_Blt () " + "failed: %08x\n", + (unsigned int) ddrval); + } + + return TRUE; +} + + +/* + * Realize the currently installed colormap + */ + +static Bool +winRealizeInstalledPaletteShadowDDNL (ScreenPtr pScreen) +{ + return TRUE; +} + + +/* + * Install the specified colormap + */ + +static Bool +winInstallColormapShadowDDNL (ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + HRESULT ddrval = DD_OK; + + /* Install the DirectDraw palette on the primary surface */ + ddrval = IDirectDrawSurface4_SetPalette (pScreenPriv->pddsPrimary4, + pCmapPriv->lpDDPalette); + if (FAILED (ddrval)) + { + ErrorF ("winInstallColormapShadowDDNL - Failed installing the " + "DirectDraw palette.\n"); + return FALSE; + } + + /* Save a pointer to the newly installed colormap */ + pScreenPriv->pcmapInstalled = pColormap; + + return TRUE; +} + + +/* + * Store the specified colors in the specified colormap + */ + +static Bool +winStoreColorsShadowDDNL (ColormapPtr pColormap, + int ndef, + xColorItem *pdefs) +{ + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + ColormapPtr curpmap = pScreenPriv->pcmapInstalled; + HRESULT ddrval = DD_OK; + + /* Put the X colormap entries into the Windows logical palette */ + ddrval = IDirectDrawPalette_SetEntries (pCmapPriv->lpDDPalette, + 0, + pdefs[0].pixel, + ndef, + pCmapPriv->peColors + + pdefs[0].pixel); + if (FAILED (ddrval)) + { + ErrorF ("winStoreColorsShadowDDNL - SetEntries () failed: %08x\n", (unsigned int) ddrval); + return FALSE; + } + + /* Don't install the DirectDraw palette if the colormap is not installed */ + if (pColormap != curpmap) + { + return TRUE; + } + + if (!winInstallColormapShadowDDNL (pColormap)) + { + ErrorF ("winStoreColorsShadowDDNL - Failed installing colormap\n"); + return FALSE; + } + + return TRUE; +} + + +/* + * Colormap initialization procedure + */ + +static Bool +winCreateColormapShadowDDNL (ColormapPtr pColormap) +{ + HRESULT ddrval = DD_OK; + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + + /* Create a DirectDraw palette */ + ddrval = IDirectDraw4_CreatePalette (pScreenPriv->pdd4, + DDPCAPS_8BIT | DDPCAPS_ALLOW256, + pCmapPriv->peColors, + &pCmapPriv->lpDDPalette, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winCreateColormapShadowDDNL - CreatePalette failed\n"); + return FALSE; + } + + return TRUE; +} + + +/* + * Colormap destruction procedure + */ + +static Bool +winDestroyColormapShadowDDNL (ColormapPtr pColormap) +{ + winScreenPriv(pColormap->pScreen); + winCmapPriv(pColormap); + HRESULT ddrval = DD_OK; + + /* + * Is colormap to be destroyed the default? + * + * Non-default colormaps should have had winUninstallColormap + * called on them before we get here. The default colormap + * will not have had winUninstallColormap called on it. Thus, + * we need to handle the default colormap in a special way. + */ + if (pColormap->flags & IsDefault) + { +#if CYGDEBUG + winDebug ("winDestroyColormapShadowDDNL - Destroying default colormap\n"); +#endif + + /* + * FIXME: Walk the list of all screens, popping the default + * palette out of each screen device context. + */ + + /* Pop the palette out of the primary surface */ + ddrval = IDirectDrawSurface4_SetPalette (pScreenPriv->pddsPrimary4, + NULL); + if (FAILED (ddrval)) + { + ErrorF ("winDestroyColormapShadowDDNL - Failed freeing the " + "default colormap DirectDraw palette.\n"); + return FALSE; + } + + /* Clear our private installed colormap pointer */ + pScreenPriv->pcmapInstalled = NULL; + } + + /* Release the palette */ + IDirectDrawPalette_Release (pCmapPriv->lpDDPalette); + + /* Invalidate the colormap privates */ + pCmapPriv->lpDDPalette = NULL; + + return TRUE; +} + + +/* + * Set pointers to our engine specific functions + */ + +Bool +winSetEngineFunctionsShadowDDNL (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Set our pointers */ + pScreenPriv->pwinAllocateFB = winAllocateFBShadowDDNL; + pScreenPriv->pwinFreeFB = winFreeFBShadowDDNL; + pScreenPriv->pwinShadowUpdate = winShadowUpdateDDNL; + pScreenPriv->pwinInitScreen = winInitScreenShadowDDNL; + pScreenPriv->pwinCloseScreen = winCloseScreenShadowDDNL; + pScreenPriv->pwinInitVisuals = winInitVisualsShadowDDNL; + pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowDDNL; + if (pScreenInfo->fFullScreen) + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; + else + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; + pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; + pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDDNL; + pScreenPriv->pwinActivateApp = winActivateAppShadowDDNL; + pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDDNL; + pScreenPriv->pwinRealizeInstalledPalette + = winRealizeInstalledPaletteShadowDDNL; + pScreenPriv->pwinInstallColormap = winInstallColormapShadowDDNL; + pScreenPriv->pwinStoreColors = winStoreColorsShadowDDNL; + pScreenPriv->pwinCreateColormap = winCreateColormapShadowDDNL; + pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowDDNL; + pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinCreatePrimarySurface = winCreatePrimarySurfaceShadowDDNL; + pScreenPriv->pwinReleasePrimarySurface = winReleasePrimarySurfaceShadowDDNL; +#ifdef XWIN_MULTIWINDOW + pScreenPriv->pwinFinishCreateWindowsWindow + = winFinishCreateWindowsWindowDDNL; +#endif + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winshadgdi.c b/xorg-server/hw/xwin/winshadgdi.c index 4f36547f9..499037656 100644 --- a/xorg-server/hw/xwin/winshadgdi.c +++ b/xorg-server/hw/xwin/winshadgdi.c @@ -1,1267 +1,1259 @@ -/* - *Copyright (C) 2001-2004 Harold L Hunt II All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of Harold L Hunt II - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. - * - * Authors: Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" - - -/* - * Local function prototypes - */ - -#ifdef XWIN_MULTIWINDOW -static wBOOL CALLBACK -winRedrawAllProcShadowGDI (HWND hwnd, LPARAM lParam); - -static wBOOL CALLBACK -winRedrawDamagedWindowShadowGDI (HWND hwnd, LPARAM lParam); -#endif - -static Bool -winAllocateFBShadowGDI (ScreenPtr pScreen); - -static void -winShadowUpdateGDI (ScreenPtr pScreen, - shadowBufPtr pBuf); - -static Bool -winCloseScreenShadowGDI (int nIndex, ScreenPtr pScreen); - -static Bool -winInitVisualsShadowGDI (ScreenPtr pScreen); - -static Bool -winAdjustVideoModeShadowGDI (ScreenPtr pScreen); - -static Bool -winBltExposedRegionsShadowGDI (ScreenPtr pScreen); - -static Bool -winActivateAppShadowGDI (ScreenPtr pScreen); - -static Bool -winRedrawScreenShadowGDI (ScreenPtr pScreen); - -static Bool -winRealizeInstalledPaletteShadowGDI (ScreenPtr pScreen); - -static Bool -winInstallColormapShadowGDI (ColormapPtr pColormap); - -static Bool -winStoreColorsShadowGDI (ColormapPtr pmap, - int ndef, - xColorItem *pdefs); - -static Bool -winCreateColormapShadowGDI (ColormapPtr pColormap); - -static Bool -winDestroyColormapShadowGDI (ColormapPtr pColormap); - - -/* - * Internal function to get the DIB format that is compatible with the screen - */ - -static -Bool -winQueryScreenDIBFormat (ScreenPtr pScreen, BITMAPINFOHEADER *pbmih) -{ - winScreenPriv(pScreen); - HBITMAP hbmp; -#if CYGDEBUG - LPDWORD pdw = NULL; -#endif - - /* Create a memory bitmap compatible with the screen */ - hbmp = CreateCompatibleBitmap (pScreenPriv->hdcScreen, 1, 1); - if (hbmp == NULL) - { - ErrorF ("winQueryScreenDIBFormat - CreateCompatibleBitmap failed\n"); - return FALSE; - } - - /* Initialize our bitmap info header */ - ZeroMemory (pbmih, sizeof (BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD)); - pbmih->biSize = sizeof (BITMAPINFOHEADER); - - /* Get the biBitCount */ - if (!GetDIBits (pScreenPriv->hdcScreen, - hbmp, - 0, 1, - NULL, - (BITMAPINFO*) pbmih, - DIB_RGB_COLORS)) - { - ErrorF ("winQueryScreenDIBFormat - First call to GetDIBits failed\n"); - DeleteObject (hbmp); - return FALSE; - } - -#if CYGDEBUG - /* Get a pointer to bitfields */ - pdw = (DWORD*) ((CARD8*)pbmih + sizeof (BITMAPINFOHEADER)); - - winDebug ("winQueryScreenDIBFormat - First call masks: %08x %08x %08x\n", - pdw[0], pdw[1], pdw[2]); -#endif - - /* Get optimal color table, or the optimal bitfields */ - if (!GetDIBits (pScreenPriv->hdcScreen, - hbmp, - 0, 1, - NULL, - (BITMAPINFO*)pbmih, - DIB_RGB_COLORS)) - { - ErrorF ("winQueryScreenDIBFormat - Second call to GetDIBits " - "failed\n"); - DeleteObject (hbmp); - return FALSE; - } - - /* Free memory */ - DeleteObject (hbmp); - - return TRUE; -} - - -/* - * Internal function to determine the GDI bits per rgb and bit masks - */ - -static -Bool -winQueryRGBBitsAndMasks (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - BITMAPINFOHEADER *pbmih = NULL; - Bool fReturn = TRUE; - LPDWORD pdw = NULL; - DWORD dwRedBits, dwGreenBits, dwBlueBits; - - /* Color masks for 8 bpp are standardized */ - if (GetDeviceCaps (pScreenPriv->hdcScreen, RASTERCAPS) & RC_PALETTE) - { - /* - * RGB BPP for 8 bit palletes is always 8 - * and the color masks are always 0. - */ - pScreenPriv->dwBitsPerRGB = 8; - pScreenPriv->dwRedMask = 0x0L; - pScreenPriv->dwGreenMask = 0x0L; - pScreenPriv->dwBlueMask = 0x0L; - return TRUE; - } - - /* Color masks for 24 bpp are standardized */ - if (GetDeviceCaps (pScreenPriv->hdcScreen, PLANES) - * GetDeviceCaps (pScreenPriv->hdcScreen, BITSPIXEL) == 24) - { - ErrorF ("winQueryRGBBitsAndMasks - GetDeviceCaps (BITSPIXEL) " - "returned 24 for the screen. Using default 24bpp masks.\n"); - - /* 8 bits per primary color */ - pScreenPriv->dwBitsPerRGB = 8; - - /* Set screen privates masks */ - pScreenPriv->dwRedMask = WIN_24BPP_MASK_RED; - pScreenPriv->dwGreenMask = WIN_24BPP_MASK_GREEN; - pScreenPriv->dwBlueMask = WIN_24BPP_MASK_BLUE; - - return TRUE; - } - - /* Allocate a bitmap header and color table */ - pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER) - + 256 * sizeof (RGBQUAD)); - if (pbmih == NULL) - { - ErrorF ("winQueryRGBBitsAndMasks - malloc failed\n"); - return FALSE; - } - - /* Get screen description */ - if (winQueryScreenDIBFormat (pScreen, pbmih)) - { - /* Get a pointer to bitfields */ - pdw = (DWORD*) ((CARD8*)pbmih + sizeof (BITMAPINFOHEADER)); - -#if CYGDEBUG - winDebug ("%s - Masks: %08x %08x %08x\n", __FUNCTION__, - pdw[0], pdw[1], pdw[2]); - winDebug ("%s - Bitmap: %dx%d %d bpp %d planes\n", __FUNCTION__, - pbmih->biWidth, pbmih->biHeight, pbmih->biBitCount, pbmih->biPlanes); - winDebug ("%s - Compression: %d %s\n", __FUNCTION__, - pbmih->biCompression, - (pbmih->biCompression == BI_RGB?"(BI_RGB)": - (pbmih->biCompression == BI_RLE8?"(BI_RLE8)": - (pbmih->biCompression == BI_RLE4?"(BI_RLE4)": - (pbmih->biCompression == BI_BITFIELDS?"(BI_BITFIELDS)":"" - ))))); -#endif - - /* Handle BI_RGB case, which is returned by Wine */ - if (pbmih->biCompression == BI_RGB) - { - dwRedBits = 5; - dwGreenBits = 5; - dwBlueBits = 5; - - pScreenPriv->dwBitsPerRGB = 5; - - /* Set screen privates masks */ - pScreenPriv->dwRedMask = 0x7c00; - pScreenPriv->dwGreenMask = 0x03e0; - pScreenPriv->dwBlueMask = 0x001f; - } - else - { - /* Count the number of bits in each mask */ - dwRedBits = winCountBits (pdw[0]); - dwGreenBits = winCountBits (pdw[1]); - dwBlueBits = winCountBits (pdw[2]); - - /* Find maximum bits per red, green, blue */ - if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwRedBits; - else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) - pScreenPriv->dwBitsPerRGB = dwGreenBits; - else - pScreenPriv->dwBitsPerRGB = dwBlueBits; - - /* Set screen privates masks */ - pScreenPriv->dwRedMask = pdw[0]; - pScreenPriv->dwGreenMask = pdw[1]; - pScreenPriv->dwBlueMask = pdw[2]; - } - } - else - { - ErrorF ("winQueryRGBBitsAndMasks - winQueryScreenDIBFormat failed\n"); - free (pbmih); - fReturn = FALSE; - } - - /* Free memory */ - free (pbmih); - - return fReturn; -} - - -#ifdef XWIN_MULTIWINDOW -/* - * Redraw all ---? - */ - -static wBOOL CALLBACK -winRedrawAllProcShadowGDI (HWND hwnd, LPARAM lParam) -{ - if (hwnd == (HWND)lParam) - return TRUE; - InvalidateRect (hwnd, NULL, FALSE); - UpdateWindow (hwnd); - return TRUE; -} - -static wBOOL CALLBACK -winRedrawDamagedWindowShadowGDI (HWND hwnd, LPARAM lParam) -{ - BoxPtr pDamage = (BoxPtr)lParam; - RECT rcClient, rcDamage, rcRedraw; - POINT topLeft, bottomRight; - - if (IsIconic (hwnd)) - return TRUE; /* Don't care minimized windows */ - - /* Convert the damaged area from Screen coords to Client coords */ - topLeft.x = pDamage->x1; topLeft.y = pDamage->y1; - bottomRight.x = pDamage->x2; bottomRight.y = pDamage->y2; - topLeft.x += GetSystemMetrics (SM_XVIRTUALSCREEN); - bottomRight.x += GetSystemMetrics (SM_XVIRTUALSCREEN); - topLeft.y += GetSystemMetrics (SM_YVIRTUALSCREEN); - bottomRight.y += GetSystemMetrics (SM_YVIRTUALSCREEN); - ScreenToClient (hwnd, &topLeft); - ScreenToClient (hwnd, &bottomRight); - SetRect (&rcDamage, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); - - GetClientRect (hwnd, &rcClient); - - if (IntersectRect (&rcRedraw, &rcClient, &rcDamage)) - { - InvalidateRect (hwnd, &rcRedraw, FALSE); - UpdateWindow (hwnd); - } - return TRUE; -} -#endif - - -/* - * Allocate a DIB for the shadow framebuffer GDI server - */ - -static Bool -winAllocateFBShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - BITMAPINFOHEADER *pbmih = NULL; - DIBSECTION dibsection; - Bool fReturn = TRUE; - - /* Get device contexts for the screen and shadow bitmap */ - pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); - pScreenPriv->hdcShadow = CreateCompatibleDC (pScreenPriv->hdcScreen); - - /* Allocate bitmap info header */ - pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER) - + 256 * sizeof (RGBQUAD)); - if (pbmih == NULL) - { - ErrorF ("winAllocateFBShadowGDI - malloc () failed\n"); - return FALSE; - } - - /* Query the screen format */ - fReturn = winQueryScreenDIBFormat (pScreen, pbmih); - - /* Describe shadow bitmap to be created */ - pbmih->biWidth = pScreenInfo->dwWidth; - pbmih->biHeight = -pScreenInfo->dwHeight; - - ErrorF ("winAllocateFBShadowGDI - Creating DIB with width: %d height: %d " - "depth: %d\n", - (int) pbmih->biWidth, (int) -pbmih->biHeight, pbmih->biBitCount); - - /* Create a DI shadow bitmap with a bit pointer */ - pScreenPriv->hbmpShadow = CreateDIBSection (pScreenPriv->hdcScreen, - (BITMAPINFO *) pbmih, - DIB_RGB_COLORS, - (VOID**) &pScreenInfo->pfb, - NULL, - 0); - if (pScreenPriv->hbmpShadow == NULL || pScreenInfo->pfb == NULL) - { - winW32Error (2, "winAllocateFBShadowGDI - CreateDIBSection failed:"); - return FALSE; - } - else - { -#if CYGDEBUG - winDebug ("winAllocateFBShadowGDI - Shadow buffer allocated\n"); -#endif - } - - /* Get information about the bitmap that was allocated */ - GetObject (pScreenPriv->hbmpShadow, - sizeof (dibsection), - &dibsection); - -#if CYGDEBUG || YES - /* Print information about bitmap allocated */ - winDebug ("winAllocateFBShadowGDI - Dibsection width: %d height: %d " - "depth: %d size image: %d\n", - (int) dibsection.dsBmih.biWidth, (int) dibsection.dsBmih.biHeight, - dibsection.dsBmih.biBitCount, - (int) dibsection.dsBmih.biSizeImage); -#endif - - /* Select the shadow bitmap into the shadow DC */ - SelectObject (pScreenPriv->hdcShadow, - pScreenPriv->hbmpShadow); - -#if CYGDEBUG - winDebug ("winAllocateFBShadowGDI - Attempting a shadow blit\n"); -#endif - - /* Do a test blit from the shadow to the screen, I think */ - fReturn = BitBlt (pScreenPriv->hdcScreen, - 0, 0, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - pScreenPriv->hdcShadow, - 0, 0, - SRCCOPY); - if (fReturn) - { -#if CYGDEBUG - winDebug ("winAllocateFBShadowGDI - Shadow blit success\n"); -#endif - } - else - { - winW32Error (2, "winAllocateFBShadowGDI - Shadow blit failure\n"); -#if 0 - return FALSE; -#else - /* ago: ignore this error. The blit fails with wine, but does not - * cause any problems later. */ - - fReturn = TRUE; -#endif - } - - /* Look for height weirdness */ - if (dibsection.dsBmih.biHeight < 0) - { - dibsection.dsBmih.biHeight = -dibsection.dsBmih.biHeight; - } - - /* Set screeninfo stride */ - pScreenInfo->dwStride = ((dibsection.dsBmih.biSizeImage - / dibsection.dsBmih.biHeight) - * 8) / pScreenInfo->dwBPP; - -#if CYGDEBUG || YES - winDebug ("winAllocateFBShadowGDI - Created shadow stride: %d\n", - (int) pScreenInfo->dwStride); -#endif - - /* See if the shadow bitmap will be larger than the DIB size limit */ - if (pScreenInfo->dwWidth * pScreenInfo->dwHeight * pScreenInfo->dwBPP - >= WIN_DIB_MAXIMUM_SIZE) - { - ErrorF ("winAllocateFBShadowGDI - Requested DIB (bitmap) " - "will be larger than %d MB. The surface may fail to be " - "allocated on Windows 95, 98, or Me, due to a %d MB limit in " - "DIB size. This limit does not apply to Windows NT/2000, and " - "this message may be ignored on those platforms.\n", - WIN_DIB_MAXIMUM_SIZE_MB, WIN_DIB_MAXIMUM_SIZE_MB); - } - - /* Determine our color masks */ - if (!winQueryRGBBitsAndMasks (pScreen)) - { - ErrorF ("winAllocateFBShadowGDI - winQueryRGBBitsAndMasks failed\n"); - return FALSE; - } - -#ifdef XWIN_MULTIWINDOW - /* Redraw all windows */ - if (pScreenInfo->fMultiWindow) - EnumThreadWindows (g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0); -#endif - - return fReturn; -} - - -/* - * Blit the damaged regions of the shadow fb to the screen - */ - -static void -winShadowUpdateGDI (ScreenPtr pScreen, - shadowBufPtr pBuf) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - RegionPtr damage = shadowDamage(pBuf); - DWORD dwBox = RegionNumRects (damage); - BoxPtr pBox = RegionRects (damage); - int x, y, w, h; - HRGN hrgnTemp = NULL, hrgnCombined = NULL; -#ifdef XWIN_UPDATESTATS - static DWORD s_dwNonUnitRegions = 0; - static DWORD s_dwTotalUpdates = 0; - static DWORD s_dwTotalBoxes = 0; -#endif - BoxPtr pBoxExtents = RegionExtents(damage); - - /* - * Return immediately if the app is not active - * and we are fullscreen, or if we have a bad display depth - */ - if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen) - || pScreenPriv->fBadDepth) return; - -#ifdef XWIN_UPDATESTATS - ++s_dwTotalUpdates; - s_dwTotalBoxes += dwBox; - - if (dwBox != 1) - { - ++s_dwNonUnitRegions; - ErrorF ("winShadowUpdatGDI - dwBox: %d\n", dwBox); - } - - if ((s_dwTotalUpdates % 100) == 0) - ErrorF ("winShadowUpdateGDI - %d%% non-unity regions, avg boxes: %d " - "nu: %d tu: %d\n", - (s_dwNonUnitRegions * 100) / s_dwTotalUpdates, - s_dwTotalBoxes / s_dwTotalUpdates, - s_dwNonUnitRegions, s_dwTotalUpdates); -#endif /* XWIN_UPDATESTATS */ - - /* - * Handle small regions with multiple blits, - * handle large regions by creating a clipping region and - * doing a single blit constrained to that clipping region. - */ - if (!pScreenInfo->fMultiWindow && - (pScreenInfo->dwClipUpdatesNBoxes == 0 || - dwBox < pScreenInfo->dwClipUpdatesNBoxes)) - { - /* Loop through all boxes in the damaged region */ - while (dwBox--) - { - /* - * Calculate x offset, y offset, width, and height for - * current damage box - */ - x = pBox->x1; - y = pBox->y1; - w = pBox->x2 - pBox->x1; - h = pBox->y2 - pBox->y1; - - BitBlt (pScreenPriv->hdcScreen, - x, y, - w, h, - pScreenPriv->hdcShadow, - x, y, - SRCCOPY); - - /* Get a pointer to the next box */ - ++pBox; - } - } - else if (!pScreenInfo->fMultiWindow) - { - /* Compute a GDI region from the damaged region */ - hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); - dwBox--; - pBox++; - while (dwBox--) - { - hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); - CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR); - DeleteObject (hrgnTemp); - pBox++; - } - - /* Install the GDI region as a clipping region */ - SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined); - DeleteObject (hrgnCombined); - hrgnCombined = NULL; - - /* - * Blit the shadow buffer to the screen, - * constrained to the clipping region. - */ - BitBlt (pScreenPriv->hdcScreen, - pBoxExtents->x1, pBoxExtents->y1, - pBoxExtents->x2 - pBoxExtents->x1, - pBoxExtents->y2 - pBoxExtents->y1, - pScreenPriv->hdcShadow, - pBoxExtents->x1, pBoxExtents->y1, - SRCCOPY); - - /* Reset the clip region */ - SelectClipRgn (pScreenPriv->hdcScreen, NULL); - } - -#ifdef XWIN_MULTIWINDOW - /* Redraw all multiwindow windows */ - if (pScreenInfo->fMultiWindow) - EnumThreadWindows (g_dwCurrentThreadID, - winRedrawDamagedWindowShadowGDI, - (LPARAM)pBoxExtents); -#endif -} - - -/* See Porting Layer Definition - p. 33 */ -/* - * We wrap whatever CloseScreen procedure was specified by fb; - * a pointer to said procedure is stored in our privates. - */ - -static Bool -winCloseScreenShadowGDI (int nIndex, ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - Bool fReturn; - -#if CYGDEBUG - winDebug ("winCloseScreenShadowGDI - Freeing screen resources\n"); -#endif - - /* Flag that the screen is closed */ - pScreenPriv->fClosed = TRUE; - pScreenPriv->fActive = FALSE; - - /* Call the wrapped CloseScreen procedure */ - WIN_UNWRAP(CloseScreen); - fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); - - /* Delete the window property */ - RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); - - /* Free the shadow DC; which allows the bitmap to be freed */ - DeleteDC (pScreenPriv->hdcShadow); - - /* Free the shadow bitmap */ - DeleteObject (pScreenPriv->hbmpShadow); - - /* Free the screen DC */ - ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen); - - /* Delete tray icon, if we have one */ - if (!pScreenInfo->fNoTrayIcon) - winDeleteNotifyIcon (pScreenPriv); - - /* Free the exit confirmation dialog box, if it exists */ - if (g_hDlgExit != NULL) - { - DestroyWindow (g_hDlgExit); - g_hDlgExit = NULL; - } - - /* Kill our window */ - if (pScreenPriv->hwndScreen) - { - DestroyWindow (pScreenPriv->hwndScreen); - pScreenPriv->hwndScreen = NULL; - } - -#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) - /* Destroy the thread startup mutex */ - pthread_mutex_destroy (&pScreenPriv->pmServerStarted); -#endif - - /* Invalidate our screeninfo's pointer to the screen */ - pScreenInfo->pScreen = NULL; - - /* Invalidate the ScreenInfo's fb pointer */ - pScreenInfo->pfb = NULL; - - /* Free the screen privates for this screen */ - free ((pointer) pScreenPriv); - - return fReturn; -} - - -/* - * Tell mi what sort of visuals we need. - * - * Generally we only need one visual, as our screen can only - * handle one format at a time, I believe. You may want - * to verify that last sentence. - */ - -static Bool -winInitVisualsShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Display debugging information */ - ErrorF ("winInitVisualsShadowGDI - Masks %08x %08x %08x BPRGB %d d %d " - "bpp %d\n", - (unsigned int) pScreenPriv->dwRedMask, - (unsigned int) pScreenPriv->dwGreenMask, - (unsigned int) pScreenPriv->dwBlueMask, - (int) pScreenPriv->dwBitsPerRGB, - (int) pScreenInfo->dwDepth, - (int) pScreenInfo->dwBPP); - - /* Create a single visual according to the Windows screen depth */ - switch (pScreenInfo->dwDepth) - { - case 24: - case 16: - case 15: - /* Setup the real visual */ - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - TrueColorMask, - pScreenPriv->dwBitsPerRGB, - -1, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks " - "failed\n"); - return FALSE; - } - -#ifdef XWIN_EMULATEPSEUDO - if (!pScreenInfo->fEmulatePseudo) - break; - - /* Setup a pseudocolor visual */ - if (!miSetVisualTypesAndMasks (8, - PseudoColorMask, - 8, - -1, - 0, - 0, - 0)) - { - ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks " - "failed for PseudoColor\n"); - return FALSE; - } -#endif - break; - - case 8: - if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, - PseudoColorMask, - pScreenPriv->dwBitsPerRGB, - PseudoColor, - pScreenPriv->dwRedMask, - pScreenPriv->dwGreenMask, - pScreenPriv->dwBlueMask)) - { - ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks " - "failed\n"); - return FALSE; - } - break; - - default: - ErrorF ("winInitVisualsShadowGDI - Unknown screen depth\n"); - return FALSE; - } - -#if CYGDEBUG - winDebug ("winInitVisualsShadowGDI - Returning\n"); -#endif - - return TRUE; -} - - -/* - * Adjust the proposed video mode - */ - -static Bool -winAdjustVideoModeShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - HDC hdc; - DWORD dwBPP; - - hdc = GetDC (NULL); - - /* We're in serious trouble if we can't get a DC */ - if (hdc == NULL) - { - ErrorF ("winAdjustVideoModeShadowGDI - GetDC () failed\n"); - return FALSE; - } - - /* Query GDI for current display depth */ - dwBPP = GetDeviceCaps (hdc, BITSPIXEL); - - /* GDI cannot change the screen depth */ - if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP) - { - /* No -depth parameter passed, let the user know the depth being used */ - ErrorF ("winAdjustVideoModeShadowGDI - Using Windows display " - "depth of %d bits per pixel\n", (int) dwBPP); - - /* Use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - else if (dwBPP != pScreenInfo->dwBPP) - { - /* Warn user if GDI depth is different than -depth parameter */ - ErrorF ("winAdjustVideoModeShadowGDI - Command line bpp: %d, "\ - "using bpp: %d\n", (int) pScreenInfo->dwBPP, (int) dwBPP); - - /* We'll use GDI's depth */ - pScreenInfo->dwBPP = dwBPP; - } - - /* Release our DC */ - ReleaseDC (NULL, hdc); - hdc = NULL; - - return TRUE; -} - - -/* - * Blt exposed regions to the screen - */ - -static Bool -winBltExposedRegionsShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - winPrivCmapPtr pCmapPriv = NULL; - HDC hdcUpdate; - PAINTSTRUCT ps; - - /* BeginPaint gives us an hdc that clips to the invalidated region */ - hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps); - - /* Realize the palette, if we have one */ - if (pScreenPriv->pcmapInstalled != NULL) - { - pCmapPriv = winGetCmapPriv (pScreenPriv->pcmapInstalled); - - SelectPalette (hdcUpdate, pCmapPriv->hPalette, FALSE); - RealizePalette (hdcUpdate); - } - - /* Our BitBlt will be clipped to the invalidated region */ - BitBlt (hdcUpdate, - 0, 0, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - pScreenPriv->hdcShadow, - 0, 0, - SRCCOPY); - - /* EndPaint frees the DC */ - EndPaint (pScreenPriv->hwndScreen, &ps); - -#ifdef XWIN_MULTIWINDOW - /* Redraw all windows */ - if (pScreenInfo->fMultiWindow) - EnumThreadWindows(g_dwCurrentThreadID, winRedrawAllProcShadowGDI, - (LPARAM)pScreenPriv->hwndScreen); -#endif - - return TRUE; -} - - -/* - * Do any engine-specific appliation-activation processing - */ - -static Bool -winActivateAppShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* - * 2004/04/12 - Harold - We perform the restoring or minimizing - * manually for ShadowGDI in fullscreen modes so that this engine - * will perform just like ShadowDD and ShadowDDNL in fullscreen mode; - * if we do not do this then our fullscreen window will appear in the - * z-order when it is deactivated and it can be uncovered by resizing - * or minimizing another window that is on top of it, which is not how - * the DirectDraw engines work. Therefore we keep this code here to - * make sure that all engines work the same in fullscreen mode. - */ - - /* - * Are we active? - * Are we fullscreen? - */ - if (pScreenPriv->fActive - && pScreenInfo->fFullScreen) - { - /* - * Activating, attempt to bring our window - * to the top of the display - */ - ShowWindow (pScreenPriv->hwndScreen, SW_RESTORE); - } - else if (!pScreenPriv->fActive - && pScreenInfo->fFullScreen) - { - /* - * Deactivating, stuff our window onto the - * task bar. - */ - ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); - } - - return TRUE; -} - - -/* - * Reblit the shadow framebuffer to the screen. - */ - -static Bool -winRedrawScreenShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Redraw the whole window, to take account for the new colors */ - BitBlt (pScreenPriv->hdcScreen, - 0, 0, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - pScreenPriv->hdcShadow, - 0, 0, - SRCCOPY); - -#ifdef XWIN_MULTIWINDOW - /* Redraw all windows */ - if (pScreenInfo->fMultiWindow) - EnumThreadWindows(g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0); -#endif - - return TRUE; -} - - - -/* - * Realize the currently installed colormap - */ - -static Bool -winRealizeInstalledPaletteShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winPrivCmapPtr pCmapPriv = NULL; - -#if CYGDEBUG - winDebug ("winRealizeInstalledPaletteShadowGDI\n"); -#endif - - /* Don't do anything if there is not a colormap */ - if (pScreenPriv->pcmapInstalled == NULL) - { -#if CYGDEBUG - winDebug ("winRealizeInstalledPaletteShadowGDI - No colormap " - "installed\n"); -#endif - return TRUE; - } - - pCmapPriv = winGetCmapPriv (pScreenPriv->pcmapInstalled); - - /* Realize our palette for the screen */ - if (RealizePalette (pScreenPriv->hdcScreen) == GDI_ERROR) - { - ErrorF ("winRealizeInstalledPaletteShadowGDI - RealizePalette () " - "failed\n"); - return FALSE; - } - - /* Set the DIB color table */ - if (SetDIBColorTable (pScreenPriv->hdcShadow, - 0, - WIN_NUM_PALETTE_ENTRIES, - pCmapPriv->rgbColors) == 0) - { - ErrorF ("winRealizeInstalledPaletteShadowGDI - SetDIBColorTable () " - "failed\n"); - return FALSE; - } - - return TRUE; -} - - -/* - * Install the specified colormap - */ - -static Bool -winInstallColormapShadowGDI (ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - winCmapPriv(pColormap); - - /* - * Tell Windows to install the new colormap - */ - if (SelectPalette (pScreenPriv->hdcScreen, - pCmapPriv->hPalette, - FALSE) == NULL) - { - ErrorF ("winInstallColormapShadowGDI - SelectPalette () failed\n"); - return FALSE; - } - - /* Realize the palette */ - if (GDI_ERROR == RealizePalette (pScreenPriv->hdcScreen)) - { - ErrorF ("winInstallColormapShadowGDI - RealizePalette () failed\n"); - return FALSE; - } - - /* Set the DIB color table */ - if (SetDIBColorTable (pScreenPriv->hdcShadow, - 0, - WIN_NUM_PALETTE_ENTRIES, - pCmapPriv->rgbColors) == 0) - { - ErrorF ("winInstallColormapShadowGDI - SetDIBColorTable () failed\n"); - return FALSE; - } - - /* Redraw the whole window, to take account for the new colors */ - BitBlt (pScreenPriv->hdcScreen, - 0, 0, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - pScreenPriv->hdcShadow, - 0, 0, - SRCCOPY); - - /* Save a pointer to the newly installed colormap */ - pScreenPriv->pcmapInstalled = pColormap; - -#ifdef XWIN_MULTIWINDOW - /* Redraw all windows */ - if (pScreenInfo->fMultiWindow) - EnumThreadWindows (g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0); -#endif - - return TRUE; -} - - -/* - * Store the specified colors in the specified colormap - */ - -static Bool -winStoreColorsShadowGDI (ColormapPtr pColormap, - int ndef, - xColorItem *pdefs) -{ - ScreenPtr pScreen = pColormap->pScreen; - winScreenPriv(pScreen); - winCmapPriv(pColormap); - ColormapPtr curpmap = pScreenPriv->pcmapInstalled; - - /* Put the X colormap entries into the Windows logical palette */ - if (SetPaletteEntries (pCmapPriv->hPalette, - pdefs[0].pixel, - ndef, - pCmapPriv->peColors + pdefs[0].pixel) == 0) - { - ErrorF ("winStoreColorsShadowGDI - SetPaletteEntries () failed\n"); - return FALSE; - } - - /* Don't install the Windows palette if the colormap is not installed */ - if (pColormap != curpmap) - { - return TRUE; - } - - /* Try to install the newly modified colormap */ - if (!winInstallColormapShadowGDI (pColormap)) - { - ErrorF ("winInstallColormapShadowGDI - winInstallColormapShadowGDI " - "failed\n"); - return FALSE; - } - -#if 0 - /* Tell Windows that the palette has changed */ - RealizePalette (pScreenPriv->hdcScreen); - - /* Set the DIB color table */ - if (SetDIBColorTable (pScreenPriv->hdcShadow, - pdefs[0].pixel, - ndef, - pCmapPriv->rgbColors + pdefs[0].pixel) == 0) - { - ErrorF ("winInstallColormapShadowGDI - SetDIBColorTable () failed\n"); - return FALSE; - } - - /* Save a pointer to the newly installed colormap */ - pScreenPriv->pcmapInstalled = pColormap; -#endif - - return TRUE; -} - - -/* - * Colormap initialization procedure - */ - -static Bool -winCreateColormapShadowGDI (ColormapPtr pColormap) -{ - LPLOGPALETTE lpPaletteNew = NULL; - DWORD dwEntriesMax; - VisualPtr pVisual; - HPALETTE hpalNew = NULL; - winCmapPriv(pColormap); - - /* Get a pointer to the visual that the colormap belongs to */ - pVisual = pColormap->pVisual; - - /* Get the maximum number of palette entries for this visual */ - dwEntriesMax = pVisual->ColormapEntries; - - /* Allocate a Windows logical color palette with max entries */ - lpPaletteNew = malloc (sizeof (LOGPALETTE) - + (dwEntriesMax - 1) * sizeof (PALETTEENTRY)); - if (lpPaletteNew == NULL) - { - ErrorF ("winCreateColormapShadowGDI - Couldn't allocate palette " - "with %d entries\n", - (int) dwEntriesMax); - return FALSE; - } - - /* Zero out the colormap */ - ZeroMemory (lpPaletteNew, sizeof (LOGPALETTE) - + (dwEntriesMax - 1) * sizeof (PALETTEENTRY)); - - /* Set the logical palette structure */ - lpPaletteNew->palVersion = 0x0300; - lpPaletteNew->palNumEntries = dwEntriesMax; - - /* Tell Windows to create the palette */ - hpalNew = CreatePalette (lpPaletteNew); - if (hpalNew == NULL) - { - ErrorF ("winCreateColormapShadowGDI - CreatePalette () failed\n"); - free (lpPaletteNew); - return FALSE; - } - - /* Save the Windows logical palette handle in the X colormaps' privates */ - pCmapPriv->hPalette = hpalNew; - - /* Free the palette initialization memory */ - free (lpPaletteNew); - - return TRUE; -} - - -/* - * Colormap destruction procedure - */ - -static Bool -winDestroyColormapShadowGDI (ColormapPtr pColormap) -{ - winScreenPriv(pColormap->pScreen); - winCmapPriv(pColormap); - - /* - * Is colormap to be destroyed the default? - * - * Non-default colormaps should have had winUninstallColormap - * called on them before we get here. The default colormap - * will not have had winUninstallColormap called on it. Thus, - * we need to handle the default colormap in a special way. - */ - if (pColormap->flags & IsDefault) - { -#if CYGDEBUG - winDebug ("winDestroyColormapShadowGDI - Destroying default " - "colormap\n"); -#endif - - /* - * FIXME: Walk the list of all screens, popping the default - * palette out of each screen device context. - */ - - /* Pop the palette out of the device context */ - SelectPalette (pScreenPriv->hdcScreen, - GetStockObject (DEFAULT_PALETTE), - FALSE); - - /* Clear our private installed colormap pointer */ - pScreenPriv->pcmapInstalled = NULL; - } - - /* Try to delete the logical palette */ - if (DeleteObject (pCmapPriv->hPalette) == 0) - { - ErrorF ("winDestroyColormap - DeleteObject () failed\n"); - return FALSE; - } - - /* Invalidate the colormap privates */ - pCmapPriv->hPalette = NULL; - - return TRUE; -} - - -/* - * Set engine specific funtions - */ - -Bool -winSetEngineFunctionsShadowGDI (ScreenPtr pScreen) -{ - winScreenPriv(pScreen); - winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; - - /* Set our pointers */ - pScreenPriv->pwinAllocateFB = winAllocateFBShadowGDI; - pScreenPriv->pwinShadowUpdate = winShadowUpdateGDI; - pScreenPriv->pwinCloseScreen = winCloseScreenShadowGDI; - pScreenPriv->pwinInitVisuals = winInitVisualsShadowGDI; - pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowGDI; - if (pScreenInfo->fFullScreen) - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; - else - pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; - pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; - pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowGDI; - pScreenPriv->pwinActivateApp = winActivateAppShadowGDI; - pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowGDI; - pScreenPriv->pwinRealizeInstalledPalette = - winRealizeInstalledPaletteShadowGDI; - pScreenPriv->pwinInstallColormap = winInstallColormapShadowGDI; - pScreenPriv->pwinStoreColors = winStoreColorsShadowGDI; - pScreenPriv->pwinCreateColormap = winCreateColormapShadowGDI; - pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowGDI; - pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; - pScreenPriv->pwinCreatePrimarySurface - = (winCreatePrimarySurfaceProcPtr) (void (*)(void))NoopDDA; - pScreenPriv->pwinReleasePrimarySurface - = (winReleasePrimarySurfaceProcPtr) (void (*)(void))NoopDDA; -#ifdef XWIN_MULTIWINDOW - pScreenPriv->pwinFinishCreateWindowsWindow = - (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA; -#endif - - return TRUE; -} +/* + *Copyright (C) 2001-2004 Harold L Hunt II All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" + + +/* + * Local function prototypes + */ + +#ifdef XWIN_MULTIWINDOW +static wBOOL CALLBACK +winRedrawAllProcShadowGDI (HWND hwnd, LPARAM lParam); + +static wBOOL CALLBACK +winRedrawDamagedWindowShadowGDI (HWND hwnd, LPARAM lParam); +#endif + +static Bool +winAllocateFBShadowGDI (ScreenPtr pScreen); + +static void +winShadowUpdateGDI (ScreenPtr pScreen, + shadowBufPtr pBuf); + +static Bool +winCloseScreenShadowGDI (int nIndex, ScreenPtr pScreen); + +static Bool +winInitVisualsShadowGDI (ScreenPtr pScreen); + +static Bool +winAdjustVideoModeShadowGDI (ScreenPtr pScreen); + +static Bool +winBltExposedRegionsShadowGDI (ScreenPtr pScreen); + +static Bool +winActivateAppShadowGDI (ScreenPtr pScreen); + +static Bool +winRedrawScreenShadowGDI (ScreenPtr pScreen); + +static Bool +winRealizeInstalledPaletteShadowGDI (ScreenPtr pScreen); + +static Bool +winInstallColormapShadowGDI (ColormapPtr pColormap); + +static Bool +winStoreColorsShadowGDI (ColormapPtr pmap, + int ndef, + xColorItem *pdefs); + +static Bool +winCreateColormapShadowGDI (ColormapPtr pColormap); + +static Bool +winDestroyColormapShadowGDI (ColormapPtr pColormap); + + +/* + * Internal function to get the DIB format that is compatible with the screen + */ + +static +Bool +winQueryScreenDIBFormat (ScreenPtr pScreen, BITMAPINFOHEADER *pbmih) +{ + winScreenPriv(pScreen); + HBITMAP hbmp; +#if CYGDEBUG + LPDWORD pdw = NULL; +#endif + + /* Create a memory bitmap compatible with the screen */ + hbmp = CreateCompatibleBitmap (pScreenPriv->hdcScreen, 1, 1); + if (hbmp == NULL) + { + ErrorF ("winQueryScreenDIBFormat - CreateCompatibleBitmap failed\n"); + return FALSE; + } + + /* Initialize our bitmap info header */ + ZeroMemory (pbmih, sizeof (BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD)); + pbmih->biSize = sizeof (BITMAPINFOHEADER); + + /* Get the biBitCount */ + if (!GetDIBits (pScreenPriv->hdcScreen, + hbmp, + 0, 1, + NULL, + (BITMAPINFO*) pbmih, + DIB_RGB_COLORS)) + { + ErrorF ("winQueryScreenDIBFormat - First call to GetDIBits failed\n"); + DeleteObject (hbmp); + return FALSE; + } + +#if CYGDEBUG + /* Get a pointer to bitfields */ + pdw = (DWORD*) ((CARD8*)pbmih + sizeof (BITMAPINFOHEADER)); + + winDebug ("winQueryScreenDIBFormat - First call masks: %08x %08x %08x\n", + pdw[0], pdw[1], pdw[2]); +#endif + + /* Get optimal color table, or the optimal bitfields */ + if (!GetDIBits (pScreenPriv->hdcScreen, + hbmp, + 0, 1, + NULL, + (BITMAPINFO*)pbmih, + DIB_RGB_COLORS)) + { + ErrorF ("winQueryScreenDIBFormat - Second call to GetDIBits " + "failed\n"); + DeleteObject (hbmp); + return FALSE; + } + + /* Free memory */ + DeleteObject (hbmp); + + return TRUE; +} + + +/* + * Internal function to determine the GDI bits per rgb and bit masks + */ + +static +Bool +winQueryRGBBitsAndMasks (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + BITMAPINFOHEADER *pbmih = NULL; + Bool fReturn = TRUE; + LPDWORD pdw = NULL; + DWORD dwRedBits, dwGreenBits, dwBlueBits; + + /* Color masks for 8 bpp are standardized */ + if (GetDeviceCaps (pScreenPriv->hdcScreen, RASTERCAPS) & RC_PALETTE) + { + /* + * RGB BPP for 8 bit palletes is always 8 + * and the color masks are always 0. + */ + pScreenPriv->dwBitsPerRGB = 8; + pScreenPriv->dwRedMask = 0x0L; + pScreenPriv->dwGreenMask = 0x0L; + pScreenPriv->dwBlueMask = 0x0L; + return TRUE; + } + + /* Color masks for 24 bpp are standardized */ + if (GetDeviceCaps (pScreenPriv->hdcScreen, PLANES) + * GetDeviceCaps (pScreenPriv->hdcScreen, BITSPIXEL) == 24) + { + ErrorF ("winQueryRGBBitsAndMasks - GetDeviceCaps (BITSPIXEL) " + "returned 24 for the screen. Using default 24bpp masks.\n"); + + /* 8 bits per primary color */ + pScreenPriv->dwBitsPerRGB = 8; + + /* Set screen privates masks */ + pScreenPriv->dwRedMask = WIN_24BPP_MASK_RED; + pScreenPriv->dwGreenMask = WIN_24BPP_MASK_GREEN; + pScreenPriv->dwBlueMask = WIN_24BPP_MASK_BLUE; + + return TRUE; + } + + /* Allocate a bitmap header and color table */ + pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER) + + 256 * sizeof (RGBQUAD)); + if (pbmih == NULL) + { + ErrorF ("winQueryRGBBitsAndMasks - malloc failed\n"); + return FALSE; + } + + /* Get screen description */ + if (winQueryScreenDIBFormat (pScreen, pbmih)) + { + /* Get a pointer to bitfields */ + pdw = (DWORD*) ((CARD8*)pbmih + sizeof (BITMAPINFOHEADER)); + +#if CYGDEBUG + winDebug ("%s - Masks: %08x %08x %08x\n", __FUNCTION__, + pdw[0], pdw[1], pdw[2]); + winDebug ("%s - Bitmap: %dx%d %d bpp %d planes\n", __FUNCTION__, + pbmih->biWidth, pbmih->biHeight, pbmih->biBitCount, pbmih->biPlanes); + winDebug ("%s - Compression: %d %s\n", __FUNCTION__, + pbmih->biCompression, + (pbmih->biCompression == BI_RGB?"(BI_RGB)": + (pbmih->biCompression == BI_RLE8?"(BI_RLE8)": + (pbmih->biCompression == BI_RLE4?"(BI_RLE4)": + (pbmih->biCompression == BI_BITFIELDS?"(BI_BITFIELDS)":"" + ))))); +#endif + + /* Handle BI_RGB case, which is returned by Wine */ + if (pbmih->biCompression == BI_RGB) + { + dwRedBits = 5; + dwGreenBits = 5; + dwBlueBits = 5; + + pScreenPriv->dwBitsPerRGB = 5; + + /* Set screen privates masks */ + pScreenPriv->dwRedMask = 0x7c00; + pScreenPriv->dwGreenMask = 0x03e0; + pScreenPriv->dwBlueMask = 0x001f; + } + else + { + /* Count the number of bits in each mask */ + dwRedBits = winCountBits (pdw[0]); + dwGreenBits = winCountBits (pdw[1]); + dwBlueBits = winCountBits (pdw[2]); + + /* Find maximum bits per red, green, blue */ + if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwRedBits; + else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) + pScreenPriv->dwBitsPerRGB = dwGreenBits; + else + pScreenPriv->dwBitsPerRGB = dwBlueBits; + + /* Set screen privates masks */ + pScreenPriv->dwRedMask = pdw[0]; + pScreenPriv->dwGreenMask = pdw[1]; + pScreenPriv->dwBlueMask = pdw[2]; + } + } + else + { + ErrorF ("winQueryRGBBitsAndMasks - winQueryScreenDIBFormat failed\n"); + free (pbmih); + fReturn = FALSE; + } + + /* Free memory */ + free (pbmih); + + return fReturn; +} + + +#ifdef XWIN_MULTIWINDOW +/* + * Redraw all ---? + */ + +static wBOOL CALLBACK +winRedrawAllProcShadowGDI (HWND hwnd, LPARAM lParam) +{ + if (hwnd == (HWND)lParam) + return TRUE; + InvalidateRect (hwnd, NULL, FALSE); + UpdateWindow (hwnd); + return TRUE; +} + +static wBOOL CALLBACK +winRedrawDamagedWindowShadowGDI (HWND hwnd, LPARAM lParam) +{ + BoxPtr pDamage = (BoxPtr)lParam; + RECT rcClient, rcDamage, rcRedraw; + POINT topLeft, bottomRight; + + if (IsIconic (hwnd)) + return TRUE; /* Don't care minimized windows */ + + /* Convert the damaged area from Screen coords to Client coords */ + topLeft.x = pDamage->x1; topLeft.y = pDamage->y1; + bottomRight.x = pDamage->x2; bottomRight.y = pDamage->y2; + topLeft.x += GetSystemMetrics (SM_XVIRTUALSCREEN); + bottomRight.x += GetSystemMetrics (SM_XVIRTUALSCREEN); + topLeft.y += GetSystemMetrics (SM_YVIRTUALSCREEN); + bottomRight.y += GetSystemMetrics (SM_YVIRTUALSCREEN); + ScreenToClient (hwnd, &topLeft); + ScreenToClient (hwnd, &bottomRight); + SetRect (&rcDamage, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); + + GetClientRect (hwnd, &rcClient); + + if (IntersectRect (&rcRedraw, &rcClient, &rcDamage)) + { + InvalidateRect (hwnd, &rcRedraw, FALSE); + UpdateWindow (hwnd); + } + return TRUE; +} +#endif + + +/* + * Allocate a DIB for the shadow framebuffer GDI server + */ + +static Bool +winAllocateFBShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + DIBSECTION dibsection; + Bool fReturn = TRUE; + + /* Describe shadow bitmap to be created */ + pScreenPriv->pbmih->biWidth = pScreenInfo->dwWidth; + pScreenPriv->pbmih->biHeight = -pScreenInfo->dwHeight; + + ErrorF ("winAllocateFBShadowGDI - Creating DIB with width: %d height: %d " + "depth: %d\n", + (int) pScreenPriv->pbmih->biWidth, (int) -pScreenPriv->pbmih->biHeight, pScreenPriv->pbmih->biBitCount); + + /* Create a DI shadow bitmap with a bit pointer */ + pScreenPriv->hbmpShadow = CreateDIBSection (pScreenPriv->hdcScreen, + (BITMAPINFO *) pScreenPriv->pbmih, + DIB_RGB_COLORS, + (VOID**) &pScreenInfo->pfb, + NULL, + 0); + if (pScreenPriv->hbmpShadow == NULL || pScreenInfo->pfb == NULL) + { + winW32Error (2, "winAllocateFBShadowGDI - CreateDIBSection failed:"); + return FALSE; + } + else + { +#if CYGDEBUG + winDebug ("winAllocateFBShadowGDI - Shadow buffer allocated\n"); +#endif + } + + /* Get information about the bitmap that was allocated */ + GetObject (pScreenPriv->hbmpShadow, + sizeof (dibsection), + &dibsection); + +#if CYGDEBUG || YES + /* Print information about bitmap allocated */ + winDebug ("winAllocateFBShadowGDI - Dibsection width: %d height: %d " + "depth: %d size image: %d\n", + (int) dibsection.dsBmih.biWidth, (int) dibsection.dsBmih.biHeight, + dibsection.dsBmih.biBitCount, + (int) dibsection.dsBmih.biSizeImage); +#endif + + /* Select the shadow bitmap into the shadow DC */ + SelectObject (pScreenPriv->hdcShadow, + pScreenPriv->hbmpShadow); + +#if CYGDEBUG + winDebug ("winAllocateFBShadowGDI - Attempting a shadow blit\n"); +#endif + + /* Do a test blit from the shadow to the screen, I think */ + fReturn = BitBlt (pScreenPriv->hdcScreen, + 0, 0, + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + pScreenPriv->hdcShadow, + 0, 0, + SRCCOPY); + if (fReturn) + { +#if CYGDEBUG + winDebug ("winAllocateFBShadowGDI - Shadow blit success\n"); +#endif + } + else + { + winW32Error (2, "winAllocateFBShadowGDI - Shadow blit failure\n"); +#if 0 + return FALSE; +#else + /* ago: ignore this error. The blit fails with wine, but does not + * cause any problems later. */ + + fReturn = TRUE; +#endif + } + + /* Look for height weirdness */ + if (dibsection.dsBmih.biHeight < 0) + { + dibsection.dsBmih.biHeight = -dibsection.dsBmih.biHeight; + } + + /* Set screeninfo stride */ + pScreenInfo->dwStride = ((dibsection.dsBmih.biSizeImage + / dibsection.dsBmih.biHeight) + * 8) / pScreenInfo->dwBPP; + +#if CYGDEBUG || YES + winDebug ("winAllocateFBShadowGDI - Created shadow stride: %d\n", + (int) pScreenInfo->dwStride); +#endif + +#ifdef XWIN_MULTIWINDOW + /* Redraw all windows */ + if (pScreenInfo->fMultiWindow) + EnumThreadWindows (g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0); +#endif + + return fReturn; +} + +static void +winFreeFBShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Free the shadow bitmap */ + DeleteObject (pScreenPriv->hbmpShadow); + + /* Invalidate the ScreenInfo's fb pointer */ + pScreenInfo->pfb = NULL; +} + +/* + * Blit the damaged regions of the shadow fb to the screen + */ + +static void +winShadowUpdateGDI (ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + RegionPtr damage = shadowDamage(pBuf); + DWORD dwBox = RegionNumRects (damage); + BoxPtr pBox = RegionRects (damage); + int x, y, w, h; + HRGN hrgnTemp = NULL, hrgnCombined = NULL; +#ifdef XWIN_UPDATESTATS + static DWORD s_dwNonUnitRegions = 0; + static DWORD s_dwTotalUpdates = 0; + static DWORD s_dwTotalBoxes = 0; +#endif + BoxPtr pBoxExtents = RegionExtents(damage); + + /* + * Return immediately if the app is not active + * and we are fullscreen, or if we have a bad display depth + */ + if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen) + || pScreenPriv->fBadDepth) return; + +#ifdef XWIN_UPDATESTATS + ++s_dwTotalUpdates; + s_dwTotalBoxes += dwBox; + + if (dwBox != 1) + { + ++s_dwNonUnitRegions; + ErrorF ("winShadowUpdatGDI - dwBox: %d\n", dwBox); + } + + if ((s_dwTotalUpdates % 100) == 0) + ErrorF ("winShadowUpdateGDI - %d%% non-unity regions, avg boxes: %d " + "nu: %d tu: %d\n", + (s_dwNonUnitRegions * 100) / s_dwTotalUpdates, + s_dwTotalBoxes / s_dwTotalUpdates, + s_dwNonUnitRegions, s_dwTotalUpdates); +#endif /* XWIN_UPDATESTATS */ + + /* + * Handle small regions with multiple blits, + * handle large regions by creating a clipping region and + * doing a single blit constrained to that clipping region. + */ + if (!pScreenInfo->fMultiWindow && + (pScreenInfo->dwClipUpdatesNBoxes == 0 || + dwBox < pScreenInfo->dwClipUpdatesNBoxes)) + { + /* Loop through all boxes in the damaged region */ + while (dwBox--) + { + /* + * Calculate x offset, y offset, width, and height for + * current damage box + */ + x = pBox->x1; + y = pBox->y1; + w = pBox->x2 - pBox->x1; + h = pBox->y2 - pBox->y1; + + BitBlt (pScreenPriv->hdcScreen, + x, y, + w, h, + pScreenPriv->hdcShadow, + x, y, + SRCCOPY); + + /* Get a pointer to the next box */ + ++pBox; + } + } + else if (!pScreenInfo->fMultiWindow) + { + /* Compute a GDI region from the damaged region */ + hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); + dwBox--; + pBox++; + while (dwBox--) + { + hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2); + CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR); + DeleteObject (hrgnTemp); + pBox++; + } + + /* Install the GDI region as a clipping region */ + SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined); + DeleteObject (hrgnCombined); + hrgnCombined = NULL; + + /* + * Blit the shadow buffer to the screen, + * constrained to the clipping region. + */ + BitBlt (pScreenPriv->hdcScreen, + pBoxExtents->x1, pBoxExtents->y1, + pBoxExtents->x2 - pBoxExtents->x1, + pBoxExtents->y2 - pBoxExtents->y1, + pScreenPriv->hdcShadow, + pBoxExtents->x1, pBoxExtents->y1, + SRCCOPY); + + /* Reset the clip region */ + SelectClipRgn (pScreenPriv->hdcScreen, NULL); + } + +#ifdef XWIN_MULTIWINDOW + /* Redraw all multiwindow windows */ + if (pScreenInfo->fMultiWindow) + EnumThreadWindows (g_dwCurrentThreadID, + winRedrawDamagedWindowShadowGDI, + (LPARAM)pBoxExtents); +#endif +} + + +static Bool +winInitScreenShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + + /* Get device contexts for the screen and shadow bitmap */ + pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen); + pScreenPriv->hdcShadow = CreateCompatibleDC (pScreenPriv->hdcScreen); + + /* Allocate bitmap info header */ + pScreenPriv->pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER) + + 256 * sizeof (RGBQUAD)); + if (pScreenPriv->pbmih == NULL) + { + ErrorF ("winInitScreenShadowGDI - malloc () failed\n"); + return FALSE; + } + + /* Query the screen format */ + if (!winQueryScreenDIBFormat (pScreen, pScreenPriv->pbmih)) + { + ErrorF ("winInitScreenShadowGDI - winQueryScreenDIBFormat failed\n"); + return FALSE; + } + + /* Determine our color masks */ + if (!winQueryRGBBitsAndMasks (pScreen)) + { + ErrorF ("winInitScreenShadowGDI - winQueryRGBBitsAndMasks failed\n"); + return FALSE; + } + + return winAllocateFBShadowGDI(pScreen); +} + +/* See Porting Layer Definition - p. 33 */ +/* + * We wrap whatever CloseScreen procedure was specified by fb; + * a pointer to said procedure is stored in our privates. + */ + +static Bool +winCloseScreenShadowGDI (int nIndex, ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + Bool fReturn; + +#if CYGDEBUG + winDebug ("winCloseScreenShadowGDI - Freeing screen resources\n"); +#endif + + /* Flag that the screen is closed */ + pScreenPriv->fClosed = TRUE; + pScreenPriv->fActive = FALSE; + + /* Call the wrapped CloseScreen procedure */ + WIN_UNWRAP(CloseScreen); + fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); + + /* Delete the window property */ + RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); + + /* Free the shadow DC; which allows the bitmap to be freed */ + DeleteDC (pScreenPriv->hdcShadow); + + winFreeFBShadowGDI(pScreen); + + /* Free the screen DC */ + ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen); + + /* Delete tray icon, if we have one */ + if (!pScreenInfo->fNoTrayIcon) + winDeleteNotifyIcon (pScreenPriv); + + /* Free the exit confirmation dialog box, if it exists */ + if (g_hDlgExit != NULL) + { + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + } + + /* Kill our window */ + if (pScreenPriv->hwndScreen) + { + DestroyWindow (pScreenPriv->hwndScreen); + pScreenPriv->hwndScreen = NULL; + } + +#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) + /* Destroy the thread startup mutex */ + pthread_mutex_destroy (&pScreenPriv->pmServerStarted); +#endif + + /* Invalidate our screeninfo's pointer to the screen */ + pScreenInfo->pScreen = NULL; + + /* Free the screen privates for this screen */ + free ((pointer) pScreenPriv); + + return fReturn; +} + + +/* + * Tell mi what sort of visuals we need. + * + * Generally we only need one visual, as our screen can only + * handle one format at a time, I believe. You may want + * to verify that last sentence. + */ + +static Bool +winInitVisualsShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Display debugging information */ + ErrorF ("winInitVisualsShadowGDI - Masks %08x %08x %08x BPRGB %d d %d " + "bpp %d\n", + (unsigned int) pScreenPriv->dwRedMask, + (unsigned int) pScreenPriv->dwGreenMask, + (unsigned int) pScreenPriv->dwBlueMask, + (int) pScreenPriv->dwBitsPerRGB, + (int) pScreenInfo->dwDepth, + (int) pScreenInfo->dwBPP); + + /* Create a single visual according to the Windows screen depth */ + switch (pScreenInfo->dwDepth) + { + case 24: + case 16: + case 15: + /* Setup the real visual */ + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + TrueColorMask, + pScreenPriv->dwBitsPerRGB, + -1, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks " + "failed\n"); + return FALSE; + } + +#ifdef XWIN_EMULATEPSEUDO + if (!pScreenInfo->fEmulatePseudo) + break; + + /* Setup a pseudocolor visual */ + if (!miSetVisualTypesAndMasks (8, + PseudoColorMask, + 8, + -1, + 0, + 0, + 0)) + { + ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks " + "failed for PseudoColor\n"); + return FALSE; + } +#endif + break; + + case 8: + if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, + PseudoColorMask, + pScreenPriv->dwBitsPerRGB, + PseudoColor, + pScreenPriv->dwRedMask, + pScreenPriv->dwGreenMask, + pScreenPriv->dwBlueMask)) + { + ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks " + "failed\n"); + return FALSE; + } + break; + + default: + ErrorF ("winInitVisualsShadowGDI - Unknown screen depth\n"); + return FALSE; + } + +#if CYGDEBUG + winDebug ("winInitVisualsShadowGDI - Returning\n"); +#endif + + return TRUE; +} + + +/* + * Adjust the proposed video mode + */ + +static Bool +winAdjustVideoModeShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + HDC hdc; + DWORD dwBPP; + + hdc = GetDC (NULL); + + /* We're in serious trouble if we can't get a DC */ + if (hdc == NULL) + { + ErrorF ("winAdjustVideoModeShadowGDI - GetDC () failed\n"); + return FALSE; + } + + /* Query GDI for current display depth */ + dwBPP = GetDeviceCaps (hdc, BITSPIXEL); + + /* GDI cannot change the screen depth, so always use GDI's depth */ + pScreenInfo->dwBPP = dwBPP; + + /* Release our DC */ + ReleaseDC (NULL, hdc); + hdc = NULL; + + return TRUE; +} + + +/* + * Blt exposed regions to the screen + */ + +static Bool +winBltExposedRegionsShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + winPrivCmapPtr pCmapPriv = NULL; + HDC hdcUpdate; + PAINTSTRUCT ps; + + /* BeginPaint gives us an hdc that clips to the invalidated region */ + hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps); + + /* Realize the palette, if we have one */ + if (pScreenPriv->pcmapInstalled != NULL) + { + pCmapPriv = winGetCmapPriv (pScreenPriv->pcmapInstalled); + + SelectPalette (hdcUpdate, pCmapPriv->hPalette, FALSE); + RealizePalette (hdcUpdate); + } + + /* Our BitBlt will be clipped to the invalidated region */ + BitBlt (hdcUpdate, + 0, 0, + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + pScreenPriv->hdcShadow, + 0, 0, + SRCCOPY); + + /* EndPaint frees the DC */ + EndPaint (pScreenPriv->hwndScreen, &ps); + +#ifdef XWIN_MULTIWINDOW + /* Redraw all windows */ + if (pScreenInfo->fMultiWindow) + EnumThreadWindows(g_dwCurrentThreadID, winRedrawAllProcShadowGDI, + (LPARAM)pScreenPriv->hwndScreen); +#endif + + return TRUE; +} + + +/* + * Do any engine-specific appliation-activation processing + */ + +static Bool +winActivateAppShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* + * 2004/04/12 - Harold - We perform the restoring or minimizing + * manually for ShadowGDI in fullscreen modes so that this engine + * will perform just like ShadowDD and ShadowDDNL in fullscreen mode; + * if we do not do this then our fullscreen window will appear in the + * z-order when it is deactivated and it can be uncovered by resizing + * or minimizing another window that is on top of it, which is not how + * the DirectDraw engines work. Therefore we keep this code here to + * make sure that all engines work the same in fullscreen mode. + */ + + /* + * Are we active? + * Are we fullscreen? + */ + if (pScreenPriv->fActive + && pScreenInfo->fFullScreen) + { + /* + * Activating, attempt to bring our window + * to the top of the display + */ + ShowWindow (pScreenPriv->hwndScreen, SW_RESTORE); + } + else if (!pScreenPriv->fActive + && pScreenInfo->fFullScreen) + { + /* + * Deactivating, stuff our window onto the + * task bar. + */ + ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); + } + + return TRUE; +} + + +/* + * Reblit the shadow framebuffer to the screen. + */ + +static Bool +winRedrawScreenShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Redraw the whole window, to take account for the new colors */ + BitBlt (pScreenPriv->hdcScreen, + 0, 0, + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + pScreenPriv->hdcShadow, + 0, 0, + SRCCOPY); + +#ifdef XWIN_MULTIWINDOW + /* Redraw all windows */ + if (pScreenInfo->fMultiWindow) + EnumThreadWindows(g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0); +#endif + + return TRUE; +} + + + +/* + * Realize the currently installed colormap + */ + +static Bool +winRealizeInstalledPaletteShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winPrivCmapPtr pCmapPriv = NULL; + +#if CYGDEBUG + winDebug ("winRealizeInstalledPaletteShadowGDI\n"); +#endif + + /* Don't do anything if there is not a colormap */ + if (pScreenPriv->pcmapInstalled == NULL) + { +#if CYGDEBUG + winDebug ("winRealizeInstalledPaletteShadowGDI - No colormap " + "installed\n"); +#endif + return TRUE; + } + + pCmapPriv = winGetCmapPriv (pScreenPriv->pcmapInstalled); + + /* Realize our palette for the screen */ + if (RealizePalette (pScreenPriv->hdcScreen) == GDI_ERROR) + { + ErrorF ("winRealizeInstalledPaletteShadowGDI - RealizePalette () " + "failed\n"); + return FALSE; + } + + /* Set the DIB color table */ + if (SetDIBColorTable (pScreenPriv->hdcShadow, + 0, + WIN_NUM_PALETTE_ENTRIES, + pCmapPriv->rgbColors) == 0) + { + ErrorF ("winRealizeInstalledPaletteShadowGDI - SetDIBColorTable () " + "failed\n"); + return FALSE; + } + + return TRUE; +} + + +/* + * Install the specified colormap + */ + +static Bool +winInstallColormapShadowGDI (ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + winCmapPriv(pColormap); + + /* + * Tell Windows to install the new colormap + */ + if (SelectPalette (pScreenPriv->hdcScreen, + pCmapPriv->hPalette, + FALSE) == NULL) + { + ErrorF ("winInstallColormapShadowGDI - SelectPalette () failed\n"); + return FALSE; + } + + /* Realize the palette */ + if (GDI_ERROR == RealizePalette (pScreenPriv->hdcScreen)) + { + ErrorF ("winInstallColormapShadowGDI - RealizePalette () failed\n"); + return FALSE; + } + + /* Set the DIB color table */ + if (SetDIBColorTable (pScreenPriv->hdcShadow, + 0, + WIN_NUM_PALETTE_ENTRIES, + pCmapPriv->rgbColors) == 0) + { + ErrorF ("winInstallColormapShadowGDI - SetDIBColorTable () failed\n"); + return FALSE; + } + + /* Redraw the whole window, to take account for the new colors */ + BitBlt (pScreenPriv->hdcScreen, + 0, 0, + pScreenInfo->dwWidth, pScreenInfo->dwHeight, + pScreenPriv->hdcShadow, + 0, 0, + SRCCOPY); + + /* Save a pointer to the newly installed colormap */ + pScreenPriv->pcmapInstalled = pColormap; + +#ifdef XWIN_MULTIWINDOW + /* Redraw all windows */ + if (pScreenInfo->fMultiWindow) + EnumThreadWindows (g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0); +#endif + + return TRUE; +} + + +/* + * Store the specified colors in the specified colormap + */ + +static Bool +winStoreColorsShadowGDI (ColormapPtr pColormap, + int ndef, + xColorItem *pdefs) +{ + ScreenPtr pScreen = pColormap->pScreen; + winScreenPriv(pScreen); + winCmapPriv(pColormap); + ColormapPtr curpmap = pScreenPriv->pcmapInstalled; + + /* Put the X colormap entries into the Windows logical palette */ + if (SetPaletteEntries (pCmapPriv->hPalette, + pdefs[0].pixel, + ndef, + pCmapPriv->peColors + pdefs[0].pixel) == 0) + { + ErrorF ("winStoreColorsShadowGDI - SetPaletteEntries () failed\n"); + return FALSE; + } + + /* Don't install the Windows palette if the colormap is not installed */ + if (pColormap != curpmap) + { + return TRUE; + } + + /* Try to install the newly modified colormap */ + if (!winInstallColormapShadowGDI (pColormap)) + { + ErrorF ("winInstallColormapShadowGDI - winInstallColormapShadowGDI " + "failed\n"); + return FALSE; + } + +#if 0 + /* Tell Windows that the palette has changed */ + RealizePalette (pScreenPriv->hdcScreen); + + /* Set the DIB color table */ + if (SetDIBColorTable (pScreenPriv->hdcShadow, + pdefs[0].pixel, + ndef, + pCmapPriv->rgbColors + pdefs[0].pixel) == 0) + { + ErrorF ("winInstallColormapShadowGDI - SetDIBColorTable () failed\n"); + return FALSE; + } + + /* Save a pointer to the newly installed colormap */ + pScreenPriv->pcmapInstalled = pColormap; +#endif + + return TRUE; +} + + +/* + * Colormap initialization procedure + */ + +static Bool +winCreateColormapShadowGDI (ColormapPtr pColormap) +{ + LPLOGPALETTE lpPaletteNew = NULL; + DWORD dwEntriesMax; + VisualPtr pVisual; + HPALETTE hpalNew = NULL; + winCmapPriv(pColormap); + + /* Get a pointer to the visual that the colormap belongs to */ + pVisual = pColormap->pVisual; + + /* Get the maximum number of palette entries for this visual */ + dwEntriesMax = pVisual->ColormapEntries; + + /* Allocate a Windows logical color palette with max entries */ + lpPaletteNew = malloc (sizeof (LOGPALETTE) + + (dwEntriesMax - 1) * sizeof (PALETTEENTRY)); + if (lpPaletteNew == NULL) + { + ErrorF ("winCreateColormapShadowGDI - Couldn't allocate palette " + "with %d entries\n", + (int) dwEntriesMax); + return FALSE; + } + + /* Zero out the colormap */ + ZeroMemory (lpPaletteNew, sizeof (LOGPALETTE) + + (dwEntriesMax - 1) * sizeof (PALETTEENTRY)); + + /* Set the logical palette structure */ + lpPaletteNew->palVersion = 0x0300; + lpPaletteNew->palNumEntries = dwEntriesMax; + + /* Tell Windows to create the palette */ + hpalNew = CreatePalette (lpPaletteNew); + if (hpalNew == NULL) + { + ErrorF ("winCreateColormapShadowGDI - CreatePalette () failed\n"); + free (lpPaletteNew); + return FALSE; + } + + /* Save the Windows logical palette handle in the X colormaps' privates */ + pCmapPriv->hPalette = hpalNew; + + /* Free the palette initialization memory */ + free (lpPaletteNew); + + return TRUE; +} + + +/* + * Colormap destruction procedure + */ + +static Bool +winDestroyColormapShadowGDI (ColormapPtr pColormap) +{ + winScreenPriv(pColormap->pScreen); + winCmapPriv(pColormap); + + /* + * Is colormap to be destroyed the default? + * + * Non-default colormaps should have had winUninstallColormap + * called on them before we get here. The default colormap + * will not have had winUninstallColormap called on it. Thus, + * we need to handle the default colormap in a special way. + */ + if (pColormap->flags & IsDefault) + { +#if CYGDEBUG + winDebug ("winDestroyColormapShadowGDI - Destroying default " + "colormap\n"); +#endif + + /* + * FIXME: Walk the list of all screens, popping the default + * palette out of each screen device context. + */ + + /* Pop the palette out of the device context */ + SelectPalette (pScreenPriv->hdcScreen, + GetStockObject (DEFAULT_PALETTE), + FALSE); + + /* Clear our private installed colormap pointer */ + pScreenPriv->pcmapInstalled = NULL; + } + + /* Try to delete the logical palette */ + if (DeleteObject (pCmapPriv->hPalette) == 0) + { + ErrorF ("winDestroyColormap - DeleteObject () failed\n"); + return FALSE; + } + + /* Invalidate the colormap privates */ + pCmapPriv->hPalette = NULL; + + return TRUE; +} + + +/* + * Set engine specific funtions + */ + +Bool +winSetEngineFunctionsShadowGDI (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + /* Set our pointers */ + pScreenPriv->pwinAllocateFB = winAllocateFBShadowGDI; + pScreenPriv->pwinFreeFB = winFreeFBShadowGDI; + pScreenPriv->pwinShadowUpdate = winShadowUpdateGDI; + pScreenPriv->pwinInitScreen = winInitScreenShadowGDI; + pScreenPriv->pwinCloseScreen = winCloseScreenShadowGDI; + pScreenPriv->pwinInitVisuals = winInitVisualsShadowGDI; + pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowGDI; + if (pScreenInfo->fFullScreen) + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; + else + pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; + pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; + pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowGDI; + pScreenPriv->pwinActivateApp = winActivateAppShadowGDI; + pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowGDI; + pScreenPriv->pwinRealizeInstalledPalette = + winRealizeInstalledPaletteShadowGDI; + pScreenPriv->pwinInstallColormap = winInstallColormapShadowGDI; + pScreenPriv->pwinStoreColors = winStoreColorsShadowGDI; + pScreenPriv->pwinCreateColormap = winCreateColormapShadowGDI; + pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowGDI; + pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinCreatePrimarySurface + = (winCreatePrimarySurfaceProcPtr) (void (*)(void))NoopDDA; + pScreenPriv->pwinReleasePrimarySurface + = (winReleasePrimarySurfaceProcPtr) (void (*)(void))NoopDDA; +#ifdef XWIN_MULTIWINDOW + pScreenPriv->pwinFinishCreateWindowsWindow = + (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA; +#endif + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winvalargs.c b/xorg-server/hw/xwin/winvalargs.c index f97bce610..04db777b0 100644 --- a/xorg-server/hw/xwin/winvalargs.c +++ b/xorg-server/hw/xwin/winvalargs.c @@ -1,180 +1,180 @@ -/* - *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of Harold L Hunt II - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from Harold L Hunt II. - * - * Authors: Harold L Hunt II - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" -#include "winmsg.h" - - - - -/* - * Verify all screens have been explicitly specified - */ -static BOOL -isEveryScreenExplicit(void) -{ - int i; - - for (i = 0; i < g_iNumScreens; i++) - if (!g_ScreenInfo[i].fExplicitScreen) - return FALSE; - - return TRUE; -} - -/* - * winValidateArgs - Look for invalid argument combinations - */ - -Bool -winValidateArgs (void) -{ - int i; - int iMaxConsecutiveScreen = 0; - BOOL fHasNormalScreen0 = FALSE; - BOOL fImplicitScreenFound = FALSE; - - /* - * Check for a malformed set of -screen parameters. - * Examples of malformed parameters: - * XWin -screen 1 - * XWin -screen 0 -screen 2 - * XWin -screen 1 -screen 2 - */ - if (!isEveryScreenExplicit()) - { - ErrorF ("winValidateArgs - Malformed set of screen parameter(s). " - "Screens must be specified consecutively starting with " - "screen 0. That is, you cannot have only a screen 1, nor " - "could you have screen 0 and screen 2. You instead must " - "have screen 0, or screen 0 and screen 1, respectively. " - "You can specify as many screens as you want.\n"); - return FALSE; - } - - /* Loop through all screens */ - for (i = 0; i < g_iNumScreens; ++i) - { - /* - * Check for any combination of - * -multiwindow, -mwextwm, and -rootless. - */ - { - int iCount = 0; - - /* Count conflicting options */ -#ifdef XWIN_MULTIWINDOW - if (g_ScreenInfo[i].fMultiWindow) - ++iCount; -#endif -#ifdef XWIN_MULTIWINDOWEXTWM - if (g_ScreenInfo[i].fMWExtWM) - ++iCount; -#endif - if (g_ScreenInfo[i].fRootless) - ++iCount; - - /* Check if the first screen is without rootless and multiwindow */ - if (iCount == 0 && i == 0) - fHasNormalScreen0 = TRUE; - - /* Fail if two or more conflicting options */ - if (iCount > 1) - { - ErrorF ("winValidateArgs - Only one of -multiwindow, -mwextwm, " - "and -rootless can be specific at a time.\n"); - return FALSE; - } - } - - /* Check for -multiwindow or -mwextwm and Xdmcp */ - /* allow xdmcp if screen 0 is normal. */ - if (g_fXdmcpEnabled && !fHasNormalScreen0 - && (FALSE -#ifdef XWIN_MULTIWINDOW - || g_ScreenInfo[i].fMultiWindow -#endif -#ifdef XWIN_MULTIWINDOWEXTWM - || g_ScreenInfo[i].fMWExtWM -#endif - ) - ) - { - ErrorF ("winValidateArgs - Xdmcp (-query, -broadcast, or -indirect) " - "is invalid with -multiwindow or -mwextwm.\n"); - return FALSE; - } - - /* Check for -multiwindow, -mwextwm, or -rootless and fullscreen */ - if (g_ScreenInfo[i].fFullScreen - && (FALSE -#ifdef XWIN_MULTIWINDOW - || g_ScreenInfo[i].fMultiWindow -#endif -#ifdef XWIN_MULTIWINDOWEXTWM - || g_ScreenInfo[i].fMWExtWM -#endif - || g_ScreenInfo[i].fRootless) - ) - { - ErrorF ("winValidateArgs - -fullscreen is invalid with " - "-multiwindow, -mwextwm, or -rootless.\n"); - return FALSE; - } - - /* Check for !fullscreen and any fullscreen-only parameters */ - if (!g_ScreenInfo[i].fFullScreen - && (g_ScreenInfo[i].dwRefreshRate != WIN_DEFAULT_BPP - || g_ScreenInfo[i].dwBPP != WIN_DEFAULT_REFRESH)) - { - ErrorF ("winValidateArgs - -refresh and -depth are only valid " - "with -fullscreen.\n"); - return FALSE; - } - - /* Check for fullscreen and any non-fullscreen parameters */ - if (g_ScreenInfo[i].fFullScreen - && (g_ScreenInfo[i].fScrollbars - || !g_ScreenInfo[i].fDecoration - || g_ScreenInfo[i].fLessPointer)) - { - ErrorF ("winValidateArgs - -fullscreen is invalid with " - "-scrollbars, -nodecoration, or -lesspointer.\n"); - return FALSE; - } - } - - winDebug ("winValidateArgs - Returning.\n"); - - return TRUE; -} +/* + *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of Harold L Hunt II + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from Harold L Hunt II. + * + * Authors: Harold L Hunt II + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" +#include "winmsg.h" + + + + +/* + * Verify all screens have been explicitly specified + */ +static BOOL +isEveryScreenExplicit(void) +{ + int i; + + for (i = 0; i < g_iNumScreens; i++) + if (!g_ScreenInfo[i].fExplicitScreen) + return FALSE; + + return TRUE; +} + +/* + * winValidateArgs - Look for invalid argument combinations + */ + +Bool +winValidateArgs (void) +{ + int i; + int iMaxConsecutiveScreen = 0; + BOOL fHasNormalScreen0 = FALSE; + BOOL fImplicitScreenFound = FALSE; + + /* + * Check for a malformed set of -screen parameters. + * Examples of malformed parameters: + * XWin -screen 1 + * XWin -screen 0 -screen 2 + * XWin -screen 1 -screen 2 + */ + if (!isEveryScreenExplicit()) + { + ErrorF ("winValidateArgs - Malformed set of screen parameter(s). " + "Screens must be specified consecutively starting with " + "screen 0. That is, you cannot have only a screen 1, nor " + "could you have screen 0 and screen 2. You instead must " + "have screen 0, or screen 0 and screen 1, respectively. " + "You can specify as many screens as you want.\n"); + return FALSE; + } + + /* Loop through all screens */ + for (i = 0; i < g_iNumScreens; ++i) + { + /* + * Check for any combination of + * -multiwindow, -mwextwm, and -rootless. + */ + { + int iCount = 0; + + /* Count conflicting options */ +#ifdef XWIN_MULTIWINDOW + if (g_ScreenInfo[i].fMultiWindow) + ++iCount; +#endif +#ifdef XWIN_MULTIWINDOWEXTWM + if (g_ScreenInfo[i].fMWExtWM) + ++iCount; +#endif + if (g_ScreenInfo[i].fRootless) + ++iCount; + + /* Check if the first screen is without rootless and multiwindow */ + if (iCount == 0 && i == 0) + fHasNormalScreen0 = TRUE; + + /* Fail if two or more conflicting options */ + if (iCount > 1) + { + ErrorF ("winValidateArgs - Only one of -multiwindow, -mwextwm, " + "and -rootless can be specific at a time.\n"); + return FALSE; + } + } + + /* Check for -multiwindow or -mwextwm and Xdmcp */ + /* allow xdmcp if screen 0 is normal. */ + if (g_fXdmcpEnabled && !fHasNormalScreen0 + && (FALSE +#ifdef XWIN_MULTIWINDOW + || g_ScreenInfo[i].fMultiWindow +#endif +#ifdef XWIN_MULTIWINDOWEXTWM + || g_ScreenInfo[i].fMWExtWM +#endif + ) + ) + { + ErrorF ("winValidateArgs - Xdmcp (-query, -broadcast, or -indirect) " + "is invalid with -multiwindow or -mwextwm.\n"); + return FALSE; + } + + /* Check for -multiwindow, -mwextwm, or -rootless and fullscreen */ + if (g_ScreenInfo[i].fFullScreen + && (FALSE +#ifdef XWIN_MULTIWINDOW + || g_ScreenInfo[i].fMultiWindow +#endif +#ifdef XWIN_MULTIWINDOWEXTWM + || g_ScreenInfo[i].fMWExtWM +#endif + || g_ScreenInfo[i].fRootless) + ) + { + ErrorF ("winValidateArgs - -fullscreen is invalid with " + "-multiwindow, -mwextwm, or -rootless.\n"); + return FALSE; + } + + /* Check for !fullscreen and any fullscreen-only parameters */ + if (!g_ScreenInfo[i].fFullScreen + && (g_ScreenInfo[i].dwRefreshRate != WIN_DEFAULT_REFRESH + || g_ScreenInfo[i].dwBPP != WIN_DEFAULT_BPP)) + { + ErrorF ("winValidateArgs - -refresh and -depth are only valid " + "with -fullscreen.\n"); + return FALSE; + } + + /* Check for fullscreen and any non-fullscreen parameters */ + if (g_ScreenInfo[i].fFullScreen + && ((g_ScreenInfo[i].iResizeMode != notAllowed) + || !g_ScreenInfo[i].fDecoration + || g_ScreenInfo[i].fLessPointer)) + { + ErrorF ("winValidateArgs - -fullscreen is invalid with " + "-scrollbars, -resize, -nodecoration, or -lesspointer.\n"); + return FALSE; + } + } + + winDebug ("winValidateArgs - Returning.\n"); + + return TRUE; +} diff --git a/xorg-server/hw/xwin/winwindow.c b/xorg-server/hw/xwin/winwindow.c index f6371a65c..7975d71a9 100644 --- a/xorg-server/hw/xwin/winwindow.c +++ b/xorg-server/hw/xwin/winwindow.c @@ -1,636 +1,637 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Harold L Hunt II - * Kensuke Matsuzaki - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" - - -/* - * Prototypes for local functions - */ - -static int -winAddRgn (WindowPtr pWindow, pointer data); - -static -void -winUpdateRgnRootless (WindowPtr pWindow); - -static -void -winReshapeRootless (WindowPtr pWin); - - -#ifdef XWIN_NATIVEGDI -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbCreateWindow() */ - -Bool -winCreateWindowNativeGDI (WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winCreateWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(CreateWindow); - fResult = (*pScreen->CreateWindow) (pWin); - WIN_WRAP(CreateWindow, winCreateWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbDestroyWindow() */ - -Bool -winDestroyWindowNativeGDI (WindowPtr pWin) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winDestroyWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(DestroyWindow); - fResult = (*pScreen->DestroyWindow)(pWin); - WIN_WRAP(DestroyWindow, winDestroyWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbPositionWindow() */ - -Bool -winPositionWindowNativeGDI (WindowPtr pWin, int x, int y) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winPositionWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(PositionWindow); - fResult = (*pScreen->PositionWindow)(pWin, x, y); - WIN_WRAP(PositionWindow, winPositionWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 39 */ -/* See mfb/mfbwindow.c - mfbCopyWindow() */ - -void -winCopyWindowNativeGDI (WindowPtr pWin, - DDXPointRec ptOldOrg, - RegionPtr prgnSrc) -{ - DDXPointPtr pptSrc; - DDXPointPtr ppt; - RegionPtr prgnDst; - BoxPtr pBox; - int dx, dy; - int i, nbox; - WindowPtr pwinRoot; - BoxPtr pBoxDst; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if 0 - ErrorF ("winCopyWindow\n"); -#endif - - /* Get a pointer to the root window */ - pwinRoot = pWin->drawable.pScreen->root; - - /* Create a region for the destination */ - prgnDst = RegionCreate(NULL, 1); - - /* Calculate the shift from the source to the destination */ - dx = ptOldOrg.x - pWin->drawable.x; - dy = ptOldOrg.y - pWin->drawable.y; - - /* Translate the region from the destination to the source? */ - RegionTranslate(prgnSrc, -dx, -dy); - RegionIntersect(prgnDst, &pWin->borderClip, - prgnSrc); - - /* Get a pointer to the first box in the region to be copied */ - pBox = RegionRects(prgnDst); - - /* Get the number of boxes in the region */ - nbox = RegionNumRects(prgnDst); - - /* Allocate source points for each box */ - if(!(pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))) - return; - - /* Set an iterator pointer */ - ppt = pptSrc; - - /* Calculate the source point of each box? */ - for (i = nbox; --i >= 0; ppt++, pBox++) - { - ppt->x = pBox->x1 + dx; - ppt->y = pBox->y1 + dy; - } - - /* Setup loop pointers again */ - pBoxDst = RegionRects(prgnDst); - ppt = pptSrc; - -#if 0 - ErrorF ("winCopyWindow - x1\tx2\ty1\ty2\tx\ty\n"); -#endif - - /* BitBlt each source to the destination point */ - for (i = nbox; --i >= 0; pBoxDst++, ppt++) - { -#if 0 - ErrorF ("winCopyWindow - %d\t%d\t%d\t%d\t%d\t%d\n", - pBoxDst->x1, pBoxDst->x2, pBoxDst->y1, pBoxDst->y2, - ppt->x, ppt->y); -#endif - - BitBlt (pScreenPriv->hdcScreen, - pBoxDst->x1, pBoxDst->y1, - pBoxDst->x2 - pBoxDst->x1, pBoxDst->y2 - pBoxDst->y1, - pScreenPriv->hdcScreen, - ppt->x, ppt->y, - SRCCOPY); - } - - /* Cleanup the regions, etc. */ - free(pptSrc); - RegionDestroy(prgnDst); -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ - -Bool -winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winChangeWindowAttributesNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(ChangeWindowAttributes); - fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); - WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesNativeGDI); - - /* - * NOTE: We do not currently need to do anything here. - */ - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as UnrealizeWindow - */ - -Bool -winUnmapWindowNativeGDI (WindowPtr pWin) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winUnmapWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(UnrealizeWindow); - fResult = (*pScreen->UnrealizeWindow)(pWin); - WIN_WRAP(UnrealizeWindow, winUnmapWindowNativeGDI); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as RealizeWindow - */ - -Bool -winMapWindowNativeGDI (WindowPtr pWin) -{ - Bool fResult = TRUE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winMapWindowNativeGDI (%p)\n", pWin); -#endif - - WIN_UNWRAP(RealizeWindow); - fResult = (*pScreen->RealizeWindow)(pWin); - WIN_WRAP(RealizeWindow, winMapWindowMultiWindow); - - return fResult; - -} -#endif - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbCreateWindow() */ - -Bool -winCreateWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winCreateWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(CreateWindow); - fResult = (*pScreen->CreateWindow) (pWin); - WIN_WRAP(CreateWindow, winCreateWindowRootless); - - pWinPriv->hRgn = NULL; - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbDestroyWindow() */ - -Bool -winDestroyWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winDestroyWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(DestroyWindow); - fResult = (*pScreen->DestroyWindow)(pWin); - WIN_WRAP(DestroyWindow, winDestroyWindowRootless); - - if (pWinPriv->hRgn != NULL) - { - DeleteObject(pWinPriv->hRgn); - pWinPriv->hRgn = NULL; - } - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbPositionWindow() */ - -Bool -winPositionWindowRootless (WindowPtr pWin, int x, int y) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - - -#if CYGDEBUG - winTrace ("winPositionWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(PositionWindow); - fResult = (*pScreen->PositionWindow)(pWin, x, y); - WIN_WRAP(PositionWindow, winPositionWindowRootless); - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 */ -/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ - -Bool -winChangeWindowAttributesRootless (WindowPtr pWin, unsigned long mask) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winChangeWindowAttributesRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(ChangeWindowAttributes); - fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); - WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesRootless); - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as UnrealizeWindow - */ - -Bool -winUnmapWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winWindowPriv(pWin); - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winUnmapWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(UnrealizeWindow); - fResult = (*pScreen->UnrealizeWindow)(pWin); - WIN_WRAP(UnrealizeWindow, winUnmapWindowRootless); - - if (pWinPriv->hRgn != NULL) - { - DeleteObject(pWinPriv->hRgn); - pWinPriv->hRgn = NULL; - } - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -/* See Porting Layer Definition - p. 37 - * Also referred to as RealizeWindow - */ - -Bool -winMapWindowRootless (WindowPtr pWin) -{ - Bool fResult = FALSE; - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winMapWindowRootless (%p)\n", pWin); -#endif - - WIN_UNWRAP(RealizeWindow); - fResult = (*pScreen->RealizeWindow)(pWin); - WIN_WRAP(RealizeWindow, winMapWindowRootless); - - winReshapeRootless (pWin); - - winUpdateRgnRootless (pWin); - - return fResult; -} - - -void -winSetShapeRootless (WindowPtr pWin, int kind) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - winScreenPriv(pScreen); - -#if CYGDEBUG - winTrace ("winSetShapeRootless (%p, %i)\n", pWin, kind); -#endif - - WIN_UNWRAP(SetShape); - (*pScreen->SetShape)(pWin, kind); - WIN_WRAP(SetShape, winSetShapeRootless); - - winReshapeRootless (pWin); - winUpdateRgnRootless (pWin); - - return; -} - - -/* - * Local function for adding a region to the Windows window region - */ - -static -int -winAddRgn (WindowPtr pWin, pointer data) -{ - int iX, iY, iWidth, iHeight, iBorder; - HRGN hRgn = *(HRGN*)data; - HRGN hRgnWin; - winWindowPriv(pWin); - - /* If pWin is not Root */ - if (pWin->parent != NULL) - { -#if CYGDEBUG - winDebug ("winAddRgn ()\n"); -#endif - if (pWin->mapped) - { - iBorder = wBorderWidth (pWin); - - iX = pWin->drawable.x - iBorder; - iY = pWin->drawable.y - iBorder; - - iWidth = pWin->drawable.width + iBorder * 2; - iHeight = pWin->drawable.height + iBorder * 2; - - hRgnWin = CreateRectRgn (0, 0, iWidth, iHeight); - - if (hRgnWin == NULL) - { - ErrorF ("winAddRgn - CreateRectRgn () failed\n"); - ErrorF (" Rect %d %d %d %d\n", - iX, iY, iX + iWidth, iY + iHeight); - } - - if (pWinPriv->hRgn) - { - if (CombineRgn (hRgnWin, hRgnWin, pWinPriv->hRgn, RGN_AND) - == ERROR) - { - ErrorF ("winAddRgn - CombineRgn () failed\n"); - } - } - - OffsetRgn (hRgnWin, iX, iY); - - if (CombineRgn (hRgn, hRgn, hRgnWin, RGN_OR) == ERROR) - { - ErrorF ("winAddRgn - CombineRgn () failed\n"); - } - - DeleteObject (hRgnWin); - } - return WT_DONTWALKCHILDREN; - } - else - { - return WT_WALKCHILDREN; - } -} - - -/* - * Local function to update the Windows window's region - */ - -static -void -winUpdateRgnRootless (WindowPtr pWin) -{ - HRGN hRgn = CreateRectRgn (0, 0, 0, 0); - - if (hRgn != NULL) - { - WalkTree (pWin->drawable.pScreen, winAddRgn, &hRgn); - SetWindowRgn (winGetScreenPriv(pWin->drawable.pScreen)->hwndScreen, - hRgn, TRUE); - } - else - { - ErrorF ("winUpdateRgnRootless - CreateRectRgn failed.\n"); - } -} - - -static -void -winReshapeRootless (WindowPtr pWin) -{ - int nRects; - RegionRec rrNewShape; - BoxPtr pShape, pRects, pEnd; - HRGN hRgn, hRgnRect; - winWindowPriv(pWin); - -#if CYGDEBUG - winDebug ("winReshapeRootless ()\n"); -#endif - - /* Bail if the window is the root window */ - if (pWin->parent == NULL) - return; - - /* Bail if the window is not top level */ - if (pWin->parent->parent != NULL) - return; - - /* Free any existing window region stored in the window privates */ - if (pWinPriv->hRgn != NULL) - { - DeleteObject (pWinPriv->hRgn); - pWinPriv->hRgn = NULL; - } - - /* Bail if the window has no bounding region defined */ - if (!wBoundingShape (pWin)) - return; - - RegionNull(&rrNewShape); - RegionCopy(&rrNewShape, wBoundingShape(pWin)); - RegionTranslate(&rrNewShape, pWin->borderWidth, - pWin->borderWidth); - - nRects = RegionNumRects(&rrNewShape); - pShape = RegionRects(&rrNewShape); - - if (nRects > 0) - { - /* Create initial empty Windows region */ - hRgn = CreateRectRgn (0, 0, 0, 0); - - /* Loop through all rectangles in the X region */ - for (pRects = pShape, pEnd = pShape + nRects; pRects < pEnd; pRects++) - { - /* Create a Windows region for the X rectangle */ - hRgnRect = CreateRectRgn (pRects->x1, pRects->y1, - pRects->x2, pRects->y2); - if (hRgnRect == NULL) - { - ErrorF("winReshapeRootless - CreateRectRgn() failed\n"); - } - - /* Merge the Windows region with the accumulated region */ - if (CombineRgn (hRgn, hRgn, hRgnRect, RGN_OR) == ERROR) - { - ErrorF("winReshapeRootless - CombineRgn() failed\n"); - } - - /* Delete the temporary Windows region */ - DeleteObject (hRgnRect); - } - - /* Save a handle to the composite region in the window privates */ - pWinPriv->hRgn = hRgn; - } - - RegionUninit(&rrNewShape); - - return; -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + * Kensuke Matsuzaki + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" + + +/* + * Prototypes for local functions + */ + +static int +winAddRgn (WindowPtr pWindow, pointer data); + +static +void +winUpdateRgnRootless (WindowPtr pWindow); + +static +void +winReshapeRootless (WindowPtr pWin); + + +#ifdef XWIN_NATIVEGDI +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbCreateWindow() */ + +Bool +winCreateWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winCreateWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(CreateWindow); + fResult = (*pScreen->CreateWindow) (pWin); + WIN_WRAP(CreateWindow, winCreateWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbDestroyWindow() */ + +Bool +winDestroyWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winDestroyWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(DestroyWindow); + fResult = (*pScreen->DestroyWindow)(pWin); + WIN_WRAP(DestroyWindow, winDestroyWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbPositionWindow() */ + +Bool +winPositionWindowNativeGDI (WindowPtr pWin, int x, int y) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winPositionWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(PositionWindow); + fResult = (*pScreen->PositionWindow)(pWin, x, y); + WIN_WRAP(PositionWindow, winPositionWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 39 */ +/* See mfb/mfbwindow.c - mfbCopyWindow() */ + +void +winCopyWindowNativeGDI (WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + DDXPointPtr pptSrc; + DDXPointPtr ppt; + RegionPtr prgnDst; + BoxPtr pBox; + int dx, dy; + int i, nbox; + WindowPtr pwinRoot; + BoxPtr pBoxDst; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if 0 + ErrorF ("winCopyWindow\n"); +#endif + + /* Get a pointer to the root window */ + pwinRoot = pWin->drawable.pScreen->root; + + /* Create a region for the destination */ + prgnDst = RegionCreate(NULL, 1); + + /* Calculate the shift from the source to the destination */ + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + + /* Translate the region from the destination to the source? */ + RegionTranslate(prgnSrc, -dx, -dy); + RegionIntersect(prgnDst, &pWin->borderClip, + prgnSrc); + + /* Get a pointer to the first box in the region to be copied */ + pBox = RegionRects(prgnDst); + + /* Get the number of boxes in the region */ + nbox = RegionNumRects(prgnDst); + + /* Allocate source points for each box */ + if(!(pptSrc = (DDXPointPtr )malloc(nbox * sizeof(DDXPointRec)))) + return; + + /* Set an iterator pointer */ + ppt = pptSrc; + + /* Calculate the source point of each box? */ + for (i = nbox; --i >= 0; ppt++, pBox++) + { + ppt->x = pBox->x1 + dx; + ppt->y = pBox->y1 + dy; + } + + /* Setup loop pointers again */ + pBoxDst = RegionRects(prgnDst); + ppt = pptSrc; + +#if 0 + ErrorF ("winCopyWindow - x1\tx2\ty1\ty2\tx\ty\n"); +#endif + + /* BitBlt each source to the destination point */ + for (i = nbox; --i >= 0; pBoxDst++, ppt++) + { +#if 0 + ErrorF ("winCopyWindow - %d\t%d\t%d\t%d\t%d\t%d\n", + pBoxDst->x1, pBoxDst->x2, pBoxDst->y1, pBoxDst->y2, + ppt->x, ppt->y); +#endif + + BitBlt (pScreenPriv->hdcScreen, + pBoxDst->x1, pBoxDst->y1, + pBoxDst->x2 - pBoxDst->x1, pBoxDst->y2 - pBoxDst->y1, + pScreenPriv->hdcScreen, + ppt->x, ppt->y, + SRCCOPY); + } + + /* Cleanup the regions, etc. */ + free(pptSrc); + RegionDestroy(prgnDst); +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ + +Bool +winChangeWindowAttributesNativeGDI (WindowPtr pWin, unsigned long mask) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winChangeWindowAttributesNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(ChangeWindowAttributes); + fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); + WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesNativeGDI); + + /* + * NOTE: We do not currently need to do anything here. + */ + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as UnrealizeWindow + */ + +Bool +winUnmapWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winUnmapWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(UnrealizeWindow); + fResult = (*pScreen->UnrealizeWindow)(pWin); + WIN_WRAP(UnrealizeWindow, winUnmapWindowNativeGDI); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as RealizeWindow + */ + +Bool +winMapWindowNativeGDI (WindowPtr pWin) +{ + Bool fResult = TRUE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winMapWindowNativeGDI (%p)\n", pWin); +#endif + + WIN_UNWRAP(RealizeWindow); + fResult = (*pScreen->RealizeWindow)(pWin); + WIN_WRAP(RealizeWindow, winMapWindowMultiWindow); + + return fResult; + +} +#endif + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbCreateWindow() */ + +Bool +winCreateWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winCreateWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(CreateWindow); + fResult = (*pScreen->CreateWindow) (pWin); + WIN_WRAP(CreateWindow, winCreateWindowRootless); + + pWinPriv->hRgn = NULL; + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbDestroyWindow() */ + +Bool +winDestroyWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winDestroyWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(DestroyWindow); + fResult = (*pScreen->DestroyWindow)(pWin); + WIN_WRAP(DestroyWindow, winDestroyWindowRootless); + + if (pWinPriv->hRgn != NULL) + { + DeleteObject(pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbPositionWindow() */ + +Bool +winPositionWindowRootless (WindowPtr pWin, int x, int y) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + + +#if CYGDEBUG + winTrace ("winPositionWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(PositionWindow); + fResult = (*pScreen->PositionWindow)(pWin, x, y); + WIN_WRAP(PositionWindow, winPositionWindowRootless); + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 */ +/* See mfb/mfbwindow.c - mfbChangeWindowAttributes() */ + +Bool +winChangeWindowAttributesRootless (WindowPtr pWin, unsigned long mask) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winChangeWindowAttributesRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(ChangeWindowAttributes); + fResult = (*pScreen->ChangeWindowAttributes)(pWin, mask); + WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesRootless); + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as UnrealizeWindow + */ + +Bool +winUnmapWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winWindowPriv(pWin); + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winUnmapWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(UnrealizeWindow); + fResult = (*pScreen->UnrealizeWindow)(pWin); + WIN_WRAP(UnrealizeWindow, winUnmapWindowRootless); + + if (pWinPriv->hRgn != NULL) + { + DeleteObject(pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +/* See Porting Layer Definition - p. 37 + * Also referred to as RealizeWindow + */ + +Bool +winMapWindowRootless (WindowPtr pWin) +{ + Bool fResult = FALSE; + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winMapWindowRootless (%p)\n", pWin); +#endif + + WIN_UNWRAP(RealizeWindow); + fResult = (*pScreen->RealizeWindow)(pWin); + WIN_WRAP(RealizeWindow, winMapWindowRootless); + + winReshapeRootless (pWin); + + winUpdateRgnRootless (pWin); + + return fResult; +} + + +void +winSetShapeRootless (WindowPtr pWin, int kind) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + winScreenPriv(pScreen); + +#if CYGDEBUG + winTrace ("winSetShapeRootless (%p, %i)\n", pWin, kind); +#endif + + WIN_UNWRAP(SetShape); + (*pScreen->SetShape)(pWin, kind); + WIN_WRAP(SetShape, winSetShapeRootless); + + winReshapeRootless (pWin); + winUpdateRgnRootless (pWin); + + return; +} + + +/* + * Local function for adding a region to the Windows window region + */ + +static +int +winAddRgn (WindowPtr pWin, pointer data) +{ + int iX, iY, iWidth, iHeight, iBorder; + HRGN hRgn = *(HRGN*)data; + HRGN hRgnWin; + winWindowPriv(pWin); + + /* If pWin is not Root */ + if (pWin->parent != NULL) + { +#if CYGDEBUG + winDebug ("winAddRgn ()\n"); +#endif + if (pWin->mapped) + { + iBorder = wBorderWidth (pWin); + + iX = pWin->drawable.x - iBorder; + iY = pWin->drawable.y - iBorder; + + iWidth = pWin->drawable.width + iBorder * 2; + iHeight = pWin->drawable.height + iBorder * 2; + + hRgnWin = CreateRectRgn (0, 0, iWidth, iHeight); + + if (hRgnWin == NULL) + { + ErrorF ("winAddRgn - CreateRectRgn () failed\n"); + ErrorF (" Rect %d %d %d %d\n", + iX, iY, iX + iWidth, iY + iHeight); + } + + if (pWinPriv->hRgn) + { + if (CombineRgn (hRgnWin, hRgnWin, pWinPriv->hRgn, RGN_AND) + == ERROR) + { + ErrorF ("winAddRgn - CombineRgn () failed\n"); + } + } + + OffsetRgn (hRgnWin, iX, iY); + + if (CombineRgn (hRgn, hRgn, hRgnWin, RGN_OR) == ERROR) + { + ErrorF ("winAddRgn - CombineRgn () failed\n"); + } + + DeleteObject (hRgnWin); + } + return WT_DONTWALKCHILDREN; + } + else + { + return WT_WALKCHILDREN; + } +} + + +/* + * Local function to update the Windows window's region + */ + +static +void +winUpdateRgnRootless (WindowPtr pWin) +{ + HRGN hRgn = CreateRectRgn (0, 0, 0, 0); + + if (hRgn != NULL) + { + WalkTree (pWin->drawable.pScreen, winAddRgn, &hRgn); + SetWindowRgn (winGetScreenPriv(pWin->drawable.pScreen)->hwndScreen, + hRgn, TRUE); + } + else + { + ErrorF ("winUpdateRgnRootless - CreateRectRgn failed.\n"); + } +} + + +static +void +winReshapeRootless (WindowPtr pWin) +{ + int nRects; + RegionRec rrNewShape; + BoxPtr pShape, pRects, pEnd; + HRGN hRgn, hRgnRect; + winWindowPriv(pWin); + +#if CYGDEBUG + winDebug ("winReshapeRootless ()\n"); +#endif + + /* Bail if the window is the root window */ + if (pWin->parent == NULL) + return; + + /* Bail if the window is not top level */ + if (pWin->parent->parent != NULL) + return; + + /* Free any existing window region stored in the window privates */ + if (pWinPriv->hRgn != NULL) + { + DeleteObject (pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + /* Bail if the window has no bounding region defined */ + if (!wBoundingShape (pWin)) + return; + + RegionNull(&rrNewShape); + RegionCopy(&rrNewShape, wBoundingShape(pWin)); + RegionTranslate(&rrNewShape, pWin->borderWidth, + pWin->borderWidth); + + nRects = RegionNumRects(&rrNewShape); + pShape = RegionRects(&rrNewShape); + + if (nRects > 0) + { + /* Create initial empty Windows region */ + hRgn = CreateRectRgn (0, 0, 0, 0); + + /* Loop through all rectangles in the X region */ + for (pRects = pShape, pEnd = pShape + nRects; pRects < pEnd; pRects++) + { + /* Create a Windows region for the X rectangle */ + hRgnRect = CreateRectRgn (pRects->x1, pRects->y1, + pRects->x2, pRects->y2); + if (hRgnRect == NULL) + { + ErrorF("winReshapeRootless - CreateRectRgn() failed\n"); + } + + /* Merge the Windows region with the accumulated region */ + if (CombineRgn (hRgn, hRgn, hRgnRect, RGN_OR) == ERROR) + { + ErrorF("winReshapeRootless - CombineRgn() failed\n"); + } + + /* Delete the temporary Windows region */ + DeleteObject (hRgnRect); + } + + /* Save a handle to the composite region in the window privates */ + pWinPriv->hRgn = hRgn; + } + + RegionUninit(&rrNewShape); + + return; +} diff --git a/xorg-server/hw/xwin/winwndproc.c b/xorg-server/hw/xwin/winwndproc.c index 6d03de174..bccd6f9f2 100644 --- a/xorg-server/hw/xwin/winwndproc.c +++ b/xorg-server/hw/xwin/winwndproc.c @@ -1,1263 +1,1312 @@ -/* - *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. - * - *Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - *"Software"), to deal in the Software without restriction, including - *without limitation the rights to use, copy, modify, merge, publish, - *distribute, sublicense, and/or sell copies of the Software, and to - *permit persons to whom the Software is furnished to do so, subject to - *the following conditions: - * - *The above copyright notice and this permission notice shall be - *included in all copies or substantial portions of the Software. - * - *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR - *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - *Except as contained in this notice, the name of the XFree86 Project - *shall not be used in advertising or otherwise to promote the sale, use - *or other dealings in this Software without prior written authorization - *from the XFree86 Project. - * - * Authors: Dakshinamurthy Karra - * Suhaib M Siddiqi - * Peter Busch - * Harold L Hunt II - * MATSUZAKI Kensuke - */ - -#ifdef HAVE_XWIN_CONFIG_H -#include -#endif -#include "win.h" -#include -#include "winprefs.h" -#include "winconfig.h" -#include "winmsg.h" -#include "inputstr.h" - -/* - * Global variables - */ - -Bool g_fCursor = TRUE; -Bool g_fButton[3] = { FALSE, FALSE, FALSE }; - - -/* - * Called by winWakeupHandler - * Processes current Windows message - */ - -LRESULT CALLBACK -winWindowProc (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - static winPrivScreenPtr s_pScreenPriv = NULL; - static winScreenInfo *s_pScreenInfo = NULL; - static ScreenPtr s_pScreen = NULL; - static HWND s_hwndLastPrivates = NULL; - static HINSTANCE s_hInstance; - static Bool s_fTracking = FALSE; - static unsigned long s_ulServerGeneration = 0; - static UINT s_uTaskbarRestart = 0; - int iScanCode; - int i; - -#if CYGDEBUG - winDebugWin32Message("winWindowProc", hwnd, message, wParam, lParam); -#endif - - /* Watch for server regeneration */ - if (g_ulServerGeneration != s_ulServerGeneration) - { - /* Store new server generation */ - s_ulServerGeneration = g_ulServerGeneration; - } - - /* Only retrieve new privates pointers if window handle is null or changed */ - if ((s_pScreenPriv == NULL || hwnd != s_hwndLastPrivates) - && (s_pScreenPriv = GetProp (hwnd, WIN_SCR_PROP)) != NULL) - { -#if CYGDEBUG - winDebug ("winWindowProc - Setting privates handle\n"); -#endif - s_pScreenInfo = s_pScreenPriv->pScreenInfo; - s_pScreen = s_pScreenInfo->pScreen; - s_hwndLastPrivates = hwnd; - } - else if (s_pScreenPriv == NULL) - { - /* For safety, handle case that should never happen */ - s_pScreenInfo = NULL; - s_pScreen = NULL; - s_hwndLastPrivates = NULL; - } - - /* Branch on message type */ - switch (message) - { - case WM_TRAYICON: - return winHandleIconMessage (hwnd, message, wParam, lParam, - s_pScreenPriv); - - case WM_CREATE: -#if CYGDEBUG - winDebug ("winWindowProc - WM_CREATE\n"); -#endif - - /* - * Add a property to our display window that references - * this screens' privates. - * - * This allows the window procedure to refer to the - * appropriate window DC and shadow DC for the window that - * it is processing. We use this to repaint exposed - * areas of our display window. - */ - s_pScreenPriv = ((LPCREATESTRUCT) lParam)->lpCreateParams; - s_hInstance = ((LPCREATESTRUCT) lParam)->hInstance; - s_pScreenInfo = s_pScreenPriv->pScreenInfo; - s_pScreen = s_pScreenInfo->pScreen; - s_hwndLastPrivates = hwnd; - s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); - SetProp (hwnd, WIN_SCR_PROP, s_pScreenPriv); - - /* Setup tray icon */ - if (!s_pScreenInfo->fNoTrayIcon) - { - /* - * NOTE: The WM_CREATE message is processed before CreateWindowEx - * returns, so s_pScreenPriv->hwndScreen is invalid at this point. - * We go ahead and copy our hwnd parameter over top of the screen - * privates hwndScreen so that we have a valid value for - * that member. Otherwise, the tray icon will disappear - * the first time you move the mouse over top of it. - */ - - s_pScreenPriv->hwndScreen = hwnd; - - winInitNotifyIcon (s_pScreenPriv); - } - return 0; - - case WM_DISPLAYCHANGE: - /* We cannot handle a display mode change during initialization */ - if (s_pScreenInfo == NULL) - FatalError ("winWindowProc - WM_DISPLAYCHANGE - The display " - "mode changed while we were intializing. This is " - "very bad and unexpected. Exiting.\n"); - - /* - * We do not care about display changes with - * fullscreen DirectDraw engines, because those engines set - * their own mode when they become active. - */ - if (s_pScreenInfo->fFullScreen - && (s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD - || s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL -#ifdef XWIN_PRIMARYFB - || s_pScreenInfo->dwEngine == WIN_SERVER_PRIMARY_DD -#endif - )) - { - /* - * Store the new display dimensions and depth. - * We do this here for future compatibility in case we - * ever allow switching from fullscreen to windowed mode. - */ - s_pScreenPriv->dwLastWindowsWidth = GetSystemMetrics (SM_CXSCREEN); - s_pScreenPriv->dwLastWindowsHeight = GetSystemMetrics (SM_CYSCREEN); - s_pScreenPriv->dwLastWindowsBitsPixel - = GetDeviceCaps (s_pScreenPriv->hdcScreen, BITSPIXEL); - break; - } - - ErrorF ("winWindowProc - WM_DISPLAYCHANGE - orig bpp: %d, last bpp: %d, " - "new bpp: %d\n", - (int) s_pScreenInfo->dwBPP, - (int) s_pScreenPriv->dwLastWindowsBitsPixel, - wParam); - - ErrorF ("winWindowProc - WM_DISPLAYCHANGE - new width: %d " - "new height: %d\n", - LOWORD (lParam), HIWORD (lParam)); - - /* - * TrueColor --> TrueColor depth changes are disruptive for: - * Windowed: - * Shadow DirectDraw - * Shadow DirectDraw Non-Locking - * Primary DirectDraw - * - * TrueColor --> TrueColor depth changes are non-optimal for: - * Windowed: - * Shadow GDI - * - * FullScreen: - * Shadow GDI - * - * TrueColor --> PseudoColor or vice versa are disruptive for: - * Windowed: - * Shadow DirectDraw - * Shadow DirectDraw Non-Locking - * Primary DirectDraw - * Shadow GDI - */ - - /* - * Check for a disruptive change in depth. - * We can only display a message for a disruptive depth change, - * we cannot do anything to correct the situation. - */ - if ((s_pScreenInfo->dwBPP != wParam) - && (s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD - || s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL -#ifdef XWIN_PRIMARYFB - || s_pScreenInfo->dwEngine == WIN_SERVER_PRIMARY_DD -#endif - )) - { - /* Cannot display the visual until the depth is restored */ - ErrorF ("winWindowProc - Disruptive change in depth\n"); - - /* Display Exit dialog */ - winDisplayDepthChangeDialog (s_pScreenPriv); - - /* Flag that we have an invalid screen depth */ - s_pScreenPriv->fBadDepth = TRUE; - - /* Minimize the display window */ - ShowWindow (hwnd, SW_MINIMIZE); - } - else - { - /* Flag that we have a valid screen depth */ - s_pScreenPriv->fBadDepth = FALSE; - } - - /* - * Check for a change in display dimensions. - * We can simply recreate the same-sized primary surface when - * the display dimensions change. - */ - if (s_pScreenPriv->dwLastWindowsWidth != LOWORD (lParam) - || s_pScreenPriv->dwLastWindowsHeight != HIWORD (lParam)) - { - /* - * NOTE: The non-DirectDraw engines set the ReleasePrimarySurface - * and CreatePrimarySurface function pointers to point - * to the no operation function, NoopDDA. This allows us - * to blindly call these functions, even if they are not - * relevant to the current engine (e.g., Shadow GDI). - */ - -#if CYGDEBUG - winDebug ("winWindowProc - WM_DISPLAYCHANGE - Dimensions changed\n"); -#endif - - /* Release the old primary surface */ - (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen); - -#if CYGDEBUG - winDebug ("winWindowProc - WM_DISPLAYCHANGE - Released " - "primary surface\n"); -#endif - - /* Create the new primary surface */ - (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen); - -#if CYGDEBUG - winDebug ("winWindowProc - WM_DISPLAYCHANGE - Recreated " - "primary surface\n"); -#endif - -#if 0 - /* Multi-Window mode uses RandR for resizes */ - if (s_pScreenInfo->fMultiWindow) - { - RRSetScreenConfig (); - } -#endif - } - else - { -#if CYGDEBUG - winDebug ("winWindowProc - WM_DISPLAYCHANGE - Dimensions did not " - "change\n"); -#endif - } - - /* Store the new display dimensions and depth */ - if (s_pScreenInfo->fMultipleMonitors) - { - s_pScreenPriv->dwLastWindowsWidth - = GetSystemMetrics (SM_CXVIRTUALSCREEN); - s_pScreenPriv->dwLastWindowsHeight - = GetSystemMetrics (SM_CYVIRTUALSCREEN); - } - else - { - s_pScreenPriv->dwLastWindowsWidth - = GetSystemMetrics (SM_CXSCREEN); - s_pScreenPriv->dwLastWindowsHeight - = GetSystemMetrics (SM_CYSCREEN); - } - s_pScreenPriv->dwLastWindowsBitsPixel - = GetDeviceCaps (s_pScreenPriv->hdcScreen, BITSPIXEL); - break; - - case WM_SIZE: - { - SCROLLINFO si; - RECT rcWindow; - int iWidth, iHeight; - -#if CYGDEBUG - winDebug ("winWindowProc - WM_SIZE\n"); -#endif - - /* Break if we do not use scrollbars */ - if (!s_pScreenInfo->fScrollbars - || !s_pScreenInfo->fDecoration -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - || s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOW - || s_pScreenInfo->fMultiWindow -#endif - || s_pScreenInfo->fFullScreen) - break; - - /* No need to resize if we get minimized */ - if (wParam == SIZE_MINIMIZED) - return 0; - - /* - * Get the size of the whole window, including client area, - * scrollbars, and non-client area decorations (caption, borders). - * We do this because we need to check if the client area - * without scrollbars is large enough to display the whole visual. - * The new client area size passed by lParam already subtracts - * the size of the scrollbars if they are currently displayed. - * So checking is LOWORD(lParam) == visual_width and - * HIWORD(lParam) == visual_height will never tell us to hide - * the scrollbars because the client area would always be too small. - * GetClientRect returns the same sizes given by lParam, so we - * cannot use GetClientRect either. - */ - GetWindowRect (hwnd, &rcWindow); - iWidth = rcWindow.right - rcWindow.left; - iHeight = rcWindow.bottom - rcWindow.top; - - ErrorF ("winWindowProc - WM_SIZE - window w: %d h: %d, " - "new client area w: %d h: %d\n", - iWidth, iHeight, LOWORD (lParam), HIWORD (lParam)); - - /* Subtract the frame size from the window size. */ - iWidth -= 2 * GetSystemMetrics (SM_CXSIZEFRAME); - iHeight -= (2 * GetSystemMetrics (SM_CYSIZEFRAME) - + GetSystemMetrics (SM_CYCAPTION)); - - /* - * Update scrollbar page sizes. - * NOTE: If page size == range, then the scrollbar is - * automatically hidden. - */ - - /* Is the naked client area large enough to show the whole visual? */ - if (iWidth < s_pScreenInfo->dwWidth - || iHeight < s_pScreenInfo->dwHeight) - { - /* Client area too small to display visual, use scrollbars */ - iWidth -= GetSystemMetrics (SM_CXVSCROLL); - iHeight -= GetSystemMetrics (SM_CYHSCROLL); - } - - /* Set the horizontal scrollbar page size */ - si.cbSize = sizeof (si); - si.fMask = SIF_PAGE | SIF_RANGE; - si.nMin = 0; - si.nMax = s_pScreenInfo->dwWidth - 1; - si.nPage = iWidth; - SetScrollInfo (hwnd, SB_HORZ, &si, TRUE); - - /* Set the vertical scrollbar page size */ - si.cbSize = sizeof (si); - si.fMask = SIF_PAGE | SIF_RANGE; - si.nMin = 0; - si.nMax = s_pScreenInfo->dwHeight - 1; - si.nPage = iHeight; - SetScrollInfo (hwnd, SB_VERT, &si, TRUE); - - /* - * NOTE: Scrollbars may have moved if they were at the - * far right/bottom, so we query their current position. - */ - - /* Get the horizontal scrollbar position and set the offset */ - si.cbSize = sizeof (si); - si.fMask = SIF_POS; - GetScrollInfo (hwnd, SB_HORZ, &si); - s_pScreenInfo->dwXOffset = -si.nPos; - - /* Get the vertical scrollbar position and set the offset */ - si.cbSize = sizeof (si); - si.fMask = SIF_POS; - GetScrollInfo (hwnd, SB_VERT, &si); - s_pScreenInfo->dwYOffset = -si.nPos; - } - return 0; - - case WM_VSCROLL: - { - SCROLLINFO si; - int iVertPos; - -#if CYGDEBUG - winDebug ("winWindowProc - WM_VSCROLL\n"); -#endif - - /* Get vertical scroll bar info */ - si.cbSize = sizeof (si); - si.fMask = SIF_ALL; - GetScrollInfo (hwnd, SB_VERT, &si); - - /* Save the vertical position for comparison later */ - iVertPos = si.nPos; - - /* - * Don't forget: - * moving the scrollbar to the DOWN, scroll the content UP - */ - switch (LOWORD(wParam)) - { - case SB_TOP: - si.nPos = si.nMin; - break; - - case SB_BOTTOM: - si.nPos = si.nMax - si.nPage + 1; - break; - - case SB_LINEUP: - si.nPos -= 1; - break; - - case SB_LINEDOWN: - si.nPos += 1; - break; - - case SB_PAGEUP: - si.nPos -= si.nPage; - break; - - case SB_PAGEDOWN: - si.nPos += si.nPage; - break; - - case SB_THUMBTRACK: - si.nPos = si.nTrackPos; - break; - - default: - break; - } - - /* - * We retrieve the position after setting it, - * because Windows may adjust it. - */ - si.fMask = SIF_POS; - SetScrollInfo (hwnd, SB_VERT, &si, TRUE); - GetScrollInfo (hwnd, SB_VERT, &si); - - /* Scroll the window if the position has changed */ - if (si.nPos != iVertPos) - { - /* Save the new offset for bit block transfers, etc. */ - s_pScreenInfo->dwYOffset = -si.nPos; - - /* Change displayed region in the window */ - ScrollWindowEx (hwnd, - 0, - iVertPos - si.nPos, - NULL, - NULL, - NULL, - NULL, - SW_INVALIDATE); - - /* Redraw the window contents */ - UpdateWindow (hwnd); - } - } - return 0; - - case WM_HSCROLL: - { - SCROLLINFO si; - int iHorzPos; - -#if CYGDEBUG - winDebug ("winWindowProc - WM_HSCROLL\n"); -#endif - - /* Get horizontal scroll bar info */ - si.cbSize = sizeof (si); - si.fMask = SIF_ALL; - GetScrollInfo (hwnd, SB_HORZ, &si); - - /* Save the horizontal position for comparison later */ - iHorzPos = si.nPos; - - /* - * Don't forget: - * moving the scrollbar to the RIGHT, scroll the content LEFT - */ - switch (LOWORD(wParam)) - { - case SB_LEFT: - si.nPos = si.nMin; - break; - - case SB_RIGHT: - si.nPos = si.nMax - si.nPage + 1; - break; - - case SB_LINELEFT: - si.nPos -= 1; - break; - - case SB_LINERIGHT: - si.nPos += 1; - break; - - case SB_PAGELEFT: - si.nPos -= si.nPage; - break; - - case SB_PAGERIGHT: - si.nPos += si.nPage; - break; - - case SB_THUMBTRACK: - si.nPos = si.nTrackPos; - break; - - default: - break; - } - - /* - * We retrieve the position after setting it, - * because Windows may adjust it. - */ - si.fMask = SIF_POS; - SetScrollInfo (hwnd, SB_HORZ, &si, TRUE); - GetScrollInfo (hwnd, SB_HORZ, &si); - - /* Scroll the window if the position has changed */ - if (si.nPos != iHorzPos) - { - /* Save the new offset for bit block transfers, etc. */ - s_pScreenInfo->dwXOffset = -si.nPos; - - /* Change displayed region in the window */ - ScrollWindowEx (hwnd, - iHorzPos - si.nPos, - 0, - NULL, - NULL, - NULL, - NULL, - SW_INVALIDATE); - - /* Redraw the window contents */ - UpdateWindow (hwnd); - } - } - return 0; - - case WM_GETMINMAXINFO: - { - MINMAXINFO *pMinMaxInfo = (MINMAXINFO *) lParam; - int iCaptionHeight; - int iBorderHeight, iBorderWidth; - -#if CYGDEBUG - winDebug ("winWindowProc - WM_GETMINMAXINFO - pScreenInfo: %08x\n", - s_pScreenInfo); -#endif - - /* Can't do anything without screen info */ - if (s_pScreenInfo == NULL - || !s_pScreenInfo->fScrollbars - || s_pScreenInfo->fFullScreen - || !s_pScreenInfo->fDecoration -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - || s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOW - || s_pScreenInfo->fMultiWindow -#endif - ) - break; - - /* - * Here we can override the maximum tracking size, which - * is the largest size that can be assigned to our window - * via the sizing border. - */ - - /* - * FIXME: Do we only need to do this once, since our visual size - * does not change? Does Windows store this value statically - * once we have set it once? - */ - - /* Get the border and caption sizes */ - iCaptionHeight = GetSystemMetrics (SM_CYCAPTION); - iBorderWidth = 2 * GetSystemMetrics (SM_CXSIZEFRAME); - iBorderHeight = 2 * GetSystemMetrics (SM_CYSIZEFRAME); - - /* Allow the full visual to be displayed */ - pMinMaxInfo->ptMaxTrackSize.x - = s_pScreenInfo->dwWidth + iBorderWidth; - pMinMaxInfo->ptMaxTrackSize.y - = s_pScreenInfo->dwHeight + iBorderHeight + iCaptionHeight; - } - return 0; - - case WM_ERASEBKGND: -#if CYGDEBUG - winDebug ("winWindowProc - WM_ERASEBKGND\n"); -#endif - /* - * Pretend that we did erase the background but we don't care, - * the application uses the full window estate. This avoids some - * flickering when resizing. - */ - return TRUE; - - case WM_PAINT: -#if CYGDEBUG - winDebug ("winWindowProc - WM_PAINT\n"); -#endif - /* Only paint if we have privates and the server is enabled */ - if (s_pScreenPriv == NULL - || !s_pScreenPriv->fEnabled - || (s_pScreenInfo->fFullScreen && !s_pScreenPriv->fActive) - || s_pScreenPriv->fBadDepth) - { - /* We don't want to paint */ - break; - } - - /* Break out here if we don't have a valid paint routine */ - if (s_pScreenPriv->pwinBltExposedRegions == NULL) - break; - - /* Call the engine dependent repainter */ - (*s_pScreenPriv->pwinBltExposedRegions) (s_pScreen); - return 0; - - case WM_PALETTECHANGED: - { -#if CYGDEBUG - winDebug ("winWindowProc - WM_PALETTECHANGED\n"); -#endif - /* - * Don't process if we don't have privates or a colormap, - * or if we have an invalid depth. - */ - if (s_pScreenPriv == NULL - || s_pScreenPriv->pcmapInstalled == NULL - || s_pScreenPriv->fBadDepth) - break; - - /* Return if we caused the palette to change */ - if ((HWND) wParam == hwnd) - { - /* Redraw the screen */ - (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); - return 0; - } - - /* Reinstall the windows palette */ - (*s_pScreenPriv->pwinRealizeInstalledPalette) (s_pScreen); - - /* Redraw the screen */ - (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); - return 0; - } - - case WM_MOUSEMOVE: - /* We can't do anything without privates */ - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* We can't do anything without g_pwinPointer */ - if (g_pwinPointer == NULL) - break; - - /* Has the mouse pointer crossed screens? */ - if (s_pScreen != miPointerGetScreen(g_pwinPointer)) - miPointerSetScreen (g_pwinPointer, s_pScreenInfo->dwScreen, - GET_X_LPARAM(lParam)-s_pScreenInfo->dwXOffset, - GET_Y_LPARAM(lParam)-s_pScreenInfo->dwYOffset); - - /* Are we tracking yet? */ - if (!s_fTracking) - { - TRACKMOUSEEVENT tme; - - /* Setup data structure */ - ZeroMemory (&tme, sizeof (tme)); - tme.cbSize = sizeof (tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hwnd; - - /* Call the tracking function */ - if (!(*g_fpTrackMouseEvent) (&tme)) - ErrorF ("winWindowProc - _TrackMouseEvent failed\n"); - - /* Flag that we are tracking now */ - s_fTracking = TRUE; - } - - /* Hide or show the Windows mouse cursor */ - if (g_fSoftwareCursor && g_fCursor && (s_pScreenPriv->fActive || s_pScreenInfo->fLessPointer)) - { - /* Hide Windows cursor */ - g_fCursor = FALSE; - ShowCursor (FALSE); - } - else if (g_fSoftwareCursor && !g_fCursor && !s_pScreenPriv->fActive - && !s_pScreenInfo->fLessPointer) - { - /* Show Windows cursor */ - g_fCursor = TRUE; - ShowCursor (TRUE); - } - - /* Deliver absolute cursor position to X Server */ - winEnqueueMotion(GET_X_LPARAM(lParam)-s_pScreenInfo->dwXOffset, - GET_Y_LPARAM(lParam)-s_pScreenInfo->dwYOffset); - return 0; - - case WM_NCMOUSEMOVE: - /* - * We break instead of returning 0 since we need to call - * DefWindowProc to get the mouse cursor changes - * and min/max/close button highlighting in Windows XP. - * The Platform SDK says that you should return 0 if you - * process this message, but it fails to mention that you - * will give up any default functionality if you do return 0. - */ - - /* We can't do anything without privates */ - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* Non-client mouse movement, show Windows cursor */ - if (g_fSoftwareCursor && !g_fCursor) - { - g_fCursor = TRUE; - ShowCursor (TRUE); - } - break; - - case WM_MOUSELEAVE: - /* Mouse has left our client area */ - - /* Flag that we are no longer tracking */ - s_fTracking = FALSE; - - /* Show the mouse cursor, if necessary */ - if (g_fSoftwareCursor && !g_fCursor) - { - g_fCursor = TRUE; - ShowCursor (TRUE); - } - return 0; - - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - SetCapture (hwnd); - return winMouseButtonsHandle (s_pScreen, ButtonPress, Button1, wParam); - - case WM_LBUTTONUP: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - ReleaseCapture (); - return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button1, wParam); - - case WM_MBUTTONDBLCLK: - case WM_MBUTTONDOWN: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - SetCapture (hwnd); - return winMouseButtonsHandle (s_pScreen, ButtonPress, Button2, wParam); - - case WM_MBUTTONUP: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - ReleaseCapture (); - return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button2, wParam); - - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - SetCapture (hwnd); - return winMouseButtonsHandle (s_pScreen, ButtonPress, Button3, wParam); - - case WM_RBUTTONUP: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - ReleaseCapture (); - return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button3, wParam); - - case WM_XBUTTONDBLCLK: - case WM_XBUTTONDOWN: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - SetCapture (hwnd); - return winMouseButtonsHandle (s_pScreen, ButtonPress, HIWORD(wParam) + 5, wParam); - case WM_XBUTTONUP: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - if (s_pScreenInfo->fRootless -#ifdef XWIN_MULTIWINDOWEXTWM - || s_pScreenInfo->fMWExtWM -#endif - ) - ReleaseCapture (); - return winMouseButtonsHandle (s_pScreen, ButtonRelease, HIWORD(wParam) + 5, wParam); - - case WM_TIMER: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* Branch on the timer id */ - switch (wParam) - { - case WIN_E3B_TIMER_ID: - /* Send delayed button press */ - winMouseButtonsSendEvent (ButtonPress, - s_pScreenPriv->iE3BCachedPress); - - /* Kill this timer */ - KillTimer (s_pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); - - /* Clear screen privates flags */ - s_pScreenPriv->iE3BCachedPress = 0; - break; - - case WIN_POLLING_MOUSE_TIMER_ID: - { - POINT point; - WPARAM wL, wM, wR, wShift, wCtrl; - LPARAM lPos; - - /* Get the current position of the mouse cursor */ - GetCursorPos (&point); - - /* Map from screen (-X, -Y) to root (0, 0) */ - point.x -= GetSystemMetrics (SM_XVIRTUALSCREEN); - point.y -= GetSystemMetrics (SM_YVIRTUALSCREEN); - - /* Deliver absolute cursor position to X Server */ - winEnqueueMotion(point.x , point.y); - - /* Check if a button was released but we didn't see it */ - GetCursorPos (&point); - wL = (GetKeyState (VK_LBUTTON) & 0x8000)?MK_LBUTTON:0; - wM = (GetKeyState (VK_MBUTTON) & 0x8000)?MK_MBUTTON:0; - wR = (GetKeyState (VK_RBUTTON) & 0x8000)?MK_RBUTTON:0; - wShift = (GetKeyState (VK_SHIFT) & 0x8000)?MK_SHIFT:0; - wCtrl = (GetKeyState (VK_CONTROL) & 0x8000)?MK_CONTROL:0; - lPos = MAKELPARAM(point.x, point.y); - if (g_fButton[0] & !wL) - PostMessage (hwnd, WM_LBUTTONUP, wCtrl|wM|wR|wShift, lPos); - if (g_fButton[1] & !wM) - PostMessage (hwnd, WM_MBUTTONUP, wCtrl|wL|wR|wShift, lPos); - if (g_fButton[2] & !wR) - PostMessage (hwnd, WM_RBUTTONUP, wCtrl|wL|wM|wShift, lPos); - } - } - return 0; - - case WM_CTLCOLORSCROLLBAR: - FatalError ("winWindowProc - WM_CTLCOLORSCROLLBAR - We are not " - "supposed to get this message. Exiting.\n"); - return 0; - - case WM_MOUSEWHEEL: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; -#if CYGDEBUG - winDebug ("winWindowProc - WM_MOUSEWHEEL\n"); -#endif - winMouseWheel (s_pScreen, GET_WHEEL_DELTA_WPARAM(wParam)); - break; - - case WM_SETFOCUS: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* Restore the state of all mode keys */ - winRestoreModeKeyStates (); - - /* Add the keyboard hook if possible */ - if (g_fKeyboardHookLL) - g_fKeyboardHookLL = winInstallKeyboardHookLL (); - return 0; - - case WM_KILLFOCUS: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* Release any pressed keys */ - winKeybdReleaseKeys (); - - /* Remove our keyboard hook if it is installed */ - winRemoveKeyboardHookLL (); - return 0; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* - * FIXME: Catching Alt-F4 like this is really terrible. This should - * be generalized to handle other Windows keyboard signals. Actually, - * the list keys to catch and the actions to perform when caught should - * be configurable; that way user's can customize the keys that they - * need to have passed through to their window manager or apps, or they - * can remap certain actions to new key codes that do not conflict - * with the X apps that they are using. Yeah, that'll take awhile. - */ - if ((s_pScreenInfo->fUseWinKillKey && wParam == VK_F4 - && (GetKeyState (VK_MENU) & 0x8000)) - || (s_pScreenInfo->fUseUnixKillKey && wParam == VK_BACK - && (GetKeyState (VK_MENU) & 0x8000) - && (GetKeyState (VK_CONTROL) & 0x8000))) - { - /* - * Better leave this message here, just in case some unsuspecting - * user enters Alt + F4 and is surprised when the application - * quits. - */ - ErrorF ("winWindowProc - WM_*KEYDOWN - Closekey hit, quitting\n"); - - /* Display Exit dialog */ - winDisplayExitDialog (s_pScreenPriv); - return 0; - } - - /* - * Don't do anything for the Windows keys, as focus will soon - * be returned to Windows. We may be able to trap the Windows keys, - * but we should determine if that is desirable before doing so. - */ - if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) - break; - - /* - * Discard presses generated from Windows auto-repeat - */ - if (lParam & (1<<30)) - { - switch (wParam) - { - /* ago: Pressing LControl while RControl is pressed is - * Indicated as repeat. Fix this! - */ - case VK_CONTROL: - case VK_SHIFT: - if (winCheckKeyPressed(wParam, lParam)) - return 0; - break; - default: - return 0; - } - } - - /* Discard fake Ctrl_L presses that precede AltGR on non-US keyboards */ - if (winIsFakeCtrl_L (message, wParam, lParam)) - return 0; - - /* Translate Windows key code to X scan code */ - winTranslateKey (wParam, lParam, &iScanCode); - - /* Ignore repeats for CapsLock */ - if (wParam == VK_CAPITAL) - lParam = 1; - - /* Send the key event(s) */ - for (i = 0; i < LOWORD(lParam); ++i) - winSendKeyEvent (iScanCode, TRUE); - return 0; - - case WM_SYSKEYUP: - case WM_KEYUP: - if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) - break; - - /* - * Don't do anything for the Windows keys, as focus will soon - * be returned to Windows. We may be able to trap the Windows keys, - * but we should determine if that is desirable before doing so. - */ - if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) - break; - - /* Ignore the fake Ctrl_L that follows an AltGr release */ - if (winIsFakeCtrl_L (message, wParam, lParam)) - return 0; - - /* Enqueue a keyup event */ - winTranslateKey (wParam, lParam, &iScanCode); - winSendKeyEvent (iScanCode, FALSE); - - /* Release all pressed shift keys */ - if (wParam == VK_SHIFT) - winFixShiftKeys (iScanCode); - return 0; - - case WM_HOTKEY: - if (s_pScreenPriv == NULL) - break; - - /* Call the engine-specific hot key handler */ - (*s_pScreenPriv->pwinHotKeyAltTab) (s_pScreen); - return 0; - - case WM_ACTIVATE: - if (s_pScreenPriv == NULL - || s_pScreenInfo->fIgnoreInput) - break; - - /* TODO: Override display of window when we have a bad depth */ - if (LOWORD(wParam) != WA_INACTIVE && s_pScreenPriv->fBadDepth) - { - ErrorF ("winWindowProc - WM_ACTIVATE - Bad depth, trying " - "to override window activation\n"); - - /* Minimize the window */ - ShowWindow (hwnd, SW_MINIMIZE); - - /* Display dialog box */ - if (g_hDlgDepthChange != NULL) - { - /* Make the existing dialog box active */ - SetActiveWindow (g_hDlgDepthChange); - } - else - { - /* TODO: Recreate the dialog box and bring to the top */ - ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); - } - - /* Don't do any other processing of this message */ - return 0; - } - -#if CYGDEBUG - winDebug ("winWindowProc - WM_ACTIVATE\n"); -#endif - - /* - * Focus is being changed to another window. - * The other window may or may not belong to - * our process. - */ - - /* Clear any lingering wheel delta */ - s_pScreenPriv->iDeltaZ = 0; - - /* Reshow the Windows mouse cursor if we are being deactivated */ - if (g_fSoftwareCursor && LOWORD(wParam) == WA_INACTIVE - && !g_fCursor) - { - /* Show Windows cursor */ - g_fCursor = TRUE; - ShowCursor (TRUE); - } - return 0; - - case WM_ACTIVATEAPP: - if (s_pScreenPriv == NULL - || s_pScreenInfo->fIgnoreInput) - break; - -#if CYGDEBUG || TRUE - winDebug ("winWindowProc - WM_ACTIVATEAPP\n"); -#endif - - /* Activate or deactivate */ - s_pScreenPriv->fActive = wParam; - - /* Reshow the Windows mouse cursor if we are being deactivated */ - if (g_fSoftwareCursor && !s_pScreenPriv->fActive - && !g_fCursor) - { - /* Show Windows cursor */ - g_fCursor = TRUE; - ShowCursor (TRUE); - } - -#ifdef XWIN_CLIPBOARD - /* Make sure the clipboard chain is ok. */ - winFixClipboardChain (); -#endif - - /* Call engine specific screen activation/deactivation function */ - (*s_pScreenPriv->pwinActivateApp) (s_pScreen); - -#ifdef XWIN_MULTIWINDOWEXTWM - if (s_pScreenPriv->fActive) - { - /* Restack all window unless using built-in wm. */ - if (s_pScreenInfo->fInternalWM && s_pScreenInfo->fAnotherWMRunning) - winMWExtWMRestackWindows (s_pScreen); - } -#endif - - return 0; - - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case ID_APP_EXIT: - /* Display Exit dialog */ - winDisplayExitDialog (s_pScreenPriv); - return 0; - -#ifdef XWIN_MULTIWINDOW - case ID_APP_HIDE_ROOT: - if (s_pScreenPriv->fRootWindowShown) - ShowWindow (s_pScreenPriv->hwndScreen, SW_HIDE); - else - ShowWindow (s_pScreenPriv->hwndScreen, SW_SHOW); - s_pScreenPriv->fRootWindowShown = !s_pScreenPriv->fRootWindowShown; - return 0; -#endif - - case ID_APP_ABOUT: - /* Display the About box */ - winDisplayAboutDialog (s_pScreenPriv); - return 0; - - default: - /* It's probably one of the custom menus... */ - if (HandleCustomWM_COMMAND (0, LOWORD (wParam))) - return 0; - } - break; - - case WM_ENDSESSION: - case WM_GIVEUP: - /* Tell X that we are giving up */ -#ifdef XWIN_MULTIWINDOW - if (s_pScreenInfo->fMultiWindow) - winDeinitMultiWindowWM (); -#endif - GiveUp (0); - return 0; - - case WM_CLOSE: - /* Display Exit dialog */ - winDisplayExitDialog (s_pScreenPriv); - return 0; - - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) - { - if (!g_fSoftwareCursor) SetCursor (s_pScreenPriv->cursor.handle); - return TRUE; - } - break; - -#ifdef XWIN_MULTIWINDOWEXTWM - case WM_MANAGE: - ErrorF ("winWindowProc - WM_MANAGE\n"); - s_pScreenInfo->fAnotherWMRunning = FALSE; - - if (s_pScreenInfo->fInternalWM) - { - EnumThreadWindows (g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0); - //RootlessRepositionWindows (s_pScreen); - } - break; - - case WM_UNMANAGE: - ErrorF ("winWindowProc - WM_UNMANAGE\n"); - s_pScreenInfo->fAnotherWMRunning = TRUE; - - if (s_pScreenInfo->fInternalWM) - { - EnumThreadWindows (g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0); - winMWExtWMRestackWindows (s_pScreen); - } - break; -#endif - - default: - if(message == s_uTaskbarRestart) - { - winInitNotifyIcon (s_pScreenPriv); - } - break; - } - - return DefWindowProc (hwnd, message, wParam, lParam); -} +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Dakshinamurthy Karra + * Suhaib M Siddiqi + * Peter Busch + * Harold L Hunt II + * MATSUZAKI Kensuke + */ + +#ifdef HAVE_XWIN_CONFIG_H +#include +#endif +#include "win.h" +#include +#include "winprefs.h" +#include "winconfig.h" +#include "winmsg.h" +#include "winmonitors.h" +#include "inputstr.h" + +/* + * Global variables + */ + +Bool g_fCursor = TRUE; +Bool g_fButton[3] = { FALSE, FALSE, FALSE }; + + +/* + * Called by winWakeupHandler + * Processes current Windows message + */ + +LRESULT CALLBACK +winWindowProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + static HWND s_hwndLastPrivates = NULL; + static HINSTANCE s_hInstance; + static Bool s_fTracking = FALSE; + static unsigned long s_ulServerGeneration = 0; + static UINT s_uTaskbarRestart = 0; + int iScanCode; + int i; + +#if CYGDEBUG + winDebugWin32Message("winWindowProc", hwnd, message, wParam, lParam); +#endif + + /* Watch for server regeneration */ + if (g_ulServerGeneration != s_ulServerGeneration) + { + /* Store new server generation */ + s_ulServerGeneration = g_ulServerGeneration; + } + + /* Only retrieve new privates pointers if window handle is null or changed */ + if ((s_pScreenPriv == NULL || hwnd != s_hwndLastPrivates) + && (s_pScreenPriv = GetProp (hwnd, WIN_SCR_PROP)) != NULL) + { +#if CYGDEBUG + winDebug ("winWindowProc - Setting privates handle\n"); +#endif + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + s_hwndLastPrivates = hwnd; + } + else if (s_pScreenPriv == NULL) + { + /* For safety, handle case that should never happen */ + s_pScreenInfo = NULL; + s_pScreen = NULL; + s_hwndLastPrivates = NULL; + } + + /* Branch on message type */ + switch (message) + { + case WM_TRAYICON: + return winHandleIconMessage (hwnd, message, wParam, lParam, + s_pScreenPriv); + + case WM_CREATE: +#if CYGDEBUG + winDebug ("winWindowProc - WM_CREATE\n"); +#endif + + /* + * Add a property to our display window that references + * this screens' privates. + * + * This allows the window procedure to refer to the + * appropriate window DC and shadow DC for the window that + * it is processing. We use this to repaint exposed + * areas of our display window. + */ + s_pScreenPriv = ((LPCREATESTRUCT) lParam)->lpCreateParams; + s_hInstance = ((LPCREATESTRUCT) lParam)->hInstance; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + s_hwndLastPrivates = hwnd; + s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); + SetProp (hwnd, WIN_SCR_PROP, s_pScreenPriv); + + /* Setup tray icon */ + if (!s_pScreenInfo->fNoTrayIcon) + { + /* + * NOTE: The WM_CREATE message is processed before CreateWindowEx + * returns, so s_pScreenPriv->hwndScreen is invalid at this point. + * We go ahead and copy our hwnd parameter over top of the screen + * privates hwndScreen so that we have a valid value for + * that member. Otherwise, the tray icon will disappear + * the first time you move the mouse over top of it. + */ + + s_pScreenPriv->hwndScreen = hwnd; + + winInitNotifyIcon (s_pScreenPriv); + } + return 0; + + case WM_DISPLAYCHANGE: + /* + WM_DISPLAYCHANGE seems to be sent when the monitor layout or + any monitor's resolution or depth changes, but it's lParam and + wParam always indicate the resolution and bpp for the primary + monitor (so ignore that as we could be on any monitor...) + */ + + /* We cannot handle a display mode change during initialization */ + if (s_pScreenInfo == NULL) + FatalError ("winWindowProc - WM_DISPLAYCHANGE - The display " + "mode changed while we were intializing. This is " + "very bad and unexpected. Exiting.\n"); + + /* + * We do not care about display changes with + * fullscreen DirectDraw engines, because those engines set + * their own mode when they become active. + */ + if (s_pScreenInfo->fFullScreen + && (s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD + || s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL +#ifdef XWIN_PRIMARYFB + || s_pScreenInfo->dwEngine == WIN_SERVER_PRIMARY_DD +#endif + )) + { + break; + } + + ErrorF ("winWindowProc - WM_DISPLAYCHANGE - new width: %d " + "new height: %d new bpp: %d\n", + LOWORD (lParam), HIWORD (lParam), wParam); + + /* + * Check for a disruptive change in depth. + * We can only display a message for a disruptive depth change, + * we cannot do anything to correct the situation. + */ + /* + XXX: maybe we need to check if GetSystemMetrics(SM_SAMEDISPLAYFORMAT) + has changed as well... + */ + if (s_pScreenInfo->dwBPP != GetDeviceCaps (s_pScreenPriv->hdcScreen, BITSPIXEL)) + { + if ((s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DD + || s_pScreenInfo->dwEngine == WIN_SERVER_SHADOW_DDNL +#ifdef XWIN_PRIMARYFB + || s_pScreenInfo->dwEngine == WIN_SERVER_PRIMARY_DD +#endif + )) + { + /* Cannot display the visual until the depth is restored */ + ErrorF ("winWindowProc - Disruptive change in depth\n"); + + /* Display depth change dialog */ + winDisplayDepthChangeDialog (s_pScreenPriv); + + /* Flag that we have an invalid screen depth */ + s_pScreenPriv->fBadDepth = TRUE; + + /* Minimize the display window */ + ShowWindow (hwnd, SW_MINIMIZE); + } + else + { + /* For GDI, performance may suffer until original depth is restored */ + ErrorF ("winWindowProc - Performance may be non-optimal after change in depth\n"); + } + } + else + { + /* Flag that we have a valid screen depth */ + s_pScreenPriv->fBadDepth = FALSE; + } + + /* + If we could cheaply check if this WM_DISPLAYCHANGE change + affects the monitor(s) which this X screen is displayed on + then we should do so here. For the moment, assume it does. + (this is probably usually the case so that might be an + overoptimization) + */ + { + /* + In rootless modes which are monitor or virtual desktop size + use RandR to resize the X screen + */ + if ((!s_pScreenInfo->fUserGaveHeightAndWidth) && + (s_pScreenInfo->iResizeMode == resizeWithRandr) && + (FALSE +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + || s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOW + || s_pScreenInfo->fMultiWindow +#endif + )) + { + DWORD dwWidth, dwHeight; + + if (s_pScreenInfo->fMultipleMonitors) + { + /* resize to new virtual desktop size */ + dwWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); + dwHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); + } + else + { + /* resize to new size of specified monitor */ + struct GetMonitorInfoData data; + if (QueryMonitor(s_pScreenInfo->iMonitor, &data)) + { + if (data.bMonitorSpecifiedExists == TRUE) + { + dwWidth = data.monitorWidth; + dwHeight = data.monitorHeight; + /* + XXX: monitor may have changed position, + so we might need to update xinerama data + */ + } + else + { + ErrorF ("Monitor number %d no longer exists!\n", s_pScreenInfo->iMonitor); + } + } + } + + /* + XXX: probably a small bug here: we don't compute the work area + and allow for task bar + + XXX: generally, we don't allow for the task bar being moved after + the server is started + */ + + /* Set screen size to match new size, if it is different to current */ + if ((s_pScreenInfo->dwWidth != dwWidth) || + (s_pScreenInfo->dwHeight != dwHeight)) + { + winDoRandRScreenSetSize(s_pScreen, + dwWidth, + dwHeight, + (dwWidth * 25.4) / monitorResolution, + (dwHeight * 25.4) / monitorResolution); + } + } + else + { + /* + * We can simply recreate the same-sized primary surface when + * the display dimensions change. + */ + + /* + * NOTE: The non-DirectDraw engines set the ReleasePrimarySurface + * and CreatePrimarySurface function pointers to point + * to the no operation function, NoopDDA. This allows us + * to blindly call these functions, even if they are not + * relevant to the current engine (e.g., Shadow GDI). + */ + + winDebug ("winWindowProc - WM_DISPLAYCHANGE - Releasing and recreating primary surface\n"); + + /* Release the old primary surface */ + (*s_pScreenPriv->pwinReleasePrimarySurface) (s_pScreen); + + /* Create the new primary surface */ + (*s_pScreenPriv->pwinCreatePrimarySurface) (s_pScreen); + } + } + + break; + + case WM_SIZE: + { + SCROLLINFO si; + RECT rcWindow; + int iWidth, iHeight; + +#if CYGDEBUG + winDebug ("winWindowProc - WM_SIZE\n"); +#endif + + /* Break if we do not allow resizing */ + if ((s_pScreenInfo->iResizeMode == notAllowed) + || !s_pScreenInfo->fDecoration +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + || s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOW + || s_pScreenInfo->fMultiWindow +#endif + || s_pScreenInfo->fFullScreen) + break; + + /* No need to resize if we get minimized */ + if (wParam == SIZE_MINIMIZED) + return 0; + + ErrorF ("winWindowProc - WM_SIZE - new client area w: %d h: %d\n", + LOWORD (lParam), HIWORD (lParam)); + + if (s_pScreenInfo->iResizeMode == resizeWithRandr) + { + /* Actual resizing is done on WM_EXITSIZEMOVE */ + return 0; + } + + /* Otherwise iResizeMode == resizeWithScrollbars */ + + /* + * Get the size of the whole window, including client area, + * scrollbars, and non-client area decorations (caption, borders). + * We do this because we need to check if the client area + * without scrollbars is large enough to display the whole visual. + * The new client area size passed by lParam already subtracts + * the size of the scrollbars if they are currently displayed. + * So checking is LOWORD(lParam) == visual_width and + * HIWORD(lParam) == visual_height will never tell us to hide + * the scrollbars because the client area would always be too small. + * GetClientRect returns the same sizes given by lParam, so we + * cannot use GetClientRect either. + */ + GetWindowRect (hwnd, &rcWindow); + iWidth = rcWindow.right - rcWindow.left; + iHeight = rcWindow.bottom - rcWindow.top; + + /* Subtract the frame size from the window size. */ + iWidth -= 2 * GetSystemMetrics (SM_CXSIZEFRAME); + iHeight -= (2 * GetSystemMetrics (SM_CYSIZEFRAME) + + GetSystemMetrics (SM_CYCAPTION)); + + /* + * Update scrollbar page sizes. + * NOTE: If page size == range, then the scrollbar is + * automatically hidden. + */ + + /* Is the naked client area large enough to show the whole visual? */ + if (iWidth < s_pScreenInfo->dwWidth + || iHeight < s_pScreenInfo->dwHeight) + { + /* Client area too small to display visual, use scrollbars */ + iWidth -= GetSystemMetrics (SM_CXVSCROLL); + iHeight -= GetSystemMetrics (SM_CYHSCROLL); + } + + /* Set the horizontal scrollbar page size */ + si.cbSize = sizeof (si); + si.fMask = SIF_PAGE | SIF_RANGE; + si.nMin = 0; + si.nMax = s_pScreenInfo->dwWidth - 1; + si.nPage = iWidth; + SetScrollInfo (hwnd, SB_HORZ, &si, TRUE); + + /* Set the vertical scrollbar page size */ + si.cbSize = sizeof (si); + si.fMask = SIF_PAGE | SIF_RANGE; + si.nMin = 0; + si.nMax = s_pScreenInfo->dwHeight - 1; + si.nPage = iHeight; + SetScrollInfo (hwnd, SB_VERT, &si, TRUE); + + /* + * NOTE: Scrollbars may have moved if they were at the + * far right/bottom, so we query their current position. + */ + + /* Get the horizontal scrollbar position and set the offset */ + si.cbSize = sizeof (si); + si.fMask = SIF_POS; + GetScrollInfo (hwnd, SB_HORZ, &si); + s_pScreenInfo->dwXOffset = -si.nPos; + + /* Get the vertical scrollbar position and set the offset */ + si.cbSize = sizeof (si); + si.fMask = SIF_POS; + GetScrollInfo (hwnd, SB_VERT, &si); + s_pScreenInfo->dwYOffset = -si.nPos; + } + return 0; + + case WM_ENTERSIZEMOVE: + ErrorF("winWindowProc - WM_ENTERSIZEMOVE\n"); + break; + + case WM_EXITSIZEMOVE: + ErrorF("winWindowProc - WM_EXITSIZEMOVE\n"); + + if (s_pScreenInfo->iResizeMode == resizeWithRandr) + { + /* Set screen size to match new client area, if it is different to current */ + RECT rcClient; + DWORD dwWidth, dwHeight; + + GetClientRect (hwnd, &rcClient); + dwWidth = rcClient.right - rcClient.left; + dwHeight = rcClient.bottom - rcClient.top; + + if ((s_pScreenInfo->dwWidth != dwWidth) || + (s_pScreenInfo->dwHeight != dwHeight)) + { + /* mm = dots * (25.4 mm / inch) / (dots / inch) */ + winDoRandRScreenSetSize(s_pScreen, + dwWidth, + dwHeight, + (dwWidth * 25.4) / monitorResolution, + (dwHeight * 25.4) / monitorResolution); + } + } + + break; + + case WM_VSCROLL: + { + SCROLLINFO si; + int iVertPos; + +#if CYGDEBUG + winDebug ("winWindowProc - WM_VSCROLL\n"); +#endif + + /* Get vertical scroll bar info */ + si.cbSize = sizeof (si); + si.fMask = SIF_ALL; + GetScrollInfo (hwnd, SB_VERT, &si); + + /* Save the vertical position for comparison later */ + iVertPos = si.nPos; + + /* + * Don't forget: + * moving the scrollbar to the DOWN, scroll the content UP + */ + switch (LOWORD(wParam)) + { + case SB_TOP: + si.nPos = si.nMin; + break; + + case SB_BOTTOM: + si.nPos = si.nMax - si.nPage + 1; + break; + + case SB_LINEUP: + si.nPos -= 1; + break; + + case SB_LINEDOWN: + si.nPos += 1; + break; + + case SB_PAGEUP: + si.nPos -= si.nPage; + break; + + case SB_PAGEDOWN: + si.nPos += si.nPage; + break; + + case SB_THUMBTRACK: + si.nPos = si.nTrackPos; + break; + + default: + break; + } + + /* + * We retrieve the position after setting it, + * because Windows may adjust it. + */ + si.fMask = SIF_POS; + SetScrollInfo (hwnd, SB_VERT, &si, TRUE); + GetScrollInfo (hwnd, SB_VERT, &si); + + /* Scroll the window if the position has changed */ + if (si.nPos != iVertPos) + { + /* Save the new offset for bit block transfers, etc. */ + s_pScreenInfo->dwYOffset = -si.nPos; + + /* Change displayed region in the window */ + ScrollWindowEx (hwnd, + 0, + iVertPos - si.nPos, + NULL, + NULL, + NULL, + NULL, + SW_INVALIDATE); + + /* Redraw the window contents */ + UpdateWindow (hwnd); + } + } + return 0; + + case WM_HSCROLL: + { + SCROLLINFO si; + int iHorzPos; + +#if CYGDEBUG + winDebug ("winWindowProc - WM_HSCROLL\n"); +#endif + + /* Get horizontal scroll bar info */ + si.cbSize = sizeof (si); + si.fMask = SIF_ALL; + GetScrollInfo (hwnd, SB_HORZ, &si); + + /* Save the horizontal position for comparison later */ + iHorzPos = si.nPos; + + /* + * Don't forget: + * moving the scrollbar to the RIGHT, scroll the content LEFT + */ + switch (LOWORD(wParam)) + { + case SB_LEFT: + si.nPos = si.nMin; + break; + + case SB_RIGHT: + si.nPos = si.nMax - si.nPage + 1; + break; + + case SB_LINELEFT: + si.nPos -= 1; + break; + + case SB_LINERIGHT: + si.nPos += 1; + break; + + case SB_PAGELEFT: + si.nPos -= si.nPage; + break; + + case SB_PAGERIGHT: + si.nPos += si.nPage; + break; + + case SB_THUMBTRACK: + si.nPos = si.nTrackPos; + break; + + default: + break; + } + + /* + * We retrieve the position after setting it, + * because Windows may adjust it. + */ + si.fMask = SIF_POS; + SetScrollInfo (hwnd, SB_HORZ, &si, TRUE); + GetScrollInfo (hwnd, SB_HORZ, &si); + + /* Scroll the window if the position has changed */ + if (si.nPos != iHorzPos) + { + /* Save the new offset for bit block transfers, etc. */ + s_pScreenInfo->dwXOffset = -si.nPos; + + /* Change displayed region in the window */ + ScrollWindowEx (hwnd, + iHorzPos - si.nPos, + 0, + NULL, + NULL, + NULL, + NULL, + SW_INVALIDATE); + + /* Redraw the window contents */ + UpdateWindow (hwnd); + } + } + return 0; + + case WM_GETMINMAXINFO: + { + MINMAXINFO *pMinMaxInfo = (MINMAXINFO *) lParam; + int iCaptionHeight; + int iBorderHeight, iBorderWidth; + +#if CYGDEBUG + winDebug ("winWindowProc - WM_GETMINMAXINFO - pScreenInfo: %08x\n", + s_pScreenInfo); +#endif + + /* Can't do anything without screen info */ + if (s_pScreenInfo == NULL + || (s_pScreenInfo->iResizeMode != resizeWithScrollbars) + || s_pScreenInfo->fFullScreen + || !s_pScreenInfo->fDecoration +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + || s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOW + || s_pScreenInfo->fMultiWindow +#endif + ) + break; + + /* + * Here we can override the maximum tracking size, which + * is the largest size that can be assigned to our window + * via the sizing border. + */ + + /* + * FIXME: Do we only need to do this once, since our visual size + * does not change? Does Windows store this value statically + * once we have set it once? + */ + + /* Get the border and caption sizes */ + iCaptionHeight = GetSystemMetrics (SM_CYCAPTION); + iBorderWidth = 2 * GetSystemMetrics (SM_CXSIZEFRAME); + iBorderHeight = 2 * GetSystemMetrics (SM_CYSIZEFRAME); + + /* Allow the full visual to be displayed */ + pMinMaxInfo->ptMaxTrackSize.x + = s_pScreenInfo->dwWidth + iBorderWidth; + pMinMaxInfo->ptMaxTrackSize.y + = s_pScreenInfo->dwHeight + iBorderHeight + iCaptionHeight; + } + return 0; + + case WM_ERASEBKGND: +#if CYGDEBUG + winDebug ("winWindowProc - WM_ERASEBKGND\n"); +#endif + /* + * Pretend that we did erase the background but we don't care, + * the application uses the full window estate. This avoids some + * flickering when resizing. + */ + return TRUE; + + case WM_PAINT: +#if CYGDEBUG + winDebug ("winWindowProc - WM_PAINT\n"); +#endif + /* Only paint if we have privates and the server is enabled */ + if (s_pScreenPriv == NULL + || !s_pScreenPriv->fEnabled + || (s_pScreenInfo->fFullScreen && !s_pScreenPriv->fActive) + || s_pScreenPriv->fBadDepth) + { + /* We don't want to paint */ + break; + } + + /* Break out here if we don't have a valid paint routine */ + if (s_pScreenPriv->pwinBltExposedRegions == NULL) + break; + + /* Call the engine dependent repainter */ + (*s_pScreenPriv->pwinBltExposedRegions) (s_pScreen); + return 0; + + case WM_PALETTECHANGED: + { +#if CYGDEBUG + winDebug ("winWindowProc - WM_PALETTECHANGED\n"); +#endif + /* + * Don't process if we don't have privates or a colormap, + * or if we have an invalid depth. + */ + if (s_pScreenPriv == NULL + || s_pScreenPriv->pcmapInstalled == NULL + || s_pScreenPriv->fBadDepth) + break; + + /* Return if we caused the palette to change */ + if ((HWND) wParam == hwnd) + { + /* Redraw the screen */ + (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); + return 0; + } + + /* Reinstall the windows palette */ + (*s_pScreenPriv->pwinRealizeInstalledPalette) (s_pScreen); + + /* Redraw the screen */ + (*s_pScreenPriv->pwinRedrawScreen) (s_pScreen); + return 0; + } + + case WM_MOUSEMOVE: + /* We can't do anything without privates */ + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* We can't do anything without g_pwinPointer */ + if (g_pwinPointer == NULL) + break; + + /* Has the mouse pointer crossed screens? */ + if (s_pScreen != miPointerGetScreen(g_pwinPointer)) + miPointerSetScreen (g_pwinPointer, s_pScreenInfo->dwScreen, + GET_X_LPARAM(lParam)-s_pScreenInfo->dwXOffset, + GET_Y_LPARAM(lParam)-s_pScreenInfo->dwYOffset); + + /* Are we tracking yet? */ + if (!s_fTracking) + { + TRACKMOUSEEVENT tme; + + /* Setup data structure */ + ZeroMemory (&tme, sizeof (tme)); + tme.cbSize = sizeof (tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd; + + /* Call the tracking function */ + if (!(*g_fpTrackMouseEvent) (&tme)) + ErrorF ("winWindowProc - _TrackMouseEvent failed\n"); + + /* Flag that we are tracking now */ + s_fTracking = TRUE; + } + + /* Hide or show the Windows mouse cursor */ + if (g_fSoftwareCursor && g_fCursor && (s_pScreenPriv->fActive || s_pScreenInfo->fLessPointer)) + { + /* Hide Windows cursor */ + g_fCursor = FALSE; + ShowCursor (FALSE); + } + else if (g_fSoftwareCursor && !g_fCursor && !s_pScreenPriv->fActive + && !s_pScreenInfo->fLessPointer) + { + /* Show Windows cursor */ + g_fCursor = TRUE; + ShowCursor (TRUE); + } + + /* Deliver absolute cursor position to X Server */ + winEnqueueMotion(GET_X_LPARAM(lParam)-s_pScreenInfo->dwXOffset, + GET_Y_LPARAM(lParam)-s_pScreenInfo->dwYOffset); + return 0; + + case WM_NCMOUSEMOVE: + /* + * We break instead of returning 0 since we need to call + * DefWindowProc to get the mouse cursor changes + * and min/max/close button highlighting in Windows XP. + * The Platform SDK says that you should return 0 if you + * process this message, but it fails to mention that you + * will give up any default functionality if you do return 0. + */ + + /* We can't do anything without privates */ + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* Non-client mouse movement, show Windows cursor */ + if (g_fSoftwareCursor && !g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + break; + + case WM_MOUSELEAVE: + /* Mouse has left our client area */ + + /* Flag that we are no longer tracking */ + s_fTracking = FALSE; + + /* Show the mouse cursor, if necessary */ + if (g_fSoftwareCursor && !g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return 0; + + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + SetCapture (hwnd); + return winMouseButtonsHandle (s_pScreen, ButtonPress, Button1, wParam); + + case WM_LBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + ReleaseCapture (); + return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button1, wParam); + + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + SetCapture (hwnd); + return winMouseButtonsHandle (s_pScreen, ButtonPress, Button2, wParam); + + case WM_MBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + ReleaseCapture (); + return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button2, wParam); + + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + SetCapture (hwnd); + return winMouseButtonsHandle (s_pScreen, ButtonPress, Button3, wParam); + + case WM_RBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + ReleaseCapture (); + return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button3, wParam); + + case WM_XBUTTONDBLCLK: + case WM_XBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + SetCapture (hwnd); + return winMouseButtonsHandle (s_pScreen, ButtonPress, HIWORD(wParam) + 5, wParam); + case WM_XBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + if (s_pScreenInfo->fRootless +#ifdef XWIN_MULTIWINDOWEXTWM + || s_pScreenInfo->fMWExtWM +#endif + ) + ReleaseCapture (); + return winMouseButtonsHandle (s_pScreen, ButtonRelease, HIWORD(wParam) + 5, wParam); + + case WM_TIMER: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* Branch on the timer id */ + switch (wParam) + { + case WIN_E3B_TIMER_ID: + /* Send delayed button press */ + winMouseButtonsSendEvent (ButtonPress, + s_pScreenPriv->iE3BCachedPress); + + /* Kill this timer */ + KillTimer (s_pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); + + /* Clear screen privates flags */ + s_pScreenPriv->iE3BCachedPress = 0; + break; + + case WIN_POLLING_MOUSE_TIMER_ID: + { + POINT point; + WPARAM wL, wM, wR, wShift, wCtrl; + LPARAM lPos; + + /* Get the current position of the mouse cursor */ + GetCursorPos (&point); + + /* Map from screen (-X, -Y) to root (0, 0) */ + point.x -= GetSystemMetrics (SM_XVIRTUALSCREEN); + point.y -= GetSystemMetrics (SM_YVIRTUALSCREEN); + + /* Deliver absolute cursor position to X Server */ + winEnqueueMotion(point.x , point.y); + + /* Check if a button was released but we didn't see it */ + GetCursorPos (&point); + wL = (GetKeyState (VK_LBUTTON) & 0x8000)?MK_LBUTTON:0; + wM = (GetKeyState (VK_MBUTTON) & 0x8000)?MK_MBUTTON:0; + wR = (GetKeyState (VK_RBUTTON) & 0x8000)?MK_RBUTTON:0; + wShift = (GetKeyState (VK_SHIFT) & 0x8000)?MK_SHIFT:0; + wCtrl = (GetKeyState (VK_CONTROL) & 0x8000)?MK_CONTROL:0; + lPos = MAKELPARAM(point.x, point.y); + if (g_fButton[0] & !wL) + PostMessage (hwnd, WM_LBUTTONUP, wCtrl|wM|wR|wShift, lPos); + if (g_fButton[1] & !wM) + PostMessage (hwnd, WM_MBUTTONUP, wCtrl|wL|wR|wShift, lPos); + if (g_fButton[2] & !wR) + PostMessage (hwnd, WM_RBUTTONUP, wCtrl|wL|wM|wShift, lPos); + } + } + return 0; + + case WM_CTLCOLORSCROLLBAR: + FatalError ("winWindowProc - WM_CTLCOLORSCROLLBAR - We are not " + "supposed to get this message. Exiting.\n"); + return 0; + + case WM_MOUSEWHEEL: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; +#if CYGDEBUG + winDebug ("winWindowProc - WM_MOUSEWHEEL\n"); +#endif + winMouseWheel (s_pScreen, GET_WHEEL_DELTA_WPARAM(wParam)); + break; + + case WM_SETFOCUS: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* Restore the state of all mode keys */ + winRestoreModeKeyStates (); + + /* Add the keyboard hook if possible */ + if (g_fKeyboardHookLL) + g_fKeyboardHookLL = winInstallKeyboardHookLL (); + return 0; + + case WM_KILLFOCUS: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* Release any pressed keys */ + winKeybdReleaseKeys (); + + /* Remove our keyboard hook if it is installed */ + winRemoveKeyboardHookLL (); + return 0; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* + * FIXME: Catching Alt-F4 like this is really terrible. This should + * be generalized to handle other Windows keyboard signals. Actually, + * the list keys to catch and the actions to perform when caught should + * be configurable; that way user's can customize the keys that they + * need to have passed through to their window manager or apps, or they + * can remap certain actions to new key codes that do not conflict + * with the X apps that they are using. Yeah, that'll take awhile. + */ + if ((s_pScreenInfo->fUseWinKillKey && wParam == VK_F4 + && (GetKeyState (VK_MENU) & 0x8000)) + || (s_pScreenInfo->fUseUnixKillKey && wParam == VK_BACK + && (GetKeyState (VK_MENU) & 0x8000) + && (GetKeyState (VK_CONTROL) & 0x8000))) + { + /* + * Better leave this message here, just in case some unsuspecting + * user enters Alt + F4 and is surprised when the application + * quits. + */ + ErrorF ("winWindowProc - WM_*KEYDOWN - Closekey hit, quitting\n"); + + /* Display Exit dialog */ + winDisplayExitDialog (s_pScreenPriv); + return 0; + } + + /* + * Don't do anything for the Windows keys, as focus will soon + * be returned to Windows. We may be able to trap the Windows keys, + * but we should determine if that is desirable before doing so. + */ + if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) + break; + + /* + * Discard presses generated from Windows auto-repeat + */ + if (lParam & (1<<30)) + { + switch (wParam) + { + /* ago: Pressing LControl while RControl is pressed is + * Indicated as repeat. Fix this! + */ + case VK_CONTROL: + case VK_SHIFT: + if (winCheckKeyPressed(wParam, lParam)) + return 0; + break; + default: + return 0; + } + } + + /* Discard fake Ctrl_L presses that precede AltGR on non-US keyboards */ + if (winIsFakeCtrl_L (message, wParam, lParam)) + return 0; + + /* Translate Windows key code to X scan code */ + winTranslateKey (wParam, lParam, &iScanCode); + + /* Ignore repeats for CapsLock */ + if (wParam == VK_CAPITAL) + lParam = 1; + + /* Send the key event(s) */ + for (i = 0; i < LOWORD(lParam); ++i) + winSendKeyEvent (iScanCode, TRUE); + return 0; + + case WM_SYSKEYUP: + case WM_KEYUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* + * Don't do anything for the Windows keys, as focus will soon + * be returned to Windows. We may be able to trap the Windows keys, + * but we should determine if that is desirable before doing so. + */ + if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) + break; + + /* Ignore the fake Ctrl_L that follows an AltGr release */ + if (winIsFakeCtrl_L (message, wParam, lParam)) + return 0; + + /* Enqueue a keyup event */ + winTranslateKey (wParam, lParam, &iScanCode); + winSendKeyEvent (iScanCode, FALSE); + + /* Release all pressed shift keys */ + if (wParam == VK_SHIFT) + winFixShiftKeys (iScanCode); + return 0; + + case WM_HOTKEY: + if (s_pScreenPriv == NULL) + break; + + /* Call the engine-specific hot key handler */ + (*s_pScreenPriv->pwinHotKeyAltTab) (s_pScreen); + return 0; + + case WM_ACTIVATE: + if (s_pScreenPriv == NULL + || s_pScreenInfo->fIgnoreInput) + break; + + /* TODO: Override display of window when we have a bad depth */ + if (LOWORD(wParam) != WA_INACTIVE && s_pScreenPriv->fBadDepth) + { + ErrorF ("winWindowProc - WM_ACTIVATE - Bad depth, trying " + "to override window activation\n"); + + /* Minimize the window */ + ShowWindow (hwnd, SW_MINIMIZE); + + /* Display dialog box */ + if (g_hDlgDepthChange != NULL) + { + /* Make the existing dialog box active */ + SetActiveWindow (g_hDlgDepthChange); + } + else + { + /* TODO: Recreate the dialog box and bring to the top */ + ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); + } + + /* Don't do any other processing of this message */ + return 0; + } + +#if CYGDEBUG + winDebug ("winWindowProc - WM_ACTIVATE\n"); +#endif + + /* + * Focus is being changed to another window. + * The other window may or may not belong to + * our process. + */ + + /* Clear any lingering wheel delta */ + s_pScreenPriv->iDeltaZ = 0; + + /* Reshow the Windows mouse cursor if we are being deactivated */ + if (g_fSoftwareCursor && LOWORD(wParam) == WA_INACTIVE + && !g_fCursor) + { + /* Show Windows cursor */ + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return 0; + + case WM_ACTIVATEAPP: + if (s_pScreenPriv == NULL + || s_pScreenInfo->fIgnoreInput) + break; + +#if CYGDEBUG || TRUE + winDebug ("winWindowProc - WM_ACTIVATEAPP\n"); +#endif + + /* Activate or deactivate */ + s_pScreenPriv->fActive = wParam; + + /* Reshow the Windows mouse cursor if we are being deactivated */ + if (g_fSoftwareCursor && !s_pScreenPriv->fActive + && !g_fCursor) + { + /* Show Windows cursor */ + g_fCursor = TRUE; + ShowCursor (TRUE); + } + +#ifdef XWIN_CLIPBOARD + /* Make sure the clipboard chain is ok. */ + winFixClipboardChain (); +#endif + + /* Call engine specific screen activation/deactivation function */ + (*s_pScreenPriv->pwinActivateApp) (s_pScreen); + +#ifdef XWIN_MULTIWINDOWEXTWM + if (s_pScreenPriv->fActive) + { + /* Restack all window unless using built-in wm. */ + if (s_pScreenInfo->fInternalWM && s_pScreenInfo->fAnotherWMRunning) + winMWExtWMRestackWindows (s_pScreen); + } +#endif + + return 0; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case ID_APP_EXIT: + /* Display Exit dialog */ + winDisplayExitDialog (s_pScreenPriv); + return 0; + +#ifdef XWIN_MULTIWINDOW + case ID_APP_HIDE_ROOT: + if (s_pScreenPriv->fRootWindowShown) + ShowWindow (s_pScreenPriv->hwndScreen, SW_HIDE); + else + ShowWindow (s_pScreenPriv->hwndScreen, SW_SHOW); + s_pScreenPriv->fRootWindowShown = !s_pScreenPriv->fRootWindowShown; + return 0; +#endif + + case ID_APP_ABOUT: + /* Display the About box */ + winDisplayAboutDialog (s_pScreenPriv); + return 0; + + default: + /* It's probably one of the custom menus... */ + if (HandleCustomWM_COMMAND (0, LOWORD (wParam))) + return 0; + } + break; + + case WM_ENDSESSION: + case WM_GIVEUP: + /* Tell X that we are giving up */ +#ifdef XWIN_MULTIWINDOW + if (s_pScreenInfo->fMultiWindow) + winDeinitMultiWindowWM (); +#endif + GiveUp (0); + return 0; + + case WM_CLOSE: + /* Display Exit dialog */ + winDisplayExitDialog (s_pScreenPriv); + return 0; + + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) + { + if (!g_fSoftwareCursor) SetCursor (s_pScreenPriv->cursor.handle); + return TRUE; + } + break; + +#ifdef XWIN_MULTIWINDOWEXTWM + case WM_MANAGE: + ErrorF ("winWindowProc - WM_MANAGE\n"); + s_pScreenInfo->fAnotherWMRunning = FALSE; + + if (s_pScreenInfo->fInternalWM) + { + EnumThreadWindows (g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0); + //RootlessRepositionWindows (s_pScreen); + } + break; + + case WM_UNMANAGE: + ErrorF ("winWindowProc - WM_UNMANAGE\n"); + s_pScreenInfo->fAnotherWMRunning = TRUE; + + if (s_pScreenInfo->fInternalWM) + { + EnumThreadWindows (g_dwCurrentThreadID, winMWExtWMDecorateWindow, 0); + winMWExtWMRestackWindows (s_pScreen); + } + break; +#endif + + default: + if(message == s_uTaskbarRestart) + { + winInitNotifyIcon (s_pScreenPriv); + } + break; + } + + return DefWindowProc (hwnd, message, wParam, lParam); +} diff --git a/xorg-server/include/dix.h b/xorg-server/include/dix.h index ac19a9536..12e4b5977 100644 --- a/xorg-server/include/dix.h +++ b/xorg-server/include/dix.h @@ -1,602 +1,609 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL 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. - -******************************************************************/ - -#ifndef DIX_H -#define DIX_H - -#include "callback.h" -#include "gc.h" -#include "window.h" -#include "input.h" -#include "cursor.h" -#include "geext.h" -#include "events.h" -#include - -#define EARLIER -1 -#define SAMETIME 0 -#define LATER 1 - -#define NullClient ((ClientPtr) 0) -#define REQUEST(type) \ - type *stuff = (type *)client->requestBuffer - - -#define REQUEST_SIZE_MATCH(req)\ - if ((sizeof(req) >> 2) != client->req_len)\ - return(BadLength) - -#define REQUEST_AT_LEAST_SIZE(req) \ - if ((sizeof(req) >> 2) > client->req_len )\ - return(BadLength) - -#define REQUEST_FIXED_SIZE(req, n)\ - if (((sizeof(req) >> 2) > client->req_len) || \ - (((sizeof(req) + (n) + 3) >> 2) != client->req_len)) \ - return(BadLength) - -#define LEGAL_NEW_RESOURCE(id,client)\ - if (!LegalNewID(id,client)) \ - {\ - client->errorValue = id;\ - return BadIDChoice;\ - } - -#define VALIDATE_DRAWABLE_AND_GC(drawID, pDraw, mode)\ - {\ - int rc = dixLookupDrawable(&(pDraw), drawID, client, M_ANY, mode);\ - if (rc != Success)\ - return rc;\ - rc = dixLookupGC(&(pGC), stuff->gc, client, DixUseAccess);\ - if (rc != Success)\ - return rc;\ - if ((pGC->depth != pDraw->depth) || (pGC->pScreen != pDraw->pScreen))\ - return BadMatch;\ - }\ - if (pGC->serialNumber != pDraw->serialNumber)\ - ValidateGC(pDraw, pGC); - - -#define WriteReplyToClient(pClient, size, pReply) { \ - if ((pClient)->swapped) \ - (*ReplySwapVector[((xReq *)(pClient)->requestBuffer)->reqType]) \ - (pClient, (int)(size), pReply); \ - else (void) WriteToClient(pClient, (int)(size), (char *)(pReply)); } - -#define WriteSwappedDataToClient(pClient, size, pbuf) \ - if ((pClient)->swapped) \ - (*(pClient)->pSwapReplyFunc)(pClient, (int)(size), pbuf); \ - else (void) WriteToClient (pClient, (int)(size), (char *)(pbuf)); - -typedef struct _TimeStamp *TimeStampPtr; - -#ifndef _XTYPEDEF_CLIENTPTR -typedef struct _Client *ClientPtr; /* also in misc.h */ -#define _XTYPEDEF_CLIENTPTR -#endif - -typedef struct _WorkQueue *WorkQueuePtr; - -extern _X_EXPORT ClientPtr clients[MAXCLIENTS]; -extern _X_EXPORT ClientPtr serverClient; -extern _X_EXPORT int currentMaxClients; -extern _X_EXPORT char dispatchExceptionAtReset; - -typedef int HWEventQueueType; -typedef HWEventQueueType* HWEventQueuePtr; - -extern _X_EXPORT HWEventQueuePtr checkForInput[2]; - -typedef struct _TimeStamp { - CARD32 months; /* really ~49.7 days */ - CARD32 milliseconds; -} TimeStamp; - -/* dispatch.c */ - -extern _X_EXPORT void SetInputCheck( - HWEventQueuePtr /*c0*/, - HWEventQueuePtr /*c1*/); - -extern _X_EXPORT void CloseDownClient( - ClientPtr /*client*/); - -extern _X_EXPORT void UpdateCurrentTime(void); - -extern _X_EXPORT void UpdateCurrentTimeIf(void); - -extern _X_EXPORT int dixDestroyPixmap( - pointer /*value*/, - XID /*pid*/); - -extern _X_EXPORT void InitClient( - ClientPtr /*client*/, - int /*i*/, - pointer /*ospriv*/); - -extern _X_EXPORT ClientPtr NextAvailableClient( - pointer /*ospriv*/); - -extern _X_EXPORT void SendErrorToClient( - ClientPtr /*client*/, - unsigned int /*majorCode*/, - unsigned int /*minorCode*/, - XID /*resId*/, - int /*errorCode*/); - -extern _X_EXPORT void MarkClientException( - ClientPtr /*client*/); - -extern _X_HIDDEN Bool CreateConnectionBlock(void); -/* dixutils.c */ - -extern _X_EXPORT int CompareISOLatin1Lowered( - unsigned char * /*a*/, - int alen, - unsigned char * /*b*/, - int blen); - -extern _X_EXPORT int dixLookupWindow( - WindowPtr *result, - XID id, - ClientPtr client, - Mask access_mode); - -extern _X_EXPORT int dixLookupDrawable( - DrawablePtr *result, - XID id, - ClientPtr client, - Mask type_mask, - Mask access_mode); - -extern _X_EXPORT int dixLookupGC( - GCPtr *result, - XID id, - ClientPtr client, - Mask access_mode); - -extern _X_EXPORT int dixLookupFontable( - FontPtr *result, - XID id, - ClientPtr client, - Mask access_mode); - -extern _X_EXPORT int dixLookupClient( - ClientPtr *result, - XID id, - ClientPtr client, - Mask access_mode); - -extern _X_EXPORT void NoopDDA(void); - -extern _X_EXPORT int AlterSaveSetForClient( - ClientPtr /*client*/, - WindowPtr /*pWin*/, - unsigned /*mode*/, - Bool /*toRoot*/, - Bool /*map*/); - -extern _X_EXPORT void DeleteWindowFromAnySaveSet( - WindowPtr /*pWin*/); - -extern _X_EXPORT void BlockHandler( - pointer /*pTimeout*/, - pointer /*pReadmask*/); - -extern _X_EXPORT void WakeupHandler( - int /*result*/, - pointer /*pReadmask*/); - -void -EnableLimitedSchedulingLatency(void); - -void -DisableLimitedSchedulingLatency(void); - -typedef void (* WakeupHandlerProcPtr)( - pointer /* blockData */, - int /* result */, - pointer /* pReadmask */); - -extern _X_EXPORT Bool RegisterBlockAndWakeupHandlers( - BlockHandlerProcPtr /*blockHandler*/, - WakeupHandlerProcPtr /*wakeupHandler*/, - pointer /*blockData*/); - -extern _X_EXPORT void RemoveBlockAndWakeupHandlers( - BlockHandlerProcPtr /*blockHandler*/, - WakeupHandlerProcPtr /*wakeupHandler*/, - pointer /*blockData*/); - -extern _X_EXPORT void InitBlockAndWakeupHandlers(void); - -extern _X_EXPORT void ProcessWorkQueue(void); - -extern _X_EXPORT void ProcessWorkQueueZombies(void); - -extern _X_EXPORT Bool QueueWorkProc( - Bool (* /*function*/)( - ClientPtr /*clientUnused*/, - pointer /*closure*/), - ClientPtr /*client*/, - pointer /*closure*/ -); - -typedef Bool (* ClientSleepProcPtr)( - ClientPtr /*client*/, - pointer /*closure*/); - -extern _X_EXPORT Bool ClientSleep( - ClientPtr /*client*/, - ClientSleepProcPtr /* function */, - pointer /*closure*/); - -#ifndef ___CLIENTSIGNAL_DEFINED___ -#define ___CLIENTSIGNAL_DEFINED___ -extern _X_EXPORT Bool ClientSignal( - ClientPtr /*client*/); -#endif /* ___CLIENTSIGNAL_DEFINED___ */ - -extern _X_EXPORT void ClientWakeup( - ClientPtr /*client*/); - -extern _X_EXPORT Bool ClientIsAsleep( - ClientPtr /*client*/); - -/* atom.c */ - -extern _X_EXPORT Atom MakeAtom( - const char * /*string*/, - unsigned /*len*/, - Bool /*makeit*/); - -extern _X_EXPORT Bool ValidAtom( - Atom /*atom*/); - -extern _X_EXPORT const char *NameForAtom( - Atom /*atom*/); - -extern _X_EXPORT void AtomError(void) _X_NORETURN; - -extern _X_EXPORT void FreeAllAtoms(void); - -extern _X_EXPORT void InitAtoms(void); - -/* main.c */ - -extern _X_EXPORT void SetVendorRelease(int release); - -extern _X_EXPORT void SetVendorString(char *string); - -/* events.c */ - -extern void SetMaskForEvent( - int /* deviceid */, - Mask /* mask */, - int /* event */); - -extern _X_EXPORT void ConfineToShape( - DeviceIntPtr /* pDev */, - RegionPtr /* shape */, - int* /* px */, - int* /* py */); - -extern _X_EXPORT Bool IsParent( - WindowPtr /* maybeparent */, - WindowPtr /* child */); - -extern _X_EXPORT WindowPtr GetCurrentRootWindow(DeviceIntPtr pDev); - -extern _X_EXPORT WindowPtr GetSpriteWindow(DeviceIntPtr pDev); - - -extern _X_EXPORT void NoticeEventTime(InternalEvent *ev); - -extern void EnqueueEvent( - InternalEvent * /* ev */, - DeviceIntPtr /* device */); - -extern void ActivatePointerGrab( - DeviceIntPtr /* mouse */, - GrabPtr /* grab */, - TimeStamp /* time */, - Bool /* autoGrab */); - -extern void DeactivatePointerGrab( - DeviceIntPtr /* mouse */); - -extern void ActivateKeyboardGrab( - DeviceIntPtr /* keybd */, - GrabPtr /* grab */, - TimeStamp /* time */, - Bool /* passive */); - -extern void DeactivateKeyboardGrab( - DeviceIntPtr /* keybd */); - -extern BOOL ActivateFocusInGrab( - DeviceIntPtr /* dev */, - WindowPtr /* old */, - WindowPtr /* win */); - -extern void AllowSome( - ClientPtr /* client */, - TimeStamp /* time */, - DeviceIntPtr /* thisDev */, - int /* newState */); - -extern void ReleaseActiveGrabs( - ClientPtr client); - -extern _X_EXPORT int DeliverEventsToWindow( - DeviceIntPtr /* pWin */, - WindowPtr /* pWin */, - xEventPtr /* pEvents */, - int /* count */, - Mask /* filter */, - GrabPtr /* grab */); - -extern int DeliverDeviceEvents( - WindowPtr /* pWin */, - InternalEvent* /* event */, - GrabPtr /* grab */, - WindowPtr /* stopAt */, - DeviceIntPtr /* dev */); - -extern void InitializeSprite( - DeviceIntPtr /* pDev */, - WindowPtr /* pWin */); - -extern void UpdateSpriteForScreen( - DeviceIntPtr /* pDev */, - ScreenPtr /* pScreen */); - -extern _X_EXPORT void WindowHasNewCursor( - WindowPtr /* pWin */); - -extern Bool CheckDeviceGrabs( - DeviceIntPtr /* device */, - DeviceEvent* /* event */, - WindowPtr /* ancestor */); - -extern void DeliverFocusedEvent( - DeviceIntPtr /* keybd */, - InternalEvent* /* event */, - WindowPtr /* window */); - -extern void DeliverGrabbedEvent( - InternalEvent* /* event */, - DeviceIntPtr /* thisDev */, - Bool /* deactivateGrab */); - -extern void FixKeyState( - DeviceEvent* /* event */, - DeviceIntPtr /* keybd */); - -extern void RecalculateDeliverableEvents( - WindowPtr /* pWin */); - -extern _X_EXPORT int OtherClientGone( - pointer /* value */, - XID /* id */); - -extern void DoFocusEvents( - DeviceIntPtr /* dev */, - WindowPtr /* fromWin */, - WindowPtr /* toWin */, - int /* mode */); - -extern int SetInputFocus( - ClientPtr /* client */, - DeviceIntPtr /* dev */, - Window /* focusID */, - CARD8 /* revertTo */, - Time /* ctime */, - Bool /* followOK */); - -extern int GrabDevice( - ClientPtr /* client */, - DeviceIntPtr /* dev */, - unsigned /* this_mode */, - unsigned /* other_mode */, - Window /* grabWindow */, - unsigned /* ownerEvents */, - Time /* ctime */, - GrabMask* /* mask */, - int /* grabtype */, - Cursor /* curs */, - Window /* confineToWin */, - CARD8 * /* status */); - -extern void InitEvents(void); - -extern void CloseDownEvents(void); - -extern void DeleteWindowFromAnyEvents( - WindowPtr /* pWin */, - Bool /* freeResources */); - - -extern Mask EventMaskForClient( - WindowPtr /* pWin */, - ClientPtr /* client */); - - - -extern _X_EXPORT int DeliverEvents( - WindowPtr /*pWin*/, - xEventPtr /*xE*/, - int /*count*/, - WindowPtr /*otherParent*/); - -extern Bool CheckMotion( - DeviceEvent* /* ev */, - DeviceIntPtr /* pDev */); - -extern _X_EXPORT void WriteEventsToClient( - ClientPtr /*pClient*/, - int /*count*/, - xEventPtr /*events*/); - -extern _X_EXPORT int TryClientEvents( - ClientPtr /*client*/, - DeviceIntPtr /* device */, - xEventPtr /*pEvents*/, - int /*count*/, - Mask /*mask*/, - Mask /*filter*/, - GrabPtr /*grab*/); - -extern _X_EXPORT void WindowsRestructured(void); - -extern int SetClientPointer( - ClientPtr /* client */, - DeviceIntPtr /* device */); - -extern _X_EXPORT DeviceIntPtr PickPointer( - ClientPtr /* client */); - -extern _X_EXPORT DeviceIntPtr PickKeyboard( - ClientPtr /* client */); - -extern Bool IsInterferingGrab( - ClientPtr /* client */, - DeviceIntPtr /* dev */, - xEvent* /* events */); - -#ifdef PANORAMIX -extern _X_EXPORT void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff); -#endif - -#ifdef RANDR -extern _X_EXPORT void -ScreenRestructured (ScreenPtr pScreen); -#endif - -extern _X_EXPORT int ffs(int i); - - -/* - * ServerGrabCallback stuff - */ - -extern _X_EXPORT CallbackListPtr ServerGrabCallback; - -typedef enum {SERVER_GRABBED, SERVER_UNGRABBED, - CLIENT_PERVIOUS, CLIENT_IMPERVIOUS } ServerGrabState; - -typedef struct { - ClientPtr client; - ServerGrabState grabstate; -} ServerGrabInfoRec; - -/* - * EventCallback stuff - */ - -extern _X_EXPORT CallbackListPtr EventCallback; - -typedef struct { - ClientPtr client; - xEventPtr events; - int count; -} EventInfoRec; - -/* - * DeviceEventCallback stuff - */ - -extern _X_EXPORT CallbackListPtr DeviceEventCallback; - -typedef struct { - InternalEvent *event; - DeviceIntPtr device; -} DeviceEventInfoRec; - -extern int XItoCoreType(int xi_type); -extern Bool DevHasCursor(DeviceIntPtr pDev); -extern Bool _X_EXPORT IsPointerDevice( DeviceIntPtr dev); -extern Bool _X_EXPORT IsKeyboardDevice(DeviceIntPtr dev); -extern Bool IsPointerEvent(InternalEvent *event); -extern _X_EXPORT Bool IsMaster(DeviceIntPtr dev); - -extern _X_HIDDEN void CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); -extern _X_HIDDEN int CorePointerProc(DeviceIntPtr dev, int what); -extern _X_HIDDEN int CoreKeyboardProc(DeviceIntPtr dev, int what); - - -/* - * These are deprecated compatibility functions and will be removed soon! - * Please use the noted replacements instead. - */ -/* replaced by dixLookupWindow */ -extern _X_EXPORT WindowPtr SecurityLookupWindow( - XID id, - ClientPtr client, - Mask access_mode); -/* replaced by dixLookupWindow */ -extern _X_EXPORT WindowPtr LookupWindow( - XID id, - ClientPtr client); - -/* replaced by dixLookupDrawable */ -extern _X_EXPORT pointer SecurityLookupDrawable( - XID id, - ClientPtr client, - Mask access_mode); - -/* replaced by dixLookupDrawable */ -extern _X_EXPORT pointer LookupDrawable( - XID id, - ClientPtr client); - -/* replaced by dixLookupClient */ -extern _X_EXPORT ClientPtr LookupClient( - XID id, - ClientPtr client); - -#endif /* DIX_H */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +******************************************************************/ + +#ifndef DIX_H +#define DIX_H + +#include "callback.h" +#include "gc.h" +#include "window.h" +#include "input.h" +#include "cursor.h" +#include "geext.h" +#include "events.h" +#include + +#define EARLIER -1 +#define SAMETIME 0 +#define LATER 1 + +#define NullClient ((ClientPtr) 0) +#define REQUEST(type) \ + type *stuff = (type *)client->requestBuffer + + +#define REQUEST_SIZE_MATCH(req)\ + if ((sizeof(req) >> 2) != client->req_len)\ + return(BadLength) + +#define REQUEST_AT_LEAST_SIZE(req) \ + if ((sizeof(req) >> 2) > client->req_len )\ + return(BadLength) + +#define REQUEST_FIXED_SIZE(req, n)\ + if (((sizeof(req) >> 2) > client->req_len) || \ + (((sizeof(req) + (n) + 3) >> 2) != client->req_len)) \ + return(BadLength) + +#define LEGAL_NEW_RESOURCE(id,client)\ + if (!LegalNewID(id,client)) \ + {\ + client->errorValue = id;\ + return BadIDChoice;\ + } + +#define VALIDATE_DRAWABLE_AND_GC(drawID, pDraw, mode)\ + {\ + int rc = dixLookupDrawable(&(pDraw), drawID, client, M_ANY, mode);\ + if (rc != Success)\ + return rc;\ + rc = dixLookupGC(&(pGC), stuff->gc, client, DixUseAccess);\ + if (rc != Success)\ + return rc;\ + if ((pGC->depth != pDraw->depth) || (pGC->pScreen != pDraw->pScreen))\ + return BadMatch;\ + }\ + if (pGC->serialNumber != pDraw->serialNumber)\ + ValidateGC(pDraw, pGC); + + +#define WriteReplyToClient(pClient, size, pReply) { \ + if ((pClient)->swapped) \ + (*ReplySwapVector[((xReq *)(pClient)->requestBuffer)->reqType]) \ + (pClient, (int)(size), pReply); \ + else (void) WriteToClient(pClient, (int)(size), (char *)(pReply)); } + +#define WriteSwappedDataToClient(pClient, size, pbuf) \ + if ((pClient)->swapped) \ + (*(pClient)->pSwapReplyFunc)(pClient, (int)(size), pbuf); \ + else (void) WriteToClient (pClient, (int)(size), (char *)(pbuf)); + +typedef struct _TimeStamp *TimeStampPtr; + +#ifndef _XTYPEDEF_CLIENTPTR +typedef struct _Client *ClientPtr; /* also in misc.h */ +#define _XTYPEDEF_CLIENTPTR +#endif + +typedef struct _WorkQueue *WorkQueuePtr; + +extern _X_EXPORT ClientPtr clients[MAXCLIENTS]; +extern _X_EXPORT ClientPtr serverClient; +extern _X_EXPORT int currentMaxClients; +extern _X_EXPORT char dispatchExceptionAtReset; + +typedef int HWEventQueueType; +typedef HWEventQueueType* HWEventQueuePtr; + +extern _X_EXPORT HWEventQueuePtr checkForInput[2]; + +typedef struct _TimeStamp { + CARD32 months; /* really ~49.7 days */ + CARD32 milliseconds; +} TimeStamp; + +/* dispatch.c */ + +extern _X_EXPORT void SetInputCheck( + HWEventQueuePtr /*c0*/, + HWEventQueuePtr /*c1*/); + +extern _X_EXPORT void CloseDownClient( + ClientPtr /*client*/); + +extern _X_EXPORT void UpdateCurrentTime(void); + +extern _X_EXPORT void UpdateCurrentTimeIf(void); + +extern _X_EXPORT int dixDestroyPixmap( + pointer /*value*/, + XID /*pid*/); + +extern _X_EXPORT void InitClient( + ClientPtr /*client*/, + int /*i*/, + pointer /*ospriv*/); + +extern _X_EXPORT ClientPtr NextAvailableClient( + pointer /*ospriv*/); + +extern _X_EXPORT void SendErrorToClient( + ClientPtr /*client*/, + unsigned int /*majorCode*/, + unsigned int /*minorCode*/, + XID /*resId*/, + int /*errorCode*/); + +extern _X_EXPORT void MarkClientException( + ClientPtr /*client*/); + +extern _X_HIDDEN Bool CreateConnectionBlock(void); +/* dixutils.c */ + +extern _X_EXPORT int CompareISOLatin1Lowered( + unsigned char * /*a*/, + int alen, + unsigned char * /*b*/, + int blen); + +extern _X_EXPORT int dixLookupWindow( + WindowPtr *result, + XID id, + ClientPtr client, + Mask access_mode); + +extern _X_EXPORT int dixLookupDrawable( + DrawablePtr *result, + XID id, + ClientPtr client, + Mask type_mask, + Mask access_mode); + +extern _X_EXPORT int dixLookupGC( + GCPtr *result, + XID id, + ClientPtr client, + Mask access_mode); + +extern _X_EXPORT int dixLookupFontable( + FontPtr *result, + XID id, + ClientPtr client, + Mask access_mode); + +extern _X_EXPORT int dixLookupClient( + ClientPtr *result, + XID id, + ClientPtr client, + Mask access_mode); + +extern _X_EXPORT void NoopDDA(void); + +extern _X_EXPORT int AlterSaveSetForClient( + ClientPtr /*client*/, + WindowPtr /*pWin*/, + unsigned /*mode*/, + Bool /*toRoot*/, + Bool /*map*/); + +extern _X_EXPORT void DeleteWindowFromAnySaveSet( + WindowPtr /*pWin*/); + +extern _X_EXPORT void BlockHandler( + pointer /*pTimeout*/, + pointer /*pReadmask*/); + +extern _X_EXPORT void WakeupHandler( + int /*result*/, + pointer /*pReadmask*/); + +void +EnableLimitedSchedulingLatency(void); + +void +DisableLimitedSchedulingLatency(void); + +typedef void (* WakeupHandlerProcPtr)( + pointer /* blockData */, + int /* result */, + pointer /* pReadmask */); + +extern _X_EXPORT Bool RegisterBlockAndWakeupHandlers( + BlockHandlerProcPtr /*blockHandler*/, + WakeupHandlerProcPtr /*wakeupHandler*/, + pointer /*blockData*/); + +extern _X_EXPORT void RemoveBlockAndWakeupHandlers( + BlockHandlerProcPtr /*blockHandler*/, + WakeupHandlerProcPtr /*wakeupHandler*/, + pointer /*blockData*/); + +extern _X_EXPORT void InitBlockAndWakeupHandlers(void); + +extern _X_EXPORT void ProcessWorkQueue(void); + +extern _X_EXPORT void ProcessWorkQueueZombies(void); + +extern _X_EXPORT Bool QueueWorkProc( + Bool (* /*function*/)( + ClientPtr /*clientUnused*/, + pointer /*closure*/), + ClientPtr /*client*/, + pointer /*closure*/ +); + +typedef Bool (* ClientSleepProcPtr)( + ClientPtr /*client*/, + pointer /*closure*/); + +extern _X_EXPORT Bool ClientSleep( + ClientPtr /*client*/, + ClientSleepProcPtr /* function */, + pointer /*closure*/); + +#ifndef ___CLIENTSIGNAL_DEFINED___ +#define ___CLIENTSIGNAL_DEFINED___ +extern _X_EXPORT Bool ClientSignal( + ClientPtr /*client*/); +#endif /* ___CLIENTSIGNAL_DEFINED___ */ + +extern _X_EXPORT void ClientWakeup( + ClientPtr /*client*/); + +extern _X_EXPORT Bool ClientIsAsleep( + ClientPtr /*client*/); + +/* atom.c */ + +extern _X_EXPORT Atom MakeAtom( + const char * /*string*/, + unsigned /*len*/, + Bool /*makeit*/); + +extern _X_EXPORT Bool ValidAtom( + Atom /*atom*/); + +extern _X_EXPORT const char *NameForAtom( + Atom /*atom*/); + +extern _X_EXPORT void AtomError(void) _X_NORETURN; + +extern _X_EXPORT void FreeAllAtoms(void); + +extern _X_EXPORT void InitAtoms(void); + +/* main.c */ + +extern _X_EXPORT void SetVendorRelease(int release); + +extern _X_EXPORT void SetVendorString(char *string); + +/* events.c */ + +extern void SetMaskForEvent( + int /* deviceid */, + Mask /* mask */, + int /* event */); + +extern _X_EXPORT void ConfineToShape( + DeviceIntPtr /* pDev */, + RegionPtr /* shape */, + int* /* px */, + int* /* py */); + +extern _X_EXPORT Bool IsParent( + WindowPtr /* maybeparent */, + WindowPtr /* child */); + +extern _X_EXPORT WindowPtr GetCurrentRootWindow(DeviceIntPtr pDev); + +extern _X_EXPORT WindowPtr GetSpriteWindow(DeviceIntPtr pDev); + + +extern _X_EXPORT void NoticeEventTime(InternalEvent *ev); + +extern void EnqueueEvent( + InternalEvent * /* ev */, + DeviceIntPtr /* device */); + +extern void ActivatePointerGrab( + DeviceIntPtr /* mouse */, + GrabPtr /* grab */, + TimeStamp /* time */, + Bool /* autoGrab */); + +extern void DeactivatePointerGrab( + DeviceIntPtr /* mouse */); + +extern void ActivateKeyboardGrab( + DeviceIntPtr /* keybd */, + GrabPtr /* grab */, + TimeStamp /* time */, + Bool /* passive */); + +extern void DeactivateKeyboardGrab( + DeviceIntPtr /* keybd */); + +extern BOOL ActivateFocusInGrab( + DeviceIntPtr /* dev */, + WindowPtr /* old */, + WindowPtr /* win */); + +extern void AllowSome( + ClientPtr /* client */, + TimeStamp /* time */, + DeviceIntPtr /* thisDev */, + int /* newState */); + +extern void ReleaseActiveGrabs( + ClientPtr client); + +extern GrabPtr CheckPassiveGrabsOnWindow( + WindowPtr /* pWin */, + DeviceIntPtr /* device */, + DeviceEvent * /* event */, + BOOL /* checkCore */, + BOOL /* activate */); + +extern _X_EXPORT int DeliverEventsToWindow( + DeviceIntPtr /* pWin */, + WindowPtr /* pWin */, + xEventPtr /* pEvents */, + int /* count */, + Mask /* filter */, + GrabPtr /* grab */); + +extern int DeliverDeviceEvents( + WindowPtr /* pWin */, + InternalEvent* /* event */, + GrabPtr /* grab */, + WindowPtr /* stopAt */, + DeviceIntPtr /* dev */); + +extern void InitializeSprite( + DeviceIntPtr /* pDev */, + WindowPtr /* pWin */); + +extern void UpdateSpriteForScreen( + DeviceIntPtr /* pDev */, + ScreenPtr /* pScreen */); + +extern _X_EXPORT void WindowHasNewCursor( + WindowPtr /* pWin */); + +extern Bool CheckDeviceGrabs( + DeviceIntPtr /* device */, + DeviceEvent* /* event */, + WindowPtr /* ancestor */); + +extern void DeliverFocusedEvent( + DeviceIntPtr /* keybd */, + InternalEvent* /* event */, + WindowPtr /* window */); + +extern void DeliverGrabbedEvent( + InternalEvent* /* event */, + DeviceIntPtr /* thisDev */, + Bool /* deactivateGrab */); + +extern void FixKeyState( + DeviceEvent* /* event */, + DeviceIntPtr /* keybd */); + +extern void RecalculateDeliverableEvents( + WindowPtr /* pWin */); + +extern _X_EXPORT int OtherClientGone( + pointer /* value */, + XID /* id */); + +extern void DoFocusEvents( + DeviceIntPtr /* dev */, + WindowPtr /* fromWin */, + WindowPtr /* toWin */, + int /* mode */); + +extern int SetInputFocus( + ClientPtr /* client */, + DeviceIntPtr /* dev */, + Window /* focusID */, + CARD8 /* revertTo */, + Time /* ctime */, + Bool /* followOK */); + +extern int GrabDevice( + ClientPtr /* client */, + DeviceIntPtr /* dev */, + unsigned /* this_mode */, + unsigned /* other_mode */, + Window /* grabWindow */, + unsigned /* ownerEvents */, + Time /* ctime */, + GrabMask* /* mask */, + int /* grabtype */, + Cursor /* curs */, + Window /* confineToWin */, + CARD8 * /* status */); + +extern void InitEvents(void); + +extern void CloseDownEvents(void); + +extern void DeleteWindowFromAnyEvents( + WindowPtr /* pWin */, + Bool /* freeResources */); + + +extern Mask EventMaskForClient( + WindowPtr /* pWin */, + ClientPtr /* client */); + + + +extern _X_EXPORT int DeliverEvents( + WindowPtr /*pWin*/, + xEventPtr /*xE*/, + int /*count*/, + WindowPtr /*otherParent*/); + +extern Bool CheckMotion( + DeviceEvent* /* ev */, + DeviceIntPtr /* pDev */); + +extern _X_EXPORT void WriteEventsToClient( + ClientPtr /*pClient*/, + int /*count*/, + xEventPtr /*events*/); + +extern _X_EXPORT int TryClientEvents( + ClientPtr /*client*/, + DeviceIntPtr /* device */, + xEventPtr /*pEvents*/, + int /*count*/, + Mask /*mask*/, + Mask /*filter*/, + GrabPtr /*grab*/); + +extern _X_EXPORT void WindowsRestructured(void); + +extern int SetClientPointer( + ClientPtr /* client */, + DeviceIntPtr /* device */); + +extern _X_EXPORT DeviceIntPtr PickPointer( + ClientPtr /* client */); + +extern _X_EXPORT DeviceIntPtr PickKeyboard( + ClientPtr /* client */); + +extern Bool IsInterferingGrab( + ClientPtr /* client */, + DeviceIntPtr /* dev */, + xEvent* /* events */); + +#ifdef PANORAMIX +extern _X_EXPORT void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff); +#endif + +#ifdef RANDR +extern _X_EXPORT void +ScreenRestructured (ScreenPtr pScreen); +#endif + +extern _X_EXPORT int ffs(int i); + + +/* + * ServerGrabCallback stuff + */ + +extern _X_EXPORT CallbackListPtr ServerGrabCallback; + +typedef enum {SERVER_GRABBED, SERVER_UNGRABBED, + CLIENT_PERVIOUS, CLIENT_IMPERVIOUS } ServerGrabState; + +typedef struct { + ClientPtr client; + ServerGrabState grabstate; +} ServerGrabInfoRec; + +/* + * EventCallback stuff + */ + +extern _X_EXPORT CallbackListPtr EventCallback; + +typedef struct { + ClientPtr client; + xEventPtr events; + int count; +} EventInfoRec; + +/* + * DeviceEventCallback stuff + */ + +extern _X_EXPORT CallbackListPtr DeviceEventCallback; + +typedef struct { + InternalEvent *event; + DeviceIntPtr device; +} DeviceEventInfoRec; + +extern int XItoCoreType(int xi_type); +extern Bool DevHasCursor(DeviceIntPtr pDev); +extern Bool _X_EXPORT IsPointerDevice( DeviceIntPtr dev); +extern Bool _X_EXPORT IsKeyboardDevice(DeviceIntPtr dev); +extern Bool IsPointerEvent(InternalEvent *event); +extern _X_EXPORT Bool IsMaster(DeviceIntPtr dev); + +extern _X_HIDDEN void CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); +extern _X_HIDDEN int CorePointerProc(DeviceIntPtr dev, int what); +extern _X_HIDDEN int CoreKeyboardProc(DeviceIntPtr dev, int what); + + +/* + * These are deprecated compatibility functions and will be removed soon! + * Please use the noted replacements instead. + */ +/* replaced by dixLookupWindow */ +extern _X_EXPORT WindowPtr SecurityLookupWindow( + XID id, + ClientPtr client, + Mask access_mode); +/* replaced by dixLookupWindow */ +extern _X_EXPORT WindowPtr LookupWindow( + XID id, + ClientPtr client); + +/* replaced by dixLookupDrawable */ +extern _X_EXPORT pointer SecurityLookupDrawable( + XID id, + ClientPtr client, + Mask access_mode); + +/* replaced by dixLookupDrawable */ +extern _X_EXPORT pointer LookupDrawable( + XID id, + ClientPtr client); + +/* replaced by dixLookupClient */ +extern _X_EXPORT ClientPtr LookupClient( + XID id, + ClientPtr client); + +#endif /* DIX_H */ diff --git a/xorg-server/include/input.h b/xorg-server/include/input.h index 31aad9aa4..f96a0a988 100644 --- a/xorg-server/include/input.h +++ b/xorg-server/include/input.h @@ -1,585 +1,589 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL 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. - -********************************************************/ - -#ifndef INPUT_H -#define INPUT_H - -#include "misc.h" -#include "screenint.h" -#include -#include -#include -#include "window.h" /* for WindowPtr */ -#include "xkbrules.h" -#include "events.h" - -#define DEVICE_INIT 0 -#define DEVICE_ON 1 -#define DEVICE_OFF 2 -#define DEVICE_CLOSE 3 - -#define POINTER_RELATIVE (1 << 1) -#define POINTER_ABSOLUTE (1 << 2) -#define POINTER_ACCELERATE (1 << 3) -#define POINTER_SCREEN (1 << 4) /* Data in screen coordinates */ - -/*int constants for pointer acceleration schemes*/ -#define PtrAccelNoOp 0 -#define PtrAccelPredictable 1 -#define PtrAccelLightweight 2 -#define PtrAccelDefault PtrAccelPredictable - -#define MAX_VALUATORS 36 -/* Maximum number of valuators, divided by six, rounded up, to get number - * of events. */ -#define MAX_VALUATOR_EVENTS 6 -#define MAX_BUTTONS 256 /* completely arbitrarily chosen */ - -#define NO_AXIS_LIMITS -1 - -#define MAP_LENGTH 256 -#define DOWN_LENGTH 32 /* 256/8 => number of bytes to hold 256 bits */ -#define NullGrab ((GrabPtr)NULL) -#define PointerRootWin ((WindowPtr)PointerRoot) -#define NoneWin ((WindowPtr)None) -#define NullDevice ((DevicePtr)NULL) - -#ifndef FollowKeyboard -#define FollowKeyboard 3 -#endif -#ifndef FollowKeyboardWin -#define FollowKeyboardWin ((WindowPtr) FollowKeyboard) -#endif -#ifndef RevertToFollowKeyboard -#define RevertToFollowKeyboard 3 -#endif - -typedef unsigned long Leds; -typedef struct _OtherClients *OtherClientsPtr; -typedef struct _InputClients *InputClientsPtr; -typedef struct _DeviceIntRec *DeviceIntPtr; -typedef struct _ClassesRec *ClassesPtr; -typedef union _GrabMask GrabMask; - -typedef struct _EventList { - xEvent* event; - int evlen; /* length of allocated memory for event in bytes. This is not - the actual length of the event. The event's actual length is - 32 for standard events or 32 + - ((xGenericEvent*)event)->length * 4 for GenericEvents. - For events in the EQ, the length is - ((InternalEvent*)event)->u.any.length */ -} EventList, *EventListPtr; - -/* The DIX stores incoming input events in this list */ -extern EventListPtr InputEventList; -extern int InputEventListLen; - -typedef int (*DeviceProc)( - DeviceIntPtr /*device*/, - int /*what*/); - -typedef void (*ProcessInputProc)( - InternalEvent * /*event*/, - DeviceIntPtr /*device*/); - -typedef Bool (*DeviceHandleProc)( - DeviceIntPtr /*device*/, - void* /*data*/ - ); - -typedef void (*DeviceUnwrapProc)( - DeviceIntPtr /*device*/, - DeviceHandleProc /*proc*/, - void* /*data*/ - ); - -/* pointer acceleration handling */ -typedef void (*PointerAccelSchemeProc)( - DeviceIntPtr /*pDev*/, - int /*first_valuator*/, - int /*num_valuators*/, - int* /*valuators*/, - int /*evtime*/); - -typedef void (*DeviceCallbackProc)( - DeviceIntPtr /*pDev*/); - -typedef struct _DeviceRec { - pointer devicePrivate; - ProcessInputProc processInputProc; /* current */ - ProcessInputProc realInputProc; /* deliver */ - ProcessInputProc enqueueInputProc; /* enqueue */ - Bool on; /* used by DDX to keep state */ -} DeviceRec, *DevicePtr; - -typedef struct _ValuatorMask ValuatorMask; - -typedef struct { - int click, bell, bell_pitch, bell_duration; - Bool autoRepeat; - unsigned char autoRepeats[32]; - Leds leds; - unsigned char id; -} KeybdCtrl; - -typedef struct { - KeySym *map; - KeyCode minKeyCode, - maxKeyCode; - int mapWidth; -} KeySymsRec, *KeySymsPtr; - -typedef struct { - int num, den, threshold; - unsigned char id; -} PtrCtrl; - -typedef struct { - int resolution, min_value, max_value; - int integer_displayed; - unsigned char id; -} IntegerCtrl; - -typedef struct { - int max_symbols, num_symbols_supported; - int num_symbols_displayed; - KeySym *symbols_supported; - KeySym *symbols_displayed; - unsigned char id; -} StringCtrl; - -typedef struct { - int percent, pitch, duration; - unsigned char id; -} BellCtrl; - -typedef struct { - Leds led_values; - Mask led_mask; - unsigned char id; -} LedCtrl; - -extern _X_EXPORT KeybdCtrl defaultKeyboardControl; -extern _X_EXPORT PtrCtrl defaultPointerControl; - -typedef struct _InputOption { - char *key; - char *value; - struct _InputOption *next; -} InputOption; - -typedef struct _InputAttributes { - char *product; - char *vendor; - char *device; - char *pnp_id; - char *usb_id; - char **tags; /* null-terminated */ - uint32_t flags; -} InputAttributes; - -#define ATTR_KEYBOARD (1<<0) -#define ATTR_POINTER (1<<1) -#define ATTR_JOYSTICK (1<<2) -#define ATTR_TABLET (1<<3) -#define ATTR_TOUCHPAD (1<<4) -#define ATTR_TOUCHSCREEN (1<<5) - -/* Key/Button has been run through all input processing and events sent to clients. */ -#define KEY_PROCESSED 1 -#define BUTTON_PROCESSED 1 -/* Key/Button has not been fully processed, no events have been sent. */ -#define KEY_POSTED 2 -#define BUTTON_POSTED 2 - -extern void set_key_down(DeviceIntPtr pDev, int key_code, int type); -extern void set_key_up(DeviceIntPtr pDev, int key_code, int type); -extern int key_is_down(DeviceIntPtr pDev, int key_code, int type); -extern void set_button_down(DeviceIntPtr pDev, int button, int type); -extern void set_button_up(DeviceIntPtr pDev, int button, int type); -extern int button_is_down(DeviceIntPtr pDev, int button, int type); - -extern void InitCoreDevices(void); -extern void InitXTestDevices(void); - -extern _X_EXPORT DeviceIntPtr AddInputDevice( - ClientPtr /*client*/, - DeviceProc /*deviceProc*/, - Bool /*autoStart*/); - -extern _X_EXPORT Bool EnableDevice( - DeviceIntPtr /*device*/, - BOOL /* sendevent */); - -extern _X_EXPORT Bool ActivateDevice( - DeviceIntPtr /*device*/, - BOOL /* sendevent */); - -extern _X_EXPORT Bool DisableDevice( - DeviceIntPtr /*device*/, - BOOL /* sendevent */); - -extern int InitAndStartDevices(void); - -extern void CloseDownDevices(void); - -extern void UndisplayDevices(void); - -extern _X_EXPORT int RemoveDevice( - DeviceIntPtr /*dev*/, - BOOL /* sendevent */); - -extern _X_EXPORT int NumMotionEvents(void); - -extern _X_EXPORT int dixLookupDevice( - DeviceIntPtr * /* dev */, - int /* id */, - ClientPtr /* client */, - Mask /* access_mode */); - -extern _X_EXPORT void QueryMinMaxKeyCodes( - KeyCode* /*minCode*/, - KeyCode* /*maxCode*/); - -extern _X_EXPORT Bool SetKeySymsMap( - KeySymsPtr /*dst*/, - KeySymsPtr /*src*/); - -extern _X_EXPORT Bool InitButtonClassDeviceStruct( - DeviceIntPtr /*device*/, - int /*numButtons*/, - Atom* /* labels */, - CARD8* /*map*/); - -extern _X_EXPORT Bool InitValuatorClassDeviceStruct( - DeviceIntPtr /*device*/, - int /*numAxes*/, - Atom* /* labels */, - int /*numMotionEvents*/, - int /*mode*/); - -extern _X_EXPORT Bool InitPointerAccelerationScheme( - DeviceIntPtr /*dev*/, - int /*scheme*/); - -extern _X_EXPORT Bool InitAbsoluteClassDeviceStruct( - DeviceIntPtr /*device*/); - -extern _X_EXPORT Bool InitFocusClassDeviceStruct( - DeviceIntPtr /*device*/); - -typedef void (*BellProcPtr)( - int /*percent*/, - DeviceIntPtr /*device*/, - pointer /*ctrl*/, - int); - -typedef void (*KbdCtrlProcPtr)( - DeviceIntPtr /*device*/, - KeybdCtrl * /*ctrl*/); - -typedef void (*PtrCtrlProcPtr)( - DeviceIntPtr /*device*/, - PtrCtrl * /*ctrl*/); - -extern _X_EXPORT Bool InitPtrFeedbackClassDeviceStruct( - DeviceIntPtr /*device*/, - PtrCtrlProcPtr /*controlProc*/); - -typedef void (*StringCtrlProcPtr)( - DeviceIntPtr /*device*/, - StringCtrl * /*ctrl*/); - -extern _X_EXPORT Bool InitStringFeedbackClassDeviceStruct( - DeviceIntPtr /*device*/, - StringCtrlProcPtr /*controlProc*/, - int /*max_symbols*/, - int /*num_symbols_supported*/, - KeySym* /*symbols*/); - -typedef void (*BellCtrlProcPtr)( - DeviceIntPtr /*device*/, - BellCtrl * /*ctrl*/); - -extern _X_EXPORT Bool InitBellFeedbackClassDeviceStruct( - DeviceIntPtr /*device*/, - BellProcPtr /*bellProc*/, - BellCtrlProcPtr /*controlProc*/); - -typedef void (*LedCtrlProcPtr)( - DeviceIntPtr /*device*/, - LedCtrl * /*ctrl*/); - -extern _X_EXPORT Bool InitLedFeedbackClassDeviceStruct( - DeviceIntPtr /*device*/, - LedCtrlProcPtr /*controlProc*/); - -typedef void (*IntegerCtrlProcPtr)( - DeviceIntPtr /*device*/, - IntegerCtrl * /*ctrl*/); - - -extern _X_EXPORT Bool InitIntegerFeedbackClassDeviceStruct( - DeviceIntPtr /*device*/, - IntegerCtrlProcPtr /*controlProc*/); - -extern _X_EXPORT Bool InitPointerDeviceStruct( - DevicePtr /*device*/, - CARD8* /*map*/, - int /*numButtons*/, - Atom* /* btn_labels */, - PtrCtrlProcPtr /*controlProc*/, - int /*numMotionEvents*/, - int /*numAxes*/, - Atom* /* axes_labels */); - -extern _X_EXPORT Bool InitKeyboardDeviceStruct( - DeviceIntPtr /*device*/, - XkbRMLVOSet * /*rmlvo*/, - BellProcPtr /*bellProc*/, - KbdCtrlProcPtr /*controlProc*/); - -extern int ApplyPointerMapping( - DeviceIntPtr /* pDev */, - CARD8 * /* map */, - int /* len */, - ClientPtr /* client */); - -extern Bool BadDeviceMap( - BYTE* /*buff*/, - int /*length*/, - unsigned /*low*/, - unsigned /*high*/, - XID* /*errval*/); - -extern void NoteLedState( - DeviceIntPtr /*keybd*/, - int /*led*/, - Bool /*on*/); - -extern void MaybeStopHint( - DeviceIntPtr /*device*/, - ClientPtr /*client*/); - -extern void ProcessPointerEvent( - InternalEvent* /* ev */, - DeviceIntPtr /*mouse*/); - -extern void ProcessKeyboardEvent( - InternalEvent* /*ev*/, - DeviceIntPtr /*keybd*/); - -extern Bool LegalModifier( - unsigned int /*key*/, - DeviceIntPtr /*pDev*/); - -extern _X_EXPORT void ProcessInputEvents(void); - -extern _X_EXPORT void InitInput( - int /*argc*/, - char ** /*argv*/); -extern _X_EXPORT void CloseInput(void); - -extern _X_EXPORT int GetMaximumEventsNum(void); - -extern _X_EXPORT int GetEventList(EventListPtr* list); -extern _X_EXPORT EventListPtr InitEventList(int num_events); -extern _X_EXPORT void FreeEventList(EventListPtr list, int num_events); - -extern void CreateClassesChangedEvent(EventListPtr event, - DeviceIntPtr master, - DeviceIntPtr slave, - int type); -extern EventListPtr UpdateFromMaster( - EventListPtr events, - DeviceIntPtr pDev, - int type, - int *num_events); - -extern _X_EXPORT int GetPointerEvents( - EventListPtr events, - DeviceIntPtr pDev, - int type, - int buttons, - int flags, - const ValuatorMask *mask); - -extern _X_EXPORT int GetKeyboardEvents( - EventListPtr events, - DeviceIntPtr pDev, - int type, - int key_code); - -extern int GetKeyboardValuatorEvents( - EventListPtr events, - DeviceIntPtr pDev, - int type, - int key_code, - const ValuatorMask *mask); - -extern int GetProximityEvents( - EventListPtr events, - DeviceIntPtr pDev, - int type, - const ValuatorMask *mask); - -extern void PostSyntheticMotion( - DeviceIntPtr pDev, - int x, - int y, - int screen, - unsigned long time); - -extern _X_EXPORT int GetMotionHistorySize( - void); - -extern _X_EXPORT void AllocateMotionHistory( - DeviceIntPtr pDev); - -extern _X_EXPORT int GetMotionHistory( - DeviceIntPtr pDev, - xTimecoord **buff, - unsigned long start, - unsigned long stop, - ScreenPtr pScreen, - BOOL core); - -extern int AttachDevice(ClientPtr client, - DeviceIntPtr slave, - DeviceIntPtr master); - -extern _X_EXPORT DeviceIntPtr GetPairedDevice(DeviceIntPtr kbd); -extern DeviceIntPtr GetMaster(DeviceIntPtr dev, int type); - -extern _X_EXPORT int AllocDevicePair(ClientPtr client, - char* name, - DeviceIntPtr* ptr, - DeviceIntPtr* keybd, - DeviceProc ptr_proc, - DeviceProc keybd_proc, - Bool master); -extern void DeepCopyDeviceClasses(DeviceIntPtr from, - DeviceIntPtr to, - DeviceChangedEvent *dce); - -/* Helper functions. */ -extern _X_EXPORT int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, - KeyCode **modkeymap, int *max_keys_per_mod); -extern int change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *map, - int max_keys_per_mod); -extern int AllocXTestDevice(ClientPtr client, - char* name, - DeviceIntPtr* ptr, - DeviceIntPtr* keybd, - DeviceIntPtr master_ptr, - DeviceIntPtr master_keybd); -extern BOOL IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master); -extern DeviceIntPtr GetXTestDevice(DeviceIntPtr master); -extern void SendDevicePresenceEvent(int deviceid, int type); -extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs); -extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs); - -/* misc event helpers */ -extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event); -extern Mask GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev); -void FixUpEventFromWindow(DeviceIntPtr pDev, - xEvent *xE, - WindowPtr pWin, - Window child, - Bool calcChild); -extern int EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, - WindowPtr win); -/** - * Return masks for EventIsDeliverable. - * @defgroup EventIsDeliverable return flags - * @{ - */ -#define XI_MASK (1 << 0) /**< XI mask set on window */ -#define CORE_MASK (1 << 1) /**< Core mask set on window */ -#define DONT_PROPAGATE_MASK (1 << 2) /**< DontPropagate mask set on window */ -#define XI2_MASK (1 << 3) /**< XI2 mask set on window */ -/* @} */ - -/* Implemented by the DDX. */ -extern _X_EXPORT int NewInputDeviceRequest( - InputOption *options, - InputAttributes *attrs, - DeviceIntPtr *dev); -extern _X_EXPORT void DeleteInputDeviceRequest( - DeviceIntPtr dev); - -extern _X_EXPORT void DDXRingBell( - int volume, - int pitch, - int duration); - -#define VALUATOR_MODE_ALL_AXES -1 -extern _X_HIDDEN int valuator_get_mode(DeviceIntPtr dev, int axis); -extern _X_HIDDEN void valuator_set_mode(DeviceIntPtr dev, int axis, int mode); - -/* Set to TRUE by default - os/utils.c sets it to FALSE on user request, - xfixes/cursor.c uses it to determine if the cursor is enabled */ -extern Bool EnableCursor; - -extern _X_EXPORT ValuatorMask *valuator_mask_new(int num_valuators); -extern _X_EXPORT void valuator_mask_set_range(ValuatorMask *mask, - int first_valuator, int num_valuators, - const int* valuators); -extern _X_EXPORT void valuator_mask_set(ValuatorMask *mask, - int valuator, - int data); -extern _X_EXPORT void valuator_mask_zero(ValuatorMask *mask); -extern _X_EXPORT int valuator_mask_size(const ValuatorMask *mask); -extern _X_EXPORT int valuator_mask_isset(const ValuatorMask *mask, int bit); -extern _X_EXPORT void valuator_mask_unset(ValuatorMask *mask, int bit); -extern _X_EXPORT int valuator_mask_num_valuators(const ValuatorMask *mask); -extern _X_EXPORT void valuator_mask_copy(ValuatorMask *dest, - const ValuatorMask *src); -extern _X_EXPORT int valuator_mask_get(const ValuatorMask *mask, int valnum); - -#endif /* INPUT_H */ +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +********************************************************/ + +#ifndef INPUT_H +#define INPUT_H + +#include "misc.h" +#include "screenint.h" +#include +#include +#include +#include "window.h" /* for WindowPtr */ +#include "xkbrules.h" +#include "events.h" + +#define DEVICE_INIT 0 +#define DEVICE_ON 1 +#define DEVICE_OFF 2 +#define DEVICE_CLOSE 3 + +#define POINTER_RELATIVE (1 << 1) +#define POINTER_ABSOLUTE (1 << 2) +#define POINTER_ACCELERATE (1 << 3) +#define POINTER_SCREEN (1 << 4) /* Data in screen coordinates */ + +/*int constants for pointer acceleration schemes*/ +#define PtrAccelNoOp 0 +#define PtrAccelPredictable 1 +#define PtrAccelLightweight 2 +#define PtrAccelDefault PtrAccelPredictable + +#define MAX_VALUATORS 36 +/* Maximum number of valuators, divided by six, rounded up, to get number + * of events. */ +#define MAX_VALUATOR_EVENTS 6 +#define MAX_BUTTONS 256 /* completely arbitrarily chosen */ + +#define NO_AXIS_LIMITS -1 + +#define MAP_LENGTH 256 +#define DOWN_LENGTH 32 /* 256/8 => number of bytes to hold 256 bits */ +#define NullGrab ((GrabPtr)NULL) +#define PointerRootWin ((WindowPtr)PointerRoot) +#define NoneWin ((WindowPtr)None) +#define NullDevice ((DevicePtr)NULL) + +#ifndef FollowKeyboard +#define FollowKeyboard 3 +#endif +#ifndef FollowKeyboardWin +#define FollowKeyboardWin ((WindowPtr) FollowKeyboard) +#endif +#ifndef RevertToFollowKeyboard +#define RevertToFollowKeyboard 3 +#endif + +typedef unsigned long Leds; +typedef struct _OtherClients *OtherClientsPtr; +typedef struct _InputClients *InputClientsPtr; +typedef struct _DeviceIntRec *DeviceIntPtr; +typedef struct _ClassesRec *ClassesPtr; +typedef struct _SpriteRec *SpritePtr; +typedef union _GrabMask GrabMask; + +typedef struct _EventList { + xEvent* event; + int evlen; /* length of allocated memory for event in bytes. This is not + the actual length of the event. The event's actual length is + 32 for standard events or 32 + + ((xGenericEvent*)event)->length * 4 for GenericEvents. + For events in the EQ, the length is + ((InternalEvent*)event)->u.any.length */ +} EventList, *EventListPtr; + +/* The DIX stores incoming input events in this list */ +extern EventListPtr InputEventList; +extern int InputEventListLen; + +typedef int (*DeviceProc)( + DeviceIntPtr /*device*/, + int /*what*/); + +typedef void (*ProcessInputProc)( + InternalEvent * /*event*/, + DeviceIntPtr /*device*/); + +typedef Bool (*DeviceHandleProc)( + DeviceIntPtr /*device*/, + void* /*data*/ + ); + +typedef void (*DeviceUnwrapProc)( + DeviceIntPtr /*device*/, + DeviceHandleProc /*proc*/, + void* /*data*/ + ); + +/* pointer acceleration handling */ +typedef void (*PointerAccelSchemeProc)( + DeviceIntPtr /*pDev*/, + int /*first_valuator*/, + int /*num_valuators*/, + int* /*valuators*/, + int /*evtime*/); + +typedef void (*DeviceCallbackProc)( + DeviceIntPtr /*pDev*/); + +typedef struct _DeviceRec { + pointer devicePrivate; + ProcessInputProc processInputProc; /* current */ + ProcessInputProc realInputProc; /* deliver */ + ProcessInputProc enqueueInputProc; /* enqueue */ + Bool on; /* used by DDX to keep state */ +} DeviceRec, *DevicePtr; + +typedef struct _ValuatorMask ValuatorMask; + +typedef struct { + int click, bell, bell_pitch, bell_duration; + Bool autoRepeat; + unsigned char autoRepeats[32]; + Leds leds; + unsigned char id; +} KeybdCtrl; + +typedef struct { + KeySym *map; + KeyCode minKeyCode, + maxKeyCode; + int mapWidth; +} KeySymsRec, *KeySymsPtr; + +typedef struct { + int num, den, threshold; + unsigned char id; +} PtrCtrl; + +typedef struct { + int resolution, min_value, max_value; + int integer_displayed; + unsigned char id; +} IntegerCtrl; + +typedef struct { + int max_symbols, num_symbols_supported; + int num_symbols_displayed; + KeySym *symbols_supported; + KeySym *symbols_displayed; + unsigned char id; +} StringCtrl; + +typedef struct { + int percent, pitch, duration; + unsigned char id; +} BellCtrl; + +typedef struct { + Leds led_values; + Mask led_mask; + unsigned char id; +} LedCtrl; + +extern _X_EXPORT KeybdCtrl defaultKeyboardControl; +extern _X_EXPORT PtrCtrl defaultPointerControl; + +typedef struct _InputOption { + char *key; + char *value; + struct _InputOption *next; +} InputOption; + +typedef struct _InputAttributes { + char *product; + char *vendor; + char *device; + char *pnp_id; + char *usb_id; + char **tags; /* null-terminated */ + uint32_t flags; +} InputAttributes; + +#define ATTR_KEYBOARD (1<<0) +#define ATTR_POINTER (1<<1) +#define ATTR_JOYSTICK (1<<2) +#define ATTR_TABLET (1<<3) +#define ATTR_TOUCHPAD (1<<4) +#define ATTR_TOUCHSCREEN (1<<5) + +/* Key/Button has been run through all input processing and events sent to clients. */ +#define KEY_PROCESSED 1 +#define BUTTON_PROCESSED 1 +/* Key/Button has not been fully processed, no events have been sent. */ +#define KEY_POSTED 2 +#define BUTTON_POSTED 2 + +extern void set_key_down(DeviceIntPtr pDev, int key_code, int type); +extern void set_key_up(DeviceIntPtr pDev, int key_code, int type); +extern int key_is_down(DeviceIntPtr pDev, int key_code, int type); +extern void set_button_down(DeviceIntPtr pDev, int button, int type); +extern void set_button_up(DeviceIntPtr pDev, int button, int type); +extern int button_is_down(DeviceIntPtr pDev, int button, int type); + +extern void InitCoreDevices(void); +extern void InitXTestDevices(void); + +extern _X_EXPORT DeviceIntPtr AddInputDevice( + ClientPtr /*client*/, + DeviceProc /*deviceProc*/, + Bool /*autoStart*/); + +extern _X_EXPORT Bool EnableDevice( + DeviceIntPtr /*device*/, + BOOL /* sendevent */); + +extern _X_EXPORT Bool ActivateDevice( + DeviceIntPtr /*device*/, + BOOL /* sendevent */); + +extern _X_EXPORT Bool DisableDevice( + DeviceIntPtr /*device*/, + BOOL /* sendevent */); + +extern int InitAndStartDevices(void); + +extern void CloseDownDevices(void); + +extern void UndisplayDevices(void); + +extern _X_EXPORT int RemoveDevice( + DeviceIntPtr /*dev*/, + BOOL /* sendevent */); + +extern _X_EXPORT int NumMotionEvents(void); + +extern _X_EXPORT int dixLookupDevice( + DeviceIntPtr * /* dev */, + int /* id */, + ClientPtr /* client */, + Mask /* access_mode */); + +extern _X_EXPORT void QueryMinMaxKeyCodes( + KeyCode* /*minCode*/, + KeyCode* /*maxCode*/); + +extern _X_EXPORT Bool SetKeySymsMap( + KeySymsPtr /*dst*/, + KeySymsPtr /*src*/); + +extern _X_EXPORT Bool InitButtonClassDeviceStruct( + DeviceIntPtr /*device*/, + int /*numButtons*/, + Atom* /* labels */, + CARD8* /*map*/); + +extern _X_EXPORT Bool InitValuatorClassDeviceStruct( + DeviceIntPtr /*device*/, + int /*numAxes*/, + Atom* /* labels */, + int /*numMotionEvents*/, + int /*mode*/); + +extern _X_EXPORT Bool InitPointerAccelerationScheme( + DeviceIntPtr /*dev*/, + int /*scheme*/); + +extern _X_EXPORT Bool InitAbsoluteClassDeviceStruct( + DeviceIntPtr /*device*/); + +extern _X_EXPORT Bool InitFocusClassDeviceStruct( + DeviceIntPtr /*device*/); + +typedef void (*BellProcPtr)( + int /*percent*/, + DeviceIntPtr /*device*/, + pointer /*ctrl*/, + int); + +typedef void (*KbdCtrlProcPtr)( + DeviceIntPtr /*device*/, + KeybdCtrl * /*ctrl*/); + +typedef void (*PtrCtrlProcPtr)( + DeviceIntPtr /*device*/, + PtrCtrl * /*ctrl*/); + +extern _X_EXPORT Bool InitPtrFeedbackClassDeviceStruct( + DeviceIntPtr /*device*/, + PtrCtrlProcPtr /*controlProc*/); + +typedef void (*StringCtrlProcPtr)( + DeviceIntPtr /*device*/, + StringCtrl * /*ctrl*/); + +extern _X_EXPORT Bool InitStringFeedbackClassDeviceStruct( + DeviceIntPtr /*device*/, + StringCtrlProcPtr /*controlProc*/, + int /*max_symbols*/, + int /*num_symbols_supported*/, + KeySym* /*symbols*/); + +typedef void (*BellCtrlProcPtr)( + DeviceIntPtr /*device*/, + BellCtrl * /*ctrl*/); + +extern _X_EXPORT Bool InitBellFeedbackClassDeviceStruct( + DeviceIntPtr /*device*/, + BellProcPtr /*bellProc*/, + BellCtrlProcPtr /*controlProc*/); + +typedef void (*LedCtrlProcPtr)( + DeviceIntPtr /*device*/, + LedCtrl * /*ctrl*/); + +extern _X_EXPORT Bool InitLedFeedbackClassDeviceStruct( + DeviceIntPtr /*device*/, + LedCtrlProcPtr /*controlProc*/); + +typedef void (*IntegerCtrlProcPtr)( + DeviceIntPtr /*device*/, + IntegerCtrl * /*ctrl*/); + + +extern _X_EXPORT Bool InitIntegerFeedbackClassDeviceStruct( + DeviceIntPtr /*device*/, + IntegerCtrlProcPtr /*controlProc*/); + +extern _X_EXPORT Bool InitPointerDeviceStruct( + DevicePtr /*device*/, + CARD8* /*map*/, + int /*numButtons*/, + Atom* /* btn_labels */, + PtrCtrlProcPtr /*controlProc*/, + int /*numMotionEvents*/, + int /*numAxes*/, + Atom* /* axes_labels */); + +extern _X_EXPORT Bool InitKeyboardDeviceStruct( + DeviceIntPtr /*device*/, + XkbRMLVOSet * /*rmlvo*/, + BellProcPtr /*bellProc*/, + KbdCtrlProcPtr /*controlProc*/); + +extern int ApplyPointerMapping( + DeviceIntPtr /* pDev */, + CARD8 * /* map */, + int /* len */, + ClientPtr /* client */); + +extern Bool BadDeviceMap( + BYTE* /*buff*/, + int /*length*/, + unsigned /*low*/, + unsigned /*high*/, + XID* /*errval*/); + +extern void NoteLedState( + DeviceIntPtr /*keybd*/, + int /*led*/, + Bool /*on*/); + +extern void MaybeStopHint( + DeviceIntPtr /*device*/, + ClientPtr /*client*/); + +extern void ProcessPointerEvent( + InternalEvent* /* ev */, + DeviceIntPtr /*mouse*/); + +extern void ProcessKeyboardEvent( + InternalEvent* /*ev*/, + DeviceIntPtr /*keybd*/); + +extern Bool LegalModifier( + unsigned int /*key*/, + DeviceIntPtr /*pDev*/); + +extern _X_EXPORT void ProcessInputEvents(void); + +extern _X_EXPORT void InitInput( + int /*argc*/, + char ** /*argv*/); +extern _X_EXPORT void CloseInput(void); + +extern _X_EXPORT int GetMaximumEventsNum(void); + +extern _X_EXPORT int GetEventList(EventListPtr* list); +extern _X_EXPORT EventListPtr InitEventList(int num_events); +extern _X_EXPORT void FreeEventList(EventListPtr list, int num_events); + +extern void CreateClassesChangedEvent(EventListPtr event, + DeviceIntPtr master, + DeviceIntPtr slave, + int type); +extern EventListPtr UpdateFromMaster( + EventListPtr events, + DeviceIntPtr pDev, + int type, + int *num_events); + +extern _X_EXPORT int GetPointerEvents( + EventListPtr events, + DeviceIntPtr pDev, + int type, + int buttons, + int flags, + const ValuatorMask *mask); + +extern _X_EXPORT int GetKeyboardEvents( + EventListPtr events, + DeviceIntPtr pDev, + int type, + int key_code); + +extern int GetKeyboardValuatorEvents( + EventListPtr events, + DeviceIntPtr pDev, + int type, + int key_code, + const ValuatorMask *mask); + +extern int GetProximityEvents( + EventListPtr events, + DeviceIntPtr pDev, + int type, + const ValuatorMask *mask); + +extern void PostSyntheticMotion( + DeviceIntPtr pDev, + int x, + int y, + int screen, + unsigned long time); + +extern _X_EXPORT int GetMotionHistorySize( + void); + +extern _X_EXPORT void AllocateMotionHistory( + DeviceIntPtr pDev); + +extern _X_EXPORT int GetMotionHistory( + DeviceIntPtr pDev, + xTimecoord **buff, + unsigned long start, + unsigned long stop, + ScreenPtr pScreen, + BOOL core); + +extern int AttachDevice(ClientPtr client, + DeviceIntPtr slave, + DeviceIntPtr master); + +extern _X_EXPORT DeviceIntPtr GetPairedDevice(DeviceIntPtr kbd); +extern DeviceIntPtr GetMaster(DeviceIntPtr dev, int type); + +extern _X_EXPORT int AllocDevicePair(ClientPtr client, + char* name, + DeviceIntPtr* ptr, + DeviceIntPtr* keybd, + DeviceProc ptr_proc, + DeviceProc keybd_proc, + Bool master); +extern void DeepCopyDeviceClasses(DeviceIntPtr from, + DeviceIntPtr to, + DeviceChangedEvent *dce); + +/* Helper functions. */ +extern _X_EXPORT int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, + KeyCode **modkeymap, int *max_keys_per_mod); +extern int change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *map, + int max_keys_per_mod); +extern int AllocXTestDevice(ClientPtr client, + char* name, + DeviceIntPtr* ptr, + DeviceIntPtr* keybd, + DeviceIntPtr master_ptr, + DeviceIntPtr master_keybd); +extern BOOL IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master); +extern DeviceIntPtr GetXTestDevice(DeviceIntPtr master); +extern void SendDevicePresenceEvent(int deviceid, int type); +extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs); +extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs); + +/* misc event helpers */ +extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients); +extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event); +extern Mask GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev); +void FixUpEventFromWindow(SpritePtr pSprite, + xEvent *xE, + WindowPtr pWin, + Window child, + Bool calcChild); +extern WindowPtr XYToWindow(SpritePtr pSprite, int x, int y); +extern int EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, + WindowPtr win); +/** + * Return masks for EventIsDeliverable. + * @defgroup EventIsDeliverable return flags + * @{ + */ +#define XI_MASK (1 << 0) /**< XI mask set on window */ +#define CORE_MASK (1 << 1) /**< Core mask set on window */ +#define DONT_PROPAGATE_MASK (1 << 2) /**< DontPropagate mask set on window */ +#define XI2_MASK (1 << 3) /**< XI2 mask set on window */ +/* @} */ + +/* Implemented by the DDX. */ +extern _X_EXPORT int NewInputDeviceRequest( + InputOption *options, + InputAttributes *attrs, + DeviceIntPtr *dev); +extern _X_EXPORT void DeleteInputDeviceRequest( + DeviceIntPtr dev); + +extern _X_EXPORT void DDXRingBell( + int volume, + int pitch, + int duration); + +#define VALUATOR_MODE_ALL_AXES -1 +extern _X_HIDDEN int valuator_get_mode(DeviceIntPtr dev, int axis); +extern _X_HIDDEN void valuator_set_mode(DeviceIntPtr dev, int axis, int mode); + +/* Set to TRUE by default - os/utils.c sets it to FALSE on user request, + xfixes/cursor.c uses it to determine if the cursor is enabled */ +extern Bool EnableCursor; + +extern _X_EXPORT ValuatorMask *valuator_mask_new(int num_valuators); +extern _X_EXPORT void valuator_mask_free(ValuatorMask **mask); +extern _X_EXPORT void valuator_mask_set_range(ValuatorMask *mask, + int first_valuator, int num_valuators, + const int* valuators); +extern _X_EXPORT void valuator_mask_set(ValuatorMask *mask, + int valuator, + int data); +extern _X_EXPORT void valuator_mask_zero(ValuatorMask *mask); +extern _X_EXPORT int valuator_mask_size(const ValuatorMask *mask); +extern _X_EXPORT int valuator_mask_isset(const ValuatorMask *mask, int bit); +extern _X_EXPORT void valuator_mask_unset(ValuatorMask *mask, int bit); +extern _X_EXPORT int valuator_mask_num_valuators(const ValuatorMask *mask); +extern _X_EXPORT void valuator_mask_copy(ValuatorMask *dest, + const ValuatorMask *src); +extern _X_EXPORT int valuator_mask_get(const ValuatorMask *mask, int valnum); + +#endif /* INPUT_H */ diff --git a/xorg-server/include/inputstr.h b/xorg-server/include/inputstr.h index 325d5934f..b74ee0454 100644 --- a/xorg-server/include/inputstr.h +++ b/xorg-server/include/inputstr.h @@ -1,615 +1,615 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL 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. - -********************************************************/ - - -#ifndef INPUTSTRUCT_H -#define INPUTSTRUCT_H - -#include -#include "input.h" -#include "window.h" -#include "dixstruct.h" -#include "cursorstr.h" -#include "geext.h" -#include "privates.h" - -#define BitIsOn(ptr, bit) (!!(((BYTE *) (ptr))[(bit)>>3] & (1 << ((bit) & 7)))) -#define SetBit(ptr, bit) (((BYTE *) (ptr))[(bit)>>3] |= (1 << ((bit) & 7))) -#define ClearBit(ptr, bit) (((BYTE *)(ptr))[(bit)>>3] &= ~(1 << ((bit) & 7))) -extern _X_EXPORT int CountBits(const uint8_t *mask, int len); - -#define SameClient(obj,client) \ - (CLIENT_BITS((obj)->resource) == (client)->clientAsMask) - -#define EMASKSIZE MAXDEVICES + 2 - -/* This is the last XI2 event supported by the server. If you add - * events to the protocol, the server will not support these events until - * this number here is bumped. - */ -#define XI2LASTEVENT 17 /* XI_RawMotion */ -#define XI2MASKSIZE ((XI2LASTEVENT + 7)/8) /* no of bits for masks */ - -/** - * This struct stores the core event mask for each client except the client - * that created the window. - * - * Each window that has events selected from other clients has at least one of - * these masks. If multiple clients selected for events on the same window, - * these masks are in a linked list. - * - * The event mask for the client that created the window is stored in - * win->eventMask instead. - * - * The resource id is simply a fake client ID to associate this mask with a - * client. - * - * Kludge: OtherClients and InputClients must be compatible, see code. - */ -typedef struct _OtherClients { - OtherClientsPtr next; /**< Pointer to the next mask */ - XID resource; /**< id for putting into resource manager */ - Mask mask; /**< Core event mask */ -} OtherClients; - -/** - * This struct stores the XI event mask for each client. - * - * Each window that has events selected has at least one of these masks. If - * multiple client selected for events on the same window, these masks are in - * a linked list. - */ -typedef struct _InputClients { - InputClientsPtr next; /**< Pointer to the next mask */ - XID resource; /**< id for putting into resource manager */ - Mask mask[EMASKSIZE]; /**< Actual XI event mask, deviceid is index */ - /** XI2 event masks. One per device, each bit is a mask of (1 << type) */ - unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; -} InputClients; - -/** - * Combined XI event masks from all devices. - * - * This is the XI equivalent of the deliverableEvents, eventMask and - * dontPropagate mask of the WindowRec (or WindowOptRec). - * - * A window that has an XI client selecting for events has exactly one - * OtherInputMasks struct and exactly one InputClients struct hanging off - * inputClients. Each further client appends to the inputClients list. - * Each Mask field is per-device, with the device id as the index. - * Exception: for non-device events (Presence events), the MAXDEVICES - * deviceid is used. - */ -typedef struct _OtherInputMasks { - /** - * Bitwise OR of all masks by all clients and the window's parent's masks. - */ - Mask deliverableEvents[EMASKSIZE]; - /** - * Bitwise OR of all masks by all clients on this window. - */ - Mask inputEvents[EMASKSIZE]; - /** The do-not-propagate masks for each device. */ - Mask dontPropagateMask[EMASKSIZE]; - /** The clients that selected for events */ - InputClientsPtr inputClients; - /* XI2 event masks. One per device, each bit is a mask of (1 << type) */ - unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; -} OtherInputMasks; - -/* - * The following structure gets used for both active and passive grabs. For - * active grabs some of the fields (e.g. modifiers) are not used. However, - * that is not much waste since there aren't many active grabs (one per - * keyboard/pointer device) going at once in the server. - */ - -#define MasksPerDetailMask 8 /* 256 keycodes and 256 possible - modifier combinations, but only - 3 buttons. */ - -typedef struct _DetailRec { /* Grab details may be bit masks */ - unsigned int exact; - Mask *pMask; -} DetailRec; - -typedef enum { - GRABTYPE_CORE, - GRABTYPE_XI, - GRABTYPE_XI2 -} GrabType; - -union _GrabMask { - Mask core; - Mask xi; - char xi2mask[EMASKSIZE][XI2MASKSIZE]; -}; - -/** - * Central struct for device grabs. - * The same struct is used for both core grabs and device grabs, with - * different fields being set. - * If the grab is a core grab (GrabPointer/GrabKeyboard), then the eventMask - * is a combination of standard event masks (i.e. PointerMotionMask | - * ButtonPressMask). - * If the grab is a device grab (GrabDevice), then the eventMask is a - * combination of event masks for a given XI event type (see SetEventInfo). - * - * If the grab is a result of a ButtonPress, then eventMask is the core mask - * and deviceMask is set to the XI event mask for the grab. - */ -typedef struct _GrabRec { - GrabPtr next; /* for chain of passive grabs */ - XID resource; - DeviceIntPtr device; - WindowPtr window; - unsigned ownerEvents:1; - unsigned keyboardMode:1; - unsigned pointerMode:1; - GrabType grabtype; - CARD8 type; /* event type */ - DetailRec modifiersDetail; - DeviceIntPtr modifierDevice; - DetailRec detail; /* key or button */ - WindowPtr confineTo; /* always NULL for keyboards */ - CursorPtr cursor; /* always NULL for keyboards */ - Mask eventMask; - Mask deviceMask; - /* XI2 event masks. One per device, each bit is a mask of (1 << type) */ - unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; -} GrabRec; - -typedef struct _KeyClassRec { - int sourceid; - CARD8 down[DOWN_LENGTH]; - CARD8 postdown[DOWN_LENGTH]; - int modifierKeyCount[8]; - struct _XkbSrvInfo *xkbInfo; -} KeyClassRec, *KeyClassPtr; - -typedef struct _AxisInfo { - int resolution; - int min_resolution; - int max_resolution; - int min_value; - int max_value; - Atom label; - CARD8 mode; -} AxisInfo, *AxisInfoPtr; - -typedef struct _ValuatorAccelerationRec { - int number; - PointerAccelSchemeProc AccelSchemeProc; - void *accelData; /* at disposal of AccelScheme */ - DeviceCallbackProc AccelCleanupProc; -} ValuatorAccelerationRec, *ValuatorAccelerationPtr; - -typedef struct _ValuatorClassRec { - int sourceid; - int numMotionEvents; - int first_motion; - int last_motion; - void *motion; /* motion history buffer. Different layout - for MDs and SDs!*/ - WindowPtr motionHintWindow; - - AxisInfoPtr axes; - unsigned short numAxes; - double *axisVal; /* always absolute, but device-coord system */ - ValuatorAccelerationRec accelScheme; -} ValuatorClassRec, *ValuatorClassPtr; - -typedef struct _ButtonClassRec { - int sourceid; - CARD8 numButtons; - CARD8 buttonsDown; /* number of buttons currently down - This counts logical buttons, not - physical ones, i.e if some buttons - are mapped to 0, they're not counted - here */ - unsigned short state; - Mask motionMask; - CARD8 down[DOWN_LENGTH]; - CARD8 postdown[DOWN_LENGTH]; - CARD8 map[MAP_LENGTH]; - union _XkbAction *xkb_acts; - Atom labels[MAX_BUTTONS]; -} ButtonClassRec, *ButtonClassPtr; - -typedef struct _FocusClassRec { - int sourceid; - WindowPtr win; /* May be set to a int constant (e.g. PointerRootWin)! */ - int revert; - TimeStamp time; - WindowPtr *trace; - int traceSize; - int traceGood; -} FocusClassRec, *FocusClassPtr; - -typedef struct _ProximityClassRec { - int sourceid; - char in_proximity; -} ProximityClassRec, *ProximityClassPtr; - -typedef struct _AbsoluteClassRec { - int sourceid; - /* Calibration. */ - int min_x; - int max_x; - int min_y; - int max_y; - int flip_x; - int flip_y; - int rotation; - int button_threshold; - - /* Area. */ - int offset_x; - int offset_y; - int width; - int height; - int screen; - XID following; -} AbsoluteClassRec, *AbsoluteClassPtr; - -typedef struct _KbdFeedbackClassRec *KbdFeedbackPtr; -typedef struct _PtrFeedbackClassRec *PtrFeedbackPtr; -typedef struct _IntegerFeedbackClassRec *IntegerFeedbackPtr; -typedef struct _StringFeedbackClassRec *StringFeedbackPtr; -typedef struct _BellFeedbackClassRec *BellFeedbackPtr; -typedef struct _LedFeedbackClassRec *LedFeedbackPtr; - -typedef struct _KbdFeedbackClassRec { - BellProcPtr BellProc; - KbdCtrlProcPtr CtrlProc; - KeybdCtrl ctrl; - KbdFeedbackPtr next; - struct _XkbSrvLedInfo *xkb_sli; -} KbdFeedbackClassRec; - -typedef struct _PtrFeedbackClassRec { - PtrCtrlProcPtr CtrlProc; - PtrCtrl ctrl; - PtrFeedbackPtr next; -} PtrFeedbackClassRec; - -typedef struct _IntegerFeedbackClassRec { - IntegerCtrlProcPtr CtrlProc; - IntegerCtrl ctrl; - IntegerFeedbackPtr next; -} IntegerFeedbackClassRec; - -typedef struct _StringFeedbackClassRec { - StringCtrlProcPtr CtrlProc; - StringCtrl ctrl; - StringFeedbackPtr next; -} StringFeedbackClassRec; - -typedef struct _BellFeedbackClassRec { - BellProcPtr BellProc; - BellCtrlProcPtr CtrlProc; - BellCtrl ctrl; - BellFeedbackPtr next; -} BellFeedbackClassRec; - -typedef struct _LedFeedbackClassRec { - LedCtrlProcPtr CtrlProc; - LedCtrl ctrl; - LedFeedbackPtr next; - struct _XkbSrvLedInfo *xkb_sli; -} LedFeedbackClassRec; - - -typedef struct _ClassesRec { - KeyClassPtr key; - ValuatorClassPtr valuator; - ButtonClassPtr button; - FocusClassPtr focus; - ProximityClassPtr proximity; - AbsoluteClassPtr absolute; - KbdFeedbackPtr kbdfeed; - PtrFeedbackPtr ptrfeed; - IntegerFeedbackPtr intfeed; - StringFeedbackPtr stringfeed; - BellFeedbackPtr bell; - LedFeedbackPtr leds; -} ClassesRec; - - -/** - * Sprite information for a device. - */ -typedef struct { - CursorPtr current; - BoxRec hotLimits; /* logical constraints of hot spot */ - Bool confined; /* confined to screen */ - RegionPtr hotShape; /* additional logical shape constraint */ - BoxRec physLimits; /* physical constraints of hot spot */ - WindowPtr win; /* window of logical position */ - HotSpot hot; /* logical pointer position */ - HotSpot hotPhys; /* physical pointer position */ -#ifdef PANORAMIX - ScreenPtr screen; /* all others are in Screen 0 coordinates */ - RegionRec Reg1; /* Region 1 for confining motion */ - RegionRec Reg2; /* Region 2 for confining virtual motion */ - WindowPtr windows[MAXSCREENS]; - WindowPtr confineWin; /* confine window */ -#endif - /* The window trace information is used at dix/events.c to avoid having - * to compute all the windows between the root and the current pointer - * window each time a button or key goes down. The grabs on each of those - * windows must be checked. - * spriteTraces should only be used at dix/events.c! */ - WindowPtr *spriteTrace; - int spriteTraceSize; - int spriteTraceGood; - - /* Due to delays between event generation and event processing, it is - * possible that the pointer has crossed screen boundaries between the - * time in which it begins generating events and the time when - * those events are processed. - * - * pEnqueueScreen: screen the pointer was on when the event was generated - * pDequeueScreen: screen the pointer was on when the event is processed - */ - ScreenPtr pEnqueueScreen; - ScreenPtr pDequeueScreen; - -} SpriteRec, *SpritePtr; - -/* Device properties */ -typedef struct _XIPropertyValue -{ - Atom type; /* ignored by server */ - short format; /* format of data for swapping - 8,16,32 */ - long size; /* size of data in (format/8) bytes */ - pointer data; /* private to client */ -} XIPropertyValueRec; - -typedef struct _XIProperty -{ - struct _XIProperty *next; - Atom propertyName; - BOOL deletable; /* clients can delete this prop? */ - XIPropertyValueRec value; -} XIPropertyRec; - -typedef XIPropertyRec *XIPropertyPtr; -typedef XIPropertyValueRec *XIPropertyValuePtr; - - -typedef struct _XIPropertyHandler -{ - struct _XIPropertyHandler* next; - long id; - int (*SetProperty) (DeviceIntPtr dev, - Atom property, - XIPropertyValuePtr prop, - BOOL checkonly); - int (*GetProperty) (DeviceIntPtr dev, - Atom property); - int (*DeleteProperty) (DeviceIntPtr dev, - Atom property); -} XIPropertyHandler, *XIPropertyHandlerPtr; - -/* states for devices */ - -#define NOT_GRABBED 0 -#define THAWED 1 -#define THAWED_BOTH 2 /* not a real state */ -#define FREEZE_NEXT_EVENT 3 -#define FREEZE_BOTH_NEXT_EVENT 4 -#define FROZEN 5 /* any state >= has device frozen */ -#define FROZEN_NO_EVENT 5 -#define FROZEN_WITH_EVENT 6 -#define THAW_OTHERS 7 - - -typedef struct _GrabInfoRec { - TimeStamp grabTime; - Bool fromPassiveGrab; /* true if from passive grab */ - Bool implicitGrab; /* implicit from ButtonPress */ - GrabRec activeGrab; - GrabPtr grab; - CARD8 activatingKey; - void (*ActivateGrab) ( - DeviceIntPtr /*device*/, - GrabPtr /*grab*/, - TimeStamp /*time*/, - Bool /*autoGrab*/); - void (*DeactivateGrab)( - DeviceIntPtr /*device*/); - struct { - Bool frozen; - int state; - GrabPtr other; /* if other grab has this frozen */ - DeviceEvent *event; /* saved to be replayed */ - } sync; -} GrabInfoRec, *GrabInfoPtr; - -typedef struct _SpriteInfoRec { - /* sprite must always point to a valid sprite. For devices sharing the - * sprite, let sprite point to a paired spriteOwner's sprite. */ - SpritePtr sprite; /* sprite information */ - Bool spriteOwner; /* True if device owns the sprite */ - DeviceIntPtr paired; /* The paired device. Keyboard if - spriteOwner is TRUE, otherwise the - pointer that owns the sprite. */ - - /* keep states for animated cursor */ - struct { - CursorPtr pCursor; - ScreenPtr pScreen; - int elt; - CARD32 time; - } anim; -} SpriteInfoRec, *SpriteInfoPtr; - -/* device types */ -#define MASTER_POINTER 1 -#define MASTER_KEYBOARD 2 -#define SLAVE 3 - -typedef struct _DeviceIntRec { - DeviceRec public; - DeviceIntPtr next; - Bool startup; /* true if needs to be turned on at - server intialization time */ - DeviceProc deviceProc; /* proc(DevicePtr, DEVICE_xx). It is - used to initialize, turn on, or - turn off the device */ - Bool inited; /* TRUE if INIT returns Success */ - Bool enabled; /* TRUE if ON returns Success */ - Bool coreEvents; /* TRUE if device also sends core */ - GrabInfoRec deviceGrab; /* grab on the device */ - int type; /* MASTER_POINTER, MASTER_KEYBOARD, SLAVE */ - Atom xinput_type; - char *name; - int id; - KeyClassPtr key; - ValuatorClassPtr valuator; - ButtonClassPtr button; - FocusClassPtr focus; - ProximityClassPtr proximity; - AbsoluteClassPtr absolute; - KbdFeedbackPtr kbdfeed; - PtrFeedbackPtr ptrfeed; - IntegerFeedbackPtr intfeed; - StringFeedbackPtr stringfeed; - BellFeedbackPtr bell; - LedFeedbackPtr leds; - struct _XkbInterest *xkb_interest; - char *config_info; /* used by the hotplug layer */ - ClassesPtr unused_classes; /* for master devices */ - int saved_master_id; /* for slaves while grabbed */ - PrivateRec *devPrivates; - DeviceUnwrapProc unwrapProc; - SpriteInfoPtr spriteInfo; - union { - DeviceIntPtr master; /* master device */ - DeviceIntPtr lastSlave; /* last slave device used */ - } u; - - /* last valuator values recorded, not posted to client; - * for slave devices, valuators is in device coordinates - * for master devices, valuators is in screen coordinates - * see dix/getevents.c - * remainder supports acceleration - */ - struct { - int valuators[MAX_VALUATORS]; - float remainder[MAX_VALUATORS]; - int numValuators; - DeviceIntPtr slave; - } last; - - /* Input device property handling. */ - struct { - XIPropertyPtr properties; - XIPropertyHandlerPtr handlers; /* NULL-terminated */ - } properties; - - /* coordinate transformation matrix for absolute input devices */ - struct pixman_f_transform transform; - - /* XTest related master device id */ - int xtest_master_id; -} DeviceIntRec; - -typedef struct { - int numDevices; /* total number of devices */ - DeviceIntPtr devices; /* all devices turned on */ - DeviceIntPtr off_devices; /* all devices turned off */ - DeviceIntPtr keyboard; /* the main one for the server */ - DeviceIntPtr pointer; - DeviceIntPtr all_devices; - DeviceIntPtr all_master_devices; -} InputInfo; - -extern _X_EXPORT InputInfo inputInfo; - -/* for keeping the events for devices grabbed synchronously */ -typedef struct _QdEvent *QdEventPtr; -typedef struct _QdEvent { - QdEventPtr next; - DeviceIntPtr device; - ScreenPtr pScreen; /* what screen the pointer was on */ - unsigned long months; /* milliseconds is in the event */ - InternalEvent *event; -} QdEventRec; - -/** - * syncEvents is the global structure for queued events. - * - * Devices can be frozen through GrabModeSync pointer grabs. If this is the - * case, events from these devices are added to "pending" instead of being - * processed normally. When the device is unfrozen, events in "pending" are - * replayed and processed as if they would come from the device directly. - */ -typedef struct _EventSyncInfo { - QdEventPtr pending, /**< list of queued events */ - *pendtail; /**< last event in list */ - /** The device to replay events for. Only set in AllowEvents(), in which - * case it is set to the device specified in the request. */ - DeviceIntPtr replayDev; /* kludgy rock to put flag for */ - - /** - * The window the events are supposed to be replayed on. - * This window may be set to the grab's window (but only when - * Replay{Pointer|Keyboard} is given in the XAllowEvents() - * request. */ - WindowPtr replayWin; /* ComputeFreezes */ - /** - * Flag to indicate whether we're in the process of - * replaying events. Only set in ComputeFreezes(). */ - Bool playingEvents; - TimeStamp time; -} EventSyncInfoRec, *EventSyncInfoPtr; - -extern EventSyncInfoRec syncEvents; - -#endif /* INPUTSTRUCT_H */ +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +********************************************************/ + + +#ifndef INPUTSTRUCT_H +#define INPUTSTRUCT_H + +#include +#include "input.h" +#include "window.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "geext.h" +#include "privates.h" + +#define BitIsOn(ptr, bit) (!!(((BYTE *) (ptr))[(bit)>>3] & (1 << ((bit) & 7)))) +#define SetBit(ptr, bit) (((BYTE *) (ptr))[(bit)>>3] |= (1 << ((bit) & 7))) +#define ClearBit(ptr, bit) (((BYTE *)(ptr))[(bit)>>3] &= ~(1 << ((bit) & 7))) +extern _X_EXPORT int CountBits(const uint8_t *mask, int len); + +#define SameClient(obj,client) \ + (CLIENT_BITS((obj)->resource) == (client)->clientAsMask) + +#define EMASKSIZE MAXDEVICES + 2 + +/* This is the last XI2 event supported by the server. If you add + * events to the protocol, the server will not support these events until + * this number here is bumped. + */ +#define XI2LASTEVENT 17 /* XI_RawMotion */ +#define XI2MASKSIZE ((XI2LASTEVENT + 7)/8) /* no of bits for masks */ + +/** + * This struct stores the core event mask for each client except the client + * that created the window. + * + * Each window that has events selected from other clients has at least one of + * these masks. If multiple clients selected for events on the same window, + * these masks are in a linked list. + * + * The event mask for the client that created the window is stored in + * win->eventMask instead. + * + * The resource id is simply a fake client ID to associate this mask with a + * client. + * + * Kludge: OtherClients and InputClients must be compatible, see code. + */ +typedef struct _OtherClients { + OtherClientsPtr next; /**< Pointer to the next mask */ + XID resource; /**< id for putting into resource manager */ + Mask mask; /**< Core event mask */ +} OtherClients; + +/** + * This struct stores the XI event mask for each client. + * + * Each window that has events selected has at least one of these masks. If + * multiple client selected for events on the same window, these masks are in + * a linked list. + */ +typedef struct _InputClients { + InputClientsPtr next; /**< Pointer to the next mask */ + XID resource; /**< id for putting into resource manager */ + Mask mask[EMASKSIZE]; /**< Actual XI event mask, deviceid is index */ + /** XI2 event masks. One per device, each bit is a mask of (1 << type) */ + unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; +} InputClients; + +/** + * Combined XI event masks from all devices. + * + * This is the XI equivalent of the deliverableEvents, eventMask and + * dontPropagate mask of the WindowRec (or WindowOptRec). + * + * A window that has an XI client selecting for events has exactly one + * OtherInputMasks struct and exactly one InputClients struct hanging off + * inputClients. Each further client appends to the inputClients list. + * Each Mask field is per-device, with the device id as the index. + * Exception: for non-device events (Presence events), the MAXDEVICES + * deviceid is used. + */ +typedef struct _OtherInputMasks { + /** + * Bitwise OR of all masks by all clients and the window's parent's masks. + */ + Mask deliverableEvents[EMASKSIZE]; + /** + * Bitwise OR of all masks by all clients on this window. + */ + Mask inputEvents[EMASKSIZE]; + /** The do-not-propagate masks for each device. */ + Mask dontPropagateMask[EMASKSIZE]; + /** The clients that selected for events */ + InputClientsPtr inputClients; + /* XI2 event masks. One per device, each bit is a mask of (1 << type) */ + unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; +} OtherInputMasks; + +/* + * The following structure gets used for both active and passive grabs. For + * active grabs some of the fields (e.g. modifiers) are not used. However, + * that is not much waste since there aren't many active grabs (one per + * keyboard/pointer device) going at once in the server. + */ + +#define MasksPerDetailMask 8 /* 256 keycodes and 256 possible + modifier combinations, but only + 3 buttons. */ + +typedef struct _DetailRec { /* Grab details may be bit masks */ + unsigned int exact; + Mask *pMask; +} DetailRec; + +typedef enum { + GRABTYPE_CORE, + GRABTYPE_XI, + GRABTYPE_XI2 +} GrabType; + +union _GrabMask { + Mask core; + Mask xi; + char xi2mask[EMASKSIZE][XI2MASKSIZE]; +}; + +/** + * Central struct for device grabs. + * The same struct is used for both core grabs and device grabs, with + * different fields being set. + * If the grab is a core grab (GrabPointer/GrabKeyboard), then the eventMask + * is a combination of standard event masks (i.e. PointerMotionMask | + * ButtonPressMask). + * If the grab is a device grab (GrabDevice), then the eventMask is a + * combination of event masks for a given XI event type (see SetEventInfo). + * + * If the grab is a result of a ButtonPress, then eventMask is the core mask + * and deviceMask is set to the XI event mask for the grab. + */ +typedef struct _GrabRec { + GrabPtr next; /* for chain of passive grabs */ + XID resource; + DeviceIntPtr device; + WindowPtr window; + unsigned ownerEvents:1; + unsigned keyboardMode:1; + unsigned pointerMode:1; + GrabType grabtype; + CARD8 type; /* event type */ + DetailRec modifiersDetail; + DeviceIntPtr modifierDevice; + DetailRec detail; /* key or button */ + WindowPtr confineTo; /* always NULL for keyboards */ + CursorPtr cursor; /* always NULL for keyboards */ + Mask eventMask; + Mask deviceMask; + /* XI2 event masks. One per device, each bit is a mask of (1 << type) */ + unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; +} GrabRec; + +/** + * Sprite information for a device. + */ +typedef struct _SpriteRec { + CursorPtr current; + BoxRec hotLimits; /* logical constraints of hot spot */ + Bool confined; /* confined to screen */ + RegionPtr hotShape; /* additional logical shape constraint */ + BoxRec physLimits; /* physical constraints of hot spot */ + WindowPtr win; /* window of logical position */ + HotSpot hot; /* logical pointer position */ + HotSpot hotPhys; /* physical pointer position */ +#ifdef PANORAMIX + ScreenPtr screen; /* all others are in Screen 0 coordinates */ + RegionRec Reg1; /* Region 1 for confining motion */ + RegionRec Reg2; /* Region 2 for confining virtual motion */ + WindowPtr windows[MAXSCREENS]; + WindowPtr confineWin; /* confine window */ +#endif + /* The window trace information is used at dix/events.c to avoid having + * to compute all the windows between the root and the current pointer + * window each time a button or key goes down. The grabs on each of those + * windows must be checked. + * spriteTraces should only be used at dix/events.c! */ + WindowPtr *spriteTrace; + int spriteTraceSize; + int spriteTraceGood; + + /* Due to delays between event generation and event processing, it is + * possible that the pointer has crossed screen boundaries between the + * time in which it begins generating events and the time when + * those events are processed. + * + * pEnqueueScreen: screen the pointer was on when the event was generated + * pDequeueScreen: screen the pointer was on when the event is processed + */ + ScreenPtr pEnqueueScreen; + ScreenPtr pDequeueScreen; + +} SpriteRec; + +typedef struct _KeyClassRec { + int sourceid; + CARD8 down[DOWN_LENGTH]; + CARD8 postdown[DOWN_LENGTH]; + int modifierKeyCount[8]; + struct _XkbSrvInfo *xkbInfo; +} KeyClassRec, *KeyClassPtr; + +typedef struct _AxisInfo { + int resolution; + int min_resolution; + int max_resolution; + int min_value; + int max_value; + Atom label; + CARD8 mode; +} AxisInfo, *AxisInfoPtr; + +typedef struct _ValuatorAccelerationRec { + int number; + PointerAccelSchemeProc AccelSchemeProc; + void *accelData; /* at disposal of AccelScheme */ + DeviceCallbackProc AccelCleanupProc; +} ValuatorAccelerationRec, *ValuatorAccelerationPtr; + +typedef struct _ValuatorClassRec { + int sourceid; + int numMotionEvents; + int first_motion; + int last_motion; + void *motion; /* motion history buffer. Different layout + for MDs and SDs!*/ + WindowPtr motionHintWindow; + + AxisInfoPtr axes; + unsigned short numAxes; + double *axisVal; /* always absolute, but device-coord system */ + ValuatorAccelerationRec accelScheme; +} ValuatorClassRec, *ValuatorClassPtr; + +typedef struct _ButtonClassRec { + int sourceid; + CARD8 numButtons; + CARD8 buttonsDown; /* number of buttons currently down + This counts logical buttons, not + physical ones, i.e if some buttons + are mapped to 0, they're not counted + here */ + unsigned short state; + Mask motionMask; + CARD8 down[DOWN_LENGTH]; + CARD8 postdown[DOWN_LENGTH]; + CARD8 map[MAP_LENGTH]; + union _XkbAction *xkb_acts; + Atom labels[MAX_BUTTONS]; +} ButtonClassRec, *ButtonClassPtr; + +typedef struct _FocusClassRec { + int sourceid; + WindowPtr win; /* May be set to a int constant (e.g. PointerRootWin)! */ + int revert; + TimeStamp time; + WindowPtr *trace; + int traceSize; + int traceGood; +} FocusClassRec, *FocusClassPtr; + +typedef struct _ProximityClassRec { + int sourceid; + char in_proximity; +} ProximityClassRec, *ProximityClassPtr; + +typedef struct _AbsoluteClassRec { + int sourceid; + /* Calibration. */ + int min_x; + int max_x; + int min_y; + int max_y; + int flip_x; + int flip_y; + int rotation; + int button_threshold; + + /* Area. */ + int offset_x; + int offset_y; + int width; + int height; + int screen; + XID following; +} AbsoluteClassRec, *AbsoluteClassPtr; + +typedef struct _KbdFeedbackClassRec *KbdFeedbackPtr; +typedef struct _PtrFeedbackClassRec *PtrFeedbackPtr; +typedef struct _IntegerFeedbackClassRec *IntegerFeedbackPtr; +typedef struct _StringFeedbackClassRec *StringFeedbackPtr; +typedef struct _BellFeedbackClassRec *BellFeedbackPtr; +typedef struct _LedFeedbackClassRec *LedFeedbackPtr; + +typedef struct _KbdFeedbackClassRec { + BellProcPtr BellProc; + KbdCtrlProcPtr CtrlProc; + KeybdCtrl ctrl; + KbdFeedbackPtr next; + struct _XkbSrvLedInfo *xkb_sli; +} KbdFeedbackClassRec; + +typedef struct _PtrFeedbackClassRec { + PtrCtrlProcPtr CtrlProc; + PtrCtrl ctrl; + PtrFeedbackPtr next; +} PtrFeedbackClassRec; + +typedef struct _IntegerFeedbackClassRec { + IntegerCtrlProcPtr CtrlProc; + IntegerCtrl ctrl; + IntegerFeedbackPtr next; +} IntegerFeedbackClassRec; + +typedef struct _StringFeedbackClassRec { + StringCtrlProcPtr CtrlProc; + StringCtrl ctrl; + StringFeedbackPtr next; +} StringFeedbackClassRec; + +typedef struct _BellFeedbackClassRec { + BellProcPtr BellProc; + BellCtrlProcPtr CtrlProc; + BellCtrl ctrl; + BellFeedbackPtr next; +} BellFeedbackClassRec; + +typedef struct _LedFeedbackClassRec { + LedCtrlProcPtr CtrlProc; + LedCtrl ctrl; + LedFeedbackPtr next; + struct _XkbSrvLedInfo *xkb_sli; +} LedFeedbackClassRec; + + +typedef struct _ClassesRec { + KeyClassPtr key; + ValuatorClassPtr valuator; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; + AbsoluteClassPtr absolute; + KbdFeedbackPtr kbdfeed; + PtrFeedbackPtr ptrfeed; + IntegerFeedbackPtr intfeed; + StringFeedbackPtr stringfeed; + BellFeedbackPtr bell; + LedFeedbackPtr leds; +} ClassesRec; + + +/* Device properties */ +typedef struct _XIPropertyValue +{ + Atom type; /* ignored by server */ + short format; /* format of data for swapping - 8,16,32 */ + long size; /* size of data in (format/8) bytes */ + pointer data; /* private to client */ +} XIPropertyValueRec; + +typedef struct _XIProperty +{ + struct _XIProperty *next; + Atom propertyName; + BOOL deletable; /* clients can delete this prop? */ + XIPropertyValueRec value; +} XIPropertyRec; + +typedef XIPropertyRec *XIPropertyPtr; +typedef XIPropertyValueRec *XIPropertyValuePtr; + + +typedef struct _XIPropertyHandler +{ + struct _XIPropertyHandler* next; + long id; + int (*SetProperty) (DeviceIntPtr dev, + Atom property, + XIPropertyValuePtr prop, + BOOL checkonly); + int (*GetProperty) (DeviceIntPtr dev, + Atom property); + int (*DeleteProperty) (DeviceIntPtr dev, + Atom property); +} XIPropertyHandler, *XIPropertyHandlerPtr; + +/* states for devices */ + +#define NOT_GRABBED 0 +#define THAWED 1 +#define THAWED_BOTH 2 /* not a real state */ +#define FREEZE_NEXT_EVENT 3 +#define FREEZE_BOTH_NEXT_EVENT 4 +#define FROZEN 5 /* any state >= has device frozen */ +#define FROZEN_NO_EVENT 5 +#define FROZEN_WITH_EVENT 6 +#define THAW_OTHERS 7 + + +typedef struct _GrabInfoRec { + TimeStamp grabTime; + Bool fromPassiveGrab; /* true if from passive grab */ + Bool implicitGrab; /* implicit from ButtonPress */ + GrabRec activeGrab; + GrabPtr grab; + CARD8 activatingKey; + void (*ActivateGrab) ( + DeviceIntPtr /*device*/, + GrabPtr /*grab*/, + TimeStamp /*time*/, + Bool /*autoGrab*/); + void (*DeactivateGrab)( + DeviceIntPtr /*device*/); + struct { + Bool frozen; + int state; + GrabPtr other; /* if other grab has this frozen */ + DeviceEvent *event; /* saved to be replayed */ + } sync; +} GrabInfoRec, *GrabInfoPtr; + +typedef struct _SpriteInfoRec { + /* sprite must always point to a valid sprite. For devices sharing the + * sprite, let sprite point to a paired spriteOwner's sprite. */ + SpritePtr sprite; /* sprite information */ + Bool spriteOwner; /* True if device owns the sprite */ + DeviceIntPtr paired; /* The paired device. Keyboard if + spriteOwner is TRUE, otherwise the + pointer that owns the sprite. */ + + /* keep states for animated cursor */ + struct { + CursorPtr pCursor; + ScreenPtr pScreen; + int elt; + CARD32 time; + } anim; +} SpriteInfoRec, *SpriteInfoPtr; + +/* device types */ +#define MASTER_POINTER 1 +#define MASTER_KEYBOARD 2 +#define SLAVE 3 + +typedef struct _DeviceIntRec { + DeviceRec public; + DeviceIntPtr next; + Bool startup; /* true if needs to be turned on at + server intialization time */ + DeviceProc deviceProc; /* proc(DevicePtr, DEVICE_xx). It is + used to initialize, turn on, or + turn off the device */ + Bool inited; /* TRUE if INIT returns Success */ + Bool enabled; /* TRUE if ON returns Success */ + Bool coreEvents; /* TRUE if device also sends core */ + GrabInfoRec deviceGrab; /* grab on the device */ + int type; /* MASTER_POINTER, MASTER_KEYBOARD, SLAVE */ + Atom xinput_type; + char *name; + int id; + KeyClassPtr key; + ValuatorClassPtr valuator; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; + AbsoluteClassPtr absolute; + KbdFeedbackPtr kbdfeed; + PtrFeedbackPtr ptrfeed; + IntegerFeedbackPtr intfeed; + StringFeedbackPtr stringfeed; + BellFeedbackPtr bell; + LedFeedbackPtr leds; + struct _XkbInterest *xkb_interest; + char *config_info; /* used by the hotplug layer */ + ClassesPtr unused_classes; /* for master devices */ + int saved_master_id; /* for slaves while grabbed */ + PrivateRec *devPrivates; + DeviceUnwrapProc unwrapProc; + SpriteInfoPtr spriteInfo; + union { + DeviceIntPtr master; /* master device */ + DeviceIntPtr lastSlave; /* last slave device used */ + } u; + + /* last valuator values recorded, not posted to client; + * for slave devices, valuators is in device coordinates + * for master devices, valuators is in screen coordinates + * see dix/getevents.c + * remainder supports acceleration + */ + struct { + int valuators[MAX_VALUATORS]; + float remainder[MAX_VALUATORS]; + int numValuators; + DeviceIntPtr slave; + } last; + + /* Input device property handling. */ + struct { + XIPropertyPtr properties; + XIPropertyHandlerPtr handlers; /* NULL-terminated */ + } properties; + + /* coordinate transformation matrix for absolute input devices */ + struct pixman_f_transform transform; + + /* XTest related master device id */ + int xtest_master_id; +} DeviceIntRec; + +typedef struct { + int numDevices; /* total number of devices */ + DeviceIntPtr devices; /* all devices turned on */ + DeviceIntPtr off_devices; /* all devices turned off */ + DeviceIntPtr keyboard; /* the main one for the server */ + DeviceIntPtr pointer; + DeviceIntPtr all_devices; + DeviceIntPtr all_master_devices; +} InputInfo; + +extern _X_EXPORT InputInfo inputInfo; + +/* for keeping the events for devices grabbed synchronously */ +typedef struct _QdEvent *QdEventPtr; +typedef struct _QdEvent { + QdEventPtr next; + DeviceIntPtr device; + ScreenPtr pScreen; /* what screen the pointer was on */ + unsigned long months; /* milliseconds is in the event */ + InternalEvent *event; +} QdEventRec; + +/** + * syncEvents is the global structure for queued events. + * + * Devices can be frozen through GrabModeSync pointer grabs. If this is the + * case, events from these devices are added to "pending" instead of being + * processed normally. When the device is unfrozen, events in "pending" are + * replayed and processed as if they would come from the device directly. + */ +typedef struct _EventSyncInfo { + QdEventPtr pending, /**< list of queued events */ + *pendtail; /**< last event in list */ + /** The device to replay events for. Only set in AllowEvents(), in which + * case it is set to the device specified in the request. */ + DeviceIntPtr replayDev; /* kludgy rock to put flag for */ + + /** + * The window the events are supposed to be replayed on. + * This window may be set to the grab's window (but only when + * Replay{Pointer|Keyboard} is given in the XAllowEvents() + * request. */ + WindowPtr replayWin; /* ComputeFreezes */ + /** + * Flag to indicate whether we're in the process of + * replaying events. Only set in ComputeFreezes(). */ + Bool playingEvents; + TimeStamp time; +} EventSyncInfoRec, *EventSyncInfoPtr; + +extern EventSyncInfoRec syncEvents; + +#endif /* INPUTSTRUCT_H */ diff --git a/xorg-server/mi/miinitext.c b/xorg-server/mi/miinitext.c index a7441c9a8..4499f377c 100644 --- a/xorg-server/mi/miinitext.c +++ b/xorg-server/mi/miinitext.c @@ -389,9 +389,7 @@ InitExtensions(int argc, char *argv[]) if (!noGEExtension) GEExtensionInit(); #ifdef PANORAMIX -# if !defined(NO_PANORAMIX) if (!noPanoramiXExtension) PanoramiXExtensionInit(); -# endif #endif #ifdef INXQUARTZ if(!noPseudoramiXExtension) PseudoramiXExtensionInit(); diff --git a/xorg-server/os/WaitFor.c b/xorg-server/os/WaitFor.c index ac4b58e48..867cb04b8 100644 --- a/xorg-server/os/WaitFor.c +++ b/xorg-server/os/WaitFor.c @@ -1,681 +1,687 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -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. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -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 Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL 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. - -******************************************************************/ - - -/***************************************************************** - * OS Dependent input routines: - * - * WaitForSomething - * TimerForce, TimerSet, TimerCheck, TimerFree - * - *****************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#ifdef WIN32 -#include -#endif -#include /* for strings, fcntl, time */ -#include -#include -#include -#include "misc.h" - -#include "osdep.h" -#include -#include "dixstruct.h" -#include "opaque.h" -#ifdef DPMSExtension -#include "dpmsproc.h" -#endif - -#ifdef WIN32 -/* Error codes from windows sockets differ from fileio error codes */ -#undef EINTR -#define EINTR WSAEINTR -#undef EINVAL -#define EINVAL WSAEINVAL -#undef EBADF -#define EBADF WSAENOTSOCK -/* Windows select does not set errno. Use GetErrno as wrapper for - WSAGetLastError */ -#define GetErrno WSAGetLastError -#else -/* This is just a fallback to errno to hide the differences between unix and - Windows in the code */ -#define GetErrno() errno -#endif - -/* like ffs, but uses fd_mask instead of int as argument, so it works - when fd_mask is longer than an int, such as common 64-bit platforms */ -/* modifications by raphael */ -int -mffs(fd_mask mask) -{ - int i; - - if (!mask) return 0; - i = 1; - while (!(mask & 1)) - { - i++; - mask >>= 1; - } - return i; -} - -#ifdef DPMSExtension -#include -#endif - -struct _OsTimerRec { - OsTimerPtr next; - CARD32 expires; - CARD32 delta; - OsTimerCallback callback; - pointer arg; -}; - -static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); -static void CheckAllTimers(void); -static OsTimerPtr timers = NULL; - -/***************** - * WaitForSomething: - * Make the server suspend until there is - * 1. data from clients or - * 2. input events available or - * 3. ddx notices something of interest (graphics - * queue ready, etc.) or - * 4. clients that have buffered replies/events are ready - * - * If the time between INPUT events is - * greater than ScreenSaverTime, the display is turned off (or - * saved, depending on the hardware). So, WaitForSomething() - * has to handle this also (that's why the select() has a timeout. - * For more info on ClientsWithInput, see ReadRequestFromClient(). - * pClientsReady is an array to store ready client->index values into. - *****************/ - -int -WaitForSomething(int *pClientsReady) -{ - int i; - struct timeval waittime, *wt; - INT32 timeout = 0; - fd_set clientsReadable; - fd_set clientsWritable; - int curclient; - int selecterr; - int nready; - fd_set devicesReadable; - CARD32 now = 0; - Bool someReady = FALSE; - - FD_ZERO(&clientsReadable); - - /* We need a while loop here to handle - crashed connections and the screen saver timeout */ - while (1) - { - /* deal with any blocked jobs */ - if (workQueue) - ProcessWorkQueue(); - if (XFD_ANYSET (&ClientsWithInput)) - { - if (!SmartScheduleDisable) - { - someReady = TRUE; - waittime.tv_sec = 0; - waittime.tv_usec = 0; - wt = &waittime; - } - else - { - XFD_COPYSET (&ClientsWithInput, &clientsReadable); - break; - } - } - if (someReady) - { - XFD_COPYSET(&AllSockets, &LastSelectMask); - XFD_UNSET(&LastSelectMask, &ClientsWithInput); - } - else - { - wt = NULL; - if (timers) - { - now = GetTimeInMillis(); - timeout = timers->expires - now; - if (timeout > 0 && timeout > timers->delta + 250) { - /* time has rewound. reset the timers. */ - CheckAllTimers(); - } - - if (timers) { - timeout = timers->expires - now; - if (timeout < 0) - timeout = 0; - waittime.tv_sec = timeout / MILLI_PER_SECOND; - waittime.tv_usec = (timeout % MILLI_PER_SECOND) * - (1000000 / MILLI_PER_SECOND); - wt = &waittime; - } - } - XFD_COPYSET(&AllSockets, &LastSelectMask); - } - SmartScheduleStopTimer (); - - BlockHandler((pointer)&wt, (pointer)&LastSelectMask); - if (NewOutputPending) - FlushAllOutput(); - /* keep this check close to select() call to minimize race */ - if (dispatchException) - i = -1; - else if (AnyClientsWriteBlocked) - { - XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); - i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); - } - else - { - i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); - } - selecterr = GetErrno(); - WakeupHandler(i, (pointer)&LastSelectMask); - SmartScheduleStartTimer (); - if (i <= 0) /* An error or timeout occurred */ - { - if (dispatchException) - return 0; - if (i < 0) - { - if (selecterr == EBADF) /* Some client disconnected */ - { - CheckConnections (); - if (! XFD_ANYSET (&AllClients)) - return 0; - } - else if (selecterr == EINVAL) - { - FatalError("WaitForSomething(): select: %s\n", - strerror(selecterr)); - } - else if (selecterr != EINTR && selecterr != EAGAIN) - { - ErrorF("WaitForSomething(): select: %s\n", - strerror(selecterr)); - } - } - else if (someReady) - { - /* - * If no-one else is home, bail quickly - */ - XFD_COPYSET(&ClientsWithInput, &LastSelectMask); - XFD_COPYSET(&ClientsWithInput, &clientsReadable); - break; - } - if (*checkForInput[0] != *checkForInput[1]) - return 0; - - if (timers) - { - int expired = 0; - now = GetTimeInMillis(); - if ((int) (timers->expires - now) <= 0) - expired = 1; - - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); - - if (expired) - return 0; - } - } - else - { - fd_set tmp_set; - - if (*checkForInput[0] == *checkForInput[1]) { - if (timers) - { - int expired = 0; - now = GetTimeInMillis(); - if ((int) (timers->expires - now) <= 0) - expired = 1; - - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); - - if (expired) - return 0; - } - } - if (someReady) - XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); - if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) - { - NewOutputPending = TRUE; - XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); - XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); - if (! XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = FALSE; - } - - XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); - XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); - XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); - if (XFD_ANYSET(&tmp_set)) - QueueWorkProc(EstablishNewConnections, NULL, - (pointer)&LastSelectMask); - - if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) - break; - /* check here for DDXes that queue events during Block/Wakeup */ - if (*checkForInput[0] != *checkForInput[1]) - return 0; - } - } - - nready = 0; - if (XFD_ANYSET (&clientsReadable)) - { -#ifndef WIN32 - for (i=0; ipriority; - if (nready == 0 || client_priority > highest_priority) - { - /* Either we found the first client, or we found - * a client whose priority is greater than all others - * that have been found so far. Either way, we want - * to initialize the list of clients to contain just - * this client. - */ - pClientsReady[0] = client_index; - highest_priority = client_priority; - nready = 1; - } - /* the following if makes sure that multiple same-priority - * clients get batched together - */ - else if (client_priority == highest_priority) - { - pClientsReady[nready++] = client_index; - } -#ifndef WIN32 - clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); - } -#else - FD_CLR(curclient, &clientsReadable); -#endif - } - } - return nready; -} - -/* If time has rewound, re-run every affected timer. - * Timers might drop out of the list, so we have to restart every time. */ -static void -CheckAllTimers(void) -{ - OsTimerPtr timer; - CARD32 now; - -start: - now = GetTimeInMillis(); - - for (timer = timers; timer; timer = timer->next) { - if (timer->expires - now > timer->delta + 250) { - TimerForce(timer); - goto start; - } - } -} - -static void -DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) -{ - CARD32 newTime; - - *prev = timer->next; - timer->next = NULL; - newTime = (*timer->callback)(timer, now, timer->arg); - if (newTime) - TimerSet(timer, 0, newTime, timer->callback, timer->arg); -} - -OsTimerPtr -TimerSet(OsTimerPtr timer, int flags, CARD32 millis, - OsTimerCallback func, pointer arg) -{ - register OsTimerPtr *prev; - CARD32 now = GetTimeInMillis(); - - if (!timer) - { - timer = malloc(sizeof(struct _OsTimerRec)); - if (!timer) - return NULL; - } - else - { - for (prev = &timers; *prev; prev = &(*prev)->next) - { - if (*prev == timer) - { - *prev = timer->next; - if (flags & TimerForceOld) - (void)(*timer->callback)(timer, now, timer->arg); - break; - } - } - } - if (!millis) - return timer; - if (flags & TimerAbsolute) { - timer->delta = millis - now; - } - else { - timer->delta = millis; - millis += now; - } - timer->expires = millis; - timer->callback = func; - timer->arg = arg; - if ((int) (millis - now) <= 0) - { - timer->next = NULL; - millis = (*timer->callback)(timer, now, timer->arg); - if (!millis) - return timer; - } - for (prev = &timers; - *prev && (int) ((*prev)->expires - millis) <= 0; - prev = &(*prev)->next) - ; - timer->next = *prev; - *prev = timer; - return timer; -} - -Bool -TimerForce(OsTimerPtr timer) -{ - OsTimerPtr *prev; - - for (prev = &timers; *prev; prev = &(*prev)->next) - { - if (*prev == timer) - { - DoTimer(timer, GetTimeInMillis(), prev); - return TRUE; - } - } - return FALSE; -} - - -void -TimerCancel(OsTimerPtr timer) -{ - OsTimerPtr *prev; - - if (!timer) - return; - for (prev = &timers; *prev; prev = &(*prev)->next) - { - if (*prev == timer) - { - *prev = timer->next; - break; - } - } -} - -void -TimerFree(OsTimerPtr timer) -{ - if (!timer) - return; - TimerCancel(timer); - free(timer); -} - -void -TimerCheck(void) -{ - CARD32 now = GetTimeInMillis(); - - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); -} - -void -TimerInit(void) -{ - OsTimerPtr timer; - - while ((timer = timers)) - { - timers = timer->next; - free(timer); - } -} - -#ifdef DPMSExtension - -#define DPMS_CHECK_MODE(mode,time)\ - if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\ - DPMSSet(serverClient, mode); - -#define DPMS_CHECK_TIMEOUT(time)\ - if (time > 0 && (time - timeout) > 0)\ - return time - timeout; - -static CARD32 -NextDPMSTimeout(INT32 timeout) -{ - /* - * Return the amount of time remaining until we should set - * the next power level. Fallthroughs are intentional. - */ - switch (DPMSPowerLevel) - { - case DPMSModeOn: - DPMS_CHECK_TIMEOUT(DPMSStandbyTime) - - case DPMSModeStandby: - DPMS_CHECK_TIMEOUT(DPMSSuspendTime) - - case DPMSModeSuspend: - DPMS_CHECK_TIMEOUT(DPMSOffTime) - - default: /* DPMSModeOff */ - return 0; - } -} -#endif /* DPMSExtension */ - -static CARD32 -ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg) -{ - INT32 timeout = now - lastDeviceEventTime.milliseconds; - CARD32 nextTimeout = 0; - -#ifdef DPMSExtension - /* - * Check each mode lowest to highest, since a lower mode can - * have the same timeout as a higher one. - */ - if (DPMSEnabled) - { - DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime) - DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime) - DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime) - - nextTimeout = NextDPMSTimeout(timeout); - } - - /* - * Only do the screensaver checks if we're not in a DPMS - * power saving mode - */ - if (DPMSPowerLevel != DPMSModeOn) - return nextTimeout; -#endif /* DPMSExtension */ - - if (!ScreenSaverTime) - return nextTimeout; - - if (timeout < ScreenSaverTime) - { - return nextTimeout > 0 ? - min(ScreenSaverTime - timeout, nextTimeout) : - ScreenSaverTime - timeout; - } - - ResetOsBuffers(); /* not ideal, but better than nothing */ - dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive); - - if (ScreenSaverInterval > 0) - { - nextTimeout = nextTimeout > 0 ? - min(ScreenSaverInterval, nextTimeout) : - ScreenSaverInterval; - } - - return nextTimeout; -} - -static OsTimerPtr ScreenSaverTimer = NULL; - -void -FreeScreenSaverTimer(void) -{ - if (ScreenSaverTimer) { - TimerFree(ScreenSaverTimer); - ScreenSaverTimer = NULL; - } -} - -void -SetScreenSaverTimer(void) -{ - CARD32 timeout = 0; - -#ifdef DPMSExtension - if (DPMSEnabled) - { - /* - * A higher DPMS level has a timeout that's either less - * than or equal to that of a lower DPMS level. - */ - if (DPMSStandbyTime > 0) - timeout = DPMSStandbyTime; - - else if (DPMSSuspendTime > 0) - timeout = DPMSSuspendTime; - - else if (DPMSOffTime > 0) - timeout = DPMSOffTime; - } -#endif - - if (ScreenSaverTime > 0) - { - timeout = timeout > 0 ? - min(ScreenSaverTime, timeout) : - ScreenSaverTime; - } - -#ifdef SCREENSAVER - if (timeout && !screenSaverSuspended) { -#else - if (timeout) { -#endif - ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout, - ScreenSaverTimeoutExpire, NULL); - } - else if (ScreenSaverTimer) { - FreeScreenSaverTimer(); - } -} - +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL 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. + +******************************************************************/ + + +/***************************************************************** + * OS Dependent input routines: + * + * WaitForSomething + * TimerForce, TimerSet, TimerCheck, TimerFree + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifdef WIN32 +#include +#endif +#include /* for strings, fcntl, time */ +#include +#include +#include +#include "misc.h" + +#include "osdep.h" +#include +#include "dixstruct.h" +#include "opaque.h" +#ifdef DPMSExtension +#include "dpmsproc.h" +#endif + +#ifdef WIN32 +/* Error codes from windows sockets differ from fileio error codes */ +#undef EINTR +#define EINTR WSAEINTR +#undef EINVAL +#define EINVAL WSAEINVAL +#undef EBADF +#define EBADF WSAENOTSOCK +/* Windows select does not set errno. Use GetErrno as wrapper for + WSAGetLastError */ +#define GetErrno WSAGetLastError +#else +/* This is just a fallback to errno to hide the differences between unix and + Windows in the code */ +#define GetErrno() errno +#endif + +/* like ffs, but uses fd_mask instead of int as argument, so it works + when fd_mask is longer than an int, such as common 64-bit platforms */ +/* modifications by raphael */ +int +mffs(fd_mask mask) +{ + int i; + + if (!mask) return 0; + i = 1; + while (!(mask & 1)) + { + i++; + mask >>= 1; + } + return i; +} + +#ifdef DPMSExtension +#include +#endif + +struct _OsTimerRec { + OsTimerPtr next; + CARD32 expires; + CARD32 delta; + OsTimerCallback callback; + pointer arg; +}; + +static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); +static void CheckAllTimers(void); +static OsTimerPtr timers = NULL; + +/***************** + * WaitForSomething: + * Make the server suspend until there is + * 1. data from clients or + * 2. input events available or + * 3. ddx notices something of interest (graphics + * queue ready, etc.) or + * 4. clients that have buffered replies/events are ready + * + * If the time between INPUT events is + * greater than ScreenSaverTime, the display is turned off (or + * saved, depending on the hardware). So, WaitForSomething() + * has to handle this also (that's why the select() has a timeout. + * For more info on ClientsWithInput, see ReadRequestFromClient(). + * pClientsReady is an array to store ready client->index values into. + *****************/ + +int +WaitForSomething(int *pClientsReady) +{ + int i; + struct timeval waittime, *wt; + INT32 timeout = 0; + fd_set clientsReadable; + fd_set clientsWritable; + int curclient; + int selecterr; + static int nready; + fd_set devicesReadable; + CARD32 now = 0; + Bool someReady = FALSE; + + FD_ZERO(&clientsReadable); + + if (nready) + SmartScheduleStopTimer(); + nready = 0; + + /* We need a while loop here to handle + crashed connections and the screen saver timeout */ + while (1) + { + /* deal with any blocked jobs */ + if (workQueue) + ProcessWorkQueue(); + if (XFD_ANYSET (&ClientsWithInput)) + { + if (!SmartScheduleDisable) + { + someReady = TRUE; + waittime.tv_sec = 0; + waittime.tv_usec = 0; + wt = &waittime; + } + else + { + XFD_COPYSET (&ClientsWithInput, &clientsReadable); + break; + } + } + if (someReady) + { + XFD_COPYSET(&AllSockets, &LastSelectMask); + XFD_UNSET(&LastSelectMask, &ClientsWithInput); + } + else + { + wt = NULL; + if (timers) + { + now = GetTimeInMillis(); + timeout = timers->expires - now; + if (timeout > 0 && timeout > timers->delta + 250) { + /* time has rewound. reset the timers. */ + CheckAllTimers(); + } + + if (timers) { + timeout = timers->expires - now; + if (timeout < 0) + timeout = 0; + waittime.tv_sec = timeout / MILLI_PER_SECOND; + waittime.tv_usec = (timeout % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + wt = &waittime; + } + } + XFD_COPYSET(&AllSockets, &LastSelectMask); + } + + BlockHandler((pointer)&wt, (pointer)&LastSelectMask); + if (NewOutputPending) + FlushAllOutput(); + /* keep this check close to select() call to minimize race */ + if (dispatchException) + i = -1; + else if (AnyClientsWriteBlocked) + { + XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); + i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); + } + else + { + i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); + } + selecterr = GetErrno(); + WakeupHandler(i, (pointer)&LastSelectMask); + if (i <= 0) /* An error or timeout occurred */ + { + if (dispatchException) + return 0; + if (i < 0) + { + if (selecterr == EBADF) /* Some client disconnected */ + { + CheckConnections (); + if (! XFD_ANYSET (&AllClients)) + return 0; + } + else if (selecterr == EINVAL) + { + FatalError("WaitForSomething(): select: %s\n", + strerror(selecterr)); + } + else if (selecterr != EINTR && selecterr != EAGAIN) + { + ErrorF("WaitForSomething(): select: %s\n", + strerror(selecterr)); + } + } + else if (someReady) + { + /* + * If no-one else is home, bail quickly + */ + XFD_COPYSET(&ClientsWithInput, &LastSelectMask); + XFD_COPYSET(&ClientsWithInput, &clientsReadable); + break; + } + if (*checkForInput[0] != *checkForInput[1]) + return 0; + + if (timers) + { + int expired = 0; + now = GetTimeInMillis(); + if ((int) (timers->expires - now) <= 0) + expired = 1; + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + + if (expired) + return 0; + } + } + else + { + fd_set tmp_set; + + if (*checkForInput[0] == *checkForInput[1]) { + if (timers) + { + int expired = 0; + now = GetTimeInMillis(); + if ((int) (timers->expires - now) <= 0) + expired = 1; + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + + if (expired) + return 0; + } + } + if (someReady) + XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); + if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) + { + NewOutputPending = TRUE; + XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); + XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + + XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); + XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); + XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); + if (XFD_ANYSET(&tmp_set)) + QueueWorkProc(EstablishNewConnections, NULL, + (pointer)&LastSelectMask); + + if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable)) + break; + /* check here for DDXes that queue events during Block/Wakeup */ + if (*checkForInput[0] != *checkForInput[1]) + return 0; + } + } + + nready = 0; + if (XFD_ANYSET (&clientsReadable)) + { +#ifndef WIN32 + for (i=0; ipriority; + if (nready == 0 || client_priority > highest_priority) + { + /* Either we found the first client, or we found + * a client whose priority is greater than all others + * that have been found so far. Either way, we want + * to initialize the list of clients to contain just + * this client. + */ + pClientsReady[0] = client_index; + highest_priority = client_priority; + nready = 1; + } + /* the following if makes sure that multiple same-priority + * clients get batched together + */ + else if (client_priority == highest_priority) + { + pClientsReady[nready++] = client_index; + } +#ifndef WIN32 + clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); + } +#else + FD_CLR(curclient, &clientsReadable); +#endif + } + } + + if (nready) + SmartScheduleStartTimer(); + + return nready; +} + +/* If time has rewound, re-run every affected timer. + * Timers might drop out of the list, so we have to restart every time. */ +static void +CheckAllTimers(void) +{ + OsTimerPtr timer; + CARD32 now; + +start: + now = GetTimeInMillis(); + + for (timer = timers; timer; timer = timer->next) { + if (timer->expires - now > timer->delta + 250) { + TimerForce(timer); + goto start; + } + } +} + +static void +DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) +{ + CARD32 newTime; + + *prev = timer->next; + timer->next = NULL; + newTime = (*timer->callback)(timer, now, timer->arg); + if (newTime) + TimerSet(timer, 0, newTime, timer->callback, timer->arg); +} + +OsTimerPtr +TimerSet(OsTimerPtr timer, int flags, CARD32 millis, + OsTimerCallback func, pointer arg) +{ + register OsTimerPtr *prev; + CARD32 now = GetTimeInMillis(); + + if (!timer) + { + timer = malloc(sizeof(struct _OsTimerRec)); + if (!timer) + return NULL; + } + else + { + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + if (flags & TimerForceOld) + (void)(*timer->callback)(timer, now, timer->arg); + break; + } + } + } + if (!millis) + return timer; + if (flags & TimerAbsolute) { + timer->delta = millis - now; + } + else { + timer->delta = millis; + millis += now; + } + timer->expires = millis; + timer->callback = func; + timer->arg = arg; + if ((int) (millis - now) <= 0) + { + timer->next = NULL; + millis = (*timer->callback)(timer, now, timer->arg); + if (!millis) + return timer; + } + for (prev = &timers; + *prev && (int) ((*prev)->expires - millis) <= 0; + prev = &(*prev)->next) + ; + timer->next = *prev; + *prev = timer; + return timer; +} + +Bool +TimerForce(OsTimerPtr timer) +{ + OsTimerPtr *prev; + + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + DoTimer(timer, GetTimeInMillis(), prev); + return TRUE; + } + } + return FALSE; +} + + +void +TimerCancel(OsTimerPtr timer) +{ + OsTimerPtr *prev; + + if (!timer) + return; + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + break; + } + } +} + +void +TimerFree(OsTimerPtr timer) +{ + if (!timer) + return; + TimerCancel(timer); + free(timer); +} + +void +TimerCheck(void) +{ + CARD32 now = GetTimeInMillis(); + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); +} + +void +TimerInit(void) +{ + OsTimerPtr timer; + + while ((timer = timers)) + { + timers = timer->next; + free(timer); + } +} + +#ifdef DPMSExtension + +#define DPMS_CHECK_MODE(mode,time)\ + if (time > 0 && DPMSPowerLevel < mode && timeout >= time)\ + DPMSSet(serverClient, mode); + +#define DPMS_CHECK_TIMEOUT(time)\ + if (time > 0 && (time - timeout) > 0)\ + return time - timeout; + +static CARD32 +NextDPMSTimeout(INT32 timeout) +{ + /* + * Return the amount of time remaining until we should set + * the next power level. Fallthroughs are intentional. + */ + switch (DPMSPowerLevel) + { + case DPMSModeOn: + DPMS_CHECK_TIMEOUT(DPMSStandbyTime) + + case DPMSModeStandby: + DPMS_CHECK_TIMEOUT(DPMSSuspendTime) + + case DPMSModeSuspend: + DPMS_CHECK_TIMEOUT(DPMSOffTime) + + default: /* DPMSModeOff */ + return 0; + } +} +#endif /* DPMSExtension */ + +static CARD32 +ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer arg) +{ + INT32 timeout = now - lastDeviceEventTime.milliseconds; + CARD32 nextTimeout = 0; + +#ifdef DPMSExtension + /* + * Check each mode lowest to highest, since a lower mode can + * have the same timeout as a higher one. + */ + if (DPMSEnabled) + { + DPMS_CHECK_MODE(DPMSModeOff, DPMSOffTime) + DPMS_CHECK_MODE(DPMSModeSuspend, DPMSSuspendTime) + DPMS_CHECK_MODE(DPMSModeStandby, DPMSStandbyTime) + + nextTimeout = NextDPMSTimeout(timeout); + } + + /* + * Only do the screensaver checks if we're not in a DPMS + * power saving mode + */ + if (DPMSPowerLevel != DPMSModeOn) + return nextTimeout; +#endif /* DPMSExtension */ + + if (!ScreenSaverTime) + return nextTimeout; + + if (timeout < ScreenSaverTime) + { + return nextTimeout > 0 ? + min(ScreenSaverTime - timeout, nextTimeout) : + ScreenSaverTime - timeout; + } + + ResetOsBuffers(); /* not ideal, but better than nothing */ + dixSaveScreens(serverClient, SCREEN_SAVER_ON, ScreenSaverActive); + + if (ScreenSaverInterval > 0) + { + nextTimeout = nextTimeout > 0 ? + min(ScreenSaverInterval, nextTimeout) : + ScreenSaverInterval; + } + + return nextTimeout; +} + +static OsTimerPtr ScreenSaverTimer = NULL; + +void +FreeScreenSaverTimer(void) +{ + if (ScreenSaverTimer) { + TimerFree(ScreenSaverTimer); + ScreenSaverTimer = NULL; + } +} + +void +SetScreenSaverTimer(void) +{ + CARD32 timeout = 0; + +#ifdef DPMSExtension + if (DPMSEnabled) + { + /* + * A higher DPMS level has a timeout that's either less + * than or equal to that of a lower DPMS level. + */ + if (DPMSStandbyTime > 0) + timeout = DPMSStandbyTime; + + else if (DPMSSuspendTime > 0) + timeout = DPMSSuspendTime; + + else if (DPMSOffTime > 0) + timeout = DPMSOffTime; + } +#endif + + if (ScreenSaverTime > 0) + { + timeout = timeout > 0 ? + min(ScreenSaverTime, timeout) : + ScreenSaverTime; + } + +#ifdef SCREENSAVER + if (timeout && !screenSaverSuspended) { +#else + if (timeout) { +#endif + ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, timeout, + ScreenSaverTimeoutExpire, NULL); + } + else if (ScreenSaverTimer) { + FreeScreenSaverTimer(); + } +} + diff --git a/xorg-server/test/input.c b/xorg-server/test/input.c index 877e9776b..879e14f2f 100644 --- a/xorg-server/test/input.c +++ b/xorg-server/test/input.c @@ -1,1089 +1,1083 @@ -/** - * Copyright © 2009 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "misc.h" -#include "resource.h" -#include -#include -#include -#include "windowstr.h" -#include "inputstr.h" -#include "eventconvert.h" -#include "exevents.h" -#include "dixgrabs.h" -#include "eventstr.h" -#include "inpututils.h" -#include - -/** - * Init a device with axes. - * Verify values set on the device. - * - * Result: All axes set to default values (usually 0). - */ -static void dix_init_valuators(void) -{ - DeviceIntRec dev; - ValuatorClassPtr val; - const int num_axes = 2; - int i; - Atom atoms[MAX_VALUATORS] = { 0 }; - - - memset(&dev, 0, sizeof(DeviceIntRec)); - dev.type = MASTER_POINTER; /* claim it's a master to stop ptracccel */ - - g_assert(InitValuatorClassDeviceStruct(NULL, 0, atoms, 0, 0) == FALSE); - g_assert(InitValuatorClassDeviceStruct(&dev, num_axes, atoms, 0, Absolute)); - - val = dev.valuator; - g_assert(val); - g_assert(val->numAxes == num_axes); - g_assert(val->numMotionEvents == 0); - g_assert(val->axisVal); - - for (i = 0; i < num_axes; i++) - { - g_assert(val->axisVal[i] == 0); - g_assert(val->axes->min_value == NO_AXIS_LIMITS); - g_assert(val->axes->max_value == NO_AXIS_LIMITS); - g_assert(val->axes->mode == Absolute); - } - - g_assert(dev.last.numValuators == num_axes); -} - -/* just check the known success cases, and that error cases set the client's - * error value correctly. */ -static void dix_check_grab_values(void) -{ - ClientRec client; - GrabParameters param; - int rc; - - memset(&client, 0, sizeof(client)); - - param.grabtype = GRABTYPE_CORE; - param.this_device_mode = GrabModeSync; - param.other_devices_mode = GrabModeSync; - param.modifiers = AnyModifier; - param.ownerEvents = FALSE; - - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == Success); - - param.this_device_mode = GrabModeAsync; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == Success); - - param.this_device_mode = GrabModeAsync + 1; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == BadValue); - g_assert(client.errorValue == param.this_device_mode); - g_assert(client.errorValue == GrabModeAsync + 1); - - param.this_device_mode = GrabModeSync; - param.other_devices_mode = GrabModeAsync; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == Success); - - param.other_devices_mode = GrabModeAsync + 1; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == BadValue); - g_assert(client.errorValue == param.other_devices_mode); - g_assert(client.errorValue == GrabModeAsync + 1); - - param.other_devices_mode = GrabModeSync; - - param.modifiers = 1 << 13; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == BadValue); - g_assert(client.errorValue == param.modifiers); - g_assert(client.errorValue == (1 << 13)); - - - param.modifiers = AnyModifier; - param.ownerEvents = TRUE; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == Success); - - param.ownerEvents = 3; - rc = CheckGrabValues(&client, ¶m); - g_assert(rc == BadValue); - g_assert(client.errorValue == param.ownerEvents); - g_assert(client.errorValue == 3); -} - - -/** - * Convert various internal events to the matching core event and verify the - * parameters. - */ -static void dix_event_to_core(int type) -{ - DeviceEvent ev; - xEvent core; - int time; - int x, y; - int rc; - int state; - int detail; - const int ROOT_WINDOW_ID = 0x100; - - /* EventToCore memsets the event to 0 */ -#define test_event() \ - g_assert(rc == Success); \ - g_assert(core.u.u.type == type); \ - g_assert(core.u.u.detail == detail); \ - g_assert(core.u.keyButtonPointer.time == time); \ - g_assert(core.u.keyButtonPointer.rootX == x); \ - g_assert(core.u.keyButtonPointer.rootY == y); \ - g_assert(core.u.keyButtonPointer.state == state); \ - g_assert(core.u.keyButtonPointer.eventX == 0); \ - g_assert(core.u.keyButtonPointer.eventY == 0); \ - g_assert(core.u.keyButtonPointer.root == ROOT_WINDOW_ID); \ - g_assert(core.u.keyButtonPointer.event == 0); \ - g_assert(core.u.keyButtonPointer.child == 0); \ - g_assert(core.u.keyButtonPointer.sameScreen == FALSE); - - x = 0; - y = 0; - time = 12345; - state = 0; - detail = 0; - - ev.header = 0xFF; - ev.length = sizeof(DeviceEvent); - ev.time = time; - ev.root_y = x; - ev.root_x = y; - SetBit(ev.valuators.mask, 0); - SetBit(ev.valuators.mask, 1); - ev.root = ROOT_WINDOW_ID; - ev.corestate = state; - ev.detail.key = detail; - - ev.type = type; - ev.detail.key = 0; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - x = 1; - y = 2; - ev.root_x = x; - ev.root_y = y; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - x = 0x7FFF; - y = 0x7FFF; - ev.root_x = x; - ev.root_y = y; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - x = 0x8000; /* too high */ - y = 0x8000; /* too high */ - ev.root_x = x; - ev.root_y = y; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(core.u.keyButtonPointer.rootX != x); - g_assert(core.u.keyButtonPointer.rootY != y); - - x = 0x7FFF; - y = 0x7FFF; - ev.root_x = x; - ev.root_y = y; - time = 0; - ev.time = time; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - detail = 1; - ev.detail.key = detail; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - detail = 0xFF; /* highest value */ - ev.detail.key = detail; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - detail = 0xFFF; /* too big */ - ev.detail.key = detail; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(rc == BadMatch); - - detail = 0xFF; /* too big */ - ev.detail.key = detail; - state = 0xFFFF; /* highest value */ - ev.corestate = state; - rc = EventToCore((InternalEvent*)&ev, &core); - test_event(); - - state = 0x10000; /* too big */ - ev.corestate = state; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(core.u.keyButtonPointer.state != state); - g_assert(core.u.keyButtonPointer.state == (state & 0xFFFF)); - -#undef test_event -} - -static void dix_event_to_core_conversion(void) -{ - DeviceEvent ev; - xEvent core; - int rc; - - ev.header = 0xFF; - ev.length = sizeof(DeviceEvent); - - ev.type = 0; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(rc == BadImplementation); - - ev.type = 1; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(rc == BadImplementation); - - ev.type = ET_ProximityOut + 1; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(rc == BadImplementation); - - ev.type = ET_ProximityIn; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(rc == BadMatch); - - ev.type = ET_ProximityOut; - rc = EventToCore((InternalEvent*)&ev, &core); - g_assert(rc == BadMatch); - - dix_event_to_core(ET_KeyPress); - dix_event_to_core(ET_KeyRelease); - dix_event_to_core(ET_ButtonPress); - dix_event_to_core(ET_ButtonRelease); - dix_event_to_core(ET_Motion); -} - -static void xi2_struct_sizes(void) -{ -#define compare(req) \ - g_assert(sizeof(req) == sz_##req); - - compare(xXIQueryVersionReq); - compare(xXIWarpPointerReq); - compare(xXIChangeCursorReq); - compare(xXIChangeHierarchyReq); - compare(xXISetClientPointerReq); - compare(xXIGetClientPointerReq); - compare(xXISelectEventsReq); - compare(xXIQueryVersionReq); - compare(xXIQueryDeviceReq); - compare(xXISetFocusReq); - compare(xXIGetFocusReq); - compare(xXIGrabDeviceReq); - compare(xXIUngrabDeviceReq); - compare(xXIAllowEventsReq); - compare(xXIPassiveGrabDeviceReq); - compare(xXIPassiveUngrabDeviceReq); - compare(xXIListPropertiesReq); - compare(xXIChangePropertyReq); - compare(xXIDeletePropertyReq); - compare(xXIGetPropertyReq); - compare(xXIGetSelectedEventsReq); -#undef compare -} - - -static void dix_grab_matching(void) -{ - DeviceIntRec xi_all_devices, xi_all_master_devices, dev1, dev2; - GrabRec a, b; - BOOL rc; - - memset(&a, 0, sizeof(a)); - memset(&b, 0, sizeof(b)); - - /* different grabtypes must fail */ - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_XI2; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI2; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_CORE; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* XI2 grabs for different devices must fail, regardless of ignoreDevice - * XI2 grabs for master devices must fail against a slave */ - memset(&xi_all_devices, 0, sizeof(DeviceIntRec)); - memset(&xi_all_master_devices, 0, sizeof(DeviceIntRec)); - memset(&dev1, 0, sizeof(DeviceIntRec)); - memset(&dev2, 0, sizeof(DeviceIntRec)); - - xi_all_devices.id = XIAllDevices; - xi_all_master_devices.id = XIAllMasterDevices; - dev1.id = 10; - dev1.type = SLAVE; - dev2.id = 11; - dev2.type = SLAVE; - - inputInfo.all_devices = &xi_all_devices; - inputInfo.all_master_devices = &xi_all_master_devices; - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.device = &dev1; - b.device = &dev2; - - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - - a.device = &dev2; - b.device = &dev1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&a, &b, TRUE); - g_assert(rc == FALSE); - - a.device = inputInfo.all_master_devices; - b.device = &dev1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&a, &b, TRUE); - g_assert(rc == FALSE); - - a.device = &dev1; - b.device = inputInfo.all_master_devices; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&a, &b, TRUE); - g_assert(rc == FALSE); - - /* ignoreDevice FALSE must fail for different devices for CORE and XI */ - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - a.device = &dev1; - b.device = &dev2; - a.modifierDevice = &dev1; - b.modifierDevice = &dev1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - a.device = &dev1; - b.device = &dev2; - a.modifierDevice = &dev1; - b.modifierDevice = &dev1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - - /* ignoreDevice FALSE must fail for different modifier devices for CORE - * and XI */ - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - a.device = &dev1; - b.device = &dev1; - a.modifierDevice = &dev1; - b.modifierDevice = &dev2; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - a.device = &dev1; - b.device = &dev1; - a.modifierDevice = &dev1; - b.modifierDevice = &dev2; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - - /* different event type must fail */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.device = &dev1; - b.device = &dev1; - a.modifierDevice = &dev1; - b.modifierDevice = &dev1; - a.type = XI_KeyPress; - b.type = XI_KeyRelease; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&a, &b, TRUE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - a.device = &dev1; - b.device = &dev1; - a.modifierDevice = &dev1; - b.modifierDevice = &dev1; - a.type = XI_KeyPress; - b.type = XI_KeyRelease; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&a, &b, TRUE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - a.device = &dev1; - b.device = &dev1; - a.modifierDevice = &dev1; - b.modifierDevice = &dev1; - a.type = XI_KeyPress; - b.type = XI_KeyRelease; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&a, &b, TRUE); - g_assert(rc == FALSE); - - /* different modifiers must fail */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.device = &dev1; - b.device = &dev1; - a.modifierDevice = &dev1; - b.modifierDevice = &dev1; - a.type = XI_KeyPress; - b.type = XI_KeyPress; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 2; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* AnyModifier must fail for XI2 */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.modifiersDetail.exact = AnyModifier; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* XIAnyModifier must fail for CORE and XI */ - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - a.modifiersDetail.exact = XIAnyModifier; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - a.modifiersDetail.exact = XIAnyModifier; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* different detail must fail */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.detail.exact = 1; - b.detail.exact = 2; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* detail of AnyModifier must fail */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.detail.exact = AnyModifier; - b.detail.exact = 1; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* detail of XIAnyModifier must fail */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.detail.exact = XIAnyModifier; - b.detail.exact = 1; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == FALSE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == FALSE); - - /* XIAnyModifier or AnyModifer must succeed */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.detail.exact = 1; - b.detail.exact = 1; - a.modifiersDetail.exact = XIAnyModifier; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == TRUE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == TRUE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - a.detail.exact = 1; - b.detail.exact = 1; - a.modifiersDetail.exact = AnyModifier; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == TRUE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == TRUE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - a.detail.exact = 1; - b.detail.exact = 1; - a.modifiersDetail.exact = AnyModifier; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == TRUE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == TRUE); - - /* AnyKey or XIAnyKeycode must succeed */ - a.grabtype = GRABTYPE_XI2; - b.grabtype = GRABTYPE_XI2; - a.detail.exact = XIAnyKeycode; - b.detail.exact = 1; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == TRUE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == TRUE); - - a.grabtype = GRABTYPE_CORE; - b.grabtype = GRABTYPE_CORE; - a.detail.exact = AnyKey; - b.detail.exact = 1; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == TRUE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == TRUE); - - a.grabtype = GRABTYPE_XI; - b.grabtype = GRABTYPE_XI; - a.detail.exact = AnyKey; - b.detail.exact = 1; - a.modifiersDetail.exact = 1; - b.modifiersDetail.exact = 1; - rc = GrabMatchesSecond(&a, &b, FALSE); - g_assert(rc == TRUE); - rc = GrabMatchesSecond(&b, &a, FALSE); - g_assert(rc == TRUE); -} - -static void test_bits_to_byte(int i) -{ - int expected_bytes; - expected_bytes = (i + 7)/8; - - g_assert(bits_to_bytes(i) >= i/8); - g_assert((bits_to_bytes(i) * 8) - i <= 7); - g_assert(expected_bytes == bits_to_bytes(i)); -} - -static void test_bytes_to_int32(int i) -{ - int expected_4byte; - expected_4byte = (i + 3)/4; - - g_assert(bytes_to_int32(i) <= i); - g_assert((bytes_to_int32(i) * 4) - i <= 3); - g_assert(expected_4byte == bytes_to_int32(i)); -} - -static void test_pad_to_int32(int i) -{ - int expected_bytes; - expected_bytes = ((i + 3)/4) * 4; - - g_assert(pad_to_int32(i) >= i); - g_assert(pad_to_int32(i) - i <= 3); - g_assert(expected_bytes == pad_to_int32(i)); -} -static void include_byte_padding_macros(void) -{ - g_test_message("Testing bits_to_bytes()"); - - /* the macros don't provide overflow protection */ - test_bits_to_byte(0); - test_bits_to_byte(1); - test_bits_to_byte(2); - test_bits_to_byte(7); - test_bits_to_byte(8); - test_bits_to_byte(0xFF); - test_bits_to_byte(0x100); - test_bits_to_byte(INT_MAX - 9); - test_bits_to_byte(INT_MAX - 8); - - g_test_message("Testing bytes_to_int32()"); - - test_bytes_to_int32(0); - test_bytes_to_int32(1); - test_bytes_to_int32(2); - test_bytes_to_int32(7); - test_bytes_to_int32(8); - test_bytes_to_int32(0xFF); - test_bytes_to_int32(0x100); - test_bytes_to_int32(0xFFFF); - test_bytes_to_int32(0x10000); - test_bytes_to_int32(0xFFFFFF); - test_bytes_to_int32(0x1000000); - test_bytes_to_int32(INT_MAX - 4); - test_bytes_to_int32(INT_MAX - 3); - - g_test_message("Testing pad_to_int32"); - - test_pad_to_int32(0); - test_pad_to_int32(0); - test_pad_to_int32(1); - test_pad_to_int32(2); - test_pad_to_int32(7); - test_pad_to_int32(8); - test_pad_to_int32(0xFF); - test_pad_to_int32(0x100); - test_pad_to_int32(0xFFFF); - test_pad_to_int32(0x10000); - test_pad_to_int32(0xFFFFFF); - test_pad_to_int32(0x1000000); - test_pad_to_int32(INT_MAX - 4); - test_pad_to_int32(INT_MAX - 3); -} - -static void xi_unregister_handlers(void) -{ - DeviceIntRec dev; - int handler; - - memset(&dev, 0, sizeof(dev)); - - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 1); - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 2); - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 3); - - g_test_message("Unlinking from front."); - - XIUnregisterPropertyHandler(&dev, 4); /* NOOP */ - g_assert(dev.properties.handlers->id == 3); - XIUnregisterPropertyHandler(&dev, 3); - g_assert(dev.properties.handlers->id == 2); - XIUnregisterPropertyHandler(&dev, 2); - g_assert(dev.properties.handlers->id == 1); - XIUnregisterPropertyHandler(&dev, 1); - g_assert(dev.properties.handlers == NULL); - - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 4); - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 5); - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 6); - XIUnregisterPropertyHandler(&dev, 3); /* NOOP */ - g_assert(dev.properties.handlers->next->next->next == NULL); - XIUnregisterPropertyHandler(&dev, 4); - g_assert(dev.properties.handlers->next->next == NULL); - XIUnregisterPropertyHandler(&dev, 5); - g_assert(dev.properties.handlers->next == NULL); - XIUnregisterPropertyHandler(&dev, 6); - g_assert(dev.properties.handlers == NULL); - - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 7); - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 8); - handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); - g_assert(handler == 9); - - XIDeleteAllDeviceProperties(&dev); - g_assert(dev.properties.handlers == NULL); - XIUnregisterPropertyHandler(&dev, 7); /* NOOP */ - -} - -static void cmp_attr_fields(InputAttributes *attr1, - InputAttributes *attr2) -{ - char **tags1, **tags2; - - g_assert(attr1 && attr2); - g_assert(attr1 != attr2); - g_assert(attr1->flags == attr2->flags); - - if (attr1->product != NULL) - { - g_assert(attr1->product != attr2->product); - g_assert(strcmp(attr1->product, attr2->product) == 0); - } else - g_assert(attr2->product == NULL); - - if (attr1->vendor != NULL) - { - g_assert(attr1->vendor != attr2->vendor); - g_assert(strcmp(attr1->vendor, attr2->vendor) == 0); - } else - g_assert(attr2->vendor == NULL); - - if (attr1->device != NULL) - { - g_assert(attr1->device != attr2->device); - g_assert(strcmp(attr1->device, attr2->device) == 0); - } else - g_assert(attr2->device == NULL); - - if (attr1->pnp_id != NULL) - { - g_assert(attr1->pnp_id != attr2->pnp_id); - g_assert(strcmp(attr1->pnp_id, attr2->pnp_id) == 0); - } else - g_assert(attr2->pnp_id == NULL); - - if (attr1->usb_id != NULL) - { - g_assert(attr1->usb_id != attr2->usb_id); - g_assert(strcmp(attr1->usb_id, attr2->usb_id) == 0); - } else - g_assert(attr2->usb_id == NULL); - - tags1 = attr1->tags; - tags2 = attr2->tags; - - /* if we don't have any tags, skip the tag checking bits */ - if (!tags1) - { - g_assert(!tags2); - return; - } - - /* Don't lug around empty arrays */ - g_assert(*tags1); - g_assert(*tags2); - - /* check for identical content, but duplicated */ - while (*tags1) - { - g_assert(*tags1 != *tags2); - g_assert(strcmp(*tags1, *tags2) == 0); - tags1++; - tags2++; - } - - /* ensure tags1 and tags2 have the same no of elements */ - g_assert(!*tags2); - - /* check for not sharing memory */ - tags1 = attr1->tags; - while (*tags1) - { - tags2 = attr2->tags; - while (*tags2) - g_assert(*tags1 != *tags2++); - - tags1++; - } -} - -static void dix_input_attributes(void) -{ - InputAttributes orig = {0}; - InputAttributes *new; - char *tags[4] = {"tag1", "tag2", "tag2", NULL}; - - new = DuplicateInputAttributes(NULL); - g_assert(!new); - - new = DuplicateInputAttributes(&orig); - g_assert(memcmp(&orig, new, sizeof(InputAttributes)) == 0); - - orig.product = "product name"; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); - - orig.vendor = "vendor name"; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); - - orig.device = "device path"; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); - - orig.pnp_id = "PnPID"; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); - - orig.usb_id = "USBID"; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); - - orig.flags = 0xF0; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); - - orig.tags = tags; - new = DuplicateInputAttributes(&orig); - cmp_attr_fields(&orig, new); - FreeInputAttributes(new); -} - -static void dix_input_valuator_masks(void) -{ - ValuatorMask *mask = NULL, *copy; - int nvaluators = MAX_VALUATORS; - int valuators[nvaluators]; - int i; - int first_val, num_vals; - - for (i = 0; i < nvaluators; i++) - valuators[i] = i; - - mask = valuator_mask_new(nvaluators); - g_assert(mask != NULL); - g_assert(valuator_mask_size(mask) == 0); - g_assert(valuator_mask_num_valuators(mask) == 0); - - for (i = 0; i < nvaluators; i++) - { - g_assert(!valuator_mask_isset(mask, i)); - valuator_mask_set(mask, i, valuators[i]); - g_assert(valuator_mask_isset(mask, i)); - g_assert(valuator_mask_get(mask, i) == valuators[i]); - g_assert(valuator_mask_size(mask) == i + 1); - g_assert(valuator_mask_num_valuators(mask) == i + 1); - } - - for (i = 0; i < nvaluators; i++) - { - g_assert(valuator_mask_isset(mask, i)); - valuator_mask_unset(mask, i); - /* we're removing valuators from the front, so size should stay the - * same until the last bit is removed */ - if (i < nvaluators - 1) - g_assert(valuator_mask_size(mask) == nvaluators); - g_assert(!valuator_mask_isset(mask, i)); - } - - g_assert(valuator_mask_size(mask) == 0); - valuator_mask_zero(mask); - g_assert(valuator_mask_size(mask) == 0); - g_assert(valuator_mask_num_valuators(mask) == 0); - for (i = 0; i < nvaluators; i++) - g_assert(!valuator_mask_isset(mask, i)); - - first_val = 5; - num_vals = 6; - - valuator_mask_set_range(mask, first_val, num_vals, valuators); - g_assert(valuator_mask_size(mask) == first_val + num_vals); - g_assert(valuator_mask_num_valuators(mask) == num_vals); - for (i = 0; i < nvaluators; i++) - { - if (i < first_val || i >= first_val + num_vals) - g_assert(!valuator_mask_isset(mask, i)); - else - { - g_assert(valuator_mask_isset(mask, i)); - g_assert(valuator_mask_get(mask, i) == valuators[i - first_val]); - } - } - - copy = valuator_mask_new(nvaluators); - valuator_mask_copy(copy, mask); - g_assert(mask != copy); - g_assert(valuator_mask_size(mask) == valuator_mask_size(copy)); - g_assert(valuator_mask_num_valuators(mask) == valuator_mask_num_valuators(copy)); - - for (i = 0; i < nvaluators; i++) - { - g_assert(valuator_mask_isset(mask, i) == valuator_mask_isset(copy, i)); - g_assert(valuator_mask_get(mask, i) == valuator_mask_get(copy, i)); - } - - free(mask); -} - -static void dix_valuator_mode(void) -{ - DeviceIntRec dev; - const int num_axes = MAX_VALUATORS; - int i; - Atom atoms[MAX_VALUATORS] = { 0 }; - - memset(&dev, 0, sizeof(DeviceIntRec)); - dev.type = MASTER_POINTER; /* claim it's a master to stop ptracccel */ - - g_assert(InitValuatorClassDeviceStruct(NULL, 0, atoms, 0, 0) == FALSE); - g_assert(InitValuatorClassDeviceStruct(&dev, num_axes, atoms, 0, Absolute)); - - for (i = 0; i < num_axes; i++) - { - g_assert(valuator_get_mode(&dev, i) == Absolute); - valuator_set_mode(&dev, i, Relative); - g_assert(dev.valuator->axes[i].mode == Relative); - g_assert(valuator_get_mode(&dev, i) == Relative); - } - - valuator_set_mode(&dev, VALUATOR_MODE_ALL_AXES, Absolute); - for (i = 0; i < num_axes; i++) - g_assert(valuator_get_mode(&dev, i) == Absolute); - - valuator_set_mode(&dev, VALUATOR_MODE_ALL_AXES, Relative); - for (i = 0; i < num_axes; i++) - g_assert(valuator_get_mode(&dev, i) == Relative); -} - -static void include_bit_test_macros(void) -{ - uint8_t mask[9] = { 0 }; - int i; - - for (i = 0; i < sizeof(mask)/sizeof(mask[0]); i++) - { - g_assert(BitIsOn(mask, i) == 0); - SetBit(mask, i); - g_assert(BitIsOn(mask, i) == 1); - g_assert(!!(mask[i/8] & (1 << (i % 8)))); - g_assert(CountBits(mask, sizeof(mask)) == 1); - ClearBit(mask, i); - g_assert(BitIsOn(mask, i) == 0); - } -} - -int main(int argc, char** argv) -{ - g_test_init(&argc, &argv,NULL); - g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); - - g_test_add_func("/dix/input/valuator-masks", dix_input_valuator_masks); - g_test_add_func("/dix/input/attributes", dix_input_attributes); - g_test_add_func("/dix/input/init-valuators", dix_init_valuators); - g_test_add_func("/dix/input/event-core-conversion", dix_event_to_core_conversion); - g_test_add_func("/dix/input/check-grab-values", dix_check_grab_values); - g_test_add_func("/dix/input/xi2-struct-sizes", xi2_struct_sizes); - g_test_add_func("/dix/input/grab_matching", dix_grab_matching); - g_test_add_func("/dix/input/valuator_mode", dix_valuator_mode); - g_test_add_func("/include/byte_padding_macros", include_byte_padding_macros); - g_test_add_func("/include/bit_test_macros", include_bit_test_macros); - g_test_add_func("/Xi/xiproperty/register-unregister", xi_unregister_handlers); - - - return g_test_run(); -} +/** + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "resource.h" +#include +#include +#include +#include "windowstr.h" +#include "inputstr.h" +#include "eventconvert.h" +#include "exevents.h" +#include "dixgrabs.h" +#include "eventstr.h" +#include "inpututils.h" +#include + +/** + * Init a device with axes. + * Verify values set on the device. + * + * Result: All axes set to default values (usually 0). + */ +static void dix_init_valuators(void) +{ + DeviceIntRec dev; + ValuatorClassPtr val; + const int num_axes = 2; + int i; + Atom atoms[MAX_VALUATORS] = { 0 }; + + + memset(&dev, 0, sizeof(DeviceIntRec)); + dev.type = MASTER_POINTER; /* claim it's a master to stop ptracccel */ + + g_assert(InitValuatorClassDeviceStruct(NULL, 0, atoms, 0, 0) == FALSE); + g_assert(InitValuatorClassDeviceStruct(&dev, num_axes, atoms, 0, Absolute)); + + val = dev.valuator; + g_assert(val); + g_assert(val->numAxes == num_axes); + g_assert(val->numMotionEvents == 0); + g_assert(val->axisVal); + + for (i = 0; i < num_axes; i++) + { + g_assert(val->axisVal[i] == 0); + g_assert(val->axes->min_value == NO_AXIS_LIMITS); + g_assert(val->axes->max_value == NO_AXIS_LIMITS); + g_assert(val->axes->mode == Absolute); + } + + g_assert(dev.last.numValuators == num_axes); +} + +/* just check the known success cases, and that error cases set the client's + * error value correctly. */ +static void dix_check_grab_values(void) +{ + ClientRec client; + GrabParameters param; + int rc; + + memset(&client, 0, sizeof(client)); + + param.grabtype = GRABTYPE_CORE; + param.this_device_mode = GrabModeSync; + param.other_devices_mode = GrabModeSync; + param.modifiers = AnyModifier; + param.ownerEvents = FALSE; + + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == Success); + + param.this_device_mode = GrabModeAsync; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == Success); + + param.this_device_mode = GrabModeAsync + 1; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == BadValue); + g_assert(client.errorValue == param.this_device_mode); + g_assert(client.errorValue == GrabModeAsync + 1); + + param.this_device_mode = GrabModeSync; + param.other_devices_mode = GrabModeAsync; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == Success); + + param.other_devices_mode = GrabModeAsync + 1; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == BadValue); + g_assert(client.errorValue == param.other_devices_mode); + g_assert(client.errorValue == GrabModeAsync + 1); + + param.other_devices_mode = GrabModeSync; + + param.modifiers = 1 << 13; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == BadValue); + g_assert(client.errorValue == param.modifiers); + g_assert(client.errorValue == (1 << 13)); + + + param.modifiers = AnyModifier; + param.ownerEvents = TRUE; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == Success); + + param.ownerEvents = 3; + rc = CheckGrabValues(&client, ¶m); + g_assert(rc == BadValue); + g_assert(client.errorValue == param.ownerEvents); + g_assert(client.errorValue == 3); +} + + +/** + * Convert various internal events to the matching core event and verify the + * parameters. + */ +static void dix_event_to_core(int type) +{ + DeviceEvent ev; + xEvent core; + int time; + int x, y; + int rc; + int state; + int detail; + const int ROOT_WINDOW_ID = 0x100; + + /* EventToCore memsets the event to 0 */ +#define test_event() \ + g_assert(rc == Success); \ + g_assert(core.u.u.type == type); \ + g_assert(core.u.u.detail == detail); \ + g_assert(core.u.keyButtonPointer.time == time); \ + g_assert(core.u.keyButtonPointer.rootX == x); \ + g_assert(core.u.keyButtonPointer.rootY == y); \ + g_assert(core.u.keyButtonPointer.state == state); \ + g_assert(core.u.keyButtonPointer.eventX == 0); \ + g_assert(core.u.keyButtonPointer.eventY == 0); \ + g_assert(core.u.keyButtonPointer.root == ROOT_WINDOW_ID); \ + g_assert(core.u.keyButtonPointer.event == 0); \ + g_assert(core.u.keyButtonPointer.child == 0); \ + g_assert(core.u.keyButtonPointer.sameScreen == FALSE); + + x = 0; + y = 0; + time = 12345; + state = 0; + detail = 0; + + ev.header = 0xFF; + ev.length = sizeof(DeviceEvent); + ev.time = time; + ev.root_y = x; + ev.root_x = y; + SetBit(ev.valuators.mask, 0); + SetBit(ev.valuators.mask, 1); + ev.root = ROOT_WINDOW_ID; + ev.corestate = state; + ev.detail.key = detail; + + ev.type = type; + ev.detail.key = 0; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + x = 1; + y = 2; + ev.root_x = x; + ev.root_y = y; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + x = 0x7FFF; + y = 0x7FFF; + ev.root_x = x; + ev.root_y = y; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + x = 0x8000; /* too high */ + y = 0x8000; /* too high */ + ev.root_x = x; + ev.root_y = y; + rc = EventToCore((InternalEvent*)&ev, &core); + g_assert(core.u.keyButtonPointer.rootX != x); + g_assert(core.u.keyButtonPointer.rootY != y); + + x = 0x7FFF; + y = 0x7FFF; + ev.root_x = x; + ev.root_y = y; + time = 0; + ev.time = time; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + detail = 1; + ev.detail.key = detail; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + detail = 0xFF; /* highest value */ + ev.detail.key = detail; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + detail = 0xFFF; /* too big */ + ev.detail.key = detail; + rc = EventToCore((InternalEvent*)&ev, &core); + g_assert(rc == BadMatch); + + detail = 0xFF; /* too big */ + ev.detail.key = detail; + state = 0xFFFF; /* highest value */ + ev.corestate = state; + rc = EventToCore((InternalEvent*)&ev, &core); + test_event(); + + state = 0x10000; /* too big */ + ev.corestate = state; + rc = EventToCore((InternalEvent*)&ev, &core); + g_assert(core.u.keyButtonPointer.state != state); + g_assert(core.u.keyButtonPointer.state == (state & 0xFFFF)); + +#undef test_event +} + +static void dix_event_to_core_fail(int evtype, int expected_rc) +{ + DeviceEvent ev; + xEvent core; + int rc; + + ev.header = 0xFF; + ev.length = sizeof(DeviceEvent); + + ev.type = evtype; + rc = EventToCore((InternalEvent*)&ev, &core); + g_assert(rc == expected_rc); +} + +static void dix_event_to_core_conversion(void) +{ + dix_event_to_core_fail(0, BadImplementation); + dix_event_to_core_fail(1, BadImplementation); + dix_event_to_core_fail(ET_ProximityOut + 1, BadImplementation); + dix_event_to_core_fail(ET_ProximityIn, BadMatch); + dix_event_to_core_fail(ET_ProximityOut, BadMatch); + + dix_event_to_core(ET_KeyPress); + dix_event_to_core(ET_KeyRelease); + dix_event_to_core(ET_ButtonPress); + dix_event_to_core(ET_ButtonRelease); + dix_event_to_core(ET_Motion); +} + +static void xi2_struct_sizes(void) +{ +#define compare(req) \ + g_assert(sizeof(req) == sz_##req); + + compare(xXIQueryVersionReq); + compare(xXIWarpPointerReq); + compare(xXIChangeCursorReq); + compare(xXIChangeHierarchyReq); + compare(xXISetClientPointerReq); + compare(xXIGetClientPointerReq); + compare(xXISelectEventsReq); + compare(xXIQueryVersionReq); + compare(xXIQueryDeviceReq); + compare(xXISetFocusReq); + compare(xXIGetFocusReq); + compare(xXIGrabDeviceReq); + compare(xXIUngrabDeviceReq); + compare(xXIAllowEventsReq); + compare(xXIPassiveGrabDeviceReq); + compare(xXIPassiveUngrabDeviceReq); + compare(xXIListPropertiesReq); + compare(xXIChangePropertyReq); + compare(xXIDeletePropertyReq); + compare(xXIGetPropertyReq); + compare(xXIGetSelectedEventsReq); +#undef compare +} + + +static void dix_grab_matching(void) +{ + DeviceIntRec xi_all_devices, xi_all_master_devices, dev1, dev2; + GrabRec a, b; + BOOL rc; + + memset(&a, 0, sizeof(a)); + memset(&b, 0, sizeof(b)); + + /* different grabtypes must fail */ + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_XI2; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI2; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_CORE; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* XI2 grabs for different devices must fail, regardless of ignoreDevice + * XI2 grabs for master devices must fail against a slave */ + memset(&xi_all_devices, 0, sizeof(DeviceIntRec)); + memset(&xi_all_master_devices, 0, sizeof(DeviceIntRec)); + memset(&dev1, 0, sizeof(DeviceIntRec)); + memset(&dev2, 0, sizeof(DeviceIntRec)); + + xi_all_devices.id = XIAllDevices; + xi_all_master_devices.id = XIAllMasterDevices; + dev1.id = 10; + dev1.type = SLAVE; + dev2.id = 11; + dev2.type = SLAVE; + + inputInfo.all_devices = &xi_all_devices; + inputInfo.all_master_devices = &xi_all_master_devices; + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.device = &dev1; + b.device = &dev2; + + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + + a.device = &dev2; + b.device = &dev1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&a, &b, TRUE); + g_assert(rc == FALSE); + + a.device = inputInfo.all_master_devices; + b.device = &dev1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&a, &b, TRUE); + g_assert(rc == FALSE); + + a.device = &dev1; + b.device = inputInfo.all_master_devices; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&a, &b, TRUE); + g_assert(rc == FALSE); + + /* ignoreDevice FALSE must fail for different devices for CORE and XI */ + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + a.device = &dev1; + b.device = &dev2; + a.modifierDevice = &dev1; + b.modifierDevice = &dev1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + a.device = &dev1; + b.device = &dev2; + a.modifierDevice = &dev1; + b.modifierDevice = &dev1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + + /* ignoreDevice FALSE must fail for different modifier devices for CORE + * and XI */ + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + a.device = &dev1; + b.device = &dev1; + a.modifierDevice = &dev1; + b.modifierDevice = &dev2; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + a.device = &dev1; + b.device = &dev1; + a.modifierDevice = &dev1; + b.modifierDevice = &dev2; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + + /* different event type must fail */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.device = &dev1; + b.device = &dev1; + a.modifierDevice = &dev1; + b.modifierDevice = &dev1; + a.type = XI_KeyPress; + b.type = XI_KeyRelease; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&a, &b, TRUE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + a.device = &dev1; + b.device = &dev1; + a.modifierDevice = &dev1; + b.modifierDevice = &dev1; + a.type = XI_KeyPress; + b.type = XI_KeyRelease; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&a, &b, TRUE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + a.device = &dev1; + b.device = &dev1; + a.modifierDevice = &dev1; + b.modifierDevice = &dev1; + a.type = XI_KeyPress; + b.type = XI_KeyRelease; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&a, &b, TRUE); + g_assert(rc == FALSE); + + /* different modifiers must fail */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.device = &dev1; + b.device = &dev1; + a.modifierDevice = &dev1; + b.modifierDevice = &dev1; + a.type = XI_KeyPress; + b.type = XI_KeyPress; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 2; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* AnyModifier must fail for XI2 */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.modifiersDetail.exact = AnyModifier; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* XIAnyModifier must fail for CORE and XI */ + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + a.modifiersDetail.exact = XIAnyModifier; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + a.modifiersDetail.exact = XIAnyModifier; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* different detail must fail */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.detail.exact = 1; + b.detail.exact = 2; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* detail of AnyModifier must fail */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.detail.exact = AnyModifier; + b.detail.exact = 1; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* detail of XIAnyModifier must fail */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.detail.exact = XIAnyModifier; + b.detail.exact = 1; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == FALSE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == FALSE); + + /* XIAnyModifier or AnyModifer must succeed */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.detail.exact = 1; + b.detail.exact = 1; + a.modifiersDetail.exact = XIAnyModifier; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + a.detail.exact = 1; + b.detail.exact = 1; + a.modifiersDetail.exact = AnyModifier; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + a.detail.exact = 1; + b.detail.exact = 1; + a.modifiersDetail.exact = AnyModifier; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); + + /* AnyKey or XIAnyKeycode must succeed */ + a.grabtype = GRABTYPE_XI2; + b.grabtype = GRABTYPE_XI2; + a.detail.exact = XIAnyKeycode; + b.detail.exact = 1; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); + + a.grabtype = GRABTYPE_CORE; + b.grabtype = GRABTYPE_CORE; + a.detail.exact = AnyKey; + b.detail.exact = 1; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); + + a.grabtype = GRABTYPE_XI; + b.grabtype = GRABTYPE_XI; + a.detail.exact = AnyKey; + b.detail.exact = 1; + a.modifiersDetail.exact = 1; + b.modifiersDetail.exact = 1; + rc = GrabMatchesSecond(&a, &b, FALSE); + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); +} + +static void test_bits_to_byte(int i) +{ + int expected_bytes; + expected_bytes = (i + 7)/8; + + g_assert(bits_to_bytes(i) >= i/8); + g_assert((bits_to_bytes(i) * 8) - i <= 7); + g_assert(expected_bytes == bits_to_bytes(i)); +} + +static void test_bytes_to_int32(int i) +{ + int expected_4byte; + expected_4byte = (i + 3)/4; + + g_assert(bytes_to_int32(i) <= i); + g_assert((bytes_to_int32(i) * 4) - i <= 3); + g_assert(expected_4byte == bytes_to_int32(i)); +} + +static void test_pad_to_int32(int i) +{ + int expected_bytes; + expected_bytes = ((i + 3)/4) * 4; + + g_assert(pad_to_int32(i) >= i); + g_assert(pad_to_int32(i) - i <= 3); + g_assert(expected_bytes == pad_to_int32(i)); +} +static void include_byte_padding_macros(void) +{ + g_test_message("Testing bits_to_bytes()"); + + /* the macros don't provide overflow protection */ + test_bits_to_byte(0); + test_bits_to_byte(1); + test_bits_to_byte(2); + test_bits_to_byte(7); + test_bits_to_byte(8); + test_bits_to_byte(0xFF); + test_bits_to_byte(0x100); + test_bits_to_byte(INT_MAX - 9); + test_bits_to_byte(INT_MAX - 8); + + g_test_message("Testing bytes_to_int32()"); + + test_bytes_to_int32(0); + test_bytes_to_int32(1); + test_bytes_to_int32(2); + test_bytes_to_int32(7); + test_bytes_to_int32(8); + test_bytes_to_int32(0xFF); + test_bytes_to_int32(0x100); + test_bytes_to_int32(0xFFFF); + test_bytes_to_int32(0x10000); + test_bytes_to_int32(0xFFFFFF); + test_bytes_to_int32(0x1000000); + test_bytes_to_int32(INT_MAX - 4); + test_bytes_to_int32(INT_MAX - 3); + + g_test_message("Testing pad_to_int32"); + + test_pad_to_int32(0); + test_pad_to_int32(0); + test_pad_to_int32(1); + test_pad_to_int32(2); + test_pad_to_int32(7); + test_pad_to_int32(8); + test_pad_to_int32(0xFF); + test_pad_to_int32(0x100); + test_pad_to_int32(0xFFFF); + test_pad_to_int32(0x10000); + test_pad_to_int32(0xFFFFFF); + test_pad_to_int32(0x1000000); + test_pad_to_int32(INT_MAX - 4); + test_pad_to_int32(INT_MAX - 3); +} + +static void xi_unregister_handlers(void) +{ + DeviceIntRec dev; + int handler; + + memset(&dev, 0, sizeof(dev)); + + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 1); + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 2); + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 3); + + g_test_message("Unlinking from front."); + + XIUnregisterPropertyHandler(&dev, 4); /* NOOP */ + g_assert(dev.properties.handlers->id == 3); + XIUnregisterPropertyHandler(&dev, 3); + g_assert(dev.properties.handlers->id == 2); + XIUnregisterPropertyHandler(&dev, 2); + g_assert(dev.properties.handlers->id == 1); + XIUnregisterPropertyHandler(&dev, 1); + g_assert(dev.properties.handlers == NULL); + + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 4); + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 5); + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 6); + XIUnregisterPropertyHandler(&dev, 3); /* NOOP */ + g_assert(dev.properties.handlers->next->next->next == NULL); + XIUnregisterPropertyHandler(&dev, 4); + g_assert(dev.properties.handlers->next->next == NULL); + XIUnregisterPropertyHandler(&dev, 5); + g_assert(dev.properties.handlers->next == NULL); + XIUnregisterPropertyHandler(&dev, 6); + g_assert(dev.properties.handlers == NULL); + + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 7); + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 8); + handler = XIRegisterPropertyHandler(&dev, NULL, NULL, NULL); + g_assert(handler == 9); + + XIDeleteAllDeviceProperties(&dev); + g_assert(dev.properties.handlers == NULL); + XIUnregisterPropertyHandler(&dev, 7); /* NOOP */ + +} + +static void cmp_attr_fields(InputAttributes *attr1, + InputAttributes *attr2) +{ + char **tags1, **tags2; + + g_assert(attr1 && attr2); + g_assert(attr1 != attr2); + g_assert(attr1->flags == attr2->flags); + + if (attr1->product != NULL) + { + g_assert(attr1->product != attr2->product); + g_assert(strcmp(attr1->product, attr2->product) == 0); + } else + g_assert(attr2->product == NULL); + + if (attr1->vendor != NULL) + { + g_assert(attr1->vendor != attr2->vendor); + g_assert(strcmp(attr1->vendor, attr2->vendor) == 0); + } else + g_assert(attr2->vendor == NULL); + + if (attr1->device != NULL) + { + g_assert(attr1->device != attr2->device); + g_assert(strcmp(attr1->device, attr2->device) == 0); + } else + g_assert(attr2->device == NULL); + + if (attr1->pnp_id != NULL) + { + g_assert(attr1->pnp_id != attr2->pnp_id); + g_assert(strcmp(attr1->pnp_id, attr2->pnp_id) == 0); + } else + g_assert(attr2->pnp_id == NULL); + + if (attr1->usb_id != NULL) + { + g_assert(attr1->usb_id != attr2->usb_id); + g_assert(strcmp(attr1->usb_id, attr2->usb_id) == 0); + } else + g_assert(attr2->usb_id == NULL); + + tags1 = attr1->tags; + tags2 = attr2->tags; + + /* if we don't have any tags, skip the tag checking bits */ + if (!tags1) + { + g_assert(!tags2); + return; + } + + /* Don't lug around empty arrays */ + g_assert(*tags1); + g_assert(*tags2); + + /* check for identical content, but duplicated */ + while (*tags1) + { + g_assert(*tags1 != *tags2); + g_assert(strcmp(*tags1, *tags2) == 0); + tags1++; + tags2++; + } + + /* ensure tags1 and tags2 have the same no of elements */ + g_assert(!*tags2); + + /* check for not sharing memory */ + tags1 = attr1->tags; + while (*tags1) + { + tags2 = attr2->tags; + while (*tags2) + g_assert(*tags1 != *tags2++); + + tags1++; + } +} + +static void dix_input_attributes(void) +{ + InputAttributes orig = {0}; + InputAttributes *new; + char *tags[4] = {"tag1", "tag2", "tag2", NULL}; + + new = DuplicateInputAttributes(NULL); + g_assert(!new); + + new = DuplicateInputAttributes(&orig); + g_assert(memcmp(&orig, new, sizeof(InputAttributes)) == 0); + + orig.product = "product name"; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); + + orig.vendor = "vendor name"; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); + + orig.device = "device path"; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); + + orig.pnp_id = "PnPID"; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); + + orig.usb_id = "USBID"; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); + + orig.flags = 0xF0; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); + + orig.tags = tags; + new = DuplicateInputAttributes(&orig); + cmp_attr_fields(&orig, new); + FreeInputAttributes(new); +} + +static void dix_input_valuator_masks(void) +{ + ValuatorMask *mask = NULL, *copy; + int nvaluators = MAX_VALUATORS; + int valuators[nvaluators]; + int i; + int first_val, num_vals; + + for (i = 0; i < nvaluators; i++) + valuators[i] = i; + + mask = valuator_mask_new(nvaluators); + g_assert(mask != NULL); + g_assert(valuator_mask_size(mask) == 0); + g_assert(valuator_mask_num_valuators(mask) == 0); + + for (i = 0; i < nvaluators; i++) + { + g_assert(!valuator_mask_isset(mask, i)); + valuator_mask_set(mask, i, valuators[i]); + g_assert(valuator_mask_isset(mask, i)); + g_assert(valuator_mask_get(mask, i) == valuators[i]); + g_assert(valuator_mask_size(mask) == i + 1); + g_assert(valuator_mask_num_valuators(mask) == i + 1); + } + + for (i = 0; i < nvaluators; i++) + { + g_assert(valuator_mask_isset(mask, i)); + valuator_mask_unset(mask, i); + /* we're removing valuators from the front, so size should stay the + * same until the last bit is removed */ + if (i < nvaluators - 1) + g_assert(valuator_mask_size(mask) == nvaluators); + g_assert(!valuator_mask_isset(mask, i)); + } + + g_assert(valuator_mask_size(mask) == 0); + valuator_mask_zero(mask); + g_assert(valuator_mask_size(mask) == 0); + g_assert(valuator_mask_num_valuators(mask) == 0); + for (i = 0; i < nvaluators; i++) + g_assert(!valuator_mask_isset(mask, i)); + + first_val = 5; + num_vals = 6; + + valuator_mask_set_range(mask, first_val, num_vals, valuators); + g_assert(valuator_mask_size(mask) == first_val + num_vals); + g_assert(valuator_mask_num_valuators(mask) == num_vals); + for (i = 0; i < nvaluators; i++) + { + if (i < first_val || i >= first_val + num_vals) + g_assert(!valuator_mask_isset(mask, i)); + else + { + g_assert(valuator_mask_isset(mask, i)); + g_assert(valuator_mask_get(mask, i) == valuators[i - first_val]); + } + } + + copy = valuator_mask_new(nvaluators); + valuator_mask_copy(copy, mask); + g_assert(mask != copy); + g_assert(valuator_mask_size(mask) == valuator_mask_size(copy)); + g_assert(valuator_mask_num_valuators(mask) == valuator_mask_num_valuators(copy)); + + for (i = 0; i < nvaluators; i++) + { + g_assert(valuator_mask_isset(mask, i) == valuator_mask_isset(copy, i)); + g_assert(valuator_mask_get(mask, i) == valuator_mask_get(copy, i)); + } + + valuator_mask_free(&mask); + g_assert(mask == NULL); +} + +static void dix_valuator_mode(void) +{ + DeviceIntRec dev; + const int num_axes = MAX_VALUATORS; + int i; + Atom atoms[MAX_VALUATORS] = { 0 }; + + memset(&dev, 0, sizeof(DeviceIntRec)); + dev.type = MASTER_POINTER; /* claim it's a master to stop ptracccel */ + + g_assert(InitValuatorClassDeviceStruct(NULL, 0, atoms, 0, 0) == FALSE); + g_assert(InitValuatorClassDeviceStruct(&dev, num_axes, atoms, 0, Absolute)); + + for (i = 0; i < num_axes; i++) + { + g_assert(valuator_get_mode(&dev, i) == Absolute); + valuator_set_mode(&dev, i, Relative); + g_assert(dev.valuator->axes[i].mode == Relative); + g_assert(valuator_get_mode(&dev, i) == Relative); + } + + valuator_set_mode(&dev, VALUATOR_MODE_ALL_AXES, Absolute); + for (i = 0; i < num_axes; i++) + g_assert(valuator_get_mode(&dev, i) == Absolute); + + valuator_set_mode(&dev, VALUATOR_MODE_ALL_AXES, Relative); + for (i = 0; i < num_axes; i++) + g_assert(valuator_get_mode(&dev, i) == Relative); +} + +static void include_bit_test_macros(void) +{ + uint8_t mask[9] = { 0 }; + int i; + + for (i = 0; i < sizeof(mask)/sizeof(mask[0]); i++) + { + g_assert(BitIsOn(mask, i) == 0); + SetBit(mask, i); + g_assert(BitIsOn(mask, i) == 1); + g_assert(!!(mask[i/8] & (1 << (i % 8)))); + g_assert(CountBits(mask, sizeof(mask)) == 1); + ClearBit(mask, i); + g_assert(BitIsOn(mask, i) == 0); + } +} + +int main(int argc, char** argv) +{ + g_test_init(&argc, &argv,NULL); + g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); + + g_test_add_func("/dix/input/valuator-masks", dix_input_valuator_masks); + g_test_add_func("/dix/input/attributes", dix_input_attributes); + g_test_add_func("/dix/input/init-valuators", dix_init_valuators); + g_test_add_func("/dix/input/event-core-conversion", dix_event_to_core_conversion); + g_test_add_func("/dix/input/check-grab-values", dix_check_grab_values); + g_test_add_func("/dix/input/xi2-struct-sizes", xi2_struct_sizes); + g_test_add_func("/dix/input/grab_matching", dix_grab_matching); + g_test_add_func("/dix/input/valuator_mode", dix_valuator_mode); + g_test_add_func("/include/byte_padding_macros", include_byte_padding_macros); + g_test_add_func("/include/bit_test_macros", include_bit_test_macros); + g_test_add_func("/Xi/xiproperty/register-unregister", xi_unregister_handlers); + + + return g_test_run(); +} diff --git a/xorg-server/test/xi2/protocol-eventconvert.c b/xorg-server/test/xi2/protocol-eventconvert.c index 8184886c0..0478c33fe 100644 --- a/xorg-server/test/xi2/protocol-eventconvert.c +++ b/xorg-server/test/xi2/protocol-eventconvert.c @@ -1,907 +1,917 @@ -/** - * Copyright © 2009 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include - -#include "inputstr.h" -#include "eventstr.h" -#include "eventconvert.h" -#include "exevents.h" -#include - - -static void test_values_XIRawEvent(RawDeviceEvent *in, xXIRawEvent *out, - BOOL swap) -{ - int i; - unsigned char *ptr; - FP3232 *value, *raw_value; - int nvals = 0; - int bits_set; - int len; - - if (swap) - { - char n; - - swaps(&out->sequenceNumber, n); - swapl(&out->length, n); - swaps(&out->evtype, n); - swaps(&out->deviceid, n); - swapl(&out->time, n); - swapl(&out->detail, n); - swaps(&out->valuators_len, n); - } - - - g_assert(out->type == GenericEvent); - g_assert(out->extension == 0); /* IReqCode defaults to 0 */ - g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); - g_assert(out->time == in->time); - g_assert(out->detail == in->detail.button); - g_assert(out->deviceid == in->deviceid); - g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(sizeof(in->valuators.mask)))); - g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ - - ptr = (unsigned char*)&out[1]; - bits_set = 0; - - for (i = 0; out->valuators_len && i < sizeof(in->valuators.mask) * 8; i++) - { - g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); - if (XIMaskIsSet(in->valuators.mask, i)) - bits_set++; - } - - /* length is len of valuator mask (in 4-byte units) + the number of bits - * set. Each bit set represents 2 8-byte values, hence the - * 'bits_set * 4' */ - len = out->valuators_len + bits_set * 4; - g_assert(out->length == len); - - nvals = 0; - - for (i = 0; out->valuators_len && i < MAX_VALUATORS; i++) - { - g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); - if (XIMaskIsSet(in->valuators.mask, i)) - { - FP3232 vi, vo; - value = (FP3232*)(((unsigned char*)&out[1]) + out->valuators_len * 4); - value += nvals; - - vi.integral = in->valuators.data[i]; - vi.frac = in->valuators.data_frac[i]; - - vo.integral = value->integral; - vo.frac = value->frac; - if (swap) - { - char n; - swapl(&vo.integral, n); - swapl(&vo.frac, n); - } - - g_assert(vi.integral == vo.integral); - g_assert(vi.frac == vo.frac); - - raw_value = value + bits_set; - - vi.integral = in->valuators.data_raw[i]; - vi.frac = in->valuators.data_raw_frac[i]; - - vo.integral = raw_value->integral; - vo.frac = raw_value->frac; - if (swap) - { - char n; - swapl(&vo.integral, n); - swapl(&vo.frac, n); - } - - g_assert(vi.integral == vo.integral); - g_assert(vi.frac == vo.frac); - - nvals++; - } - } -} - -static void test_XIRawEvent(RawDeviceEvent *in) -{ - xXIRawEvent *out, *swapped; - int rc; - - rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); - g_assert(rc == Success); - - test_values_XIRawEvent(in, out, FALSE); - - swapped = calloc(1, sizeof(xEvent) + out->length * 4); - XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); - test_values_XIRawEvent(in, swapped, TRUE); - - free(out); - free(swapped); -} - -static void test_convert_XIFocusEvent(void) -{ - xEvent *out; - DeviceEvent in; - int rc; - - in.header = ET_Internal; - in.type = ET_Enter; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == Success); - g_assert(out == NULL); - - in.header = ET_Internal; - in.type = ET_FocusIn; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == Success); - g_assert(out == NULL); - - in.header = ET_Internal; - in.type = ET_FocusOut; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == BadImplementation); - - in.header = ET_Internal; - in.type = ET_Leave; - rc = EventToXI2((InternalEvent*)&in, &out); - g_assert(rc == BadImplementation); -} - - -static void test_convert_XIRawEvent(void) -{ - RawDeviceEvent in; - int i; - - memset(&in, 0, sizeof(in)); - - g_test_message("Testing all event types"); - in.header = ET_Internal; - in.type = ET_RawMotion; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawKeyPress; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawKeyRelease; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawButtonPress; - test_XIRawEvent(&in); - - in.header = ET_Internal; - in.type = ET_RawButtonRelease; - test_XIRawEvent(&in); - - g_test_message("Testing details and other fields"); - in.detail.button = 1L; - test_XIRawEvent(&in); - in.detail.button = 1L << 8; - test_XIRawEvent(&in); - in.detail.button = 1L << 16; - test_XIRawEvent(&in); - in.detail.button = 1L << 24; - test_XIRawEvent(&in); - in.detail.button = ~0L; - test_XIRawEvent(&in); - - in.detail.button = 0; - - in.time = 1L; - test_XIRawEvent(&in); - in.time = 1L << 8; - test_XIRawEvent(&in); - in.time = 1L << 16; - test_XIRawEvent(&in); - in.time = 1L << 24; - test_XIRawEvent(&in); - in.time = ~0L; - test_XIRawEvent(&in); - - in.deviceid = 1; - test_XIRawEvent(&in); - in.deviceid = 1 << 8; - test_XIRawEvent(&in); - in.deviceid = ~0 & 0xFF; - test_XIRawEvent(&in); - - g_test_message("Testing valuator masks"); - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIRawEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < MAX_VALUATORS; i++) - { - XISetMask(in.valuators.mask, i); - - in.valuators.data[i] = i; - in.valuators.data_raw[i] = i + 10; - in.valuators.data_frac[i] = i + 20; - in.valuators.data_raw_frac[i] = i + 30; - test_XIRawEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIRawEvent(&in); - } -} - -static void test_values_XIDeviceEvent(DeviceEvent *in, xXIDeviceEvent *out, - BOOL swap) -{ - int buttons, valuators; - int i; - unsigned char *ptr; - FP3232 *values; - - if (swap) { - char n; - - swaps(&out->sequenceNumber, n); - swapl(&out->length, n); - swaps(&out->evtype, n); - swaps(&out->deviceid, n); - swaps(&out->sourceid, n); - swapl(&out->time, n); - swapl(&out->detail, n); - swapl(&out->root, n); - swapl(&out->event, n); - swapl(&out->child, n); - swapl(&out->root_x, n); - swapl(&out->root_y, n); - swapl(&out->event_x, n); - swapl(&out->event_y, n); - swaps(&out->buttons_len, n); - swaps(&out->valuators_len, n); - swapl(&out->mods.base_mods, n); - swapl(&out->mods.latched_mods, n); - swapl(&out->mods.locked_mods, n); - swapl(&out->mods.effective_mods, n); - } - - g_assert(out->extension == 0); /* IReqCode defaults to 0 */ - g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); - g_assert(out->time == in->time); - g_assert(out->detail == in->detail.button); - g_assert(out->length >= 12); - - g_assert(out->deviceid == in->deviceid); - g_assert(out->sourceid == in->sourceid); - - g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ - - g_assert(out->root == in->root); - g_assert(out->event == None); /* set in FixUpEventFromWindow */ - g_assert(out->child == None); /* set in FixUpEventFromWindow */ - - g_assert(out->mods.base_mods == in->mods.base); - g_assert(out->mods.latched_mods == in->mods.latched); - g_assert(out->mods.locked_mods == in->mods.locked); - g_assert(out->mods.effective_mods == in->mods.effective); - - g_assert(out->group.base_group == in->group.base); - g_assert(out->group.latched_group == in->group.latched); - g_assert(out->group.locked_group == in->group.locked); - g_assert(out->group.effective_group == in->group.effective); - - g_assert(out->event_x == 0); /* set in FixUpEventFromWindow */ - g_assert(out->event_y == 0); /* set in FixUpEventFromWindow */ - - g_assert(out->root_x == FP1616(in->root_x, in->root_x_frac)); - g_assert(out->root_y == FP1616(in->root_y, in->root_y_frac)); - - buttons = 0; - for (i = 0; i < bits_to_bytes(sizeof(in->buttons)); i++) - { - if (XIMaskIsSet(in->buttons, i)) - { - g_assert(out->buttons_len >= bytes_to_int32(bits_to_bytes(i))); - buttons++; - } - } - - ptr = (unsigned char*)&out[1]; - for (i = 0; i < sizeof(in->buttons) * 8; i++) - g_assert(XIMaskIsSet(in->buttons, i) == XIMaskIsSet(ptr, i)); - - - valuators = 0; - for (i = 0; i < sizeof(in->valuators.mask) * 8; i++) - if (XIMaskIsSet(in->valuators.mask, i)) - valuators++; - - g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(valuators))); - - ptr += out->buttons_len * 4; - values = (FP3232*)(ptr + out->valuators_len * 4); - for (i = 0; i < sizeof(in->valuators.mask) * 8 || - i < (out->valuators_len * 4) * 8; i++) - { - if (i > sizeof(in->valuators.mask) * 8) - g_assert(!XIMaskIsSet(ptr, i)); - else if (i > out->valuators_len * 4 * 8) - g_assert(!XIMaskIsSet(in->valuators.mask, i)); - else { - g_assert(XIMaskIsSet(in->valuators.mask, i) == - XIMaskIsSet(ptr, i)); - - if (XIMaskIsSet(ptr, i)) - { - FP3232 vi, vo; - - vi.integral = in->valuators.data[i]; - vi.frac = in->valuators.data_frac[i]; - - vo = *values; - - if (swap) - { - char n; - swapl(&vo.integral, n); - swapl(&vo.frac, n); - } - - - g_assert(vi.integral == vo.integral); - g_assert(vi.frac == vo.frac); - values++; - } - } - } -} - -static void test_XIDeviceEvent(DeviceEvent *in) -{ - xXIDeviceEvent *out, *swapped; - int rc; - - rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); - g_assert(rc == Success); - - test_values_XIDeviceEvent(in, out, FALSE); - - swapped = calloc(1, sizeof(xEvent) + out->length * 4); - XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); - test_values_XIDeviceEvent(in, swapped, TRUE); - - free(out); - free(swapped); -} - -static void test_convert_XIDeviceEvent(void) -{ - DeviceEvent in; - int i; - - memset(&in, 0, sizeof(in)); - - g_test_message("Testing simple field values"); - in.header = ET_Internal; - in.type = ET_Motion; - in.length = sizeof(DeviceEvent); - in.time = 0; - in.deviceid = 1; - in.sourceid = 2; - in.root = 3; - in.root_x = 4; - in.root_x_frac = 5; - in.root_y = 6; - in.root_y_frac = 7; - in.detail.button = 8; - in.mods.base = 9; - in.mods.latched = 10; - in.mods.locked = 11; - in.mods.effective = 11; - in.group.base = 12; - in.group.latched = 13; - in.group.locked = 14; - in.group.effective = 15; - - test_XIDeviceEvent(&in); - - g_test_message("Testing field ranges"); - /* 32 bit */ - in.detail.button = 1L; - test_XIDeviceEvent(&in); - in.detail.button = 1L << 8; - test_XIDeviceEvent(&in); - in.detail.button = 1L << 16; - test_XIDeviceEvent(&in); - in.detail.button = 1L << 24; - test_XIDeviceEvent(&in); - in.detail.button = ~0L; - test_XIDeviceEvent(&in); - - /* 32 bit */ - in.time = 1L; - test_XIDeviceEvent(&in); - in.time = 1L << 8; - test_XIDeviceEvent(&in); - in.time = 1L << 16; - test_XIDeviceEvent(&in); - in.time = 1L << 24; - test_XIDeviceEvent(&in); - in.time = ~0L; - test_XIDeviceEvent(&in); - - /* 16 bit */ - in.deviceid = 1; - test_XIDeviceEvent(&in); - in.deviceid = 1 << 8; - test_XIDeviceEvent(&in); - in.deviceid = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - /* 16 bit */ - in.sourceid = 1; - test_XIDeviceEvent(&in); - in.deviceid = 1 << 8; - test_XIDeviceEvent(&in); - in.deviceid = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - /* 32 bit */ - in.root = 1L; - test_XIDeviceEvent(&in); - in.root = 1L << 8; - test_XIDeviceEvent(&in); - in.root = 1L << 16; - test_XIDeviceEvent(&in); - in.root = 1L << 24; - test_XIDeviceEvent(&in); - in.root = ~0L; - test_XIDeviceEvent(&in); - - /* 16 bit */ - in.root_x = 1; - test_XIDeviceEvent(&in); - in.root_x = 1 << 8; - test_XIDeviceEvent(&in); - in.root_x = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.root_x_frac = 1; - test_XIDeviceEvent(&in); - in.root_x_frac = 1 << 8; - test_XIDeviceEvent(&in); - in.root_x_frac = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.root_y = 1; - test_XIDeviceEvent(&in); - in.root_y = 1 << 8; - test_XIDeviceEvent(&in); - in.root_y = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.root_y_frac = 1; - test_XIDeviceEvent(&in); - in.root_y_frac = 1 << 8; - test_XIDeviceEvent(&in); - in.root_y_frac = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - /* 32 bit */ - in.mods.base = 1L; - test_XIDeviceEvent(&in); - in.mods.base = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.base = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.base = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.base = ~0L; - test_XIDeviceEvent(&in); - - in.mods.latched = 1L; - test_XIDeviceEvent(&in); - in.mods.latched = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.latched = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.latched = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.latched = ~0L; - test_XIDeviceEvent(&in); - - in.mods.locked = 1L; - test_XIDeviceEvent(&in); - in.mods.locked = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.locked = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.locked = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.locked = ~0L; - test_XIDeviceEvent(&in); - - in.mods.effective = 1L; - test_XIDeviceEvent(&in); - in.mods.effective = 1L << 8; - test_XIDeviceEvent(&in); - in.mods.effective = 1L << 16; - test_XIDeviceEvent(&in); - in.mods.effective = 1L << 24; - test_XIDeviceEvent(&in); - in.mods.effective = ~0L; - test_XIDeviceEvent(&in); - - /* 8 bit */ - in.group.base = 1; - test_XIDeviceEvent(&in); - in.group.base = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.group.latched = 1; - test_XIDeviceEvent(&in); - in.group.latched = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.group.locked = 1; - test_XIDeviceEvent(&in); - in.group.locked = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - in.mods.effective = 1; - test_XIDeviceEvent(&in); - in.mods.effective = ~0 & 0xFF; - test_XIDeviceEvent(&in); - - g_test_message("Testing button masks"); - for (i = 0; i < sizeof(in.buttons) * 8; i++) - { - XISetMask(in.buttons, i); - test_XIDeviceEvent(&in); - XIClearMask(in.buttons, i); - } - - for (i = 0; i < sizeof(in.buttons) * 8; i++) - { - XISetMask(in.buttons, i); - test_XIDeviceEvent(&in); - } - - g_test_message("Testing valuator masks"); - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIDeviceEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - - in.valuators.data[i] = i; - in.valuators.data_frac[i] = i + 20; - test_XIDeviceEvent(&in); - XIClearMask(in.valuators.mask, i); - } - - for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) - { - XISetMask(in.valuators.mask, i); - test_XIDeviceEvent(&in); - } -} - -static void test_values_XIDeviceChangedEvent(DeviceChangedEvent *in, - xXIDeviceChangedEvent *out, - BOOL swap) -{ - int i, j; - unsigned char *ptr; - - if (swap) - { - char n; - - swaps(&out->sequenceNumber, n); - swapl(&out->length, n); - swaps(&out->evtype, n); - swaps(&out->deviceid, n); - swaps(&out->sourceid, n); - swapl(&out->time, n); - swaps(&out->num_classes, n); - } - - g_assert(out->type == GenericEvent); - g_assert(out->extension == 0); /* IReqCode defaults to 0 */ - g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); - g_assert(out->time == in->time); - g_assert(out->deviceid == in->deviceid); - g_assert(out->sourceid == in->sourceid); - - ptr = (unsigned char*)&out[1]; - for (i = 0; i < out->num_classes; i++) - { - xXIAnyInfo* any = (xXIAnyInfo*)ptr; - - if (swap) - { - char n; - swaps(&any->length, n); - swaps(&any->type, n); - swaps(&any->sourceid, n); - } - - switch(any->type) - { - case XIButtonClass: - { - xXIButtonInfo *b = (xXIButtonInfo*)any; - Atom *names; - - if (swap) - { - char n; - swaps(&b->num_buttons, n); - } - - g_assert(b->length == - bytes_to_int32(sizeof(xXIButtonInfo)) + - bytes_to_int32(bits_to_bytes(b->num_buttons)) + - b->num_buttons); - g_assert(b->num_buttons == in->buttons.num_buttons); - - names = (Atom*)((char*)&b[1] + - pad_to_int32(bits_to_bytes(b->num_buttons))); - for (j = 0; j < b->num_buttons; j++) - { - if (swap) - { - char n; - swapl(&names[j], n); - } - g_assert(names[j] == in->buttons.names[j]); - } - } - break; - case XIKeyClass: - { - xXIKeyInfo *k = (xXIKeyInfo*)any; - uint32_t *kc; - - if (swap) - { - char n; - swaps(&k->num_keycodes, n); - } - - g_assert(k->length == - bytes_to_int32(sizeof(xXIKeyInfo)) + - k->num_keycodes); - g_assert(k->num_keycodes == in->keys.max_keycode - - in->keys.min_keycode + 1); - - kc = (uint32_t*)&k[1]; - for (j = 0; j < k->num_keycodes; j++) - { - if (swap) - { - char n; - swapl(&kc[j], n); - } - g_assert(kc[j] >= in->keys.min_keycode); - g_assert(kc[j] <= in->keys.max_keycode); - } - } - break; - case XIValuatorClass: - { - xXIValuatorInfo *v = (xXIValuatorInfo*)any; - g_assert(v->length == - bytes_to_int32(sizeof(xXIValuatorInfo))); - - } - break; - default: - g_error("Invalid class type.\n"); - break; - } - - ptr += any->length * 4; - } - -} - -static void test_XIDeviceChangedEvent(DeviceChangedEvent *in) -{ - xXIDeviceChangedEvent *out, *swapped; - int rc; - - rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); - g_assert(rc == Success); - - test_values_XIDeviceChangedEvent(in, out, FALSE); - - swapped = calloc(1, sizeof(xEvent) + out->length * 4); - XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); - test_values_XIDeviceChangedEvent(in, swapped, TRUE); - - free(out); - free(swapped); -} - -static void test_convert_XIDeviceChangedEvent(void) -{ - DeviceChangedEvent in; - int i; - - g_test_message("Testing simple field values"); - memset(&in, 0, sizeof(in)); - in.header = ET_Internal; - in.type = ET_DeviceChanged; - in.length = sizeof(DeviceChangedEvent); - in.time = 0; - in.deviceid = 1; - in.sourceid = 2; - in.masterid = 3; - in.num_valuators = 4; - in.flags = DEVCHANGE_SLAVE_SWITCH | DEVCHANGE_POINTER_EVENT | DEVCHANGE_KEYBOARD_EVENT; - - for (i = 0; i < MAX_BUTTONS; i++) - in.buttons.names[i] = i + 10; - - in.keys.min_keycode = 8; - in.keys.max_keycode = 255; - - test_XIDeviceChangedEvent(&in); - - in.time = 1L; - test_XIDeviceChangedEvent(&in); - in.time = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.time = 1L << 16; - test_XIDeviceChangedEvent(&in); - in.time = 1L << 24; - test_XIDeviceChangedEvent(&in); - in.time = ~0L; - test_XIDeviceChangedEvent(&in); - - in.deviceid = 1L; - test_XIDeviceChangedEvent(&in); - in.deviceid = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.deviceid = ~0 & 0xFFFF; - test_XIDeviceChangedEvent(&in); - - in.sourceid = 1L; - test_XIDeviceChangedEvent(&in); - in.sourceid = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.sourceid = ~0 & 0xFFFF; - test_XIDeviceChangedEvent(&in); - - in.masterid = 1L; - test_XIDeviceChangedEvent(&in); - in.masterid = 1L << 8; - test_XIDeviceChangedEvent(&in); - in.masterid = ~0 & 0xFFFF; - test_XIDeviceChangedEvent(&in); - - in.buttons.num_buttons = 0; - test_XIDeviceChangedEvent(&in); - - in.buttons.num_buttons = 1; - test_XIDeviceChangedEvent(&in); - - in.buttons.num_buttons = MAX_BUTTONS; - test_XIDeviceChangedEvent(&in); - - in.keys.min_keycode = 0; - in.keys.max_keycode = 0; - test_XIDeviceChangedEvent(&in); - - in.keys.max_keycode = 1 << 8; - test_XIDeviceChangedEvent(&in); - - in.keys.max_keycode = 0xFFFC; /* highest range, above that the length - field gives up */ - test_XIDeviceChangedEvent(&in); - - in.keys.min_keycode = 1 << 8; - in.keys.max_keycode = 1 << 8; - test_XIDeviceChangedEvent(&in); - - in.keys.min_keycode = 1 << 8; - in.keys.max_keycode = 0; - test_XIDeviceChangedEvent(&in); - - in.num_valuators = 0; - test_XIDeviceChangedEvent(&in); - - in.num_valuators = 1; - test_XIDeviceChangedEvent(&in); - - in.num_valuators = MAX_VALUATORS; - test_XIDeviceChangedEvent(&in); - - for (i = 0; i < MAX_VALUATORS; i++) - { - in.valuators[i].min = 0; - in.valuators[i].max = 0; - test_XIDeviceChangedEvent(&in); - - in.valuators[i].max = 1 << 8; - test_XIDeviceChangedEvent(&in); - in.valuators[i].max = 1 << 16; - test_XIDeviceChangedEvent(&in); - in.valuators[i].max = 1 << 24; - test_XIDeviceChangedEvent(&in); - in.valuators[i].max = abs(~0); - test_XIDeviceChangedEvent(&in); - - in.valuators[i].resolution = 1 << 8; - test_XIDeviceChangedEvent(&in); - in.valuators[i].resolution = 1 << 16; - test_XIDeviceChangedEvent(&in); - in.valuators[i].resolution = 1 << 24; - test_XIDeviceChangedEvent(&in); - in.valuators[i].resolution = abs(~0); - test_XIDeviceChangedEvent(&in); - - in.valuators[i].name = i; - test_XIDeviceChangedEvent(&in); - - in.valuators[i].mode = Relative; - test_XIDeviceChangedEvent(&in); - - in.valuators[i].mode = Absolute; - test_XIDeviceChangedEvent(&in); - } -} - -int main(int argc, char** argv) -{ - g_test_init(&argc, &argv,NULL); - g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); - - g_test_add_func("/xi2/eventconvert/XIRawEvent", test_convert_XIRawEvent); - g_test_add_func("/xi2/eventconvert/XIFocusEvent", test_convert_XIFocusEvent); - g_test_add_func("/xi2/eventconvert/XIDeviceEvent", test_convert_XIDeviceEvent); - g_test_add_func("/xi2/eventconvert/XIDeviceChangedEvent", test_convert_XIDeviceChangedEvent); - - return g_test_run(); -} +/** + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include + +#include "inputstr.h" +#include "eventstr.h" +#include "eventconvert.h" +#include "exevents.h" +#include + + +static void test_values_XIRawEvent(RawDeviceEvent *in, xXIRawEvent *out, + BOOL swap) +{ + int i; + unsigned char *ptr; + FP3232 *value, *raw_value; + int nvals = 0; + int bits_set; + int len; + + if (swap) + { + char n; + + swaps(&out->sequenceNumber, n); + swapl(&out->length, n); + swaps(&out->evtype, n); + swaps(&out->deviceid, n); + swapl(&out->time, n); + swapl(&out->detail, n); + swaps(&out->valuators_len, n); + } + + + g_assert(out->type == GenericEvent); + g_assert(out->extension == 0); /* IReqCode defaults to 0 */ + g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); + g_assert(out->time == in->time); + g_assert(out->detail == in->detail.button); + g_assert(out->deviceid == in->deviceid); + g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(sizeof(in->valuators.mask)))); + g_assert(out->flags == 0); /* FIXME: we don't set the flags yet */ + + ptr = (unsigned char*)&out[1]; + bits_set = 0; + + for (i = 0; out->valuators_len && i < sizeof(in->valuators.mask) * 8; i++) + { + g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); + if (XIMaskIsSet(in->valuators.mask, i)) + bits_set++; + } + + /* length is len of valuator mask (in 4-byte units) + the number of bits + * set. Each bit set represents 2 8-byte values, hence the + * 'bits_set * 4' */ + len = out->valuators_len + bits_set * 4; + g_assert(out->length == len); + + nvals = 0; + + for (i = 0; out->valuators_len && i < MAX_VALUATORS; i++) + { + g_assert (XIMaskIsSet(in->valuators.mask, i) == XIMaskIsSet(ptr, i)); + if (XIMaskIsSet(in->valuators.mask, i)) + { + FP3232 vi, vo; + value = (FP3232*)(((unsigned char*)&out[1]) + out->valuators_len * 4); + value += nvals; + + vi.integral = in->valuators.data[i]; + vi.frac = in->valuators.data_frac[i]; + + vo.integral = value->integral; + vo.frac = value->frac; + if (swap) + { + char n; + swapl(&vo.integral, n); + swapl(&vo.frac, n); + } + + g_assert(vi.integral == vo.integral); + g_assert(vi.frac == vo.frac); + + raw_value = value + bits_set; + + vi.integral = in->valuators.data_raw[i]; + vi.frac = in->valuators.data_raw_frac[i]; + + vo.integral = raw_value->integral; + vo.frac = raw_value->frac; + if (swap) + { + char n; + swapl(&vo.integral, n); + swapl(&vo.frac, n); + } + + g_assert(vi.integral == vo.integral); + g_assert(vi.frac == vo.frac); + + nvals++; + } + } +} + +static void test_XIRawEvent(RawDeviceEvent *in) +{ + xXIRawEvent *out, *swapped; + int rc; + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + g_assert(rc == Success); + + test_values_XIRawEvent(in, out, FALSE); + + swapped = calloc(1, sizeof(xEvent) + out->length * 4); + XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); + test_values_XIRawEvent(in, swapped, TRUE); + + free(out); + free(swapped); +} + +static void test_convert_XIFocusEvent(void) +{ + xEvent *out; + DeviceEvent in; + int rc; + + in.header = ET_Internal; + in.type = ET_Enter; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == Success); + g_assert(out == NULL); + + in.header = ET_Internal; + in.type = ET_FocusIn; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == Success); + g_assert(out == NULL); + + in.header = ET_Internal; + in.type = ET_FocusOut; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == BadImplementation); + + in.header = ET_Internal; + in.type = ET_Leave; + rc = EventToXI2((InternalEvent*)&in, &out); + g_assert(rc == BadImplementation); +} + + +static void test_convert_XIRawEvent(void) +{ + RawDeviceEvent in; + int i; + + memset(&in, 0, sizeof(in)); + + g_test_message("Testing all event types"); + in.header = ET_Internal; + in.type = ET_RawMotion; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawKeyPress; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawKeyRelease; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawButtonPress; + test_XIRawEvent(&in); + + in.header = ET_Internal; + in.type = ET_RawButtonRelease; + test_XIRawEvent(&in); + + g_test_message("Testing details and other fields"); + in.detail.button = 1L; + test_XIRawEvent(&in); + in.detail.button = 1L << 8; + test_XIRawEvent(&in); + in.detail.button = 1L << 16; + test_XIRawEvent(&in); + in.detail.button = 1L << 24; + test_XIRawEvent(&in); + in.detail.button = ~0L; + test_XIRawEvent(&in); + + in.detail.button = 0; + + in.time = 1L; + test_XIRawEvent(&in); + in.time = 1L << 8; + test_XIRawEvent(&in); + in.time = 1L << 16; + test_XIRawEvent(&in); + in.time = 1L << 24; + test_XIRawEvent(&in); + in.time = ~0L; + test_XIRawEvent(&in); + + in.deviceid = 1; + test_XIRawEvent(&in); + in.deviceid = 1 << 8; + test_XIRawEvent(&in); + in.deviceid = ~0 & 0xFF; + test_XIRawEvent(&in); + + g_test_message("Testing valuator masks"); + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIRawEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < MAX_VALUATORS; i++) + { + XISetMask(in.valuators.mask, i); + + in.valuators.data[i] = i; + in.valuators.data_raw[i] = i + 10; + in.valuators.data_frac[i] = i + 20; + in.valuators.data_raw_frac[i] = i + 30; + test_XIRawEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIRawEvent(&in); + } +} + +static void test_values_XIDeviceEvent(DeviceEvent *in, xXIDeviceEvent *out, + BOOL swap) +{ + int buttons, valuators; + int i; + unsigned char *ptr; + uint32_t flagmask = 0; + FP3232 *values; + + if (swap) { + char n; + + swaps(&out->sequenceNumber, n); + swapl(&out->length, n); + swaps(&out->evtype, n); + swaps(&out->deviceid, n); + swaps(&out->sourceid, n); + swapl(&out->time, n); + swapl(&out->detail, n); + swapl(&out->root, n); + swapl(&out->event, n); + swapl(&out->child, n); + swapl(&out->root_x, n); + swapl(&out->root_y, n); + swapl(&out->event_x, n); + swapl(&out->event_y, n); + swaps(&out->buttons_len, n); + swaps(&out->valuators_len, n); + swapl(&out->mods.base_mods, n); + swapl(&out->mods.latched_mods, n); + swapl(&out->mods.locked_mods, n); + swapl(&out->mods.effective_mods, n); + swapl(&out->flags, n); + } + + g_assert(out->extension == 0); /* IReqCode defaults to 0 */ + g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); + g_assert(out->time == in->time); + g_assert(out->detail == in->detail.button); + g_assert(out->length >= 12); + + g_assert(out->deviceid == in->deviceid); + g_assert(out->sourceid == in->sourceid); + + switch (in->type) { + case ET_KeyPress: + flagmask = XIKeyRepeat; + break; + default: + flagmask = 0; + break; + } + g_assert((out->flags & ~flagmask) == 0); + + g_assert(out->root == in->root); + g_assert(out->event == None); /* set in FixUpEventFromWindow */ + g_assert(out->child == None); /* set in FixUpEventFromWindow */ + + g_assert(out->mods.base_mods == in->mods.base); + g_assert(out->mods.latched_mods == in->mods.latched); + g_assert(out->mods.locked_mods == in->mods.locked); + g_assert(out->mods.effective_mods == in->mods.effective); + + g_assert(out->group.base_group == in->group.base); + g_assert(out->group.latched_group == in->group.latched); + g_assert(out->group.locked_group == in->group.locked); + g_assert(out->group.effective_group == in->group.effective); + + g_assert(out->event_x == 0); /* set in FixUpEventFromWindow */ + g_assert(out->event_y == 0); /* set in FixUpEventFromWindow */ + + g_assert(out->root_x == FP1616(in->root_x, in->root_x_frac)); + g_assert(out->root_y == FP1616(in->root_y, in->root_y_frac)); + + buttons = 0; + for (i = 0; i < bits_to_bytes(sizeof(in->buttons)); i++) + { + if (XIMaskIsSet(in->buttons, i)) + { + g_assert(out->buttons_len >= bytes_to_int32(bits_to_bytes(i))); + buttons++; + } + } + + ptr = (unsigned char*)&out[1]; + for (i = 0; i < sizeof(in->buttons) * 8; i++) + g_assert(XIMaskIsSet(in->buttons, i) == XIMaskIsSet(ptr, i)); + + + valuators = 0; + for (i = 0; i < sizeof(in->valuators.mask) * 8; i++) + if (XIMaskIsSet(in->valuators.mask, i)) + valuators++; + + g_assert(out->valuators_len >= bytes_to_int32(bits_to_bytes(valuators))); + + ptr += out->buttons_len * 4; + values = (FP3232*)(ptr + out->valuators_len * 4); + for (i = 0; i < sizeof(in->valuators.mask) * 8 || + i < (out->valuators_len * 4) * 8; i++) + { + if (i > sizeof(in->valuators.mask) * 8) + g_assert(!XIMaskIsSet(ptr, i)); + else if (i > out->valuators_len * 4 * 8) + g_assert(!XIMaskIsSet(in->valuators.mask, i)); + else { + g_assert(XIMaskIsSet(in->valuators.mask, i) == + XIMaskIsSet(ptr, i)); + + if (XIMaskIsSet(ptr, i)) + { + FP3232 vi, vo; + + vi.integral = in->valuators.data[i]; + vi.frac = in->valuators.data_frac[i]; + + vo = *values; + + if (swap) + { + char n; + swapl(&vo.integral, n); + swapl(&vo.frac, n); + } + + + g_assert(vi.integral == vo.integral); + g_assert(vi.frac == vo.frac); + values++; + } + } + } +} + +static void test_XIDeviceEvent(DeviceEvent *in) +{ + xXIDeviceEvent *out, *swapped; + int rc; + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + g_assert(rc == Success); + + test_values_XIDeviceEvent(in, out, FALSE); + + swapped = calloc(1, sizeof(xEvent) + out->length * 4); + XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); + test_values_XIDeviceEvent(in, swapped, TRUE); + + free(out); + free(swapped); +} + +static void test_convert_XIDeviceEvent(void) +{ + DeviceEvent in; + int i; + + memset(&in, 0, sizeof(in)); + + g_test_message("Testing simple field values"); + in.header = ET_Internal; + in.type = ET_Motion; + in.length = sizeof(DeviceEvent); + in.time = 0; + in.deviceid = 1; + in.sourceid = 2; + in.root = 3; + in.root_x = 4; + in.root_x_frac = 5; + in.root_y = 6; + in.root_y_frac = 7; + in.detail.button = 8; + in.mods.base = 9; + in.mods.latched = 10; + in.mods.locked = 11; + in.mods.effective = 11; + in.group.base = 12; + in.group.latched = 13; + in.group.locked = 14; + in.group.effective = 15; + + test_XIDeviceEvent(&in); + + g_test_message("Testing field ranges"); + /* 32 bit */ + in.detail.button = 1L; + test_XIDeviceEvent(&in); + in.detail.button = 1L << 8; + test_XIDeviceEvent(&in); + in.detail.button = 1L << 16; + test_XIDeviceEvent(&in); + in.detail.button = 1L << 24; + test_XIDeviceEvent(&in); + in.detail.button = ~0L; + test_XIDeviceEvent(&in); + + /* 32 bit */ + in.time = 1L; + test_XIDeviceEvent(&in); + in.time = 1L << 8; + test_XIDeviceEvent(&in); + in.time = 1L << 16; + test_XIDeviceEvent(&in); + in.time = 1L << 24; + test_XIDeviceEvent(&in); + in.time = ~0L; + test_XIDeviceEvent(&in); + + /* 16 bit */ + in.deviceid = 1; + test_XIDeviceEvent(&in); + in.deviceid = 1 << 8; + test_XIDeviceEvent(&in); + in.deviceid = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + /* 16 bit */ + in.sourceid = 1; + test_XIDeviceEvent(&in); + in.deviceid = 1 << 8; + test_XIDeviceEvent(&in); + in.deviceid = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + /* 32 bit */ + in.root = 1L; + test_XIDeviceEvent(&in); + in.root = 1L << 8; + test_XIDeviceEvent(&in); + in.root = 1L << 16; + test_XIDeviceEvent(&in); + in.root = 1L << 24; + test_XIDeviceEvent(&in); + in.root = ~0L; + test_XIDeviceEvent(&in); + + /* 16 bit */ + in.root_x = 1; + test_XIDeviceEvent(&in); + in.root_x = 1 << 8; + test_XIDeviceEvent(&in); + in.root_x = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.root_x_frac = 1; + test_XIDeviceEvent(&in); + in.root_x_frac = 1 << 8; + test_XIDeviceEvent(&in); + in.root_x_frac = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.root_y = 1; + test_XIDeviceEvent(&in); + in.root_y = 1 << 8; + test_XIDeviceEvent(&in); + in.root_y = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.root_y_frac = 1; + test_XIDeviceEvent(&in); + in.root_y_frac = 1 << 8; + test_XIDeviceEvent(&in); + in.root_y_frac = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + /* 32 bit */ + in.mods.base = 1L; + test_XIDeviceEvent(&in); + in.mods.base = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.base = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.base = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.base = ~0L; + test_XIDeviceEvent(&in); + + in.mods.latched = 1L; + test_XIDeviceEvent(&in); + in.mods.latched = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.latched = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.latched = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.latched = ~0L; + test_XIDeviceEvent(&in); + + in.mods.locked = 1L; + test_XIDeviceEvent(&in); + in.mods.locked = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.locked = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.locked = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.locked = ~0L; + test_XIDeviceEvent(&in); + + in.mods.effective = 1L; + test_XIDeviceEvent(&in); + in.mods.effective = 1L << 8; + test_XIDeviceEvent(&in); + in.mods.effective = 1L << 16; + test_XIDeviceEvent(&in); + in.mods.effective = 1L << 24; + test_XIDeviceEvent(&in); + in.mods.effective = ~0L; + test_XIDeviceEvent(&in); + + /* 8 bit */ + in.group.base = 1; + test_XIDeviceEvent(&in); + in.group.base = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.group.latched = 1; + test_XIDeviceEvent(&in); + in.group.latched = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.group.locked = 1; + test_XIDeviceEvent(&in); + in.group.locked = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + in.mods.effective = 1; + test_XIDeviceEvent(&in); + in.mods.effective = ~0 & 0xFF; + test_XIDeviceEvent(&in); + + g_test_message("Testing button masks"); + for (i = 0; i < sizeof(in.buttons) * 8; i++) + { + XISetMask(in.buttons, i); + test_XIDeviceEvent(&in); + XIClearMask(in.buttons, i); + } + + for (i = 0; i < sizeof(in.buttons) * 8; i++) + { + XISetMask(in.buttons, i); + test_XIDeviceEvent(&in); + } + + g_test_message("Testing valuator masks"); + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIDeviceEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + + in.valuators.data[i] = i; + in.valuators.data_frac[i] = i + 20; + test_XIDeviceEvent(&in); + XIClearMask(in.valuators.mask, i); + } + + for (i = 0; i < sizeof(in.valuators.mask) * 8; i++) + { + XISetMask(in.valuators.mask, i); + test_XIDeviceEvent(&in); + } +} + +static void test_values_XIDeviceChangedEvent(DeviceChangedEvent *in, + xXIDeviceChangedEvent *out, + BOOL swap) +{ + int i, j; + unsigned char *ptr; + + if (swap) + { + char n; + + swaps(&out->sequenceNumber, n); + swapl(&out->length, n); + swaps(&out->evtype, n); + swaps(&out->deviceid, n); + swaps(&out->sourceid, n); + swapl(&out->time, n); + swaps(&out->num_classes, n); + } + + g_assert(out->type == GenericEvent); + g_assert(out->extension == 0); /* IReqCode defaults to 0 */ + g_assert(out->evtype == GetXI2Type((InternalEvent*)in)); + g_assert(out->time == in->time); + g_assert(out->deviceid == in->deviceid); + g_assert(out->sourceid == in->sourceid); + + ptr = (unsigned char*)&out[1]; + for (i = 0; i < out->num_classes; i++) + { + xXIAnyInfo* any = (xXIAnyInfo*)ptr; + + if (swap) + { + char n; + swaps(&any->length, n); + swaps(&any->type, n); + swaps(&any->sourceid, n); + } + + switch(any->type) + { + case XIButtonClass: + { + xXIButtonInfo *b = (xXIButtonInfo*)any; + Atom *names; + + if (swap) + { + char n; + swaps(&b->num_buttons, n); + } + + g_assert(b->length == + bytes_to_int32(sizeof(xXIButtonInfo)) + + bytes_to_int32(bits_to_bytes(b->num_buttons)) + + b->num_buttons); + g_assert(b->num_buttons == in->buttons.num_buttons); + + names = (Atom*)((char*)&b[1] + + pad_to_int32(bits_to_bytes(b->num_buttons))); + for (j = 0; j < b->num_buttons; j++) + { + if (swap) + { + char n; + swapl(&names[j], n); + } + g_assert(names[j] == in->buttons.names[j]); + } + } + break; + case XIKeyClass: + { + xXIKeyInfo *k = (xXIKeyInfo*)any; + uint32_t *kc; + + if (swap) + { + char n; + swaps(&k->num_keycodes, n); + } + + g_assert(k->length == + bytes_to_int32(sizeof(xXIKeyInfo)) + + k->num_keycodes); + g_assert(k->num_keycodes == in->keys.max_keycode - + in->keys.min_keycode + 1); + + kc = (uint32_t*)&k[1]; + for (j = 0; j < k->num_keycodes; j++) + { + if (swap) + { + char n; + swapl(&kc[j], n); + } + g_assert(kc[j] >= in->keys.min_keycode); + g_assert(kc[j] <= in->keys.max_keycode); + } + } + break; + case XIValuatorClass: + { + xXIValuatorInfo *v = (xXIValuatorInfo*)any; + g_assert(v->length == + bytes_to_int32(sizeof(xXIValuatorInfo))); + + } + break; + default: + g_error("Invalid class type.\n"); + break; + } + + ptr += any->length * 4; + } + +} + +static void test_XIDeviceChangedEvent(DeviceChangedEvent *in) +{ + xXIDeviceChangedEvent *out, *swapped; + int rc; + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + g_assert(rc == Success); + + test_values_XIDeviceChangedEvent(in, out, FALSE); + + swapped = calloc(1, sizeof(xEvent) + out->length * 4); + XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped); + test_values_XIDeviceChangedEvent(in, swapped, TRUE); + + free(out); + free(swapped); +} + +static void test_convert_XIDeviceChangedEvent(void) +{ + DeviceChangedEvent in; + int i; + + g_test_message("Testing simple field values"); + memset(&in, 0, sizeof(in)); + in.header = ET_Internal; + in.type = ET_DeviceChanged; + in.length = sizeof(DeviceChangedEvent); + in.time = 0; + in.deviceid = 1; + in.sourceid = 2; + in.masterid = 3; + in.num_valuators = 4; + in.flags = DEVCHANGE_SLAVE_SWITCH | DEVCHANGE_POINTER_EVENT | DEVCHANGE_KEYBOARD_EVENT; + + for (i = 0; i < MAX_BUTTONS; i++) + in.buttons.names[i] = i + 10; + + in.keys.min_keycode = 8; + in.keys.max_keycode = 255; + + test_XIDeviceChangedEvent(&in); + + in.time = 1L; + test_XIDeviceChangedEvent(&in); + in.time = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.time = 1L << 16; + test_XIDeviceChangedEvent(&in); + in.time = 1L << 24; + test_XIDeviceChangedEvent(&in); + in.time = ~0L; + test_XIDeviceChangedEvent(&in); + + in.deviceid = 1L; + test_XIDeviceChangedEvent(&in); + in.deviceid = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.deviceid = ~0 & 0xFFFF; + test_XIDeviceChangedEvent(&in); + + in.sourceid = 1L; + test_XIDeviceChangedEvent(&in); + in.sourceid = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.sourceid = ~0 & 0xFFFF; + test_XIDeviceChangedEvent(&in); + + in.masterid = 1L; + test_XIDeviceChangedEvent(&in); + in.masterid = 1L << 8; + test_XIDeviceChangedEvent(&in); + in.masterid = ~0 & 0xFFFF; + test_XIDeviceChangedEvent(&in); + + in.buttons.num_buttons = 0; + test_XIDeviceChangedEvent(&in); + + in.buttons.num_buttons = 1; + test_XIDeviceChangedEvent(&in); + + in.buttons.num_buttons = MAX_BUTTONS; + test_XIDeviceChangedEvent(&in); + + in.keys.min_keycode = 0; + in.keys.max_keycode = 0; + test_XIDeviceChangedEvent(&in); + + in.keys.max_keycode = 1 << 8; + test_XIDeviceChangedEvent(&in); + + in.keys.max_keycode = 0xFFFC; /* highest range, above that the length + field gives up */ + test_XIDeviceChangedEvent(&in); + + in.keys.min_keycode = 1 << 8; + in.keys.max_keycode = 1 << 8; + test_XIDeviceChangedEvent(&in); + + in.keys.min_keycode = 1 << 8; + in.keys.max_keycode = 0; + test_XIDeviceChangedEvent(&in); + + in.num_valuators = 0; + test_XIDeviceChangedEvent(&in); + + in.num_valuators = 1; + test_XIDeviceChangedEvent(&in); + + in.num_valuators = MAX_VALUATORS; + test_XIDeviceChangedEvent(&in); + + for (i = 0; i < MAX_VALUATORS; i++) + { + in.valuators[i].min = 0; + in.valuators[i].max = 0; + test_XIDeviceChangedEvent(&in); + + in.valuators[i].max = 1 << 8; + test_XIDeviceChangedEvent(&in); + in.valuators[i].max = 1 << 16; + test_XIDeviceChangedEvent(&in); + in.valuators[i].max = 1 << 24; + test_XIDeviceChangedEvent(&in); + in.valuators[i].max = abs(~0); + test_XIDeviceChangedEvent(&in); + + in.valuators[i].resolution = 1 << 8; + test_XIDeviceChangedEvent(&in); + in.valuators[i].resolution = 1 << 16; + test_XIDeviceChangedEvent(&in); + in.valuators[i].resolution = 1 << 24; + test_XIDeviceChangedEvent(&in); + in.valuators[i].resolution = abs(~0); + test_XIDeviceChangedEvent(&in); + + in.valuators[i].name = i; + test_XIDeviceChangedEvent(&in); + + in.valuators[i].mode = Relative; + test_XIDeviceChangedEvent(&in); + + in.valuators[i].mode = Absolute; + test_XIDeviceChangedEvent(&in); + } +} + +int main(int argc, char** argv) +{ + g_test_init(&argc, &argv,NULL); + g_test_bug_base("https://bugzilla.freedesktop.org/show_bug.cgi?id="); + + g_test_add_func("/xi2/eventconvert/XIRawEvent", test_convert_XIRawEvent); + g_test_add_func("/xi2/eventconvert/XIFocusEvent", test_convert_XIFocusEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceEvent", test_convert_XIDeviceEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceChangedEvent", test_convert_XIDeviceChangedEvent); + + return g_test_run(); +} diff --git a/xorg-server/test/xi2/protocol-xiselectevents.c b/xorg-server/test/xi2/protocol-xiselectevents.c index fe1c26df8..f951a14fe 100644 --- a/xorg-server/test/xi2/protocol-xiselectevents.c +++ b/xorg-server/test/xi2/protocol-xiselectevents.c @@ -131,7 +131,7 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req) { int i, j; xXIEventMask *mask; - int nmasks = (XI_LASTEVENT + 7)/8; + int nmasks = (XI2LASTEVENT + 7)/8; unsigned char *bits; mask = (xXIEventMask*)&req[1]; @@ -150,14 +150,14 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req) request_XISelectEvent(req, Success); /* Test 1: - * mask may be larger than needed for XI_LASTEVENT. + * mask may be larger than needed for XI2LASTEVENT. * Test setting each valid mask bit, while leaving unneeded bits 0. * -> Success */ bits = (unsigned char*)&mask[1]; mask->mask_len = (nmasks + 3)/4 * 10; memset(bits, 0, mask->mask_len * 4); - for (j = 0; j <= XI_LASTEVENT; j++) + for (j = 0; j <= XI2LASTEVENT; j++) { SetBit(bits, j); request_XISelectEvent(req, Success); @@ -165,7 +165,7 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req) } /* Test 2: - * mask may be larger than needed for XI_LASTEVENT. + * mask may be larger than needed for XI2LASTEVENT. * Test setting all valid mask bits, while leaving unneeded bits 0. * -> Success */ @@ -173,21 +173,21 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req) mask->mask_len = (nmasks + 3)/4 * 10; memset(bits, 0, mask->mask_len * 4); - for (j = 0; j <= XI_LASTEVENT; j++) + for (j = 0; j <= XI2LASTEVENT; j++) { SetBit(bits, j); request_XISelectEvent(req, Success); } /* Test 3: - * mask is larger than needed for XI_LASTEVENT. If any unneeded bit + * mask is larger than needed for XI2LASTEVENT. If any unneeded bit * is set -> BadValue */ bits = (unsigned char*)&mask[1]; mask->mask_len = (nmasks + 3)/4 * 10; memset(bits, 0, mask->mask_len * 4); - for (j = XI_LASTEVENT + 1; j < mask->mask_len * 4; j++) + for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++) { SetBit(bits, j); request_XISelectEvent(req, BadValue); @@ -200,7 +200,7 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req) bits = (unsigned char*)&mask[1]; mask->mask_len = (nmasks + 3)/4; memset(bits, 0, mask->mask_len * 4); - for (j = 0; j <= XI_LASTEVENT; j++) + for (j = 0; j <= XI2LASTEVENT; j++) { SetBit(bits, j); request_XISelectEvent(req, Success); @@ -228,7 +228,7 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req) bits = (unsigned char*)&mask[1]; mask->mask_len = (nmasks + 3)/4; memset(bits, 0, mask->mask_len * 4); - for (j = 0; j <= XI_LASTEVENT; j++) + for (j = 0; j <= XI2LASTEVENT; j++) SetBit(bits, j); ClearBit(bits, XI_HierarchyChanged); for (j = 1; j < 6; j++) diff --git a/xorg-server/xkb/XKBMisc.c b/xorg-server/xkb/XKBMisc.c index f983466ea..96688be18 100644 --- a/xorg-server/xkb/XKBMisc.c +++ b/xorg-server/xkb/XKBMisc.c @@ -1,839 +1,840 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -Permission to use, copy, modify, and distribute this -software and its documentation for any purpose and without -fee is hereby granted, 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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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. - -********************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#elif defined(HAVE_CONFIG_H) -#include -#endif - -#include -#include -#include -#include "misc.h" -#include "inputstr.h" -#include -#define XKBSRV_NEED_FILE_FUNCS -#include - -/***====================================================================***/ - -#define CORE_SYM(i) (imap->num_types)) { - nSyms[i]= xkb->map->types[types_inout[i]].num_levels; - if (nSyms[i]>groupsWidth) - groupsWidth= nSyms[i]; - } - else { - types_inout[i]= XkbTwoLevelIndex; /* don't really know, yet */ - nSyms[i]= 2; - } - } - if (nSyms[XkbGroup1Index]<2) - nSyms[XkbGroup1Index]= 2; - if (nSyms[XkbGroup2Index]<2) - nSyms[XkbGroup2Index]= 2; - /* Step 2: Copy the symbols from the core ordering to XKB ordering */ - /* symbols in the core are in the order: */ - /* G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */ - xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0); - xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1); - for (i=2;i 0 && CORE_SYM(0) != CORE_SYM(2)) || - (width > 1 && CORE_SYM(1) != CORE_SYM(3))) - replicated = FALSE; - - /* Check CDECDE in ABABCDECDEABCDE */ - for (i = 2; i < width && replicated; i++) - { - if (CORE_SYM(2 + i) != CORE_SYM(i + width)) - replicated = FALSE; - } - - /* Check ABCDE in ABABCDECDEABCDE */ - for (j = 2; replicated && - j < XkbNumKbdGroups && - map_width >= width * (j + 1); j++) - { - for (i = 0; i < width && replicated; i++) - { - if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j)) - replicated = FALSE; - } - } - } - - if (replicated) - { - nSyms[XkbGroup2Index]= 0; - nSyms[XkbGroup3Index]= 0; - nSyms[XkbGroup4Index]= 0; - nGroups= 1; - } else - { - tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index]; - if ((tmp>=map_width)&& - ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) { - nSyms[XkbGroup3Index]= 0; - nSyms[XkbGroup4Index]= 0; - nGroups= 2; - } else - { - nGroups= 3; - for (i=0;i1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) { - KeySym upper,lower; - XkbConvertCase(syms[0],&lower,&upper); - if (upper!=lower) { - xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower; - xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper; - if ((protected&(1<=0;i--) { - if (((empty&(1<1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) { - if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) { - nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index]; - types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index]; - memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn, - 2*sizeof(KeySym)); - } - else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) { - memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]], - (char *)xkb_syms_rtrn, - nSyms[XkbGroup1Index]*sizeof(KeySym)); - } - } - - /* step 7: check for all groups identical or all width 1 - * - * Special feature: if group 1 has an explicit type and all other groups - * have canonical types with same symbols, we assume it's info lost from - * the core replication. - */ - if (nGroups>1) { - Bool sameType,allOneLevel, canonical = TRUE; - allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1); - for (i=1,sameType=TRUE;(allOneLevel||sameType)&&(imap->types[types_inout[i]].num_levels==1); - if (types_inout[i] > XkbLastRequiredType) - canonical = FALSE; - } - if (((sameType) || canonical)&& - (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){ - register int s; - Bool identical; - for (i=1,identical=TRUE;identical&&(i1)) { - KeySym *syms; - syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]]; - nSyms[XkbGroup1Index]= 1; - for (i=1;icompat->sym_interpret; - for (i=0;icompat->num_si;i++,interp++) { - if ((interp->sym==NoSymbol)||(sym==interp->sym)) { - int match; - if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0)) - mods= real_mods; - else mods= 0; - switch (interp->match&XkbSI_OpMask) { - case XkbSI_NoneOf: - match= ((interp->mods&mods)==0); - break; - case XkbSI_AnyOfOrNone: - match= ((mods==0)||((interp->mods&mods)!=0)); - break; - case XkbSI_AnyOf: - match= ((interp->mods&mods)!=0); - break; - case XkbSI_AllOf: - match= ((interp->mods&mods)==interp->mods); - break; - case XkbSI_Exactly: - match= (interp->mods==mods); - break; - default: - match= 0; - break; - } - if (match) { - if (interp->sym!=NoSymbol) { - return interp; - } - else if (rtrn==NULL) { - rtrn= interp; - } - } - } - } - return rtrn; -} - -static void -_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey) -{ -KeyCode last; - - last= (*pFirst)+(*pNum); - if (newKey<*pFirst) { - *pFirst= newKey; - *pNum= (last-newKey)+1; - } - else if (newKey>last) { - *pNum= (last-*pFirst)+1; - } - return; -} - -static void -_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) -{ -unsigned tmp; - - switch (act->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: - if (act->mods.flags&XkbSA_UseModMapMods) - act->mods.real_mods= act->mods.mask= mods; - if ((tmp= XkbModActionVMods(&act->mods))!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->mods.mask|= tmp; - } - break; - case XkbSA_ISOLock: - if (act->iso.flags&XkbSA_UseModMapMods) - act->iso.real_mods= act->iso.mask= mods; - if ((tmp= XkbModActionVMods(&act->iso))!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->iso.mask|= tmp; - } - break; - } - return; -} - -#define IBUF_SIZE 8 - -Bool -XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes) -{ -KeySym * syms; -unsigned char explicit,mods; -XkbSymInterpretPtr *interps,ibuf[IBUF_SIZE]; -int n,nSyms,found; -unsigned changed,tmp; - - if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)|| - (!xkb->compat)||(!xkb->compat->sym_interpret)|| - (keymin_key_code)||(key>xkb->max_key_code)) { - return FALSE; - } - if (((!xkb->server)||(!xkb->server->key_acts))&& - (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) { - return FALSE; - } - changed= 0; /* keeps track of what has changed in _this_ call */ - explicit= xkb->server->explicit[key]; - if (explicit&XkbExplicitInterpretMask) /* nothing to do */ - return TRUE; - mods= (xkb->map->modmap?xkb->map->modmap[key]:0); - nSyms= XkbKeyNumSyms(xkb,key); - syms= XkbKeySymsPtr(xkb,key); - if (nSyms>IBUF_SIZE) { - interps= calloc(nSyms, sizeof(XkbSymInterpretPtr)); - if (interps==NULL) { - interps= ibuf; - nSyms= IBUF_SIZE; - } - } - else { - interps= ibuf; - } - found= 0; - for (n=0;nact.type!=XkbSA_NoAction) - found++; - else interps[n]= NULL; - } - } - /* 1/28/96 (ef) -- XXX! WORKING HERE */ - if (!found) { - if (xkb->server->key_acts[key]!=0) { - xkb->server->key_acts[key]= 0; - changed|= XkbKeyActionsMask; - } - } - else { - XkbAction *pActs; - unsigned int new_vmodmask; - changed|= XkbKeyActionsMask; - pActs= XkbResizeKeyActions(xkb,key,nSyms); - if (!pActs) { - if (nSyms > IBUF_SIZE) - free(interps); - return FALSE; - } - new_vmodmask= 0; - for (n=0;nact); - if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) { - effMods= mods; - if (interps[n]->virtual_mod!=XkbNoModifier) - new_vmodmask|= (1<virtual_mod); - } - else effMods= 0; - _XkbSetActionKeyMods(xkb,&pActs[n],effMods); - } - else pActs[n].type= XkbSA_NoAction; - } - if (((explicit&XkbExplicitVModMapMask)==0)&& - (xkb->server->vmodmap[key]!=new_vmodmask)) { - changed|= XkbVirtualModMapMask; - xkb->server->vmodmap[key]= new_vmodmask; - } - if (interps[0]) { - if ((interps[0]->flags&XkbSI_LockingKey)&& - ((explicit&XkbExplicitBehaviorMask)==0)) { - xkb->server->behaviors[key].type= XkbKB_Lock; - changed|= XkbKeyBehaviorsMask; - } - if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { - CARD8 old; - old= xkb->ctrls->per_key_repeat[key/8]; - if (interps[0]->flags&XkbSI_AutoRepeat) - xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8)); - else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8)); - if (changes && (old!=xkb->ctrls->per_key_repeat[key/8])) - changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; - } - } - } - if ((!found)||(interps[0]==NULL)) { - if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { - CARD8 old; - old= xkb->ctrls->per_key_repeat[key/8]; - xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8)); - if (changes && (old!=xkb->ctrls->per_key_repeat[key/8])) - changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; - } - if (((explicit&XkbExplicitBehaviorMask)==0)&& - (xkb->server->behaviors[key].type==XkbKB_Lock)) { - xkb->server->behaviors[key].type= XkbKB_Default; - changed|= XkbKeyBehaviorsMask; - } - } - if (changes) { - XkbMapChangesPtr mc; - mc= &changes->map; - tmp= (changed&mc->changed); - if (tmp&XkbKeyActionsMask) - _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key); - else if (changed&XkbKeyActionsMask) { - mc->changed|= XkbKeyActionsMask; - mc->first_key_act= key; - mc->num_key_acts= 1; - } - if (tmp&XkbKeyBehaviorsMask) { - _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors, - key); - } - else if (changed&XkbKeyBehaviorsMask) { - mc->changed|= XkbKeyBehaviorsMask; - mc->first_key_behavior= key; - mc->num_key_behaviors= 1; - } - if (tmp&XkbVirtualModMapMask) - _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key); - else if (changed&XkbVirtualModMapMask) { - mc->changed|= XkbVirtualModMapMask; - mc->first_vmodmap_key= key; - mc->num_vmodmap_keys= 1; - } - mc->changed|= changed; - } - if (interps!=ibuf) - free(interps); - return TRUE; -} - -Status -XkbChangeTypesOfKey( XkbDescPtr xkb, - int key, - int nGroups, - unsigned groups, - int * newTypesIn, - XkbMapChangesPtr changes) -{ -XkbKeyTypePtr pOldType,pNewType; -register int i; -int width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups]; - - if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) || - (!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)|| - (nGroups>XkbNumKbdGroups)) { - return BadMatch; - } - if (nGroups==0) { - for (i=0;imap->key_sym_map[key].kt_index[i]= XkbOneLevelIndex; - } - i= xkb->map->key_sym_map[key].group_info; - i= XkbSetNumGroups(i,0); - xkb->map->key_sym_map[key].group_info= i; - XkbResizeKeySyms(xkb,key,0); - return Success; - } - - nOldGroups= XkbKeyNumGroups(xkb,key); - oldWidth= XkbKeyGroupsWidth(xkb,key); - for (width=i=0;i0) - newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); - else newTypes[i]= XkbTwoLevelIndex; - if (newTypes[i]>xkb->map->num_types) - return BadMatch; - pNewType= &xkb->map->types[newTypes[i]]; - if (pNewType->num_levels>width) - width= pNewType->num_levels; - } - if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups)) - xkb->ctrls->num_groups= nGroups; - if ((width!=oldWidth)||(nGroups!=nOldGroups)) { - KeySym oldSyms[XkbMaxSymsPerKey],*pSyms; - int nCopy; - - if (nOldGroups==0) { - pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); - if (pSyms!=NULL) { - i= xkb->map->key_sym_map[key].group_info; - i= XkbSetNumGroups(i,nGroups); - xkb->map->key_sym_map[key].group_info= i; - xkb->map->key_sym_map[key].width= width; - for (i=0;imap->key_sym_map[key].kt_index[i]= newTypes[i]; - } - return Success; - } - return BadAlloc; - } - pSyms= XkbKeySymsPtr(xkb,key); - memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); - pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); - if (pSyms==NULL) - return BadAlloc; - memset(pSyms, 0, width*nGroups*sizeof(KeySym)); - for (i=0;(imap->types[newTypes[i]]; - if (pNewType->num_levels>pOldType->num_levels) - nCopy= pOldType->num_levels; - else nCopy= pNewType->num_levels; - memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym)); - } - if (XkbKeyHasActions(xkb,key)) { - XkbAction oldActs[XkbMaxSymsPerKey],*pActs; - pActs= XkbKeyActionsPtr(xkb,key); - memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction)); - pActs= XkbResizeKeyActions(xkb,key,width*nGroups); - if (pActs==NULL) - return BadAlloc; - memset(pActs, 0, width*nGroups*sizeof(XkbAction)); - for (i=0;(imap->types[newTypes[i]]; - if (pNewType->num_levels>pOldType->num_levels) - nCopy= pOldType->num_levels; - else nCopy= pNewType->num_levels; - memcpy(&pActs[i*width],&oldActs[i*oldWidth], - nCopy*sizeof(XkbAction)); - } - } - i= xkb->map->key_sym_map[key].group_info; - i= XkbSetNumGroups(i,nGroups); - xkb->map->key_sym_map[key].group_info= i; - xkb->map->key_sym_map[key].width= width; - } - width= 0; - for (i=0;imap->key_sym_map[key].kt_index[i]= newTypes[i]; - if (xkb->map->types[newTypes[i]].num_levels>width) - width= xkb->map->types[newTypes[i]].num_levels; - } - xkb->map->key_sym_map[key].width= width; - if (changes!=NULL) { - if (changes->changed&XkbKeySymsMask) { - _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms, - key); - } - else { - changes->changed|= XkbKeySymsMask; - changes->first_key_sym= key; - changes->num_key_syms= 1; - } - } - return Success; -} - -/***====================================================================***/ - -Bool -XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn) -{ -register int i,bit; -register unsigned mask; - - if (xkb==NULL) - return FALSE; - if (virtual_mask==0) { - *mask_rtrn= 0; - return TRUE; - } - if (xkb->server==NULL) - return FALSE; - for (i=mask=0,bit=1;iserver->vmods[i]; - } - *mask_rtrn= mask; - return TRUE; -} - -/***====================================================================***/ - -static Bool -XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed) -{ -unsigned int tmp; - - switch (act->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: - if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->mods.mask= act->mods.real_mods; - act->mods.mask|= tmp; - return TRUE; - } - break; - case XkbSA_ISOLock: - if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) { - XkbVirtualModsToReal(xkb,tmp,&tmp); - act->iso.mask= act->iso.real_mods; - act->iso.mask|= tmp; - return TRUE; - } - break; - } - return FALSE; -} - -static void -XkbUpdateKeyTypeVirtualMods( XkbDescPtr xkb, - XkbKeyTypePtr type, - unsigned int changed, - XkbChangesPtr changes) -{ -register unsigned int i; -unsigned int mask; - - XkbVirtualModsToReal(xkb,type->mods.vmods,&mask); - type->mods.mask= type->mods.real_mods|mask; - if ((type->map_count>0)&&(type->mods.vmods!=0)) { - XkbKTMapEntryPtr entry; - for (i=0,entry=type->map;imap_count;i++,entry++) { - if (entry->mods.vmods!=0) { - XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask); - entry->mods.mask=entry->mods.real_mods|mask; - /* entry is active if vmods are bound*/ - entry->active= (mask!=0); - } - else entry->active= 1; - } - } - if (changes) { - int type_ndx; - type_ndx= type-xkb->map->types; - if ((type_ndx<0)||(type_ndx>xkb->map->num_types)) - return; - if (changes->map.changed&XkbKeyTypesMask) { - int last; - last= changes->map.first_type+changes->map.num_types-1; - if (type_ndxmap.first_type) { - changes->map.first_type= type_ndx; - changes->map.num_types= (last-type_ndx)+1; - } - else if (type_ndx>last) { - changes->map.num_types= (type_ndx-changes->map.first_type)+1; - } - } - else { - changes->map.changed|= XkbKeyTypesMask; - changes->map.first_type= type_ndx; - changes->map.num_types= 1; - } - } - return; -} - -Bool -XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes) -{ -register int i; -unsigned int checkState = 0; - - if ((!xkb) || (!xkb->map) || (changed==0)) - return FALSE; - for (i=0;imap->num_types;i++) { - if (xkb->map->types[i].mods.vmods & changed) - XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes); - } - if (changed&xkb->ctrls->internal.vmods) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask); - newMask|= xkb->ctrls->internal.real_mods; - if (xkb->ctrls->internal.mask!=newMask) { - xkb->ctrls->internal.mask= newMask; - if (changes) { - changes->ctrls.changed_ctrls|= XkbInternalModsMask; - checkState= TRUE; - } - } - } - if (changed&xkb->ctrls->ignore_lock.vmods) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask); - newMask|= xkb->ctrls->ignore_lock.real_mods; - if (xkb->ctrls->ignore_lock.mask!=newMask) { - xkb->ctrls->ignore_lock.mask= newMask; - if (changes) { - changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask; - checkState= TRUE; - } - } - } - if (xkb->indicators!=NULL) { - XkbIndicatorMapPtr map; - map= &xkb->indicators->maps[0]; - for (i=0;imods.vmods&changed) { - unsigned int newMask; - XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask); - newMask|= map->mods.real_mods; - if (newMask!=map->mods.mask) { - map->mods.mask= newMask; - if (changes) { - changes->indicators.map_changes|= (1<compat!=NULL) { - XkbCompatMapPtr compat; - compat= xkb->compat; - for (i=0;igroups[i].vmods,&newMask); - newMask|= compat->groups[i].real_mods; - if (compat->groups[i].mask!=newMask) { - compat->groups[i].mask= newMask; - if (changes) { - changes->compat.changed_groups|= (1<map && xkb->server) { - int highChange = 0, lowChange = -1; - for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { - if (XkbKeyHasActions(xkb,i)) { - register XkbAction *pAct; - register int n; - - pAct= XkbKeyActionsPtr(xkb,i); - for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) { - if ((pAct->type!=XkbSA_NoAction)&& - XkbUpdateActionVirtualMods(xkb,pAct,changed)) { - if (lowChange<0) - lowChange= i; - highChange= i; - } - } - } - } - if (changes && (lowChange>0)) { /* something changed */ - if (changes->map.changed&XkbKeyActionsMask) { - int last; - if (changes->map.first_key_actmap.first_key_act; - last= changes->map.first_key_act+changes->map.num_key_acts-1; - if (last>highChange) - highChange= last; - } - changes->map.changed|= XkbKeyActionsMask; - changes->map.first_key_act= lowChange; - changes->map.num_key_acts= (highChange-lowChange)+1; - } - } - return checkState; -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, 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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#elif defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include +#include +#include "misc.h" +#include "inputstr.h" +#include +#define XKBSRV_NEED_FILE_FUNCS +#include + +/***====================================================================***/ + +#define CORE_SYM(i) (imap->num_types)) { + nSyms[i]= xkb->map->types[types_inout[i]].num_levels; + if (nSyms[i]>groupsWidth) + groupsWidth= nSyms[i]; + } + else { + types_inout[i]= XkbTwoLevelIndex; /* don't really know, yet */ + nSyms[i]= 2; + } + } + if (nSyms[XkbGroup1Index]<2) + nSyms[XkbGroup1Index]= 2; + if (nSyms[XkbGroup2Index]<2) + nSyms[XkbGroup2Index]= 2; + /* Step 2: Copy the symbols from the core ordering to XKB ordering */ + /* symbols in the core are in the order: */ + /* G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */ + xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0); + xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1); + for (i=2;i 0 && CORE_SYM(0) != CORE_SYM(2)) || + (width > 1 && CORE_SYM(1) != CORE_SYM(3))) + replicated = FALSE; + + /* Check CDECDE in ABABCDECDEABCDE */ + for (i = 2; i < width && replicated; i++) + { + if (CORE_SYM(2 + i) != CORE_SYM(i + width)) + replicated = FALSE; + } + + /* Check ABCDE in ABABCDECDEABCDE */ + for (j = 2; replicated && + j < XkbNumKbdGroups && + map_width >= width * (j + 1); j++) + { + for (i = 0; i < width && replicated; i++) + { + if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j)) + replicated = FALSE; + } + } + } + + if (replicated) + { + nSyms[XkbGroup2Index]= 0; + nSyms[XkbGroup3Index]= 0; + nSyms[XkbGroup4Index]= 0; + nGroups= 1; + } else + { + tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index]; + if ((tmp>=map_width)&& + ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) { + nSyms[XkbGroup3Index]= 0; + nSyms[XkbGroup4Index]= 0; + nGroups= 2; + } else + { + nGroups= 3; + for (i=0;i1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) { + KeySym upper,lower; + XkbConvertCase(syms[0],&lower,&upper); + if (upper!=lower) { + xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower; + xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper; + if ((protected&(1<=0;i--) { + if (((empty&(1<1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) { + if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) { + nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index]; + types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index]; + memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn, + 2*sizeof(KeySym)); + } + else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) { + memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]], + (char *)xkb_syms_rtrn, + nSyms[XkbGroup1Index]*sizeof(KeySym)); + } + } + + /* step 7: check for all groups identical or all width 1 + * + * Special feature: if group 1 has an explicit type and all other groups + * have canonical types with same symbols, we assume it's info lost from + * the core replication. + */ + if (nGroups>1) { + Bool sameType,allOneLevel, canonical = TRUE; + allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1); + for (i=1,sameType=TRUE;(allOneLevel||sameType)&&(imap->types[types_inout[i]].num_levels==1); + if (types_inout[i] > XkbLastRequiredType) + canonical = FALSE; + } + if (((sameType) || canonical)&& + (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){ + register int s; + Bool identical; + for (i=1,identical=TRUE;identical&&(i1)) { + KeySym *syms; + syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]]; + nSyms[XkbGroup1Index]= 1; + for (i=1;icompat->sym_interpret; + for (i=0;icompat->num_si;i++,interp++) { + if ((interp->sym==NoSymbol)||(sym==interp->sym)) { + int match; + if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0)) + mods= real_mods; + else mods= 0; + switch (interp->match&XkbSI_OpMask) { + case XkbSI_NoneOf: + match= ((interp->mods&mods)==0); + break; + case XkbSI_AnyOfOrNone: + match= ((mods==0)||((interp->mods&mods)!=0)); + break; + case XkbSI_AnyOf: + match= ((interp->mods&mods)!=0); + break; + case XkbSI_AllOf: + match= ((interp->mods&mods)==interp->mods); + break; + case XkbSI_Exactly: + match= (interp->mods==mods); + break; + default: + match= 0; + break; + } + if (match) { + if (interp->sym!=NoSymbol) { + return interp; + } + else if (rtrn==NULL) { + rtrn= interp; + } + } + } + } + return rtrn; +} + +static void +_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey) +{ +KeyCode last; + + last= (*pFirst)+(*pNum); + if (newKey<*pFirst) { + *pFirst= newKey; + *pNum= (last-newKey)+1; + } + else if (newKey>last) { + *pNum= (last-*pFirst)+1; + } + return; +} + +static void +_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) +{ +unsigned tmp; + + switch (act->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: + if (act->mods.flags&XkbSA_UseModMapMods) + act->mods.real_mods= act->mods.mask= mods; + if ((tmp= XkbModActionVMods(&act->mods))!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->mods.mask|= tmp; + } + break; + case XkbSA_ISOLock: + if (act->iso.flags&XkbSA_UseModMapMods) + act->iso.real_mods= act->iso.mask= mods; + if ((tmp= XkbModActionVMods(&act->iso))!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->iso.mask|= tmp; + } + break; + } + return; +} + +#define IBUF_SIZE 8 + +Bool +XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes) +{ +KeySym * syms; +unsigned char explicit,mods; +XkbSymInterpretPtr *interps,ibuf[IBUF_SIZE]; +int n,nSyms,found; +unsigned changed,tmp; + + if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)|| + (!xkb->compat)||(!xkb->compat->sym_interpret)|| + (keymin_key_code)||(key>xkb->max_key_code)) { + return FALSE; + } + if (((!xkb->server)||(!xkb->server->key_acts))&& + (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) { + return FALSE; + } + changed= 0; /* keeps track of what has changed in _this_ call */ + explicit= xkb->server->explicit[key]; + if (explicit&XkbExplicitInterpretMask) /* nothing to do */ + return TRUE; + mods= (xkb->map->modmap?xkb->map->modmap[key]:0); + nSyms= XkbKeyNumSyms(xkb,key); + syms= XkbKeySymsPtr(xkb,key); + if (nSyms>IBUF_SIZE) { + interps= calloc(nSyms, sizeof(XkbSymInterpretPtr)); + if (interps==NULL) { + interps= ibuf; + nSyms= IBUF_SIZE; + } + } + else { + interps= ibuf; + } + found= 0; + for (n=0;nact.type!=XkbSA_NoAction) + found++; + else interps[n]= NULL; + } + } + /* 1/28/96 (ef) -- XXX! WORKING HERE */ + if (!found) { + if (xkb->server->key_acts[key]!=0) { + xkb->server->key_acts[key]= 0; + changed|= XkbKeyActionsMask; + } + } + else { + XkbAction *pActs; + unsigned int new_vmodmask; + changed|= XkbKeyActionsMask; + pActs= XkbResizeKeyActions(xkb,key,nSyms); + if (!pActs) { + if (nSyms > IBUF_SIZE) + free(interps); + return FALSE; + } + new_vmodmask= 0; + for (n=0;nact); + if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) { + effMods= mods; + if (interps[n]->virtual_mod!=XkbNoModifier) + new_vmodmask|= (1<virtual_mod); + } + else effMods= 0; + _XkbSetActionKeyMods(xkb,&pActs[n],effMods); + } + else pActs[n].type= XkbSA_NoAction; + } + if (((explicit&XkbExplicitVModMapMask)==0)&& + (xkb->server->vmodmap[key]!=new_vmodmask)) { + changed|= XkbVirtualModMapMask; + xkb->server->vmodmap[key]= new_vmodmask; + } + if (interps[0]) { + if ((interps[0]->flags&XkbSI_LockingKey)&& + ((explicit&XkbExplicitBehaviorMask)==0)) { + xkb->server->behaviors[key].type= XkbKB_Lock; + changed|= XkbKeyBehaviorsMask; + } + if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { + CARD8 old; + old= BitIsOn(xkb->ctrls->per_key_repeat, key); + if (interps[0]->flags&XkbSI_AutoRepeat) + SetBit(xkb->ctrls->per_key_repeat, key); + else + ClearBit(xkb->ctrls->per_key_repeat, key); + if (changes && old != BitIsOn(xkb->ctrls->per_key_repeat, key)) + changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; + } + } + } + if ((!found)||(interps[0]==NULL)) { + if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) { + CARD8 old; + old = BitIsOn(xkb->ctrls->per_key_repeat, key); + SetBit(xkb->ctrls->per_key_repeat, key); + if (changes && (old != BitIsOn(xkb->ctrls->per_key_repeat, key))) + changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask; + } + if (((explicit&XkbExplicitBehaviorMask)==0)&& + (xkb->server->behaviors[key].type==XkbKB_Lock)) { + xkb->server->behaviors[key].type= XkbKB_Default; + changed|= XkbKeyBehaviorsMask; + } + } + if (changes) { + XkbMapChangesPtr mc; + mc= &changes->map; + tmp= (changed&mc->changed); + if (tmp&XkbKeyActionsMask) + _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key); + else if (changed&XkbKeyActionsMask) { + mc->changed|= XkbKeyActionsMask; + mc->first_key_act= key; + mc->num_key_acts= 1; + } + if (tmp&XkbKeyBehaviorsMask) { + _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors, + key); + } + else if (changed&XkbKeyBehaviorsMask) { + mc->changed|= XkbKeyBehaviorsMask; + mc->first_key_behavior= key; + mc->num_key_behaviors= 1; + } + if (tmp&XkbVirtualModMapMask) + _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key); + else if (changed&XkbVirtualModMapMask) { + mc->changed|= XkbVirtualModMapMask; + mc->first_vmodmap_key= key; + mc->num_vmodmap_keys= 1; + } + mc->changed|= changed; + } + if (interps!=ibuf) + free(interps); + return TRUE; +} + +Status +XkbChangeTypesOfKey( XkbDescPtr xkb, + int key, + int nGroups, + unsigned groups, + int * newTypesIn, + XkbMapChangesPtr changes) +{ +XkbKeyTypePtr pOldType,pNewType; +register int i; +int width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups]; + + if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) || + (!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)|| + (nGroups>XkbNumKbdGroups)) { + return BadMatch; + } + if (nGroups==0) { + for (i=0;imap->key_sym_map[key].kt_index[i]= XkbOneLevelIndex; + } + i= xkb->map->key_sym_map[key].group_info; + i= XkbSetNumGroups(i,0); + xkb->map->key_sym_map[key].group_info= i; + XkbResizeKeySyms(xkb,key,0); + return Success; + } + + nOldGroups= XkbKeyNumGroups(xkb,key); + oldWidth= XkbKeyGroupsWidth(xkb,key); + for (width=i=0;i0) + newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); + else newTypes[i]= XkbTwoLevelIndex; + if (newTypes[i]>xkb->map->num_types) + return BadMatch; + pNewType= &xkb->map->types[newTypes[i]]; + if (pNewType->num_levels>width) + width= pNewType->num_levels; + } + if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups)) + xkb->ctrls->num_groups= nGroups; + if ((width!=oldWidth)||(nGroups!=nOldGroups)) { + KeySym oldSyms[XkbMaxSymsPerKey],*pSyms; + int nCopy; + + if (nOldGroups==0) { + pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); + if (pSyms!=NULL) { + i= xkb->map->key_sym_map[key].group_info; + i= XkbSetNumGroups(i,nGroups); + xkb->map->key_sym_map[key].group_info= i; + xkb->map->key_sym_map[key].width= width; + for (i=0;imap->key_sym_map[key].kt_index[i]= newTypes[i]; + } + return Success; + } + return BadAlloc; + } + pSyms= XkbKeySymsPtr(xkb,key); + memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); + pSyms= XkbResizeKeySyms(xkb,key,width*nGroups); + if (pSyms==NULL) + return BadAlloc; + memset(pSyms, 0, width*nGroups*sizeof(KeySym)); + for (i=0;(imap->types[newTypes[i]]; + if (pNewType->num_levels>pOldType->num_levels) + nCopy= pOldType->num_levels; + else nCopy= pNewType->num_levels; + memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym)); + } + if (XkbKeyHasActions(xkb,key)) { + XkbAction oldActs[XkbMaxSymsPerKey],*pActs; + pActs= XkbKeyActionsPtr(xkb,key); + memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction)); + pActs= XkbResizeKeyActions(xkb,key,width*nGroups); + if (pActs==NULL) + return BadAlloc; + memset(pActs, 0, width*nGroups*sizeof(XkbAction)); + for (i=0;(imap->types[newTypes[i]]; + if (pNewType->num_levels>pOldType->num_levels) + nCopy= pOldType->num_levels; + else nCopy= pNewType->num_levels; + memcpy(&pActs[i*width],&oldActs[i*oldWidth], + nCopy*sizeof(XkbAction)); + } + } + i= xkb->map->key_sym_map[key].group_info; + i= XkbSetNumGroups(i,nGroups); + xkb->map->key_sym_map[key].group_info= i; + xkb->map->key_sym_map[key].width= width; + } + width= 0; + for (i=0;imap->key_sym_map[key].kt_index[i]= newTypes[i]; + if (xkb->map->types[newTypes[i]].num_levels>width) + width= xkb->map->types[newTypes[i]].num_levels; + } + xkb->map->key_sym_map[key].width= width; + if (changes!=NULL) { + if (changes->changed&XkbKeySymsMask) { + _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms, + key); + } + else { + changes->changed|= XkbKeySymsMask; + changes->first_key_sym= key; + changes->num_key_syms= 1; + } + } + return Success; +} + +/***====================================================================***/ + +Bool +XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn) +{ +register int i,bit; +register unsigned mask; + + if (xkb==NULL) + return FALSE; + if (virtual_mask==0) { + *mask_rtrn= 0; + return TRUE; + } + if (xkb->server==NULL) + return FALSE; + for (i=mask=0,bit=1;iserver->vmods[i]; + } + *mask_rtrn= mask; + return TRUE; +} + +/***====================================================================***/ + +static Bool +XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed) +{ +unsigned int tmp; + + switch (act->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: + if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->mods.mask= act->mods.real_mods; + act->mods.mask|= tmp; + return TRUE; + } + break; + case XkbSA_ISOLock: + if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) { + XkbVirtualModsToReal(xkb,tmp,&tmp); + act->iso.mask= act->iso.real_mods; + act->iso.mask|= tmp; + return TRUE; + } + break; + } + return FALSE; +} + +static void +XkbUpdateKeyTypeVirtualMods( XkbDescPtr xkb, + XkbKeyTypePtr type, + unsigned int changed, + XkbChangesPtr changes) +{ +register unsigned int i; +unsigned int mask; + + XkbVirtualModsToReal(xkb,type->mods.vmods,&mask); + type->mods.mask= type->mods.real_mods|mask; + if ((type->map_count>0)&&(type->mods.vmods!=0)) { + XkbKTMapEntryPtr entry; + for (i=0,entry=type->map;imap_count;i++,entry++) { + if (entry->mods.vmods!=0) { + XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask); + entry->mods.mask=entry->mods.real_mods|mask; + /* entry is active if vmods are bound*/ + entry->active= (mask!=0); + } + else entry->active= 1; + } + } + if (changes) { + int type_ndx; + type_ndx= type-xkb->map->types; + if ((type_ndx<0)||(type_ndx>xkb->map->num_types)) + return; + if (changes->map.changed&XkbKeyTypesMask) { + int last; + last= changes->map.first_type+changes->map.num_types-1; + if (type_ndxmap.first_type) { + changes->map.first_type= type_ndx; + changes->map.num_types= (last-type_ndx)+1; + } + else if (type_ndx>last) { + changes->map.num_types= (type_ndx-changes->map.first_type)+1; + } + } + else { + changes->map.changed|= XkbKeyTypesMask; + changes->map.first_type= type_ndx; + changes->map.num_types= 1; + } + } + return; +} + +Bool +XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes) +{ +register int i; +unsigned int checkState = 0; + + if ((!xkb) || (!xkb->map) || (changed==0)) + return FALSE; + for (i=0;imap->num_types;i++) { + if (xkb->map->types[i].mods.vmods & changed) + XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes); + } + if (changed&xkb->ctrls->internal.vmods) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask); + newMask|= xkb->ctrls->internal.real_mods; + if (xkb->ctrls->internal.mask!=newMask) { + xkb->ctrls->internal.mask= newMask; + if (changes) { + changes->ctrls.changed_ctrls|= XkbInternalModsMask; + checkState= TRUE; + } + } + } + if (changed&xkb->ctrls->ignore_lock.vmods) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask); + newMask|= xkb->ctrls->ignore_lock.real_mods; + if (xkb->ctrls->ignore_lock.mask!=newMask) { + xkb->ctrls->ignore_lock.mask= newMask; + if (changes) { + changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask; + checkState= TRUE; + } + } + } + if (xkb->indicators!=NULL) { + XkbIndicatorMapPtr map; + map= &xkb->indicators->maps[0]; + for (i=0;imods.vmods&changed) { + unsigned int newMask; + XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask); + newMask|= map->mods.real_mods; + if (newMask!=map->mods.mask) { + map->mods.mask= newMask; + if (changes) { + changes->indicators.map_changes|= (1<compat!=NULL) { + XkbCompatMapPtr compat; + compat= xkb->compat; + for (i=0;igroups[i].vmods,&newMask); + newMask|= compat->groups[i].real_mods; + if (compat->groups[i].mask!=newMask) { + compat->groups[i].mask= newMask; + if (changes) { + changes->compat.changed_groups|= (1<map && xkb->server) { + int highChange = 0, lowChange = -1; + for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + if (XkbKeyHasActions(xkb,i)) { + register XkbAction *pAct; + register int n; + + pAct= XkbKeyActionsPtr(xkb,i); + for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) { + if ((pAct->type!=XkbSA_NoAction)&& + XkbUpdateActionVirtualMods(xkb,pAct,changed)) { + if (lowChange<0) + lowChange= i; + highChange= i; + } + } + } + } + if (changes && (lowChange>0)) { /* something changed */ + if (changes->map.changed&XkbKeyActionsMask) { + int last; + if (changes->map.first_key_actmap.first_key_act; + last= changes->map.first_key_act+changes->map.num_key_acts-1; + if (last>highChange) + highChange= last; + } + changes->map.changed|= XkbKeyActionsMask; + changes->map.first_key_act= lowChange; + changes->map.num_key_acts= (highChange-lowChange)+1; + } + } + return checkState; +} diff --git a/xorg-server/xkb/xkbUtils.c b/xorg-server/xkb/xkbUtils.c index 9db94773f..3a56bea4c 100644 --- a/xorg-server/xkb/xkbUtils.c +++ b/xorg-server/xkb/xkbUtils.c @@ -1,2122 +1,2125 @@ -/************************************************************ -Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. - -Permission to use, copy, modify, and distribute this -software and its documentation for any purpose and without -fee is hereby granted, 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 Silicon Graphics not be -used in advertising or publicity pertaining to distribution -of the software without specific prior written permission. -Silicon Graphics makes no representation about the suitability -of this software for any purpose. It is provided "as is" -without any express or implied warranty. - -SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS -SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON -GRAPHICS 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. - -********************************************************/ -/* - -Copyright © 2008 Red Hat Inc. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next -paragraph) shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -*/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "os.h" -#include -#include -#include -#include -#include -#define XK_CYRILLIC -#include -#include "misc.h" -#include "inputstr.h" -#include "eventstr.h" - -#define XKBSRV_NEED_FILE_FUNCS -#include -#include "xkbgeom.h" -#include "xkb.h" - -/***====================================================================***/ - -int -_XkbLookupAnyDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - int rc = XkbKeyboardErrorCode; - - if (id == XkbUseCoreKbd) - id = PickKeyboard(client)->id; - else if (id == XkbUseCorePtr) - id = PickPointer(client)->id; - - rc = dixLookupDevice(pDev, id, client, access_mode); - if (rc != Success) - *xkb_err = XkbErr_BadDevice; - - return rc; -} - -int -_XkbLookupKeyboard(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - if (id == XkbDfltXIId) - id = XkbUseCoreKbd; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->key || !dev->key->xkbInfo) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -int -_XkbLookupBellDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->kbdfeed && !dev->bell) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -int -_XkbLookupLedDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - if (id == XkbDfltXIId) - id = XkbUseCorePtr; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->kbdfeed && !dev->leds) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -int -_XkbLookupButtonDevice(DeviceIntPtr *pDev, int id, ClientPtr client, - Mask access_mode, int *xkb_err) -{ - DeviceIntPtr dev; - int rc; - - rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); - if (rc != Success) - return rc; - - dev = *pDev; - if (!dev->button) { - *pDev = NULL; - *xkb_err= XkbErr_BadClass; - return XkbKeyboardErrorCode; - } - return Success; -} - -void -XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) -{ -register unsigned tmp; - - switch (act->type) { - case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: - if (act->mods.flags&XkbSA_UseModMapMods) - act->mods.real_mods= act->mods.mask= mods; - if ((tmp= XkbModActionVMods(&act->mods))!=0) - act->mods.mask|= XkbMaskForVMask(xkb,tmp); - break; - case XkbSA_ISOLock: - if (act->iso.flags&XkbSA_UseModMapMods) - act->iso.real_mods= act->iso.mask= mods; - if ((tmp= XkbModActionVMods(&act->iso))!=0) - act->iso.mask|= XkbMaskForVMask(xkb,tmp); - break; - } - return; -} - -unsigned -XkbMaskForVMask(XkbDescPtr xkb,unsigned vmask) -{ -register int i,bit; -register unsigned mask; - - for (mask=i=0,bit=1;iserver->vmods[i]; - } - return mask; -} - -/***====================================================================***/ - -void -XkbUpdateKeyTypesFromCore( DeviceIntPtr pXDev, - KeySymsPtr pCore, - KeyCode first, - CARD8 num, - XkbChangesPtr changes) -{ -XkbDescPtr xkb; -unsigned key,nG,explicit; -int types[XkbNumKbdGroups]; -KeySym tsyms[XkbMaxSymsPerKey],*syms; -XkbMapChangesPtr mc; - - xkb= pXDev->key->xkbInfo->desc; - if (first+num-1>xkb->max_key_code) { - /* 1/12/95 (ef) -- XXX! should allow XKB structures to grow */ - num= xkb->max_key_code-first+1; - } - - mc= (changes?(&changes->map):NULL); - - syms= &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth]; - for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) { - explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask; - types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); - types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index); - types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index); - types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index); - nG= XkbKeyTypesForCoreSymbols(xkb,pCore->mapWidth,syms,explicit,types, - tsyms); - XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc); - memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms, - XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); - } - if (changes->map.changed&XkbKeySymsMask) { - CARD8 oldLast,newLast; - oldLast = changes->map.first_key_sym+changes->map.num_key_syms-1; - newLast = first+num-1; - - if (firstmap.first_key_sym) - changes->map.first_key_sym = first; - if (oldLast>newLast) - newLast= oldLast; - changes->map.num_key_syms = newLast-changes->map.first_key_sym+1; - } - else { - changes->map.changed|= XkbKeySymsMask; - changes->map.first_key_sym = first; - changes->map.num_key_syms = num; - } - return; -} - -void -XkbUpdateDescActions( XkbDescPtr xkb, - KeyCode first, - CARD8 num, - XkbChangesPtr changes) -{ -register unsigned key; - - for (key=first;key<(first+num);key++) { - XkbApplyCompatMapToKey(xkb,key,changes); - } - - if (changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask)) { - unsigned char newVMods[XkbNumVirtualMods]; - register unsigned bit,i; - unsigned present; - - memset(newVMods, 0, XkbNumVirtualMods); - present= 0; - for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { - if (xkb->server->vmodmap[key]==0) - continue; - for (i=0,bit=1;iserver->vmodmap[key]) { - present|= bit; - newVMods[i]|= xkb->map->modmap[key]; - } - } - } - for (i=0,bit=1;iserver->vmods[i])) { - changes->map.changed|= XkbVirtualModsMask; - changes->map.vmods|= bit; - xkb->server->vmods[i]= newVMods[i]; - } - } - } - if (changes->map.changed&XkbVirtualModsMask) - XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes); - - if (changes->map.changed&XkbKeyActionsMask) { - CARD8 oldLast,newLast; - oldLast= changes->map.first_key_act+changes->map.num_key_acts-1; - newLast = first+num-1; - - if (firstmap.first_key_act) - changes->map.first_key_act = first; - if (newLast>oldLast) - newLast= oldLast; - changes->map.num_key_acts= newLast-changes->map.first_key_act+1; - } - else { - changes->map.changed|= XkbKeyActionsMask; - changes->map.first_key_act = first; - changes->map.num_key_acts = num; - } - return; -} - -void -XkbUpdateActions( DeviceIntPtr pXDev, - KeyCode first, - CARD8 num, - XkbChangesPtr changes, - unsigned * needChecksRtrn, - XkbEventCausePtr cause) -{ -XkbSrvInfoPtr xkbi; -XkbDescPtr xkb; -CARD8 * repeat; - - if (needChecksRtrn) - *needChecksRtrn= 0; - xkbi= pXDev->key->xkbInfo; - xkb= xkbi->desc; - repeat= xkb->ctrls->per_key_repeat; - - if (pXDev->kbdfeed) - memcpy(repeat,pXDev->kbdfeed->ctrl.autoRepeats,XkbPerKeyBitArraySize); - - XkbUpdateDescActions(xkb,first,num,changes); - - if ((pXDev->kbdfeed)&& - (changes->ctrls.enabled_ctrls_changes&XkbPerKeyRepeatMask)) { - memcpy(pXDev->kbdfeed->ctrl.autoRepeats,repeat, XkbPerKeyBitArraySize); - (*pXDev->kbdfeed->CtrlProc)(pXDev, &pXDev->kbdfeed->ctrl); - } - return; -} - -KeySymsPtr -XkbGetCoreMap(DeviceIntPtr keybd) -{ -register int key,tmp; -int maxSymsPerKey, maxGroup1Width; -XkbDescPtr xkb; -KeySymsPtr syms; -int maxNumberOfGroups; - - if (!keybd || !keybd->key || !keybd->key->xkbInfo) - return NULL; - - xkb= keybd->key->xkbInfo->desc; - maxSymsPerKey= maxGroup1Width= 0; - maxNumberOfGroups = 0; - - /* determine sizes */ - for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { - if (XkbKeycodeInRange(xkb,key)) { - int nGroups; - int w; - nGroups= XkbKeyNumGroups(xkb,key); - tmp= 0; - if (nGroups>0) { - if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup1Index))<=2) - tmp+= 2; - else tmp+= w + 2; - /* remember highest G1 width */ - if (w > maxGroup1Width) - maxGroup1Width = w; - } - if (nGroups>1) { - if (tmp <= 2) { - if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))<2) - tmp+= 2; - else tmp+= w; - } else { - if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2) - tmp+= w - 2; - } - } - if (nGroups>2) - tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup3Index); - if (nGroups>3) - tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup4Index); - if (tmp>maxSymsPerKey) - maxSymsPerKey= tmp; - if (nGroups > maxNumberOfGroups) - maxNumberOfGroups = nGroups; - } - } - - if (maxSymsPerKey <= 0) - return NULL; - - syms = calloc(1, sizeof(*syms)); - if (!syms) - return NULL; - - /* See Section 12.4 of the XKB Protocol spec. Because of the - * single-group distribution for multi-group keyboards, we have to - * have enough symbols for the largest group 1 to replicate across the - * number of groups on the keyboard. e.g. a single-group key with 4 - * symbols on a keyboard that has 3 groups -> 12 syms per key */ - if (maxSymsPerKey < maxNumberOfGroups * maxGroup1Width) - maxSymsPerKey = maxNumberOfGroups * maxGroup1Width; - - syms->mapWidth = maxSymsPerKey; - syms->minKeyCode = xkb->min_key_code; - syms->maxKeyCode = xkb->max_key_code; - - tmp = syms->mapWidth * (xkb->max_key_code - xkb->min_key_code + 1); - syms->map = calloc(tmp, sizeof(*syms->map)); - if (!syms->map) { - free(syms); - return NULL; - } - - for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { - KeySym *pCore,*pXKB; - unsigned nGroups,groupWidth,n,nOut; - - nGroups= XkbKeyNumGroups(xkb,key); - n= (key-xkb->min_key_code)*syms->mapWidth; - pCore= &syms->map[n]; - pXKB= XkbKeySymsPtr(xkb,key); - nOut= 2; - if (nGroups>0) { - groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup1Index); - if (groupWidth>0) pCore[0]= pXKB[0]; - if (groupWidth>1) pCore[1]= pXKB[1]; - for (n=2;n2) - nOut= groupWidth; - } - - /* See XKB Protocol Sec, Section 12.4. - A 1-group key with ABCDE on a 2 group keyboard must be - duplicated across all groups as ABABCDECDE. - */ - if (nGroups == 1) - { - int idx, j; - - groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index); - - /* AB..CDE... -> ABABCDE... */ - if (groupWidth > 0 && syms->mapWidth >= 3) - pCore[2] = pCore[0]; - if (groupWidth > 1 && syms->mapWidth >= 4) - pCore[3] = pCore[1]; - - /* ABABCDE... -> ABABCDECDE */ - idx = 2 + groupWidth; - while (groupWidth > 2 && idx < syms->mapWidth && - idx < groupWidth * 2) - { - pCore[idx] = pCore[idx - groupWidth + 2]; - idx++; - } - idx = 2 * groupWidth; - if (idx < 4) - idx = 4; - /* 3 or more groups: ABABCDECDEABCDEABCDE */ - for (j = 3; j <= maxNumberOfGroups; j++) - for (n = 0; n < groupWidth && idx < maxSymsPerKey; n++) - pCore[idx++] = pXKB[n]; - } - - pXKB+= XkbKeyGroupsWidth(xkb,key); - nOut+= 2; - if (nGroups>1) { - groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup2Index); - if (groupWidth>0) pCore[2]= pXKB[0]; - if (groupWidth>1) pCore[3]= pXKB[1]; - for (n=2;n2) - nOut+= (groupWidth-2); - } - pXKB+= XkbKeyGroupsWidth(xkb,key); - for (n=XkbGroup3Index;nkey && pXDev->key->xkbInfo) { - xkbControlsNotify cn; - XkbControlsPtr ctrls = pXDev->key->xkbInfo->desc->ctrls; - XkbControlsRec old; - old = *ctrls; - - if (key== -1) { /* global autorepeat setting changed */ - if (onoff) ctrls->enabled_ctrls |= XkbRepeatKeysMask; - else ctrls->enabled_ctrls &= ~XkbRepeatKeysMask; - } - else if (pXDev->kbdfeed) { - ctrls->per_key_repeat[key/8] = - pXDev->kbdfeed->ctrl.autoRepeats[key/8]; - } - - if (XkbComputeControlsNotify(pXDev,&old,ctrls,&cn,TRUE)) - XkbSendControlsNotify(pXDev,&cn); - } - return; -} - -/* Applies a change to a single device, does not traverse the device tree. */ -void -XkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key, - CARD8 num_keys, CARD8 *modmap, ClientPtr client) -{ - XkbDescPtr xkb = kbd->key->xkbInfo->desc; - XkbEventCauseRec cause; - XkbChangesRec changes; - unsigned int check; - - memset(&changes, 0, sizeof(changes)); - memset(&cause, 0, sizeof(cause)); - - if (map && first_key && num_keys) { - check = 0; - XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client); - - XkbUpdateKeyTypesFromCore(kbd, map, first_key, num_keys, &changes); - XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause); - - if (check) - XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); - } - - if (modmap) { - /* A keymap change can imply a modmap change, se we prefer the - * former. */ - if (!cause.mjr) - XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client); - - check = 0; - num_keys = xkb->max_key_code - xkb->min_key_code + 1; - changes.map.changed |= XkbModifierMapMask; - changes.map.first_modmap_key = xkb->min_key_code; - changes.map.num_modmap_keys = num_keys; - memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH); - XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check, - &cause); - - if (check) - XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); - } - - XkbSendNotification(kbd, &changes, &cause); -} - -void -XkbDisableComputedAutoRepeats(DeviceIntPtr dev,unsigned key) -{ -XkbSrvInfoPtr xkbi = dev->key->xkbInfo; -xkbMapNotify mn; - - xkbi->desc->server->explicit[key]|= XkbExplicitAutoRepeatMask; - memset(&mn, 0, sizeof(mn)); - mn.changed= XkbExplicitComponentsMask; - mn.firstKeyExplicit= key; - mn.nKeyExplicit= 1; - XkbSendMapNotify(dev,&mn); - return; -} - -unsigned -XkbStateChangedFlags(XkbStatePtr old,XkbStatePtr new) -{ -int changed; - - changed=(old->group!=new->group?XkbGroupStateMask:0); - changed|=(old->base_group!=new->base_group?XkbGroupBaseMask:0); - changed|=(old->latched_group!=new->latched_group?XkbGroupLatchMask:0); - changed|=(old->locked_group!=new->locked_group?XkbGroupLockMask:0); - changed|=(old->mods!=new->mods?XkbModifierStateMask:0); - changed|=(old->base_mods!=new->base_mods?XkbModifierBaseMask:0); - changed|=(old->latched_mods!=new->latched_mods?XkbModifierLatchMask:0); - changed|=(old->locked_mods!=new->locked_mods?XkbModifierLockMask:0); - changed|=(old->compat_state!=new->compat_state?XkbCompatStateMask:0); - changed|=(old->grab_mods!=new->grab_mods?XkbGrabModsMask:0); - if (old->compat_grab_mods!=new->compat_grab_mods) - changed|= XkbCompatGrabModsMask; - changed|=(old->lookup_mods!=new->lookup_mods?XkbLookupModsMask:0); - if (old->compat_lookup_mods!=new->compat_lookup_mods) - changed|= XkbCompatLookupModsMask; - changed|=(old->ptr_buttons!=new->ptr_buttons?XkbPointerButtonMask:0); - return changed; -} - -static void -XkbComputeCompatState(XkbSrvInfoPtr xkbi) -{ -CARD16 grp_mask; -XkbStatePtr state= &xkbi->state; -XkbCompatMapPtr map; - - if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat) - return; - - map= xkbi->desc->compat; - grp_mask= map->groups[state->group].mask; - state->compat_state = state->mods|grp_mask; - state->compat_lookup_mods= state->lookup_mods|grp_mask; - - if (xkbi->desc->ctrls->enabled_ctrls&XkbIgnoreGroupLockMask) - grp_mask= map->groups[state->base_group].mask; - state->compat_grab_mods= state->grab_mods|grp_mask; - return; -} - -unsigned -XkbAdjustGroup(int group,XkbControlsPtr ctrls) -{ -unsigned act; - - act= XkbOutOfRangeGroupAction(ctrls->groups_wrap); - if (group<0) { - while ( group < 0 ) { - if (act==XkbClampIntoRange) { - group= XkbGroup1Index; - } - else if (act==XkbRedirectIntoRange) { - int newGroup; - newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); - if (newGroup>=ctrls->num_groups) - group= XkbGroup1Index; - else group= newGroup; - } - else { - group+= ctrls->num_groups; - } - } - } - else if (group>=ctrls->num_groups) { - if (act==XkbClampIntoRange) { - group= ctrls->num_groups-1; - } - else if (act==XkbRedirectIntoRange) { - int newGroup; - newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); - if (newGroup>=ctrls->num_groups) - group= XkbGroup1Index; - else group= newGroup; - } - else { - group%= ctrls->num_groups; - } - } - return group; -} - -void -XkbComputeDerivedState(XkbSrvInfoPtr xkbi) -{ -XkbStatePtr state= &xkbi->state; -XkbControlsPtr ctrls= xkbi->desc->ctrls; -unsigned char grp; - - if (!state || !ctrls) - return; - - state->mods= (state->base_mods|state->latched_mods|state->locked_mods); - state->lookup_mods= state->mods&(~ctrls->internal.mask); - state->grab_mods= state->lookup_mods&(~ctrls->ignore_lock.mask); - state->grab_mods|= - ((state->base_mods|state->latched_mods)&ctrls->ignore_lock.mask); - - - grp= state->locked_group; - if (grp>=ctrls->num_groups) - state->locked_group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); - - grp= state->locked_group+state->base_group+state->latched_group; - if (grp>=ctrls->num_groups) - state->group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); - else state->group= grp; - XkbComputeCompatState(xkbi); - return; -} - -/***====================================================================***/ - -void -XkbCheckSecondaryEffects( XkbSrvInfoPtr xkbi, - unsigned which, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ - if (which&XkbStateNotifyMask) { - XkbStateRec old; - old= xkbi->state; - changes->state_changes|= XkbStateChangedFlags(&old,&xkbi->state); - XkbComputeDerivedState(xkbi); - } - if (which&XkbIndicatorStateNotifyMask) - XkbUpdateIndicators(xkbi->device,XkbAllIndicatorsMask,TRUE,changes, - cause); - return; -} - -/***====================================================================***/ - -Bool -XkbEnableDisableControls( XkbSrvInfoPtr xkbi, - unsigned long change, - unsigned long newValues, - XkbChangesPtr changes, - XkbEventCausePtr cause) -{ -XkbControlsPtr ctrls; -unsigned old; -XkbSrvLedInfoPtr sli; - - ctrls= xkbi->desc->ctrls; - old= ctrls->enabled_ctrls; - ctrls->enabled_ctrls&= ~change; - ctrls->enabled_ctrls|= (change&newValues); - if (old==ctrls->enabled_ctrls) - return FALSE; - if (cause!=NULL) { - xkbControlsNotify cn; - cn.numGroups= ctrls->num_groups; - cn.changedControls= XkbControlsEnabledMask; - cn.enabledControls= ctrls->enabled_ctrls; - cn.enabledControlChanges= (ctrls->enabled_ctrls^old); - cn.keycode= cause->kc; - cn.eventType= cause->event; - cn.requestMajor= cause->mjr; - cn.requestMinor= cause->mnr; - XkbSendControlsNotify(xkbi->device,&cn); - } - else { - /* Yes, this really should be an XOR. If ctrls->enabled_ctrls_changes*/ - /* is non-zero, the controls in question changed already in "this" */ - /* request and this change merely undoes the previous one. By the */ - /* same token, we have to figure out whether or not ControlsEnabled */ - /* should be set or not in the changes structure */ - changes->ctrls.enabled_ctrls_changes^= (ctrls->enabled_ctrls^old); - if (changes->ctrls.enabled_ctrls_changes) - changes->ctrls.changed_ctrls|= XkbControlsEnabledMask; - else changes->ctrls.changed_ctrls&= ~XkbControlsEnabledMask; - } - sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0); - XkbUpdateIndicators(xkbi->device,sli->usesControls,TRUE,changes,cause); - return TRUE; -} - -/***====================================================================***/ - -#define MAX_TOC 16 - -XkbGeometryPtr -XkbLookupNamedGeometry(DeviceIntPtr dev,Atom name,Bool *shouldFree) -{ -XkbSrvInfoPtr xkbi= dev->key->xkbInfo; -XkbDescPtr xkb= xkbi->desc; - - *shouldFree= 0; - if (name==None) { - if (xkb->geom!=NULL) - return xkb->geom; - name= xkb->names->geometry; - } - if ((xkb->geom!=NULL)&&(xkb->geom->name==name)) - return xkb->geom; - *shouldFree= 1; - return NULL; -} - -void -XkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper) -{ - *lower = sym; - *upper = sym; - switch(sym >> 8) { - case 0: /* Latin 1 */ - if ((sym >= XK_A) && (sym <= XK_Z)) - *lower += (XK_a - XK_A); - else if ((sym >= XK_a) && (sym <= XK_z)) - *upper -= (XK_a - XK_A); - else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) - *lower += (XK_agrave - XK_Agrave); - else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) - *upper -= (XK_agrave - XK_Agrave); - else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) - *lower += (XK_oslash - XK_Ooblique); - else if ((sym >= XK_oslash) && (sym <= XK_thorn)) - *upper -= (XK_oslash - XK_Ooblique); - break; - case 1: /* Latin 2 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym == XK_Aogonek) - *lower = XK_aogonek; - else if (sym >= XK_Lstroke && sym <= XK_Sacute) - *lower += (XK_lstroke - XK_Lstroke); - else if (sym >= XK_Scaron && sym <= XK_Zacute) - *lower += (XK_scaron - XK_Scaron); - else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) - *lower += (XK_zcaron - XK_Zcaron); - else if (sym == XK_aogonek) - *upper = XK_Aogonek; - else if (sym >= XK_lstroke && sym <= XK_sacute) - *upper -= (XK_lstroke - XK_Lstroke); - else if (sym >= XK_scaron && sym <= XK_zacute) - *upper -= (XK_scaron - XK_Scaron); - else if (sym >= XK_zcaron && sym <= XK_zabovedot) - *upper -= (XK_zcaron - XK_Zcaron); - else if (sym >= XK_Racute && sym <= XK_Tcedilla) - *lower += (XK_racute - XK_Racute); - else if (sym >= XK_racute && sym <= XK_tcedilla) - *upper -= (XK_racute - XK_Racute); - break; - case 2: /* Latin 3 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) - *lower += (XK_hstroke - XK_Hstroke); - else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) - *lower += (XK_gbreve - XK_Gbreve); - else if (sym >= XK_hstroke && sym <= XK_hcircumflex) - *upper -= (XK_hstroke - XK_Hstroke); - else if (sym >= XK_gbreve && sym <= XK_jcircumflex) - *upper -= (XK_gbreve - XK_Gbreve); - else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) - *lower += (XK_cabovedot - XK_Cabovedot); - else if (sym >= XK_cabovedot && sym <= XK_scircumflex) - *upper -= (XK_cabovedot - XK_Cabovedot); - break; - case 3: /* Latin 4 */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Rcedilla && sym <= XK_Tslash) - *lower += (XK_rcedilla - XK_Rcedilla); - else if (sym >= XK_rcedilla && sym <= XK_tslash) - *upper -= (XK_rcedilla - XK_Rcedilla); - else if (sym == XK_ENG) - *lower = XK_eng; - else if (sym == XK_eng) - *upper = XK_ENG; - else if (sym >= XK_Amacron && sym <= XK_Umacron) - *lower += (XK_amacron - XK_Amacron); - else if (sym >= XK_amacron && sym <= XK_umacron) - *upper -= (XK_amacron - XK_Amacron); - break; - case 6: /* Cyrillic */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) - *lower -= (XK_Serbian_DJE - XK_Serbian_dje); - else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) - *upper += (XK_Serbian_DJE - XK_Serbian_dje); - else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) - *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); - else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) - *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); - break; - case 7: /* Greek */ - /* Assume the KeySym is a legal value (ignore discontinuities) */ - if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) - *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); - else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && - sym != XK_Greek_iotaaccentdieresis && - sym != XK_Greek_upsilonaccentdieresis) - *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); - else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) - *lower += (XK_Greek_alpha - XK_Greek_ALPHA); - else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && - sym != XK_Greek_finalsmallsigma) - *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); - break; - } -} - -static Bool -_XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - int i; - XkbKeyTypePtr stype = NULL, dtype = NULL; - - /* client map */ - if (src->map) { - if (!dst->map) { - tmp = calloc(1, sizeof(XkbClientMapRec)); - if (!tmp) - return FALSE; - dst->map = tmp; - } - - if (src->map->syms) { - if (src->map->size_syms != dst->map->size_syms) { - tmp = realloc(dst->map->syms, - src->map->size_syms * sizeof(KeySym)); - if (!tmp) - return FALSE; - dst->map->syms = tmp; - - } - memcpy(dst->map->syms, src->map->syms, - src->map->size_syms * sizeof(KeySym)); - } - else { - free(dst->map->syms); - dst->map->syms = NULL; - } - dst->map->num_syms = src->map->num_syms; - dst->map->size_syms = src->map->size_syms; - - if (src->map->key_sym_map) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->map->key_sym_map, - (src->max_key_code + 1) * sizeof(XkbSymMapRec)); - if (!tmp) - return FALSE; - dst->map->key_sym_map = tmp; - } - memcpy(dst->map->key_sym_map, src->map->key_sym_map, - (src->max_key_code + 1) * sizeof(XkbSymMapRec)); - } - else { - free(dst->map->key_sym_map); - dst->map->key_sym_map = NULL; - } - - if (src->map->types && src->map->num_types) { - if (src->map->num_types > dst->map->size_types || - !dst->map->types || !dst->map->size_types) { - if (dst->map->types && dst->map->size_types) { - tmp = realloc(dst->map->types, - src->map->num_types * sizeof(XkbKeyTypeRec)); - if (!tmp) - return FALSE; - dst->map->types = tmp; - memset(dst->map->types + dst->map->num_types, 0, - (src->map->num_types - dst->map->num_types) * - sizeof(XkbKeyTypeRec)); - } - else { - tmp = calloc(src->map->num_types, sizeof(XkbKeyTypeRec)); - if (!tmp) - return FALSE; - dst->map->types = tmp; - } - } - else if (src->map->num_types < dst->map->num_types && - dst->map->types) { - for (i = src->map->num_types, dtype = (dst->map->types + i); - i < dst->map->num_types; i++, dtype++) { - free(dtype->level_names); - dtype->level_names = NULL; - dtype->num_levels = 0; - if (dtype->map_count) { - free(dtype->map); - free(dtype->preserve); - } - } - } - - stype = src->map->types; - dtype = dst->map->types; - for (i = 0; i < src->map->num_types; i++, dtype++, stype++) { - if (stype->num_levels && stype->level_names) { - if (stype->num_levels != dtype->num_levels && - dtype->num_levels && dtype->level_names && - i < dst->map->num_types) { - tmp = realloc(dtype->level_names, - stype->num_levels * sizeof(Atom)); - if (!tmp) - continue; - dtype->level_names = tmp; - } - else if (!dtype->num_levels || !dtype->level_names || - i >= dst->map->num_types) { - tmp = malloc(stype->num_levels * sizeof(Atom)); - if (!tmp) - continue; - dtype->level_names = tmp; - } - dtype->num_levels = stype->num_levels; - memcpy(dtype->level_names, stype->level_names, - stype->num_levels * sizeof(Atom)); - } - else { - if (dtype->num_levels && dtype->level_names && - i < dst->map->num_types) - free(dtype->level_names); - dtype->num_levels = 0; - dtype->level_names = NULL; - } - - dtype->name = stype->name; - memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec)); - - if (stype->map_count) { - if (stype->map) { - if (stype->map_count != dtype->map_count && - dtype->map_count && dtype->map && - i < dst->map->num_types) { - tmp = realloc(dtype->map, - stype->map_count * - sizeof(XkbKTMapEntryRec)); - if (!tmp) - return FALSE; - dtype->map = tmp; - } - else if (!dtype->map_count || !dtype->map || - i >= dst->map->num_types) { - tmp = malloc(stype->map_count * - sizeof(XkbKTMapEntryRec)); - if (!tmp) - return FALSE; - dtype->map = tmp; - } - - memcpy(dtype->map, stype->map, - stype->map_count * sizeof(XkbKTMapEntryRec)); - } - else { - if (dtype->map && i < dst->map->num_types) - free(dtype->map); - dtype->map = NULL; - } - - if (stype->preserve) { - if (stype->map_count != dtype->map_count && - dtype->map_count && dtype->preserve && - i < dst->map->num_types) { - tmp = realloc(dtype->preserve, - stype->map_count * - sizeof(XkbModsRec)); - if (!tmp) - return FALSE; - dtype->preserve = tmp; - } - else if (!dtype->preserve || !dtype->map_count || - i >= dst->map->num_types) { - tmp = malloc(stype->map_count * - sizeof(XkbModsRec)); - if (!tmp) - return FALSE; - dtype->preserve = tmp; - } - - memcpy(dtype->preserve, stype->preserve, - stype->map_count * sizeof(XkbModsRec)); - } - else { - if (dtype->preserve && i < dst->map->num_types) - free(dtype->preserve); - dtype->preserve = NULL; - } - - dtype->map_count = stype->map_count; - } - else { - if (dtype->map_count && i < dst->map->num_types) { - free(dtype->map); - free(dtype->preserve); - } - dtype->map_count = 0; - dtype->map = NULL; - dtype->preserve = NULL; - } - } - - dst->map->size_types = src->map->num_types; - dst->map->num_types = src->map->num_types; - } - else { - if (dst->map->types) { - for (i = 0, dtype = dst->map->types; i < dst->map->num_types; - i++, dtype++) { - free(dtype->level_names); - if (dtype->map && dtype->map_count) - free(dtype->map); - if (dtype->preserve && dtype->map_count) - free(dtype->preserve); - } - } - free(dst->map->types); - dst->map->types = NULL; - dst->map->num_types = 0; - dst->map->size_types = 0; - } - - if (src->map->modmap) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->map->modmap, src->max_key_code + 1); - if (!tmp) - return FALSE; - dst->map->modmap = tmp; - } - memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1); - } - else { - free(dst->map->modmap); - dst->map->modmap = NULL; - } - } - else { - if (dst->map) - XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - - /* server map */ - if (src->server) { - if (!dst->server) { - tmp = calloc(1, sizeof(XkbServerMapRec)); - if (!tmp) - return FALSE; - dst->server = tmp; - } - - if (src->server->explicit) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->server->explicit, src->max_key_code + 1); - if (!tmp) - return FALSE; - dst->server->explicit = tmp; - } - memcpy(dst->server->explicit, src->server->explicit, - src->max_key_code + 1); - } - else { - free(dst->server->explicit); - dst->server->explicit = NULL; - } - - if (src->server->acts) { - if (src->server->size_acts != dst->server->size_acts) { - tmp = realloc(dst->server->acts, - src->server->size_acts * sizeof(XkbAction)); - if (!tmp) - return FALSE; - dst->server->acts = tmp; - } - memcpy(dst->server->acts, src->server->acts, - src->server->size_acts * sizeof(XkbAction)); - } - else { - free(dst->server->acts); - dst->server->acts = NULL; - } - dst->server->size_acts = src->server->size_acts; - dst->server->num_acts = src->server->num_acts; - - if (src->server->key_acts) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->server->key_acts, - (src->max_key_code + 1) * sizeof(unsigned short)); - if (!tmp) - return FALSE; - dst->server->key_acts = tmp; - } - memcpy(dst->server->key_acts, src->server->key_acts, - (src->max_key_code + 1) * sizeof(unsigned short)); - } - else { - free(dst->server->key_acts); - dst->server->key_acts = NULL; - } - - if (src->server->behaviors) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->server->behaviors, - (src->max_key_code + 1) * sizeof(XkbBehavior)); - if (!tmp) - return FALSE; - dst->server->behaviors = tmp; - } - memcpy(dst->server->behaviors, src->server->behaviors, - (src->max_key_code + 1) * sizeof(XkbBehavior)); - } - else { - free(dst->server->behaviors); - dst->server->behaviors = NULL; - } - - memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods); - - if (src->server->vmodmap) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->server->vmodmap, - (src->max_key_code + 1) * sizeof(unsigned short)); - if (!tmp) - return FALSE; - dst->server->vmodmap = tmp; - } - memcpy(dst->server->vmodmap, src->server->vmodmap, - (src->max_key_code + 1) * sizeof(unsigned short)); - } - else { - free(dst->server->vmodmap); - dst->server->vmodmap = NULL; - } - } - else { - if (dst->server) - XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - - /* names */ - if (src->names) { - if (!dst->names) { - dst->names = calloc(1, sizeof(XkbNamesRec)); - if (!dst->names) - return FALSE; - } - - if (src->names->keys) { - if (src->max_key_code != dst->max_key_code) { - tmp = realloc(dst->names->keys, - (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); - if (!tmp) - return FALSE; - dst->names->keys = tmp; - } - memcpy(dst->names->keys, src->names->keys, - (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); - } - else { - free(dst->names->keys); - dst->names->keys = NULL; - } - - if (src->names->num_key_aliases) { - if (src->names->num_key_aliases != dst->names->num_key_aliases) { - tmp = realloc(dst->names->key_aliases, - src->names->num_key_aliases * - sizeof(XkbKeyAliasRec)); - if (!tmp) - return FALSE; - dst->names->key_aliases = tmp; - } - memcpy(dst->names->key_aliases, src->names->key_aliases, - src->names->num_key_aliases * sizeof(XkbKeyAliasRec)); - } - else { - free(dst->names->key_aliases); - dst->names->key_aliases = NULL; - } - dst->names->num_key_aliases = src->names->num_key_aliases; - - if (src->names->num_rg) { - if (src->names->num_rg != dst->names->num_rg) { - tmp = realloc(dst->names->radio_groups, - src->names->num_rg * sizeof(Atom)); - if (!tmp) - return FALSE; - dst->names->radio_groups = tmp; - } - memcpy(dst->names->radio_groups, src->names->radio_groups, - src->names->num_rg * sizeof(Atom)); - } - else { - free(dst->names->radio_groups); - } - dst->names->num_rg = src->names->num_rg; - - dst->names->keycodes = src->names->keycodes; - dst->names->geometry = src->names->geometry; - dst->names->symbols = src->names->symbols; - dst->names->types = src->names->types; - dst->names->compat = src->names->compat; - dst->names->phys_symbols = src->names->phys_symbols; - - memcpy(dst->names->vmods, src->names->vmods, - XkbNumVirtualMods * sizeof(Atom)); - memcpy(dst->names->indicators, src->names->indicators, - XkbNumIndicators * sizeof(Atom)); - memcpy(dst->names->groups, src->names->groups, - XkbNumKbdGroups * sizeof(Atom)); - } - else { - if (dst->names) - XkbFreeNames(dst, XkbAllNamesMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - - /* compat */ - if (src->compat) { - if (!dst->compat) { - dst->compat = calloc(1, sizeof(XkbCompatMapRec)); - if (!dst->compat) - return FALSE; - } - - if (src->compat->sym_interpret && src->compat->num_si) { - if (src->compat->num_si != dst->compat->size_si) { - tmp = realloc(dst->compat->sym_interpret, - src->compat->num_si * sizeof(XkbSymInterpretRec)); - if (!tmp) - return FALSE; - dst->compat->sym_interpret = tmp; - } - memcpy(dst->compat->sym_interpret, src->compat->sym_interpret, - src->compat->num_si * sizeof(XkbSymInterpretRec)); - - dst->compat->num_si = src->compat->num_si; - dst->compat->size_si = src->compat->num_si; - } - else { - if (dst->compat->sym_interpret && dst->compat->size_si) - free(dst->compat->sym_interpret); - - dst->compat->sym_interpret = NULL; - dst->compat->num_si = 0; - dst->compat->size_si = 0; - } - - memcpy(dst->compat->groups, src->compat->groups, - XkbNumKbdGroups * sizeof(XkbModsRec)); - } - else { - if (dst->compat) - XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE); - } - - return TRUE; -} - -static Bool -_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst) -{ - void *tmp = NULL; - int i = 0, j = 0, k = 0; - XkbColorPtr scolor = NULL, dcolor = NULL; - XkbDoodadPtr sdoodad = NULL, ddoodad = NULL; - XkbOutlinePtr soutline = NULL, doutline = NULL; - XkbPropertyPtr sprop = NULL, dprop = NULL; - XkbRowPtr srow = NULL, drow = NULL; - XkbSectionPtr ssection = NULL, dsection = NULL; - XkbShapePtr sshape = NULL, dshape = NULL; - - /* geometry */ - if (src->geom) { - if (!dst->geom) { - dst->geom = calloc(sizeof(XkbGeometryRec), 1); - if (!dst->geom) - return FALSE; - } - - /* properties */ - if (src->geom->num_properties) { - if (src->geom->num_properties != dst->geom->sz_properties) { - /* If we've got more properties in the destination than - * the source, run through and free all the excess ones - * first. */ - if (src->geom->num_properties < dst->geom->sz_properties) { - for (i = src->geom->num_properties, - dprop = dst->geom->properties + i; - i < dst->geom->num_properties; - i++, dprop++) { - free(dprop->name); - free(dprop->value); - } - } - - if (dst->geom->sz_properties) - tmp = realloc(dst->geom->properties, - src->geom->num_properties * - sizeof(XkbPropertyRec)); - else - tmp = malloc(src->geom->num_properties * - sizeof(XkbPropertyRec)); - if (!tmp) - return FALSE; - dst->geom->properties = tmp; - } - - /* We don't set num_properties as we need it to try and avoid - * too much reallocing. */ - dst->geom->sz_properties = src->geom->num_properties; - - if (dst->geom->sz_properties > dst->geom->num_properties) { - memset(dst->geom->properties + dst->geom->num_properties, 0, - (dst->geom->sz_properties - dst->geom->num_properties) * - sizeof(XkbPropertyRec)); - } - - for (i = 0, - sprop = src->geom->properties, - dprop = dst->geom->properties; - i < src->geom->num_properties; - i++, sprop++, dprop++) { - if (i < dst->geom->num_properties) { - if (strlen(sprop->name) != strlen(dprop->name)) { - tmp = realloc(dprop->name, strlen(sprop->name) + 1); - if (!tmp) - return FALSE; - dprop->name = tmp; - } - if (strlen(sprop->value) != strlen(dprop->value)) { - tmp = realloc(dprop->value, strlen(sprop->value) + 1); - if (!tmp) - return FALSE; - dprop->value = tmp; - } - strcpy(dprop->name, sprop->name); - strcpy(dprop->value, sprop->value); - } - else { - dprop->name = xstrdup(sprop->name); - dprop->value = xstrdup(sprop->value); - } - } - - /* ... which is already src->geom->num_properties. */ - dst->geom->num_properties = dst->geom->sz_properties; - } - else { - if (dst->geom->sz_properties) { - for (i = 0, dprop = dst->geom->properties; - i < dst->geom->num_properties; - i++, dprop++) { - free(dprop->name); - free(dprop->value); - } - free(dst->geom->properties); - dst->geom->properties = NULL; - } - - dst->geom->num_properties = 0; - dst->geom->sz_properties = 0; - } - - /* colors */ - if (src->geom->num_colors) { - if (src->geom->num_colors != dst->geom->sz_colors) { - if (src->geom->num_colors < dst->geom->sz_colors) { - for (i = src->geom->num_colors, - dcolor = dst->geom->colors + i; - i < dst->geom->num_colors; - i++, dcolor++) { - free(dcolor->spec); - } - } - - if (dst->geom->sz_colors) - tmp = realloc(dst->geom->colors, - src->geom->num_colors * - sizeof(XkbColorRec)); - else - tmp = malloc(src->geom->num_colors * - sizeof(XkbColorRec)); - if (!tmp) - return FALSE; - dst->geom->colors = tmp; - } - - dst->geom->sz_colors = src->geom->num_colors; - - if (dst->geom->sz_colors > dst->geom->num_colors) { - memset(dst->geom->colors + dst->geom->num_colors, 0, - (dst->geom->sz_colors - dst->geom->num_colors) * - sizeof(XkbColorRec)); - } - - for (i = 0, - scolor = src->geom->colors, - dcolor = dst->geom->colors; - i < src->geom->num_colors; - i++, scolor++, dcolor++) { - if (i < dst->geom->num_colors) { - if (strlen(scolor->spec) != strlen(dcolor->spec)) { - tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1); - if (!tmp) - return FALSE; - dcolor->spec = tmp; - } - strcpy(dcolor->spec, scolor->spec); - } - else { - dcolor->spec = xstrdup(scolor->spec); - } - dcolor->pixel = scolor->pixel; - } - - dst->geom->num_colors = dst->geom->sz_colors; - } - else { - if (dst->geom->sz_colors) { - for (i = 0, dcolor = dst->geom->colors; - i < dst->geom->num_colors; - i++, dcolor++) { - free(dcolor->spec); - } - free(dst->geom->colors); - dst->geom->colors = NULL; - } - - dst->geom->num_colors = 0; - dst->geom->sz_colors = 0; - } - - /* shapes */ - /* shapes break down into outlines, which break down into points. */ - if (dst->geom->num_shapes) { - for (i = 0, dshape = dst->geom->shapes; - i < dst->geom->num_shapes; - i++, dshape++) { - for (j = 0, doutline = dshape->outlines; - j < dshape->num_outlines; - j++, doutline++) { - if (doutline->sz_points) - free(doutline->points); - } - - if (dshape->sz_outlines) { - free(dshape->outlines); - dshape->outlines = NULL; - } - - dshape->num_outlines = 0; - dshape->sz_outlines = 0; - } - } - - if (src->geom->num_shapes) { - tmp = calloc(src->geom->num_shapes, sizeof(XkbShapeRec)); - if (!tmp) - return FALSE; - dst->geom->shapes = tmp; - - for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes; - i < src->geom->num_shapes; - i++, sshape++, dshape++) { - if (sshape->num_outlines) { - tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec)); - if (!tmp) - return FALSE; - dshape->outlines = tmp; - - for (j = 0, - soutline = sshape->outlines, - doutline = dshape->outlines; - j < sshape->num_outlines; - j++, soutline++, doutline++) { - if (soutline->num_points) { - tmp = malloc(soutline->num_points * - sizeof(XkbPointRec)); - if (!tmp) - return FALSE; - doutline->points = tmp; - - memcpy(doutline->points, soutline->points, - soutline->num_points * sizeof(XkbPointRec)); - - doutline->corner_radius = soutline->corner_radius; - } - - doutline->num_points = soutline->num_points; - doutline->sz_points = soutline->num_points; - } - } - - dshape->num_outlines = sshape->num_outlines; - dshape->sz_outlines = sshape->num_outlines; - dshape->name = sshape->name; - dshape->bounds = sshape->bounds; - - dshape->approx = NULL; - if (sshape->approx && sshape->num_outlines > 0) { - - const ptrdiff_t approx_idx = - sshape->approx - sshape->outlines; - - if (approx_idx < dshape->num_outlines) { - dshape->approx = dshape->outlines + approx_idx; - } else { - LogMessage(X_WARNING, "XKB: approx outline " - "index is out of range\n"); - } - } - - dshape->primary = NULL; - if (sshape->primary && sshape->num_outlines > 0) { - - const ptrdiff_t primary_idx = - sshape->primary - sshape->outlines; - - if (primary_idx < dshape->num_outlines) { - dshape->primary = dshape->outlines + primary_idx; - } else { - LogMessage(X_WARNING, "XKB: primary outline " - "index is out of range\n"); - } - } - } - - dst->geom->num_shapes = src->geom->num_shapes; - dst->geom->sz_shapes = src->geom->num_shapes; - } - else { - if (dst->geom->sz_shapes) { - free(dst->geom->shapes); - } - dst->geom->shapes = NULL; - dst->geom->num_shapes = 0; - dst->geom->sz_shapes = 0; - } - - /* sections */ - /* sections break down into doodads, and also into rows, which break - * down into keys. */ - if (dst->geom->num_sections) { - for (i = 0, dsection = dst->geom->sections; - i < dst->geom->num_sections; - i++, dsection++) { - for (j = 0, drow = dsection->rows; - j < dsection->num_rows; - j++, drow++) { - if (drow->num_keys) - free(drow->keys); - } - - if (dsection->num_rows) - free(dsection->rows); - - /* cut and waste from geom/doodad below. */ - for (j = 0, ddoodad = dsection->doodads; - j < dsection->num_doodads; - j++, ddoodad++) { - if (ddoodad->any.type == XkbTextDoodad) { - free(ddoodad->text.text); - ddoodad->text.text = NULL; - free(ddoodad->text.font); - ddoodad->text.font = NULL; - } - else if (ddoodad->any.type == XkbLogoDoodad) { - free(ddoodad->logo.logo_name); - ddoodad->logo.logo_name = NULL; - } - } - - free(dsection->doodads); - } - - dst->geom->num_sections = 0; - dst->geom->sections = NULL; - } - - if (src->geom->num_sections) { - if (dst->geom->sz_sections) - tmp = realloc(dst->geom->sections, - src->geom->num_sections * - sizeof(XkbSectionRec)); - else - tmp = malloc(src->geom->num_sections * sizeof(XkbSectionRec)); - if (!tmp) - return FALSE; - memset(tmp, 0, src->geom->num_sections * sizeof(XkbSectionRec)); - dst->geom->sections = tmp; - dst->geom->num_sections = src->geom->num_sections; - dst->geom->sz_sections = src->geom->num_sections; - - for (i = 0, - ssection = src->geom->sections, - dsection = dst->geom->sections; - i < src->geom->num_sections; - i++, ssection++, dsection++) { - *dsection = *ssection; - if (ssection->num_rows) { - tmp = calloc(ssection->num_rows, sizeof(XkbRowRec)); - if (!tmp) - return FALSE; - dsection->rows = tmp; - } - dsection->num_rows = ssection->num_rows; - dsection->sz_rows = ssection->num_rows; - - for (j = 0, srow = ssection->rows, drow = dsection->rows; - j < ssection->num_rows; - j++, srow++, drow++) { - if (srow->num_keys) { - tmp = malloc(srow->num_keys * sizeof(XkbKeyRec)); - if (!tmp) - return FALSE; - drow->keys = tmp; - memcpy(drow->keys, srow->keys, - srow->num_keys * sizeof(XkbKeyRec)); - } - drow->num_keys = srow->num_keys; - drow->sz_keys = srow->num_keys; - drow->top = srow->top; - drow->left = srow->left; - drow->vertical = srow->vertical; - drow->bounds = srow->bounds; - } - - if (ssection->num_doodads) { - tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec)); - if (!tmp) - return FALSE; - dsection->doodads = tmp; - } - else { - dsection->doodads = NULL; - } - - dsection->sz_doodads = ssection->num_doodads; - for (k = 0, - sdoodad = ssection->doodads, - ddoodad = dsection->doodads; - k < ssection->num_doodads; - k++, sdoodad++, ddoodad++) { - memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); - if (sdoodad->any.type == XkbTextDoodad) { - if (sdoodad->text.text) - ddoodad->text.text = - strdup(sdoodad->text.text); - if (sdoodad->text.font) - ddoodad->text.font = - strdup(sdoodad->text.font); - } - else if (sdoodad->any.type == XkbLogoDoodad) { - if (sdoodad->logo.logo_name) - ddoodad->logo.logo_name = - strdup(sdoodad->logo.logo_name); - } - } - dsection->overlays = NULL; - dsection->sz_overlays = 0; - dsection->num_overlays = 0; - } - } - else { - if (dst->geom->sz_sections) { - free(dst->geom->sections); - } - - dst->geom->sections = NULL; - dst->geom->num_sections = 0; - dst->geom->sz_sections = 0; - } - - /* doodads */ - if (dst->geom->num_doodads) { - for (i = src->geom->num_doodads, - ddoodad = dst->geom->doodads + - src->geom->num_doodads; - i < dst->geom->num_doodads; - i++, ddoodad++) { - if (ddoodad->any.type == XkbTextDoodad) { - free(ddoodad->text.text); - ddoodad->text.text = NULL; - free(ddoodad->text.font); - ddoodad->text.font = NULL; - } - else if (ddoodad->any.type == XkbLogoDoodad) { - free(ddoodad->logo.logo_name); - ddoodad->logo.logo_name = NULL; - } - } - dst->geom->num_doodads = 0; - dst->geom->doodads = NULL; - } - - if (src->geom->num_doodads) { - if (dst->geom->sz_doodads) - tmp = realloc(dst->geom->doodads, - src->geom->num_doodads * - sizeof(XkbDoodadRec)); - else - tmp = malloc(src->geom->num_doodads * - sizeof(XkbDoodadRec)); - if (!tmp) - return FALSE; - memset(tmp, 0, src->geom->num_doodads * sizeof(XkbDoodadRec)); - dst->geom->doodads = tmp; - - dst->geom->sz_doodads = src->geom->num_doodads; - - for (i = 0, - sdoodad = src->geom->doodads, - ddoodad = dst->geom->doodads; - i < src->geom->num_doodads; - i++, sdoodad++, ddoodad++) { - memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); - if (sdoodad->any.type == XkbTextDoodad) { - if (sdoodad->text.text) - ddoodad->text.text = strdup(sdoodad->text.text); - if (sdoodad->text.font) - ddoodad->text.font = strdup(sdoodad->text.font); - } - else if (sdoodad->any.type == XkbLogoDoodad) { - if (sdoodad->logo.logo_name) - ddoodad->logo.logo_name = - strdup(sdoodad->logo.logo_name); - } - } - - dst->geom->num_doodads = dst->geom->sz_doodads; - } - else { - if (dst->geom->sz_doodads) { - free(dst->geom->doodads); - } - - dst->geom->doodads = NULL; - dst->geom->num_doodads = 0; - dst->geom->sz_doodads = 0; - } - - /* key aliases */ - if (src->geom->num_key_aliases) { - if (src->geom->num_key_aliases != dst->geom->sz_key_aliases) { - if (dst->geom->sz_key_aliases) - tmp = realloc(dst->geom->key_aliases, - src->geom->num_key_aliases * - 2 * XkbKeyNameLength); - else - tmp = malloc(src->geom->num_key_aliases * - 2 * XkbKeyNameLength); - if (!tmp) - return FALSE; - dst->geom->key_aliases = tmp; - - dst->geom->sz_key_aliases = src->geom->num_key_aliases; - } - - memcpy(dst->geom->key_aliases, src->geom->key_aliases, - src->geom->num_key_aliases * 2 * XkbKeyNameLength); - - dst->geom->num_key_aliases = dst->geom->sz_key_aliases; - } - else { - free(dst->geom->key_aliases); - dst->geom->key_aliases = NULL; - dst->geom->num_key_aliases = 0; - dst->geom->sz_key_aliases = 0; - } - - /* font */ - if (src->geom->label_font) { - if (!dst->geom->label_font) { - tmp = malloc(strlen(src->geom->label_font) + 1); - if (!tmp) - return FALSE; - dst->geom->label_font = tmp; - } - else if (strlen(src->geom->label_font) != - strlen(dst->geom->label_font)) { - tmp = realloc(dst->geom->label_font, - strlen(src->geom->label_font) + 1); - if (!tmp) - return FALSE; - dst->geom->label_font = tmp; - } - - strcpy(dst->geom->label_font, src->geom->label_font); - i = XkbGeomColorIndex(src->geom, src->geom->label_color); - dst->geom->label_color = &(dst->geom->colors[i]); - i = XkbGeomColorIndex(src->geom, src->geom->base_color); - dst->geom->base_color = &(dst->geom->colors[i]); - } - else { - free(dst->geom->label_font); - dst->geom->label_font = NULL; - dst->geom->label_color = NULL; - dst->geom->base_color = NULL; - } - - dst->geom->name = src->geom->name; - dst->geom->width_mm = src->geom->width_mm; - dst->geom->height_mm = src->geom->height_mm; - } - else - { - if (dst->geom) { - /* I LOVE THE DIFFERENT CALL SIGNATURE. REALLY, I DO. */ - XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE); - dst->geom = NULL; - } - } - - return TRUE; -} - -static Bool -_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst) -{ - /* indicators */ - if (src->indicators) { - if (!dst->indicators) { - dst->indicators = malloc(sizeof(XkbIndicatorRec)); - if (!dst->indicators) - return FALSE; - } - memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec)); - } - else { - free(dst->indicators); - dst->indicators = NULL; - } - return TRUE; -} - -static Bool -_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst) -{ - /* controls */ - if (src->ctrls) { - if (!dst->ctrls) { - dst->ctrls = malloc(sizeof(XkbControlsRec)); - if (!dst->ctrls) - return FALSE; - } - memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec)); - } - else { - free(dst->ctrls); - dst->ctrls = NULL; - } - return TRUE; -} - -/** - * Copy an XKB map from src to dst, reallocating when necessary: if some - * map components are present in one, but not in the other, the destination - * components will be allocated or freed as necessary. - * - * Basic map consistency is assumed on both sides, so maps with random - * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19) - * _will_ cause failures. You've been warned. - * - * Returns TRUE on success, or FALSE on failure. If this function fails, - * dst may be in an inconsistent state: all its pointers are guaranteed - * to remain valid, but part of the map may be from src and part from dst. - * - */ - -Bool -XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src) -{ - - if (!src || !dst) { - DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst); - return FALSE; - } - - if (src == dst) - return TRUE; - - if (!_XkbCopyClientMap(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy client map\n"); - return FALSE; - } - if (!_XkbCopyServerMap(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy server map\n"); - return FALSE; - } - if (!_XkbCopyIndicators(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy indicators\n"); - return FALSE; - } - if (!_XkbCopyControls(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy controls\n"); - return FALSE; - } - if (!_XkbCopyNames(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy names\n"); - return FALSE; - } - if (!_XkbCopyCompat(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy compat map\n"); - return FALSE; - } - if (!_XkbCopyGeom(src, dst)) { - DebugF("XkbCopyKeymap: failed to copy geometry\n"); - return FALSE; - } - - dst->min_key_code = src->min_key_code; - dst->max_key_code = src->max_key_code; - - return TRUE; -} - -Bool -XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src) -{ - xkbNewKeyboardNotify nkn; - Bool ret; - - if (!dst->key || !src->key) - return FALSE; - - memset(&nkn, 0, sizeof(xkbNewKeyboardNotify)); - nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code; - nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code; - nkn.deviceID = dst->id; - nkn.oldDeviceID = dst->id; /* maybe src->id? */ - nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code; - nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code; - nkn.requestMajor = XkbReqCode; - nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */ - nkn.changed = XkbNKN_KeycodesMask; - if (src->key->xkbInfo->desc->geom) - nkn.changed |= XkbNKN_GeometryMask; - - ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc); - if (ret) - XkbSendNewKeyboardNotify(dst, &nkn); - - return ret; -} - -int -XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode) -{ - XkbDescPtr xkb = xkbi->desc; - int effectiveGroup = xkbState->group; - - if (!XkbKeycodeInRange(xkb, keycode)) - return -1; - - if (effectiveGroup == XkbGroup1Index) - return effectiveGroup; - - if (XkbKeyNumGroups(xkb,keycode) > 1U) { - if (effectiveGroup >= XkbKeyNumGroups(xkb,keycode)) { - unsigned int gi = XkbKeyGroupInfo(xkb,keycode); - switch (XkbOutOfRangeGroupAction(gi)) { - default: - case XkbWrapIntoRange: - effectiveGroup %= XkbKeyNumGroups(xkb, keycode); - break; - case XkbClampIntoRange: - effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1; - break; - case XkbRedirectIntoRange: - effectiveGroup = XkbOutOfRangeGroupInfo(gi); - if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) - effectiveGroup = 0; - break; - } - } - } - else effectiveGroup = XkbGroup1Index; - - return effectiveGroup; -} - -/* Merge the lockedPtrButtons from all attached SDs for the given master - * device into the MD's state. - */ -void -XkbMergeLockedPtrBtns(DeviceIntPtr master) -{ - DeviceIntPtr d = inputInfo.devices; - XkbSrvInfoPtr xkbi = NULL; - - if (!IsMaster(master)) - return; - - if (!master->key) - return; - - xkbi = master->key->xkbInfo; - xkbi->lockedPtrButtons = 0; - - for (; d; d = d->next) { - if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key) - continue; - - xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons; - } -} +/************************************************************ +Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, 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 Silicon Graphics not be +used in advertising or publicity pertaining to distribution +of the software without specific prior written permission. +Silicon Graphics makes no representation about the suitability +of this software for any purpose. It is provided "as is" +without any express or implied warranty. + +SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS 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. + +********************************************************/ +/* + +Copyright © 2008 Red Hat Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "os.h" +#include +#include +#include +#include +#include +#define XK_CYRILLIC +#include +#include "misc.h" +#include "inputstr.h" +#include "eventstr.h" + +#define XKBSRV_NEED_FILE_FUNCS +#include +#include "xkbgeom.h" +#include "xkb.h" + +/***====================================================================***/ + +int +_XkbLookupAnyDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + int rc = XkbKeyboardErrorCode; + + if (id == XkbUseCoreKbd) + id = PickKeyboard(client)->id; + else if (id == XkbUseCorePtr) + id = PickPointer(client)->id; + + rc = dixLookupDevice(pDev, id, client, access_mode); + if (rc != Success) + *xkb_err = XkbErr_BadDevice; + + return rc; +} + +int +_XkbLookupKeyboard(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + if (id == XkbDfltXIId) + id = XkbUseCoreKbd; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->key || !dev->key->xkbInfo) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +int +_XkbLookupBellDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->kbdfeed && !dev->bell) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +int +_XkbLookupLedDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + if (id == XkbDfltXIId) + id = XkbUseCorePtr; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->kbdfeed && !dev->leds) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +int +_XkbLookupButtonDevice(DeviceIntPtr *pDev, int id, ClientPtr client, + Mask access_mode, int *xkb_err) +{ + DeviceIntPtr dev; + int rc; + + rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err); + if (rc != Success) + return rc; + + dev = *pDev; + if (!dev->button) { + *pDev = NULL; + *xkb_err= XkbErr_BadClass; + return XkbKeyboardErrorCode; + } + return Success; +} + +void +XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods) +{ +register unsigned tmp; + + switch (act->type) { + case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods: + if (act->mods.flags&XkbSA_UseModMapMods) + act->mods.real_mods= act->mods.mask= mods; + if ((tmp= XkbModActionVMods(&act->mods))!=0) + act->mods.mask|= XkbMaskForVMask(xkb,tmp); + break; + case XkbSA_ISOLock: + if (act->iso.flags&XkbSA_UseModMapMods) + act->iso.real_mods= act->iso.mask= mods; + if ((tmp= XkbModActionVMods(&act->iso))!=0) + act->iso.mask|= XkbMaskForVMask(xkb,tmp); + break; + } + return; +} + +unsigned +XkbMaskForVMask(XkbDescPtr xkb,unsigned vmask) +{ +register int i,bit; +register unsigned mask; + + for (mask=i=0,bit=1;iserver->vmods[i]; + } + return mask; +} + +/***====================================================================***/ + +void +XkbUpdateKeyTypesFromCore( DeviceIntPtr pXDev, + KeySymsPtr pCore, + KeyCode first, + CARD8 num, + XkbChangesPtr changes) +{ +XkbDescPtr xkb; +unsigned key,nG,explicit; +int types[XkbNumKbdGroups]; +KeySym tsyms[XkbMaxSymsPerKey],*syms; +XkbMapChangesPtr mc; + + xkb= pXDev->key->xkbInfo->desc; + if (first+num-1>xkb->max_key_code) { + /* 1/12/95 (ef) -- XXX! should allow XKB structures to grow */ + num= xkb->max_key_code-first+1; + } + + mc= (changes?(&changes->map):NULL); + + syms= &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth]; + for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) { + explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask; + types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index); + types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index); + types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index); + types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index); + nG= XkbKeyTypesForCoreSymbols(xkb,pCore->mapWidth,syms,explicit,types, + tsyms); + XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc); + memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms, + XkbKeyNumSyms(xkb,key)*sizeof(KeySym)); + } + if (changes->map.changed&XkbKeySymsMask) { + CARD8 oldLast,newLast; + oldLast = changes->map.first_key_sym+changes->map.num_key_syms-1; + newLast = first+num-1; + + if (firstmap.first_key_sym) + changes->map.first_key_sym = first; + if (oldLast>newLast) + newLast= oldLast; + changes->map.num_key_syms = newLast-changes->map.first_key_sym+1; + } + else { + changes->map.changed|= XkbKeySymsMask; + changes->map.first_key_sym = first; + changes->map.num_key_syms = num; + } + return; +} + +void +XkbUpdateDescActions( XkbDescPtr xkb, + KeyCode first, + CARD8 num, + XkbChangesPtr changes) +{ +register unsigned key; + + for (key=first;key<(first+num);key++) { + XkbApplyCompatMapToKey(xkb,key,changes); + } + + if (changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask)) { + unsigned char newVMods[XkbNumVirtualMods]; + register unsigned bit,i; + unsigned present; + + memset(newVMods, 0, XkbNumVirtualMods); + present= 0; + for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { + if (xkb->server->vmodmap[key]==0) + continue; + for (i=0,bit=1;iserver->vmodmap[key]) { + present|= bit; + newVMods[i]|= xkb->map->modmap[key]; + } + } + } + for (i=0,bit=1;iserver->vmods[i])) { + changes->map.changed|= XkbVirtualModsMask; + changes->map.vmods|= bit; + xkb->server->vmods[i]= newVMods[i]; + } + } + } + if (changes->map.changed&XkbVirtualModsMask) + XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes); + + if (changes->map.changed&XkbKeyActionsMask) { + CARD8 oldLast,newLast; + oldLast= changes->map.first_key_act+changes->map.num_key_acts-1; + newLast = first+num-1; + + if (firstmap.first_key_act) + changes->map.first_key_act = first; + if (newLast>oldLast) + newLast= oldLast; + changes->map.num_key_acts= newLast-changes->map.first_key_act+1; + } + else { + changes->map.changed|= XkbKeyActionsMask; + changes->map.first_key_act = first; + changes->map.num_key_acts = num; + } + return; +} + +void +XkbUpdateActions( DeviceIntPtr pXDev, + KeyCode first, + CARD8 num, + XkbChangesPtr changes, + unsigned * needChecksRtrn, + XkbEventCausePtr cause) +{ +XkbSrvInfoPtr xkbi; +XkbDescPtr xkb; +CARD8 * repeat; + + if (needChecksRtrn) + *needChecksRtrn= 0; + xkbi= pXDev->key->xkbInfo; + xkb= xkbi->desc; + repeat= xkb->ctrls->per_key_repeat; + + /* before letting XKB do any changes, copy the current core values */ + if (pXDev->kbdfeed) + memcpy(repeat,pXDev->kbdfeed->ctrl.autoRepeats,XkbPerKeyBitArraySize); + + XkbUpdateDescActions(xkb,first,num,changes); + + if ((pXDev->kbdfeed)&& + (changes->ctrls.changed_ctrls&XkbPerKeyRepeatMask)) { + /* now copy the modified changes back to core */ + memcpy(pXDev->kbdfeed->ctrl.autoRepeats,repeat, XkbPerKeyBitArraySize); + if (pXDev->kbdfeed->CtrlProc) + (*pXDev->kbdfeed->CtrlProc)(pXDev, &pXDev->kbdfeed->ctrl); + } + return; +} + +KeySymsPtr +XkbGetCoreMap(DeviceIntPtr keybd) +{ +register int key,tmp; +int maxSymsPerKey, maxGroup1Width; +XkbDescPtr xkb; +KeySymsPtr syms; +int maxNumberOfGroups; + + if (!keybd || !keybd->key || !keybd->key->xkbInfo) + return NULL; + + xkb= keybd->key->xkbInfo->desc; + maxSymsPerKey= maxGroup1Width= 0; + maxNumberOfGroups = 0; + + /* determine sizes */ + for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { + if (XkbKeycodeInRange(xkb,key)) { + int nGroups; + int w; + nGroups= XkbKeyNumGroups(xkb,key); + tmp= 0; + if (nGroups>0) { + if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup1Index))<=2) + tmp+= 2; + else tmp+= w + 2; + /* remember highest G1 width */ + if (w > maxGroup1Width) + maxGroup1Width = w; + } + if (nGroups>1) { + if (tmp <= 2) { + if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))<2) + tmp+= 2; + else tmp+= w; + } else { + if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2) + tmp+= w - 2; + } + } + if (nGroups>2) + tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup3Index); + if (nGroups>3) + tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup4Index); + if (tmp>maxSymsPerKey) + maxSymsPerKey= tmp; + if (nGroups > maxNumberOfGroups) + maxNumberOfGroups = nGroups; + } + } + + if (maxSymsPerKey <= 0) + return NULL; + + syms = calloc(1, sizeof(*syms)); + if (!syms) + return NULL; + + /* See Section 12.4 of the XKB Protocol spec. Because of the + * single-group distribution for multi-group keyboards, we have to + * have enough symbols for the largest group 1 to replicate across the + * number of groups on the keyboard. e.g. a single-group key with 4 + * symbols on a keyboard that has 3 groups -> 12 syms per key */ + if (maxSymsPerKey < maxNumberOfGroups * maxGroup1Width) + maxSymsPerKey = maxNumberOfGroups * maxGroup1Width; + + syms->mapWidth = maxSymsPerKey; + syms->minKeyCode = xkb->min_key_code; + syms->maxKeyCode = xkb->max_key_code; + + tmp = syms->mapWidth * (xkb->max_key_code - xkb->min_key_code + 1); + syms->map = calloc(tmp, sizeof(*syms->map)); + if (!syms->map) { + free(syms); + return NULL; + } + + for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) { + KeySym *pCore,*pXKB; + unsigned nGroups,groupWidth,n,nOut; + + nGroups= XkbKeyNumGroups(xkb,key); + n= (key-xkb->min_key_code)*syms->mapWidth; + pCore= &syms->map[n]; + pXKB= XkbKeySymsPtr(xkb,key); + nOut= 2; + if (nGroups>0) { + groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup1Index); + if (groupWidth>0) pCore[0]= pXKB[0]; + if (groupWidth>1) pCore[1]= pXKB[1]; + for (n=2;n2) + nOut= groupWidth; + } + + /* See XKB Protocol Sec, Section 12.4. + A 1-group key with ABCDE on a 2 group keyboard must be + duplicated across all groups as ABABCDECDE. + */ + if (nGroups == 1) + { + int idx, j; + + groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index); + + /* AB..CDE... -> ABABCDE... */ + if (groupWidth > 0 && syms->mapWidth >= 3) + pCore[2] = pCore[0]; + if (groupWidth > 1 && syms->mapWidth >= 4) + pCore[3] = pCore[1]; + + /* ABABCDE... -> ABABCDECDE */ + idx = 2 + groupWidth; + while (groupWidth > 2 && idx < syms->mapWidth && + idx < groupWidth * 2) + { + pCore[idx] = pCore[idx - groupWidth + 2]; + idx++; + } + idx = 2 * groupWidth; + if (idx < 4) + idx = 4; + /* 3 or more groups: ABABCDECDEABCDEABCDE */ + for (j = 3; j <= maxNumberOfGroups; j++) + for (n = 0; n < groupWidth && idx < maxSymsPerKey; n++) + pCore[idx++] = pXKB[n]; + } + + pXKB+= XkbKeyGroupsWidth(xkb,key); + nOut+= 2; + if (nGroups>1) { + groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup2Index); + if (groupWidth>0) pCore[2]= pXKB[0]; + if (groupWidth>1) pCore[3]= pXKB[1]; + for (n=2;n2) + nOut+= (groupWidth-2); + } + pXKB+= XkbKeyGroupsWidth(xkb,key); + for (n=XkbGroup3Index;nkey && pXDev->key->xkbInfo) { + xkbControlsNotify cn; + XkbControlsPtr ctrls = pXDev->key->xkbInfo->desc->ctrls; + XkbControlsRec old; + old = *ctrls; + + if (key== -1) { /* global autorepeat setting changed */ + if (onoff) ctrls->enabled_ctrls |= XkbRepeatKeysMask; + else ctrls->enabled_ctrls &= ~XkbRepeatKeysMask; + } + else if (pXDev->kbdfeed) { + ctrls->per_key_repeat[key/8] = + pXDev->kbdfeed->ctrl.autoRepeats[key/8]; + } + + if (XkbComputeControlsNotify(pXDev,&old,ctrls,&cn,TRUE)) + XkbSendControlsNotify(pXDev,&cn); + } + return; +} + +/* Applies a change to a single device, does not traverse the device tree. */ +void +XkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key, + CARD8 num_keys, CARD8 *modmap, ClientPtr client) +{ + XkbDescPtr xkb = kbd->key->xkbInfo->desc; + XkbEventCauseRec cause; + XkbChangesRec changes; + unsigned int check; + + memset(&changes, 0, sizeof(changes)); + memset(&cause, 0, sizeof(cause)); + + if (map && first_key && num_keys) { + check = 0; + XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client); + + XkbUpdateKeyTypesFromCore(kbd, map, first_key, num_keys, &changes); + XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause); + + if (check) + XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); + } + + if (modmap) { + /* A keymap change can imply a modmap change, se we prefer the + * former. */ + if (!cause.mjr) + XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client); + + check = 0; + num_keys = xkb->max_key_code - xkb->min_key_code + 1; + changes.map.changed |= XkbModifierMapMask; + changes.map.first_modmap_key = xkb->min_key_code; + changes.map.num_modmap_keys = num_keys; + memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH); + XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check, + &cause); + + if (check) + XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause); + } + + XkbSendNotification(kbd, &changes, &cause); +} + +void +XkbDisableComputedAutoRepeats(DeviceIntPtr dev,unsigned key) +{ +XkbSrvInfoPtr xkbi = dev->key->xkbInfo; +xkbMapNotify mn; + + xkbi->desc->server->explicit[key]|= XkbExplicitAutoRepeatMask; + memset(&mn, 0, sizeof(mn)); + mn.changed= XkbExplicitComponentsMask; + mn.firstKeyExplicit= key; + mn.nKeyExplicit= 1; + XkbSendMapNotify(dev,&mn); + return; +} + +unsigned +XkbStateChangedFlags(XkbStatePtr old,XkbStatePtr new) +{ +int changed; + + changed=(old->group!=new->group?XkbGroupStateMask:0); + changed|=(old->base_group!=new->base_group?XkbGroupBaseMask:0); + changed|=(old->latched_group!=new->latched_group?XkbGroupLatchMask:0); + changed|=(old->locked_group!=new->locked_group?XkbGroupLockMask:0); + changed|=(old->mods!=new->mods?XkbModifierStateMask:0); + changed|=(old->base_mods!=new->base_mods?XkbModifierBaseMask:0); + changed|=(old->latched_mods!=new->latched_mods?XkbModifierLatchMask:0); + changed|=(old->locked_mods!=new->locked_mods?XkbModifierLockMask:0); + changed|=(old->compat_state!=new->compat_state?XkbCompatStateMask:0); + changed|=(old->grab_mods!=new->grab_mods?XkbGrabModsMask:0); + if (old->compat_grab_mods!=new->compat_grab_mods) + changed|= XkbCompatGrabModsMask; + changed|=(old->lookup_mods!=new->lookup_mods?XkbLookupModsMask:0); + if (old->compat_lookup_mods!=new->compat_lookup_mods) + changed|= XkbCompatLookupModsMask; + changed|=(old->ptr_buttons!=new->ptr_buttons?XkbPointerButtonMask:0); + return changed; +} + +static void +XkbComputeCompatState(XkbSrvInfoPtr xkbi) +{ +CARD16 grp_mask; +XkbStatePtr state= &xkbi->state; +XkbCompatMapPtr map; + + if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat) + return; + + map= xkbi->desc->compat; + grp_mask= map->groups[state->group].mask; + state->compat_state = state->mods|grp_mask; + state->compat_lookup_mods= state->lookup_mods|grp_mask; + + if (xkbi->desc->ctrls->enabled_ctrls&XkbIgnoreGroupLockMask) + grp_mask= map->groups[state->base_group].mask; + state->compat_grab_mods= state->grab_mods|grp_mask; + return; +} + +unsigned +XkbAdjustGroup(int group,XkbControlsPtr ctrls) +{ +unsigned act; + + act= XkbOutOfRangeGroupAction(ctrls->groups_wrap); + if (group<0) { + while ( group < 0 ) { + if (act==XkbClampIntoRange) { + group= XkbGroup1Index; + } + else if (act==XkbRedirectIntoRange) { + int newGroup; + newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); + if (newGroup>=ctrls->num_groups) + group= XkbGroup1Index; + else group= newGroup; + } + else { + group+= ctrls->num_groups; + } + } + } + else if (group>=ctrls->num_groups) { + if (act==XkbClampIntoRange) { + group= ctrls->num_groups-1; + } + else if (act==XkbRedirectIntoRange) { + int newGroup; + newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap); + if (newGroup>=ctrls->num_groups) + group= XkbGroup1Index; + else group= newGroup; + } + else { + group%= ctrls->num_groups; + } + } + return group; +} + +void +XkbComputeDerivedState(XkbSrvInfoPtr xkbi) +{ +XkbStatePtr state= &xkbi->state; +XkbControlsPtr ctrls= xkbi->desc->ctrls; +unsigned char grp; + + if (!state || !ctrls) + return; + + state->mods= (state->base_mods|state->latched_mods|state->locked_mods); + state->lookup_mods= state->mods&(~ctrls->internal.mask); + state->grab_mods= state->lookup_mods&(~ctrls->ignore_lock.mask); + state->grab_mods|= + ((state->base_mods|state->latched_mods)&ctrls->ignore_lock.mask); + + + grp= state->locked_group; + if (grp>=ctrls->num_groups) + state->locked_group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); + + grp= state->locked_group+state->base_group+state->latched_group; + if (grp>=ctrls->num_groups) + state->group= XkbAdjustGroup(XkbCharToInt(grp),ctrls); + else state->group= grp; + XkbComputeCompatState(xkbi); + return; +} + +/***====================================================================***/ + +void +XkbCheckSecondaryEffects( XkbSrvInfoPtr xkbi, + unsigned which, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ + if (which&XkbStateNotifyMask) { + XkbStateRec old; + old= xkbi->state; + changes->state_changes|= XkbStateChangedFlags(&old,&xkbi->state); + XkbComputeDerivedState(xkbi); + } + if (which&XkbIndicatorStateNotifyMask) + XkbUpdateIndicators(xkbi->device,XkbAllIndicatorsMask,TRUE,changes, + cause); + return; +} + +/***====================================================================***/ + +Bool +XkbEnableDisableControls( XkbSrvInfoPtr xkbi, + unsigned long change, + unsigned long newValues, + XkbChangesPtr changes, + XkbEventCausePtr cause) +{ +XkbControlsPtr ctrls; +unsigned old; +XkbSrvLedInfoPtr sli; + + ctrls= xkbi->desc->ctrls; + old= ctrls->enabled_ctrls; + ctrls->enabled_ctrls&= ~change; + ctrls->enabled_ctrls|= (change&newValues); + if (old==ctrls->enabled_ctrls) + return FALSE; + if (cause!=NULL) { + xkbControlsNotify cn; + cn.numGroups= ctrls->num_groups; + cn.changedControls= XkbControlsEnabledMask; + cn.enabledControls= ctrls->enabled_ctrls; + cn.enabledControlChanges= (ctrls->enabled_ctrls^old); + cn.keycode= cause->kc; + cn.eventType= cause->event; + cn.requestMajor= cause->mjr; + cn.requestMinor= cause->mnr; + XkbSendControlsNotify(xkbi->device,&cn); + } + else { + /* Yes, this really should be an XOR. If ctrls->enabled_ctrls_changes*/ + /* is non-zero, the controls in question changed already in "this" */ + /* request and this change merely undoes the previous one. By the */ + /* same token, we have to figure out whether or not ControlsEnabled */ + /* should be set or not in the changes structure */ + changes->ctrls.enabled_ctrls_changes^= (ctrls->enabled_ctrls^old); + if (changes->ctrls.enabled_ctrls_changes) + changes->ctrls.changed_ctrls|= XkbControlsEnabledMask; + else changes->ctrls.changed_ctrls&= ~XkbControlsEnabledMask; + } + sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateIndicators(xkbi->device,sli->usesControls,TRUE,changes,cause); + return TRUE; +} + +/***====================================================================***/ + +#define MAX_TOC 16 + +XkbGeometryPtr +XkbLookupNamedGeometry(DeviceIntPtr dev,Atom name,Bool *shouldFree) +{ +XkbSrvInfoPtr xkbi= dev->key->xkbInfo; +XkbDescPtr xkb= xkbi->desc; + + *shouldFree= 0; + if (name==None) { + if (xkb->geom!=NULL) + return xkb->geom; + name= xkb->names->geometry; + } + if ((xkb->geom!=NULL)&&(xkb->geom->name==name)) + return xkb->geom; + *shouldFree= 1; + return NULL; +} + +void +XkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper) +{ + *lower = sym; + *upper = sym; + switch(sym >> 8) { + case 0: /* Latin 1 */ + if ((sym >= XK_A) && (sym <= XK_Z)) + *lower += (XK_a - XK_A); + else if ((sym >= XK_a) && (sym <= XK_z)) + *upper -= (XK_a - XK_A); + else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + *lower += (XK_agrave - XK_Agrave); + else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) + *upper -= (XK_agrave - XK_Agrave); + else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) + *lower += (XK_oslash - XK_Ooblique); + else if ((sym >= XK_oslash) && (sym <= XK_thorn)) + *upper -= (XK_oslash - XK_Ooblique); + break; + case 1: /* Latin 2 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym == XK_Aogonek) + *lower = XK_aogonek; + else if (sym >= XK_Lstroke && sym <= XK_Sacute) + *lower += (XK_lstroke - XK_Lstroke); + else if (sym >= XK_Scaron && sym <= XK_Zacute) + *lower += (XK_scaron - XK_Scaron); + else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) + *lower += (XK_zcaron - XK_Zcaron); + else if (sym == XK_aogonek) + *upper = XK_Aogonek; + else if (sym >= XK_lstroke && sym <= XK_sacute) + *upper -= (XK_lstroke - XK_Lstroke); + else if (sym >= XK_scaron && sym <= XK_zacute) + *upper -= (XK_scaron - XK_Scaron); + else if (sym >= XK_zcaron && sym <= XK_zabovedot) + *upper -= (XK_zcaron - XK_Zcaron); + else if (sym >= XK_Racute && sym <= XK_Tcedilla) + *lower += (XK_racute - XK_Racute); + else if (sym >= XK_racute && sym <= XK_tcedilla) + *upper -= (XK_racute - XK_Racute); + break; + case 2: /* Latin 3 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) + *lower += (XK_hstroke - XK_Hstroke); + else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) + *lower += (XK_gbreve - XK_Gbreve); + else if (sym >= XK_hstroke && sym <= XK_hcircumflex) + *upper -= (XK_hstroke - XK_Hstroke); + else if (sym >= XK_gbreve && sym <= XK_jcircumflex) + *upper -= (XK_gbreve - XK_Gbreve); + else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) + *lower += (XK_cabovedot - XK_Cabovedot); + else if (sym >= XK_cabovedot && sym <= XK_scircumflex) + *upper -= (XK_cabovedot - XK_Cabovedot); + break; + case 3: /* Latin 4 */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Rcedilla && sym <= XK_Tslash) + *lower += (XK_rcedilla - XK_Rcedilla); + else if (sym >= XK_rcedilla && sym <= XK_tslash) + *upper -= (XK_rcedilla - XK_Rcedilla); + else if (sym == XK_ENG) + *lower = XK_eng; + else if (sym == XK_eng) + *upper = XK_ENG; + else if (sym >= XK_Amacron && sym <= XK_Umacron) + *lower += (XK_amacron - XK_Amacron); + else if (sym >= XK_amacron && sym <= XK_umacron) + *upper -= (XK_amacron - XK_Amacron); + break; + case 6: /* Cyrillic */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) + *lower -= (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) + *upper += (XK_Serbian_DJE - XK_Serbian_dje); + else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) + *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); + else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) + *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); + break; + case 7: /* Greek */ + /* Assume the KeySym is a legal value (ignore discontinuities) */ + if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) + *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && + sym != XK_Greek_iotaaccentdieresis && + sym != XK_Greek_upsilonaccentdieresis) + *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); + else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) + *lower += (XK_Greek_alpha - XK_Greek_ALPHA); + else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && + sym != XK_Greek_finalsmallsigma) + *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); + break; + } +} + +static Bool +_XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + int i; + XkbKeyTypePtr stype = NULL, dtype = NULL; + + /* client map */ + if (src->map) { + if (!dst->map) { + tmp = calloc(1, sizeof(XkbClientMapRec)); + if (!tmp) + return FALSE; + dst->map = tmp; + } + + if (src->map->syms) { + if (src->map->size_syms != dst->map->size_syms) { + tmp = realloc(dst->map->syms, + src->map->size_syms * sizeof(KeySym)); + if (!tmp) + return FALSE; + dst->map->syms = tmp; + + } + memcpy(dst->map->syms, src->map->syms, + src->map->size_syms * sizeof(KeySym)); + } + else { + free(dst->map->syms); + dst->map->syms = NULL; + } + dst->map->num_syms = src->map->num_syms; + dst->map->size_syms = src->map->size_syms; + + if (src->map->key_sym_map) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->map->key_sym_map, + (src->max_key_code + 1) * sizeof(XkbSymMapRec)); + if (!tmp) + return FALSE; + dst->map->key_sym_map = tmp; + } + memcpy(dst->map->key_sym_map, src->map->key_sym_map, + (src->max_key_code + 1) * sizeof(XkbSymMapRec)); + } + else { + free(dst->map->key_sym_map); + dst->map->key_sym_map = NULL; + } + + if (src->map->types && src->map->num_types) { + if (src->map->num_types > dst->map->size_types || + !dst->map->types || !dst->map->size_types) { + if (dst->map->types && dst->map->size_types) { + tmp = realloc(dst->map->types, + src->map->num_types * sizeof(XkbKeyTypeRec)); + if (!tmp) + return FALSE; + dst->map->types = tmp; + memset(dst->map->types + dst->map->num_types, 0, + (src->map->num_types - dst->map->num_types) * + sizeof(XkbKeyTypeRec)); + } + else { + tmp = calloc(src->map->num_types, sizeof(XkbKeyTypeRec)); + if (!tmp) + return FALSE; + dst->map->types = tmp; + } + } + else if (src->map->num_types < dst->map->num_types && + dst->map->types) { + for (i = src->map->num_types, dtype = (dst->map->types + i); + i < dst->map->num_types; i++, dtype++) { + free(dtype->level_names); + dtype->level_names = NULL; + dtype->num_levels = 0; + if (dtype->map_count) { + free(dtype->map); + free(dtype->preserve); + } + } + } + + stype = src->map->types; + dtype = dst->map->types; + for (i = 0; i < src->map->num_types; i++, dtype++, stype++) { + if (stype->num_levels && stype->level_names) { + if (stype->num_levels != dtype->num_levels && + dtype->num_levels && dtype->level_names && + i < dst->map->num_types) { + tmp = realloc(dtype->level_names, + stype->num_levels * sizeof(Atom)); + if (!tmp) + continue; + dtype->level_names = tmp; + } + else if (!dtype->num_levels || !dtype->level_names || + i >= dst->map->num_types) { + tmp = malloc(stype->num_levels * sizeof(Atom)); + if (!tmp) + continue; + dtype->level_names = tmp; + } + dtype->num_levels = stype->num_levels; + memcpy(dtype->level_names, stype->level_names, + stype->num_levels * sizeof(Atom)); + } + else { + if (dtype->num_levels && dtype->level_names && + i < dst->map->num_types) + free(dtype->level_names); + dtype->num_levels = 0; + dtype->level_names = NULL; + } + + dtype->name = stype->name; + memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec)); + + if (stype->map_count) { + if (stype->map) { + if (stype->map_count != dtype->map_count && + dtype->map_count && dtype->map && + i < dst->map->num_types) { + tmp = realloc(dtype->map, + stype->map_count * + sizeof(XkbKTMapEntryRec)); + if (!tmp) + return FALSE; + dtype->map = tmp; + } + else if (!dtype->map_count || !dtype->map || + i >= dst->map->num_types) { + tmp = malloc(stype->map_count * + sizeof(XkbKTMapEntryRec)); + if (!tmp) + return FALSE; + dtype->map = tmp; + } + + memcpy(dtype->map, stype->map, + stype->map_count * sizeof(XkbKTMapEntryRec)); + } + else { + if (dtype->map && i < dst->map->num_types) + free(dtype->map); + dtype->map = NULL; + } + + if (stype->preserve) { + if (stype->map_count != dtype->map_count && + dtype->map_count && dtype->preserve && + i < dst->map->num_types) { + tmp = realloc(dtype->preserve, + stype->map_count * + sizeof(XkbModsRec)); + if (!tmp) + return FALSE; + dtype->preserve = tmp; + } + else if (!dtype->preserve || !dtype->map_count || + i >= dst->map->num_types) { + tmp = malloc(stype->map_count * + sizeof(XkbModsRec)); + if (!tmp) + return FALSE; + dtype->preserve = tmp; + } + + memcpy(dtype->preserve, stype->preserve, + stype->map_count * sizeof(XkbModsRec)); + } + else { + if (dtype->preserve && i < dst->map->num_types) + free(dtype->preserve); + dtype->preserve = NULL; + } + + dtype->map_count = stype->map_count; + } + else { + if (dtype->map_count && i < dst->map->num_types) { + free(dtype->map); + free(dtype->preserve); + } + dtype->map_count = 0; + dtype->map = NULL; + dtype->preserve = NULL; + } + } + + dst->map->size_types = src->map->num_types; + dst->map->num_types = src->map->num_types; + } + else { + if (dst->map->types) { + for (i = 0, dtype = dst->map->types; i < dst->map->num_types; + i++, dtype++) { + free(dtype->level_names); + if (dtype->map && dtype->map_count) + free(dtype->map); + if (dtype->preserve && dtype->map_count) + free(dtype->preserve); + } + } + free(dst->map->types); + dst->map->types = NULL; + dst->map->num_types = 0; + dst->map->size_types = 0; + } + + if (src->map->modmap) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->map->modmap, src->max_key_code + 1); + if (!tmp) + return FALSE; + dst->map->modmap = tmp; + } + memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1); + } + else { + free(dst->map->modmap); + dst->map->modmap = NULL; + } + } + else { + if (dst->map) + XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + + /* server map */ + if (src->server) { + if (!dst->server) { + tmp = calloc(1, sizeof(XkbServerMapRec)); + if (!tmp) + return FALSE; + dst->server = tmp; + } + + if (src->server->explicit) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->server->explicit, src->max_key_code + 1); + if (!tmp) + return FALSE; + dst->server->explicit = tmp; + } + memcpy(dst->server->explicit, src->server->explicit, + src->max_key_code + 1); + } + else { + free(dst->server->explicit); + dst->server->explicit = NULL; + } + + if (src->server->acts) { + if (src->server->size_acts != dst->server->size_acts) { + tmp = realloc(dst->server->acts, + src->server->size_acts * sizeof(XkbAction)); + if (!tmp) + return FALSE; + dst->server->acts = tmp; + } + memcpy(dst->server->acts, src->server->acts, + src->server->size_acts * sizeof(XkbAction)); + } + else { + free(dst->server->acts); + dst->server->acts = NULL; + } + dst->server->size_acts = src->server->size_acts; + dst->server->num_acts = src->server->num_acts; + + if (src->server->key_acts) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->server->key_acts, + (src->max_key_code + 1) * sizeof(unsigned short)); + if (!tmp) + return FALSE; + dst->server->key_acts = tmp; + } + memcpy(dst->server->key_acts, src->server->key_acts, + (src->max_key_code + 1) * sizeof(unsigned short)); + } + else { + free(dst->server->key_acts); + dst->server->key_acts = NULL; + } + + if (src->server->behaviors) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->server->behaviors, + (src->max_key_code + 1) * sizeof(XkbBehavior)); + if (!tmp) + return FALSE; + dst->server->behaviors = tmp; + } + memcpy(dst->server->behaviors, src->server->behaviors, + (src->max_key_code + 1) * sizeof(XkbBehavior)); + } + else { + free(dst->server->behaviors); + dst->server->behaviors = NULL; + } + + memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods); + + if (src->server->vmodmap) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->server->vmodmap, + (src->max_key_code + 1) * sizeof(unsigned short)); + if (!tmp) + return FALSE; + dst->server->vmodmap = tmp; + } + memcpy(dst->server->vmodmap, src->server->vmodmap, + (src->max_key_code + 1) * sizeof(unsigned short)); + } + else { + free(dst->server->vmodmap); + dst->server->vmodmap = NULL; + } + } + else { + if (dst->server) + XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + + /* names */ + if (src->names) { + if (!dst->names) { + dst->names = calloc(1, sizeof(XkbNamesRec)); + if (!dst->names) + return FALSE; + } + + if (src->names->keys) { + if (src->max_key_code != dst->max_key_code) { + tmp = realloc(dst->names->keys, + (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); + if (!tmp) + return FALSE; + dst->names->keys = tmp; + } + memcpy(dst->names->keys, src->names->keys, + (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); + } + else { + free(dst->names->keys); + dst->names->keys = NULL; + } + + if (src->names->num_key_aliases) { + if (src->names->num_key_aliases != dst->names->num_key_aliases) { + tmp = realloc(dst->names->key_aliases, + src->names->num_key_aliases * + sizeof(XkbKeyAliasRec)); + if (!tmp) + return FALSE; + dst->names->key_aliases = tmp; + } + memcpy(dst->names->key_aliases, src->names->key_aliases, + src->names->num_key_aliases * sizeof(XkbKeyAliasRec)); + } + else { + free(dst->names->key_aliases); + dst->names->key_aliases = NULL; + } + dst->names->num_key_aliases = src->names->num_key_aliases; + + if (src->names->num_rg) { + if (src->names->num_rg != dst->names->num_rg) { + tmp = realloc(dst->names->radio_groups, + src->names->num_rg * sizeof(Atom)); + if (!tmp) + return FALSE; + dst->names->radio_groups = tmp; + } + memcpy(dst->names->radio_groups, src->names->radio_groups, + src->names->num_rg * sizeof(Atom)); + } + else { + free(dst->names->radio_groups); + } + dst->names->num_rg = src->names->num_rg; + + dst->names->keycodes = src->names->keycodes; + dst->names->geometry = src->names->geometry; + dst->names->symbols = src->names->symbols; + dst->names->types = src->names->types; + dst->names->compat = src->names->compat; + dst->names->phys_symbols = src->names->phys_symbols; + + memcpy(dst->names->vmods, src->names->vmods, + XkbNumVirtualMods * sizeof(Atom)); + memcpy(dst->names->indicators, src->names->indicators, + XkbNumIndicators * sizeof(Atom)); + memcpy(dst->names->groups, src->names->groups, + XkbNumKbdGroups * sizeof(Atom)); + } + else { + if (dst->names) + XkbFreeNames(dst, XkbAllNamesMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + + /* compat */ + if (src->compat) { + if (!dst->compat) { + dst->compat = calloc(1, sizeof(XkbCompatMapRec)); + if (!dst->compat) + return FALSE; + } + + if (src->compat->sym_interpret && src->compat->num_si) { + if (src->compat->num_si != dst->compat->size_si) { + tmp = realloc(dst->compat->sym_interpret, + src->compat->num_si * sizeof(XkbSymInterpretRec)); + if (!tmp) + return FALSE; + dst->compat->sym_interpret = tmp; + } + memcpy(dst->compat->sym_interpret, src->compat->sym_interpret, + src->compat->num_si * sizeof(XkbSymInterpretRec)); + + dst->compat->num_si = src->compat->num_si; + dst->compat->size_si = src->compat->num_si; + } + else { + if (dst->compat->sym_interpret && dst->compat->size_si) + free(dst->compat->sym_interpret); + + dst->compat->sym_interpret = NULL; + dst->compat->num_si = 0; + dst->compat->size_si = 0; + } + + memcpy(dst->compat->groups, src->compat->groups, + XkbNumKbdGroups * sizeof(XkbModsRec)); + } + else { + if (dst->compat) + XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE); + } + + return TRUE; +} + +static Bool +_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst) +{ + void *tmp = NULL; + int i = 0, j = 0, k = 0; + XkbColorPtr scolor = NULL, dcolor = NULL; + XkbDoodadPtr sdoodad = NULL, ddoodad = NULL; + XkbOutlinePtr soutline = NULL, doutline = NULL; + XkbPropertyPtr sprop = NULL, dprop = NULL; + XkbRowPtr srow = NULL, drow = NULL; + XkbSectionPtr ssection = NULL, dsection = NULL; + XkbShapePtr sshape = NULL, dshape = NULL; + + /* geometry */ + if (src->geom) { + if (!dst->geom) { + dst->geom = calloc(sizeof(XkbGeometryRec), 1); + if (!dst->geom) + return FALSE; + } + + /* properties */ + if (src->geom->num_properties) { + if (src->geom->num_properties != dst->geom->sz_properties) { + /* If we've got more properties in the destination than + * the source, run through and free all the excess ones + * first. */ + if (src->geom->num_properties < dst->geom->sz_properties) { + for (i = src->geom->num_properties, + dprop = dst->geom->properties + i; + i < dst->geom->num_properties; + i++, dprop++) { + free(dprop->name); + free(dprop->value); + } + } + + if (dst->geom->sz_properties) + tmp = realloc(dst->geom->properties, + src->geom->num_properties * + sizeof(XkbPropertyRec)); + else + tmp = malloc(src->geom->num_properties * + sizeof(XkbPropertyRec)); + if (!tmp) + return FALSE; + dst->geom->properties = tmp; + } + + /* We don't set num_properties as we need it to try and avoid + * too much reallocing. */ + dst->geom->sz_properties = src->geom->num_properties; + + if (dst->geom->sz_properties > dst->geom->num_properties) { + memset(dst->geom->properties + dst->geom->num_properties, 0, + (dst->geom->sz_properties - dst->geom->num_properties) * + sizeof(XkbPropertyRec)); + } + + for (i = 0, + sprop = src->geom->properties, + dprop = dst->geom->properties; + i < src->geom->num_properties; + i++, sprop++, dprop++) { + if (i < dst->geom->num_properties) { + if (strlen(sprop->name) != strlen(dprop->name)) { + tmp = realloc(dprop->name, strlen(sprop->name) + 1); + if (!tmp) + return FALSE; + dprop->name = tmp; + } + if (strlen(sprop->value) != strlen(dprop->value)) { + tmp = realloc(dprop->value, strlen(sprop->value) + 1); + if (!tmp) + return FALSE; + dprop->value = tmp; + } + strcpy(dprop->name, sprop->name); + strcpy(dprop->value, sprop->value); + } + else { + dprop->name = xstrdup(sprop->name); + dprop->value = xstrdup(sprop->value); + } + } + + /* ... which is already src->geom->num_properties. */ + dst->geom->num_properties = dst->geom->sz_properties; + } + else { + if (dst->geom->sz_properties) { + for (i = 0, dprop = dst->geom->properties; + i < dst->geom->num_properties; + i++, dprop++) { + free(dprop->name); + free(dprop->value); + } + free(dst->geom->properties); + dst->geom->properties = NULL; + } + + dst->geom->num_properties = 0; + dst->geom->sz_properties = 0; + } + + /* colors */ + if (src->geom->num_colors) { + if (src->geom->num_colors != dst->geom->sz_colors) { + if (src->geom->num_colors < dst->geom->sz_colors) { + for (i = src->geom->num_colors, + dcolor = dst->geom->colors + i; + i < dst->geom->num_colors; + i++, dcolor++) { + free(dcolor->spec); + } + } + + if (dst->geom->sz_colors) + tmp = realloc(dst->geom->colors, + src->geom->num_colors * + sizeof(XkbColorRec)); + else + tmp = malloc(src->geom->num_colors * + sizeof(XkbColorRec)); + if (!tmp) + return FALSE; + dst->geom->colors = tmp; + } + + dst->geom->sz_colors = src->geom->num_colors; + + if (dst->geom->sz_colors > dst->geom->num_colors) { + memset(dst->geom->colors + dst->geom->num_colors, 0, + (dst->geom->sz_colors - dst->geom->num_colors) * + sizeof(XkbColorRec)); + } + + for (i = 0, + scolor = src->geom->colors, + dcolor = dst->geom->colors; + i < src->geom->num_colors; + i++, scolor++, dcolor++) { + if (i < dst->geom->num_colors) { + if (strlen(scolor->spec) != strlen(dcolor->spec)) { + tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1); + if (!tmp) + return FALSE; + dcolor->spec = tmp; + } + strcpy(dcolor->spec, scolor->spec); + } + else { + dcolor->spec = xstrdup(scolor->spec); + } + dcolor->pixel = scolor->pixel; + } + + dst->geom->num_colors = dst->geom->sz_colors; + } + else { + if (dst->geom->sz_colors) { + for (i = 0, dcolor = dst->geom->colors; + i < dst->geom->num_colors; + i++, dcolor++) { + free(dcolor->spec); + } + free(dst->geom->colors); + dst->geom->colors = NULL; + } + + dst->geom->num_colors = 0; + dst->geom->sz_colors = 0; + } + + /* shapes */ + /* shapes break down into outlines, which break down into points. */ + if (dst->geom->num_shapes) { + for (i = 0, dshape = dst->geom->shapes; + i < dst->geom->num_shapes; + i++, dshape++) { + for (j = 0, doutline = dshape->outlines; + j < dshape->num_outlines; + j++, doutline++) { + if (doutline->sz_points) + free(doutline->points); + } + + if (dshape->sz_outlines) { + free(dshape->outlines); + dshape->outlines = NULL; + } + + dshape->num_outlines = 0; + dshape->sz_outlines = 0; + } + } + + if (src->geom->num_shapes) { + tmp = calloc(src->geom->num_shapes, sizeof(XkbShapeRec)); + if (!tmp) + return FALSE; + dst->geom->shapes = tmp; + + for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes; + i < src->geom->num_shapes; + i++, sshape++, dshape++) { + if (sshape->num_outlines) { + tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec)); + if (!tmp) + return FALSE; + dshape->outlines = tmp; + + for (j = 0, + soutline = sshape->outlines, + doutline = dshape->outlines; + j < sshape->num_outlines; + j++, soutline++, doutline++) { + if (soutline->num_points) { + tmp = malloc(soutline->num_points * + sizeof(XkbPointRec)); + if (!tmp) + return FALSE; + doutline->points = tmp; + + memcpy(doutline->points, soutline->points, + soutline->num_points * sizeof(XkbPointRec)); + + doutline->corner_radius = soutline->corner_radius; + } + + doutline->num_points = soutline->num_points; + doutline->sz_points = soutline->num_points; + } + } + + dshape->num_outlines = sshape->num_outlines; + dshape->sz_outlines = sshape->num_outlines; + dshape->name = sshape->name; + dshape->bounds = sshape->bounds; + + dshape->approx = NULL; + if (sshape->approx && sshape->num_outlines > 0) { + + const ptrdiff_t approx_idx = + sshape->approx - sshape->outlines; + + if (approx_idx < dshape->num_outlines) { + dshape->approx = dshape->outlines + approx_idx; + } else { + LogMessage(X_WARNING, "XKB: approx outline " + "index is out of range\n"); + } + } + + dshape->primary = NULL; + if (sshape->primary && sshape->num_outlines > 0) { + + const ptrdiff_t primary_idx = + sshape->primary - sshape->outlines; + + if (primary_idx < dshape->num_outlines) { + dshape->primary = dshape->outlines + primary_idx; + } else { + LogMessage(X_WARNING, "XKB: primary outline " + "index is out of range\n"); + } + } + } + + dst->geom->num_shapes = src->geom->num_shapes; + dst->geom->sz_shapes = src->geom->num_shapes; + } + else { + if (dst->geom->sz_shapes) { + free(dst->geom->shapes); + } + dst->geom->shapes = NULL; + dst->geom->num_shapes = 0; + dst->geom->sz_shapes = 0; + } + + /* sections */ + /* sections break down into doodads, and also into rows, which break + * down into keys. */ + if (dst->geom->num_sections) { + for (i = 0, dsection = dst->geom->sections; + i < dst->geom->num_sections; + i++, dsection++) { + for (j = 0, drow = dsection->rows; + j < dsection->num_rows; + j++, drow++) { + if (drow->num_keys) + free(drow->keys); + } + + if (dsection->num_rows) + free(dsection->rows); + + /* cut and waste from geom/doodad below. */ + for (j = 0, ddoodad = dsection->doodads; + j < dsection->num_doodads; + j++, ddoodad++) { + if (ddoodad->any.type == XkbTextDoodad) { + free(ddoodad->text.text); + ddoodad->text.text = NULL; + free(ddoodad->text.font); + ddoodad->text.font = NULL; + } + else if (ddoodad->any.type == XkbLogoDoodad) { + free(ddoodad->logo.logo_name); + ddoodad->logo.logo_name = NULL; + } + } + + free(dsection->doodads); + } + + dst->geom->num_sections = 0; + dst->geom->sections = NULL; + } + + if (src->geom->num_sections) { + if (dst->geom->sz_sections) + tmp = realloc(dst->geom->sections, + src->geom->num_sections * + sizeof(XkbSectionRec)); + else + tmp = malloc(src->geom->num_sections * sizeof(XkbSectionRec)); + if (!tmp) + return FALSE; + memset(tmp, 0, src->geom->num_sections * sizeof(XkbSectionRec)); + dst->geom->sections = tmp; + dst->geom->num_sections = src->geom->num_sections; + dst->geom->sz_sections = src->geom->num_sections; + + for (i = 0, + ssection = src->geom->sections, + dsection = dst->geom->sections; + i < src->geom->num_sections; + i++, ssection++, dsection++) { + *dsection = *ssection; + if (ssection->num_rows) { + tmp = calloc(ssection->num_rows, sizeof(XkbRowRec)); + if (!tmp) + return FALSE; + dsection->rows = tmp; + } + dsection->num_rows = ssection->num_rows; + dsection->sz_rows = ssection->num_rows; + + for (j = 0, srow = ssection->rows, drow = dsection->rows; + j < ssection->num_rows; + j++, srow++, drow++) { + if (srow->num_keys) { + tmp = malloc(srow->num_keys * sizeof(XkbKeyRec)); + if (!tmp) + return FALSE; + drow->keys = tmp; + memcpy(drow->keys, srow->keys, + srow->num_keys * sizeof(XkbKeyRec)); + } + drow->num_keys = srow->num_keys; + drow->sz_keys = srow->num_keys; + drow->top = srow->top; + drow->left = srow->left; + drow->vertical = srow->vertical; + drow->bounds = srow->bounds; + } + + if (ssection->num_doodads) { + tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec)); + if (!tmp) + return FALSE; + dsection->doodads = tmp; + } + else { + dsection->doodads = NULL; + } + + dsection->sz_doodads = ssection->num_doodads; + for (k = 0, + sdoodad = ssection->doodads, + ddoodad = dsection->doodads; + k < ssection->num_doodads; + k++, sdoodad++, ddoodad++) { + memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); + if (sdoodad->any.type == XkbTextDoodad) { + if (sdoodad->text.text) + ddoodad->text.text = + strdup(sdoodad->text.text); + if (sdoodad->text.font) + ddoodad->text.font = + strdup(sdoodad->text.font); + } + else if (sdoodad->any.type == XkbLogoDoodad) { + if (sdoodad->logo.logo_name) + ddoodad->logo.logo_name = + strdup(sdoodad->logo.logo_name); + } + } + dsection->overlays = NULL; + dsection->sz_overlays = 0; + dsection->num_overlays = 0; + } + } + else { + if (dst->geom->sz_sections) { + free(dst->geom->sections); + } + + dst->geom->sections = NULL; + dst->geom->num_sections = 0; + dst->geom->sz_sections = 0; + } + + /* doodads */ + if (dst->geom->num_doodads) { + for (i = src->geom->num_doodads, + ddoodad = dst->geom->doodads + + src->geom->num_doodads; + i < dst->geom->num_doodads; + i++, ddoodad++) { + if (ddoodad->any.type == XkbTextDoodad) { + free(ddoodad->text.text); + ddoodad->text.text = NULL; + free(ddoodad->text.font); + ddoodad->text.font = NULL; + } + else if (ddoodad->any.type == XkbLogoDoodad) { + free(ddoodad->logo.logo_name); + ddoodad->logo.logo_name = NULL; + } + } + dst->geom->num_doodads = 0; + dst->geom->doodads = NULL; + } + + if (src->geom->num_doodads) { + if (dst->geom->sz_doodads) + tmp = realloc(dst->geom->doodads, + src->geom->num_doodads * + sizeof(XkbDoodadRec)); + else + tmp = malloc(src->geom->num_doodads * + sizeof(XkbDoodadRec)); + if (!tmp) + return FALSE; + memset(tmp, 0, src->geom->num_doodads * sizeof(XkbDoodadRec)); + dst->geom->doodads = tmp; + + dst->geom->sz_doodads = src->geom->num_doodads; + + for (i = 0, + sdoodad = src->geom->doodads, + ddoodad = dst->geom->doodads; + i < src->geom->num_doodads; + i++, sdoodad++, ddoodad++) { + memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec)); + if (sdoodad->any.type == XkbTextDoodad) { + if (sdoodad->text.text) + ddoodad->text.text = strdup(sdoodad->text.text); + if (sdoodad->text.font) + ddoodad->text.font = strdup(sdoodad->text.font); + } + else if (sdoodad->any.type == XkbLogoDoodad) { + if (sdoodad->logo.logo_name) + ddoodad->logo.logo_name = + strdup(sdoodad->logo.logo_name); + } + } + + dst->geom->num_doodads = dst->geom->sz_doodads; + } + else { + if (dst->geom->sz_doodads) { + free(dst->geom->doodads); + } + + dst->geom->doodads = NULL; + dst->geom->num_doodads = 0; + dst->geom->sz_doodads = 0; + } + + /* key aliases */ + if (src->geom->num_key_aliases) { + if (src->geom->num_key_aliases != dst->geom->sz_key_aliases) { + if (dst->geom->sz_key_aliases) + tmp = realloc(dst->geom->key_aliases, + src->geom->num_key_aliases * + 2 * XkbKeyNameLength); + else + tmp = malloc(src->geom->num_key_aliases * + 2 * XkbKeyNameLength); + if (!tmp) + return FALSE; + dst->geom->key_aliases = tmp; + + dst->geom->sz_key_aliases = src->geom->num_key_aliases; + } + + memcpy(dst->geom->key_aliases, src->geom->key_aliases, + src->geom->num_key_aliases * 2 * XkbKeyNameLength); + + dst->geom->num_key_aliases = dst->geom->sz_key_aliases; + } + else { + free(dst->geom->key_aliases); + dst->geom->key_aliases = NULL; + dst->geom->num_key_aliases = 0; + dst->geom->sz_key_aliases = 0; + } + + /* font */ + if (src->geom->label_font) { + if (!dst->geom->label_font) { + tmp = malloc(strlen(src->geom->label_font) + 1); + if (!tmp) + return FALSE; + dst->geom->label_font = tmp; + } + else if (strlen(src->geom->label_font) != + strlen(dst->geom->label_font)) { + tmp = realloc(dst->geom->label_font, + strlen(src->geom->label_font) + 1); + if (!tmp) + return FALSE; + dst->geom->label_font = tmp; + } + + strcpy(dst->geom->label_font, src->geom->label_font); + i = XkbGeomColorIndex(src->geom, src->geom->label_color); + dst->geom->label_color = &(dst->geom->colors[i]); + i = XkbGeomColorIndex(src->geom, src->geom->base_color); + dst->geom->base_color = &(dst->geom->colors[i]); + } + else { + free(dst->geom->label_font); + dst->geom->label_font = NULL; + dst->geom->label_color = NULL; + dst->geom->base_color = NULL; + } + + dst->geom->name = src->geom->name; + dst->geom->width_mm = src->geom->width_mm; + dst->geom->height_mm = src->geom->height_mm; + } + else + { + if (dst->geom) { + /* I LOVE THE DIFFERENT CALL SIGNATURE. REALLY, I DO. */ + XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE); + dst->geom = NULL; + } + } + + return TRUE; +} + +static Bool +_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst) +{ + /* indicators */ + if (src->indicators) { + if (!dst->indicators) { + dst->indicators = malloc(sizeof(XkbIndicatorRec)); + if (!dst->indicators) + return FALSE; + } + memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec)); + } + else { + free(dst->indicators); + dst->indicators = NULL; + } + return TRUE; +} + +static Bool +_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst) +{ + /* controls */ + if (src->ctrls) { + if (!dst->ctrls) { + dst->ctrls = malloc(sizeof(XkbControlsRec)); + if (!dst->ctrls) + return FALSE; + } + memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec)); + } + else { + free(dst->ctrls); + dst->ctrls = NULL; + } + return TRUE; +} + +/** + * Copy an XKB map from src to dst, reallocating when necessary: if some + * map components are present in one, but not in the other, the destination + * components will be allocated or freed as necessary. + * + * Basic map consistency is assumed on both sides, so maps with random + * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19) + * _will_ cause failures. You've been warned. + * + * Returns TRUE on success, or FALSE on failure. If this function fails, + * dst may be in an inconsistent state: all its pointers are guaranteed + * to remain valid, but part of the map may be from src and part from dst. + * + */ + +Bool +XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src) +{ + + if (!src || !dst) { + DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst); + return FALSE; + } + + if (src == dst) + return TRUE; + + if (!_XkbCopyClientMap(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy client map\n"); + return FALSE; + } + if (!_XkbCopyServerMap(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy server map\n"); + return FALSE; + } + if (!_XkbCopyIndicators(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy indicators\n"); + return FALSE; + } + if (!_XkbCopyControls(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy controls\n"); + return FALSE; + } + if (!_XkbCopyNames(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy names\n"); + return FALSE; + } + if (!_XkbCopyCompat(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy compat map\n"); + return FALSE; + } + if (!_XkbCopyGeom(src, dst)) { + DebugF("XkbCopyKeymap: failed to copy geometry\n"); + return FALSE; + } + + dst->min_key_code = src->min_key_code; + dst->max_key_code = src->max_key_code; + + return TRUE; +} + +Bool +XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src) +{ + xkbNewKeyboardNotify nkn; + Bool ret; + + if (!dst->key || !src->key) + return FALSE; + + memset(&nkn, 0, sizeof(xkbNewKeyboardNotify)); + nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code; + nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code; + nkn.deviceID = dst->id; + nkn.oldDeviceID = dst->id; /* maybe src->id? */ + nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code; + nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code; + nkn.requestMajor = XkbReqCode; + nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */ + nkn.changed = XkbNKN_KeycodesMask; + if (src->key->xkbInfo->desc->geom) + nkn.changed |= XkbNKN_GeometryMask; + + ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc); + if (ret) + XkbSendNewKeyboardNotify(dst, &nkn); + + return ret; +} + +int +XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode) +{ + XkbDescPtr xkb = xkbi->desc; + int effectiveGroup = xkbState->group; + + if (!XkbKeycodeInRange(xkb, keycode)) + return -1; + + if (effectiveGroup == XkbGroup1Index) + return effectiveGroup; + + if (XkbKeyNumGroups(xkb,keycode) > 1U) { + if (effectiveGroup >= XkbKeyNumGroups(xkb,keycode)) { + unsigned int gi = XkbKeyGroupInfo(xkb,keycode); + switch (XkbOutOfRangeGroupAction(gi)) { + default: + case XkbWrapIntoRange: + effectiveGroup %= XkbKeyNumGroups(xkb, keycode); + break; + case XkbClampIntoRange: + effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1; + break; + case XkbRedirectIntoRange: + effectiveGroup = XkbOutOfRangeGroupInfo(gi); + if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) + effectiveGroup = 0; + break; + } + } + } + else effectiveGroup = XkbGroup1Index; + + return effectiveGroup; +} + +/* Merge the lockedPtrButtons from all attached SDs for the given master + * device into the MD's state. + */ +void +XkbMergeLockedPtrBtns(DeviceIntPtr master) +{ + DeviceIntPtr d = inputInfo.devices; + XkbSrvInfoPtr xkbi = NULL; + + if (!IsMaster(master)) + return; + + if (!master->key) + return; + + xkbi = master->key->xkbInfo; + xkbi->lockedPtrButtons = 0; + + for (; d; d = d->next) { + if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key) + continue; + + xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons; + } +} -- cgit v1.2.3