1706f2543Smrg/* 2706f2543Smrg * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. 3706f2543Smrg * 4706f2543Smrg * All Rights Reserved. 5706f2543Smrg * 6706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining 7706f2543Smrg * a copy of this software and associated documentation files (the 8706f2543Smrg * "Software"), to deal in the Software without restriction, including 9706f2543Smrg * without limitation on the rights to use, copy, modify, merge, 10706f2543Smrg * publish, distribute, sublicense, and/or sell copies of the Software, 11706f2543Smrg * and to permit persons to whom the Software is furnished to do so, 12706f2543Smrg * subject to the following conditions: 13706f2543Smrg * 14706f2543Smrg * The above copyright notice and this permission notice (including the 15706f2543Smrg * next paragraph) shall be included in all copies or substantial 16706f2543Smrg * portions of the Software. 17706f2543Smrg * 18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19706f2543Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20706f2543Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21706f2543Smrg * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 22706f2543Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23706f2543Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24706f2543Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25706f2543Smrg * SOFTWARE. 26706f2543Smrg */ 27706f2543Smrg 28706f2543Smrg/* 29706f2543Smrg * Authors: 30706f2543Smrg * David H. Dawes <dawes@xfree86.org> 31706f2543Smrg * Kevin E. Martin <kem@redhat.com> 32706f2543Smrg * Rickard E. (Rik) Faith <faith@redhat.com> 33706f2543Smrg * 34706f2543Smrg */ 35706f2543Smrg 36706f2543Smrg/** \file 37706f2543Smrg * 38706f2543Smrg * This file implements the console input devices. 39706f2543Smrg */ 40706f2543Smrg 41706f2543Smrg#ifdef HAVE_DMX_CONFIG_H 42706f2543Smrg#include <dmx-config.h> 43706f2543Smrg#endif 44706f2543Smrg 45706f2543Smrg#define DMX_CONSOLE_DEBUG 0 46706f2543Smrg#define DMX_WINDOW_DEBUG 0 47706f2543Smrg 48706f2543Smrg#include "dmxinputinit.h" 49706f2543Smrg#include "dmxevents.h" 50706f2543Smrg#include "dmxconsole.h" 51706f2543Smrg#include "dmxcommon.h" 52706f2543Smrg#include "dmxscrinit.h" 53706f2543Smrg#include "dmxcb.h" 54706f2543Smrg#include "dmxsync.h" 55706f2543Smrg 56706f2543Smrg#include "inputstr.h" 57706f2543Smrg#include "input.h" 58706f2543Smrg#include "mipointer.h" 59706f2543Smrg#include "windowstr.h" 60706f2543Smrg 61706f2543Smrg#define CONSOLE_NUM 3 62706f2543Smrg#define CONSOLE_DEN 4 63706f2543Smrg#define DMX_CONSOLE_NAME "DMX Console" 64706f2543Smrg#define DMX_RES_NAME "Xdmx" 65706f2543Smrg#define DMX_RES_CLASS "XDmx" 66706f2543Smrg#define CONSOLE_BG_COLOR "gray75" 67706f2543Smrg#define CONSOLE_FG_COLOR "black" 68706f2543Smrg#define CONSOLE_SCREEN_BG_COLOR "white" 69706f2543Smrg#define CONSOLE_SCREEN_FG_COLOR "black" 70706f2543Smrg#define CONSOLE_SCREEN_DET_COLOR "gray75" 71706f2543Smrg#define CONSOLE_SCREEN_CUR_COLOR "red" 72706f2543Smrg 73706f2543Smrg#if DMX_CONSOLE_DEBUG 74706f2543Smrg#define DMXDBG0(f) dmxLog(dmxDebug,f) 75706f2543Smrg#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) 76706f2543Smrg#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) 77706f2543Smrg#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) 78706f2543Smrg#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) 79706f2543Smrg#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) 80706f2543Smrg#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) 81706f2543Smrg#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) 82706f2543Smrg#else 83706f2543Smrg#define DMXDBG0(f) 84706f2543Smrg#define DMXDBG1(f,a) 85706f2543Smrg#define DMXDBG2(f,a,b) 86706f2543Smrg#define DMXDBG3(f,a,b,c) 87706f2543Smrg#define DMXDBG4(f,a,b,c,d) 88706f2543Smrg#define DMXDBG5(f,a,b,c,d,e) 89706f2543Smrg#define DMXDBG6(f,a,b,c,d,e,g) 90706f2543Smrg#define DMXDBG7(f,a,b,c,d,e,g,h) 91706f2543Smrg#endif 92706f2543Smrg 93706f2543Smrg/* Private area for consoles. */ 94706f2543Smrgtypedef struct _myPrivate { 95706f2543Smrg DMX_COMMON_PRIVATE; 96706f2543Smrg int lastX; 97706f2543Smrg int lastY; 98706f2543Smrg int globalX; 99706f2543Smrg int globalY; 100706f2543Smrg int curX; 101706f2543Smrg int curY; 102706f2543Smrg int width; 103706f2543Smrg int height; 104706f2543Smrg int consWidth; 105706f2543Smrg int consHeight; 106706f2543Smrg double xScale; 107706f2543Smrg double yScale; 108706f2543Smrg XlibGC gc, gcDet, gcRev, gcCur; 109706f2543Smrg int grabbed, fine, captured; 110706f2543Smrg Cursor cursorNormal, cursorGrabbed, cursorEmpty; 111706f2543Smrg Pixmap pixmap; 112706f2543Smrg 113706f2543Smrg CloseScreenProcPtr CloseScreen; 114706f2543Smrg struct _myPrivate *next; /* for closing multiple consoles */ 115706f2543Smrg int initialized; 116706f2543Smrg DevicePtr mou, kbd; 117706f2543Smrg} myPrivate; 118706f2543Smrg 119706f2543Smrgstatic int scalex(myPrivate *priv, int x) 120706f2543Smrg{ 121706f2543Smrg return (int)((x * priv->xScale) + .5); 122706f2543Smrg} 123706f2543Smrg 124706f2543Smrgstatic int scaley(myPrivate *priv, int y) 125706f2543Smrg{ 126706f2543Smrg return (int)((y * priv->yScale) + .5); 127706f2543Smrg} 128706f2543Smrg 129706f2543Smrgstatic int unscalex(myPrivate *priv, int x) 130706f2543Smrg{ 131706f2543Smrg return (int)((x / priv->xScale) + .5); 132706f2543Smrg} 133706f2543Smrg 134706f2543Smrgstatic int unscaley(myPrivate *priv, int y) 135706f2543Smrg{ 136706f2543Smrg return (int)((y / priv->yScale) + .5); 137706f2543Smrg} 138706f2543Smrg 139706f2543Smrg/** Create the private area for \a pDevice. */ 140706f2543Smrgpointer dmxConsoleCreatePrivate(DeviceIntPtr pDevice) 141706f2543Smrg{ 142706f2543Smrg GETDMXLOCALFROMPDEVICE; 143706f2543Smrg myPrivate *priv = calloc(1, sizeof(*priv)); 144706f2543Smrg priv->dmxLocal = dmxLocal; 145706f2543Smrg return priv; 146706f2543Smrg} 147706f2543Smrg 148706f2543Smrg/** If \a private is non-NULL, free its associated memory. */ 149706f2543Smrgvoid dmxConsoleDestroyPrivate(pointer private) 150706f2543Smrg{ 151706f2543Smrg free(private); 152706f2543Smrg} 153706f2543Smrg 154706f2543Smrgstatic void dmxConsoleDrawFineCursor(myPrivate *priv, XRectangle *rect) 155706f2543Smrg{ 156706f2543Smrg int size = 6; 157706f2543Smrg int x, y; 158706f2543Smrg 159706f2543Smrg XDrawLine(priv->display, priv->pixmap, priv->gcCur, 160706f2543Smrg x = scalex(priv, priv->globalX) - size, 161706f2543Smrg scaley(priv, priv->globalY), 162706f2543Smrg scalex(priv, priv->globalX) + size, 163706f2543Smrg scaley(priv, priv->globalY)); 164706f2543Smrg XDrawLine(priv->display, priv->pixmap, priv->gcCur, 165706f2543Smrg scalex(priv, priv->globalX), 166706f2543Smrg y = scaley(priv, priv->globalY) - size, 167706f2543Smrg scalex(priv, priv->globalX), 168706f2543Smrg scaley(priv, priv->globalY) + size); 169706f2543Smrg if (priv->grabbed) { 170706f2543Smrg XDrawLine(priv->display, priv->pixmap, priv->gcCur, 171706f2543Smrg scalex(priv, priv->globalX) - (int)(size / 1.4), 172706f2543Smrg scaley(priv, priv->globalY) - (int)(size / 1.4), 173706f2543Smrg scalex(priv, priv->globalX) + (int)(size / 1.4), 174706f2543Smrg scaley(priv, priv->globalY) + (int)(size / 1.4)); 175706f2543Smrg XDrawLine(priv->display, priv->pixmap, priv->gcCur, 176706f2543Smrg scalex(priv, priv->globalX) - (int)(size / 1.4), 177706f2543Smrg scaley(priv, priv->globalY) + (int)(size / 1.4), 178706f2543Smrg scalex(priv, priv->globalX) + (int)(size / 1.4), 179706f2543Smrg scaley(priv, priv->globalY) - (int)(size / 1.4)); 180706f2543Smrg } 181706f2543Smrg if (rect) { 182706f2543Smrg rect->x = x; 183706f2543Smrg rect->y = y; 184706f2543Smrg rect->width = 2 * size; 185706f2543Smrg rect->height = 2 * size; 186706f2543Smrg } 187706f2543Smrg} 188706f2543Smrg 189706f2543Smrgstatic void dmxConsoleDrawWindows(pointer private) 190706f2543Smrg{ 191706f2543Smrg GETONLYPRIVFROMPRIVATE; 192706f2543Smrg Display *dpy = priv->display; 193706f2543Smrg int i; 194706f2543Smrg Region whole, used, avail; 195706f2543Smrg XRectangle rect; 196706f2543Smrg 197706f2543Smrg whole = XCreateRegion(); 198706f2543Smrg used = XCreateRegion(); 199706f2543Smrg avail = XCreateRegion(); 200706f2543Smrg rect.x = 0; 201706f2543Smrg rect.y = 0; 202706f2543Smrg rect.width = priv->consWidth; 203706f2543Smrg rect.height = priv->consHeight; 204706f2543Smrg XUnionRectWithRegion(&rect, whole, whole); 205706f2543Smrg 206706f2543Smrg for (i = 0; i < dmxNumScreens; i++) { 207706f2543Smrg ScreenPtr pScreen = screenInfo.screens[i]; 208706f2543Smrg WindowPtr pRoot = pScreen->root; 209706f2543Smrg WindowPtr pChild; 210706f2543Smrg 211706f2543Smrg#if DMX_WINDOW_DEBUG 212706f2543Smrg dmxLog(dmxDebug, "%lu %p %p %p 2\n", 213706f2543Smrg pRoot->drawable.id, 214706f2543Smrg pRoot->parent, pRoot->firstChild, pRoot->lastChild); 215706f2543Smrg#endif 216706f2543Smrg 217706f2543Smrg for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) { 218706f2543Smrg if (pChild->mapped 219706f2543Smrg && pChild->realized) { 220706f2543Smrg#if DMX_WINDOW_DEBUG 221706f2543Smrg dmxLog(dmxDebug, " %p %d,%d %dx%d %d %d %d RECTS\n", 222706f2543Smrg pChild, 223706f2543Smrg pChild->drawable.x, 224706f2543Smrg pChild->drawable.y, 225706f2543Smrg pChild->drawable.width, 226706f2543Smrg pChild->drawable.height, 227706f2543Smrg pChild->visibility, 228706f2543Smrg pChild->overrideRedirect, 229706f2543Smrg RegionNumRects(&pChild->clipList)); 230706f2543Smrg#endif 231706f2543Smrg rect.x = scalex(priv, pChild->drawable.x + pScreen->x); 232706f2543Smrg rect.y = scaley(priv, pChild->drawable.y + pScreen->y); 233706f2543Smrg rect.width = scalex(priv, pChild->drawable.width); 234706f2543Smrg rect.height = scaley(priv, pChild->drawable.height); 235706f2543Smrg XDrawRectangle(dpy, priv->pixmap, priv->gc, 236706f2543Smrg rect.x, rect.y, rect.width, rect.height); 237706f2543Smrg XUnionRectWithRegion(&rect, used, used); 238706f2543Smrg XSubtractRegion(whole, used, avail); 239706f2543Smrg XSetRegion(dpy, priv->gc, avail); 240706f2543Smrg } 241706f2543Smrg } 242706f2543Smrg#ifdef PANORAMIX 243706f2543Smrg if (!noPanoramiXExtension) break; /* Screen 0 valid with Xinerama */ 244706f2543Smrg#endif 245706f2543Smrg } 246706f2543Smrg XDestroyRegion(avail); 247706f2543Smrg XDestroyRegion(used); 248706f2543Smrg XDestroyRegion(whole); 249706f2543Smrg XSetClipMask(dpy, priv->gc, None); 250706f2543Smrg} 251706f2543Smrg 252706f2543Smrgstatic void dmxConsoleDraw(myPrivate *priv, int updateCursor, int update) 253706f2543Smrg{ 254706f2543Smrg GETDMXINPUTFROMPRIV; 255706f2543Smrg Display *dpy = priv->display; 256706f2543Smrg int i; 257706f2543Smrg 258706f2543Smrg XFillRectangle(dpy, priv->pixmap, priv->gc, 0, 0, 259706f2543Smrg priv->consWidth, priv->consHeight); 260706f2543Smrg 261706f2543Smrg for (i = 0; i < dmxNumScreens; i++) { 262706f2543Smrg DMXScreenInfo *dmxScreen = &dmxScreens[i]; 263706f2543Smrg XFillRectangle(dpy, priv->pixmap, 264706f2543Smrg dmxScreen->beDisplay ? priv->gcRev : priv->gcDet, 265706f2543Smrg scalex(priv, screenInfo.screens[i]->x), 266706f2543Smrg scaley(priv, screenInfo.screens[i]->y), 267706f2543Smrg scalex(priv, screenInfo.screens[i]->width), 268706f2543Smrg scaley(priv, screenInfo.screens[i]->height)); 269706f2543Smrg } 270706f2543Smrg for (i = 0; i < dmxNumScreens; i++) { 271706f2543Smrg XDrawRectangle(dpy, priv->pixmap, priv->gc, 272706f2543Smrg scalex(priv, screenInfo.screens[i]->x), 273706f2543Smrg scaley(priv, screenInfo.screens[i]->y), 274706f2543Smrg scalex(priv, screenInfo.screens[i]->width), 275706f2543Smrg scaley(priv, screenInfo.screens[i]->height)); 276706f2543Smrg } 277706f2543Smrg if (dmxInput->windows) dmxConsoleDrawWindows(priv); 278706f2543Smrg if (priv->fine && updateCursor) dmxConsoleDrawFineCursor(priv, 0); 279706f2543Smrg if (update) { 280706f2543Smrg XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, 281706f2543Smrg 0, 0, priv->consWidth, priv->consHeight, 0, 0); 282706f2543Smrg XSync(priv->display, False); /* Not a backend display */ 283706f2543Smrg } 284706f2543Smrg} 285706f2543Smrg 286706f2543Smrgstatic void dmxConsoleClearCursor(myPrivate *priv, int x, int y, 287706f2543Smrg XRectangle *rect) 288706f2543Smrg{ 289706f2543Smrg int cw = 14, ch = 14; /* Clear width and height */ 290706f2543Smrg 291706f2543Smrg rect->x = scalex(priv, x) - cw/2; 292706f2543Smrg rect->y = scaley(priv, y) - ch/2; 293706f2543Smrg rect->width = cw; 294706f2543Smrg rect->height = ch; 295706f2543Smrg XSetClipRectangles(priv->display, priv->gc, 0, 0, rect, 1, Unsorted); 296706f2543Smrg XSetClipRectangles(priv->display, priv->gcDet, 0, 0, rect, 1, Unsorted); 297706f2543Smrg XSetClipRectangles(priv->display, priv->gcRev, 0, 0, rect, 1, Unsorted); 298706f2543Smrg dmxConsoleDraw(priv, 0, 0); 299706f2543Smrg XSetClipMask(priv->display, priv->gc, None); 300706f2543Smrg XSetClipMask(priv->display, priv->gcDet, None); 301706f2543Smrg XSetClipMask(priv->display, priv->gcRev, None); 302706f2543Smrg} 303706f2543Smrg 304706f2543Smrg 305706f2543Smrgstatic void dmxConsoleUpdateFineCursor(myPrivate *priv) 306706f2543Smrg{ 307706f2543Smrg int leave = 0; 308706f2543Smrg XRectangle rects[2]; 309706f2543Smrg 310706f2543Smrg dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rects[0]); 311706f2543Smrg if (priv->dmxLocal->sendsCore) { 312706f2543Smrg dmxGetGlobalPosition(&priv->globalX, &priv->globalY); 313706f2543Smrg } else { 314706f2543Smrg priv->globalX = priv->dmxLocal->lastX; 315706f2543Smrg priv->globalY = priv->dmxLocal->lastY; 316706f2543Smrg } 317706f2543Smrg 318706f2543Smrg priv->lastX = scalex(priv, priv->width / 2); 319706f2543Smrg priv->lastY = scaley(priv, priv->height / 2); 320706f2543Smrg 321706f2543Smrg /* Compute new warp position, which may be 322706f2543Smrg outside the window */ 323706f2543Smrg if (priv->globalX < 1 || priv->globalX >= priv->width) { 324706f2543Smrg if (priv->globalX < 1) priv->lastX = 0; 325706f2543Smrg else priv->lastX = scalex(priv, priv->width); 326706f2543Smrg priv->lastY = scaley(priv, priv->globalY); 327706f2543Smrg ++leave; 328706f2543Smrg } 329706f2543Smrg if (priv->globalY < 1 || priv->globalY >= priv->height) { 330706f2543Smrg if (priv->globalY < 1) priv->lastY = 0; 331706f2543Smrg else priv->lastY = scaley(priv, priv->height); 332706f2543Smrg priv->lastX = scalex(priv, priv->globalX); 333706f2543Smrg ++leave; 334706f2543Smrg } 335706f2543Smrg 336706f2543Smrg /* Draw pseudo cursor in window */ 337706f2543Smrg dmxConsoleDrawFineCursor(priv, &rects[1]); 338706f2543Smrg 339706f2543Smrg XSetClipRectangles(priv->display, priv->gc, 0, 0, rects, 2, Unsorted); 340706f2543Smrg XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, 341706f2543Smrg 0, 0, priv->consWidth, priv->consHeight, 0, 0); 342706f2543Smrg XSetClipMask(priv->display, priv->gc, None); 343706f2543Smrg 344706f2543Smrg DMXDBG2("dmxConsoleUpdateFineCursor: WARP %d %d\n", 345706f2543Smrg priv->lastX, priv->lastY); 346706f2543Smrg XWarpPointer(priv->display, priv->window, priv->window, 347706f2543Smrg 0, 0, 0, 0, priv->lastX, priv->lastY); 348706f2543Smrg XSync(priv->display, False); /* Not a backend display */ 349706f2543Smrg 350706f2543Smrg if (leave) { 351706f2543Smrg XEvent X; 352706f2543Smrg while (XCheckMaskEvent(priv->display, PointerMotionMask, &X)) { 353706f2543Smrg if (X.type == MotionNotify) { 354706f2543Smrg if (X.xmotion.x != priv->lastX || X.xmotion.y != priv->lastY) { 355706f2543Smrg DMXDBG4("Ignoring motion to %d %d after leave frm %d %d\n", 356706f2543Smrg X.xmotion.x, X.xmotion.y, 357706f2543Smrg priv->lastX, priv->lastY); 358706f2543Smrg } 359706f2543Smrg } else { 360706f2543Smrg dmxLog(dmxInfo, "Ignoring event (%d): %s ****************\n", 361706f2543Smrg X.type, dmxEventName(X.type)); 362706f2543Smrg } 363706f2543Smrg } 364706f2543Smrg } 365706f2543Smrg DMXDBG6("dmxConsoleUpdateFineCursor: Warp %d %d on %d %d [%d %d]\n", 366706f2543Smrg priv->lastX, priv->lastY, 367706f2543Smrg scalex(priv, priv->width), 368706f2543Smrg scaley(priv, priv->height), 369706f2543Smrg priv->globalX, priv->globalY); 370706f2543Smrg} 371706f2543Smrg 372706f2543Smrg/** Whenever the window layout (size, position, stacking order) might be 373706f2543Smrg * changed, this routine is called with the \a pWindow that changed and 374706f2543Smrg * the \a type of change. This routine is called in a conservative 375706f2543Smrg * fashion: the actual layout of the windows of the screen might not 376706f2543Smrg * have had any human-visible changes. */ 377706f2543Smrgvoid dmxConsoleUpdateInfo(pointer private, DMXUpdateType type, 378706f2543Smrg WindowPtr pWindow) 379706f2543Smrg{ 380706f2543Smrg GETONLYPRIVFROMPRIVATE; 381706f2543Smrg dmxConsoleDraw(priv, 1, 1); 382706f2543Smrg} 383706f2543Smrg 384706f2543Smrgstatic void dmxConsoleMoveAbsolute(myPrivate *priv, int x, int y, 385706f2543Smrg DevicePtr pDev, dmxMotionProcPtr motion, 386706f2543Smrg DMXBlockType block) 387706f2543Smrg{ 388706f2543Smrg int tmpX, tmpY, v[2]; 389706f2543Smrg 390706f2543Smrg tmpX = unscalex(priv, x); 391706f2543Smrg tmpY = unscalex(priv, y); 392706f2543Smrg DMXDBG6("dmxConsoleMoveAbsolute(,%d,%d) %d %d =? %d %d\n", 393706f2543Smrg x, y, tmpX, tmpY, priv->curX, priv->curY); 394706f2543Smrg if (tmpX == priv->curX && tmpY == priv->curY) return; 395706f2543Smrg v[0] = unscalex(priv, x); 396706f2543Smrg v[1] = unscaley(priv, y); 397706f2543Smrg motion(pDev, v, 0, 2, DMX_ABSOLUTE_CONFINED, block); 398706f2543Smrg /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ 399706f2543Smrg} 400706f2543Smrg 401706f2543Smrgstatic void dmxConsoleMoveRelative(myPrivate *priv, int x, int y, 402706f2543Smrg DevicePtr pDev, dmxMotionProcPtr motion, 403706f2543Smrg DMXBlockType block) 404706f2543Smrg{ 405706f2543Smrg int v[2]; 406706f2543Smrg /* Ignore the event generated from * warping back to middle */ 407706f2543Smrg if (x == priv->lastX && y == priv->lastY) return; 408706f2543Smrg v[0] = priv->lastX - x; 409706f2543Smrg v[1] = priv->lastY - y; 410706f2543Smrg motion(pDev, v, 0, 2, DMX_RELATIVE, block); 411706f2543Smrg /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ 412706f2543Smrg} 413706f2543Smrg 414706f2543Smrg/** This routine gets called from #dmxCoreMotion for each motion. This 415706f2543Smrg * allows the console's notion of the cursor postion to change when 416706f2543Smrg * another input device actually caused the change. */ 417706f2543Smrgvoid dmxConsoleUpdatePosition(pointer private, int x, int y) 418706f2543Smrg{ 419706f2543Smrg GETONLYPRIVFROMPRIVATE; 420706f2543Smrg int tmpX, tmpY; 421706f2543Smrg Display *dpy = priv->display; 422706f2543Smrg static unsigned long dmxGeneration = 0; 423706f2543Smrg 424706f2543Smrg 425706f2543Smrg tmpX = scalex(priv, x); 426706f2543Smrg tmpY = scaley(priv, y); 427706f2543Smrg DMXDBG6("dmxConsoleUpdatePosition(,%d,%d) new=%d,%d dims=%d,%d\n", 428706f2543Smrg x, y, tmpX, tmpY, priv->consWidth, priv->consHeight); 429706f2543Smrg 430706f2543Smrg if (priv->fine) dmxConsoleUpdateFineCursor(priv); 431706f2543Smrg if (tmpX != priv->curX || tmpY != priv->curY) { 432706f2543Smrg if (tmpX < 0) tmpX = 0; 433706f2543Smrg if (tmpY < 0) tmpY = 0; 434706f2543Smrg if (tmpX >= priv->consWidth) tmpX = priv->consWidth - 1; 435706f2543Smrg if (tmpY >= priv->consHeight) tmpY = priv->consHeight - 1; 436706f2543Smrg priv->curX = tmpX; 437706f2543Smrg priv->curY = tmpY; 438706f2543Smrg if (!priv->fine) { 439706f2543Smrg DMXDBG2(" WARP B %d %d\n", priv->curX, priv->curY); 440706f2543Smrg XWarpPointer(dpy, priv->window, 441706f2543Smrg priv->window, 0, 0, 0, 0, tmpX, tmpY); 442706f2543Smrg XSync(dpy, False); /* Not a backend display */ 443706f2543Smrg } 444706f2543Smrg } 445706f2543Smrg 446706f2543Smrg if (dmxGeneration != serverGeneration) { 447706f2543Smrg dmxGeneration = serverGeneration; 448706f2543Smrg dmxConsoleDraw(priv, 1, 1); 449706f2543Smrg } 450706f2543Smrg} 451706f2543Smrg 452706f2543Smrg/** Collect all pending events from the console's display. Plase these 453706f2543Smrg * events on the server event queue using the \a motion and \a enqueue 454706f2543Smrg * routines. The \a checkspecial routine is used to check for special 455706f2543Smrg * keys that need handling. \a block tells if signals should be blocked 456706f2543Smrg * when updating the event queue. */ 457706f2543Smrgvoid dmxConsoleCollectEvents(DevicePtr pDev, 458706f2543Smrg dmxMotionProcPtr motion, 459706f2543Smrg dmxEnqueueProcPtr enqueue, 460706f2543Smrg dmxCheckSpecialProcPtr checkspecial, 461706f2543Smrg DMXBlockType block) 462706f2543Smrg{ 463706f2543Smrg GETPRIVFROMPDEV; 464706f2543Smrg GETDMXINPUTFROMPRIV; 465706f2543Smrg Display *dpy = priv->display; 466706f2543Smrg Window win = priv->window; 467706f2543Smrg int width = priv->width; 468706f2543Smrg int height = priv->height; 469706f2543Smrg XEvent X, N; 470706f2543Smrg XSetWindowAttributes attribs; 471706f2543Smrg static int rInitialized = 0; 472706f2543Smrg static Region r; 473706f2543Smrg XRectangle rect; 474706f2543Smrg static int raising = 0, raiseX, raiseY; /* FIXME */ 475706f2543Smrg 476706f2543Smrg while (XPending(dpy)) { 477706f2543Smrg XNextEvent(dpy, &X); 478706f2543Smrg switch(X.type) { 479706f2543Smrg case VisibilityNotify: 480706f2543Smrg break; 481706f2543Smrg case Expose: 482706f2543Smrg DMXDBG5("dmxConsoleCollectEvents: Expose #%d %d %d %d %d\n", 483706f2543Smrg X.xexpose.count, 484706f2543Smrg X.xexpose.x, X.xexpose.y, 485706f2543Smrg X.xexpose.width, X.xexpose.height); 486706f2543Smrg if (!rInitialized++) r = XCreateRegion(); 487706f2543Smrg rect.x = X.xexpose.x; 488706f2543Smrg rect.y = X.xexpose.y; 489706f2543Smrg rect.width = X.xexpose.width; 490706f2543Smrg rect.height = X.xexpose.height; 491706f2543Smrg XUnionRectWithRegion(&rect, r, r); 492706f2543Smrg if (X.xexpose.count == 0) { 493706f2543Smrg XSetRegion(dpy, priv->gc, r); 494706f2543Smrg XSetRegion(dpy, priv->gcDet, r); 495706f2543Smrg XSetRegion(dpy, priv->gcRev, r); 496706f2543Smrg dmxConsoleDraw(priv, 1, 1); 497706f2543Smrg XSetClipMask(dpy, priv->gc, None); 498706f2543Smrg XSetClipMask(dpy, priv->gcDet, None); 499706f2543Smrg XSetClipMask(dpy, priv->gcRev, None); 500706f2543Smrg XDestroyRegion(r); 501706f2543Smrg rInitialized = 0; 502706f2543Smrg } 503706f2543Smrg break; 504706f2543Smrg case ResizeRequest: 505706f2543Smrg DMXDBG2("dmxConsoleCollectEvents: Resize %d %d\n", 506706f2543Smrg X.xresizerequest.width, X.xresizerequest.height); 507706f2543Smrg priv->consWidth = X.xresizerequest.width; 508706f2543Smrg priv->consHeight = X.xresizerequest.height; 509706f2543Smrg priv->xScale = (double)priv->consWidth / width; 510706f2543Smrg priv->yScale = (double)priv->consHeight / height; 511706f2543Smrg attribs.override_redirect = True; 512706f2543Smrg XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); 513706f2543Smrg XResizeWindow(dpy, win, priv->consWidth, priv->consHeight); 514706f2543Smrg XFreePixmap(dpy, priv->pixmap); 515706f2543Smrg priv->pixmap = XCreatePixmap(dpy, 516706f2543Smrg RootWindow(dpy, DefaultScreen(dpy)), 517706f2543Smrg priv->consWidth, 518706f2543Smrg priv->consHeight, 519706f2543Smrg DefaultDepth(dpy,DefaultScreen(dpy))); 520706f2543Smrg dmxConsoleDraw(priv, 1, 1); 521706f2543Smrg attribs.override_redirect = False; 522706f2543Smrg XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); 523706f2543Smrg break; 524706f2543Smrg case LeaveNotify: 525706f2543Smrg DMXDBG4("dmxConsoleCollectEvents: Leave @ %d,%d; r=%d f=%d\n", 526706f2543Smrg X.xcrossing.x, X.xcrossing.y, raising, priv->fine); 527706f2543Smrg if (!priv->captured) dmxCommonRestoreState(priv); 528706f2543Smrg else { 529706f2543Smrg dmxConsoleUncapture(dmxInput); 530706f2543Smrg dmxCommonRestoreState(priv); 531706f2543Smrg } 532706f2543Smrg break; 533706f2543Smrg case EnterNotify: 534706f2543Smrg DMXDBG6("dmxConsoleCollectEvents: Enter %d,%d r=%d f=%d (%d,%d)\n", 535706f2543Smrg X.xcrossing.x, X.xcrossing.y, raising, priv->fine, 536706f2543Smrg priv->curX, priv->curY); 537706f2543Smrg dmxCommonSaveState(priv); 538706f2543Smrg if (raising) { 539706f2543Smrg raising = 0; 540706f2543Smrg dmxConsoleMoveAbsolute(priv, raiseX, raiseY, 541706f2543Smrg priv->mou, motion, block); 542706f2543Smrg } else { 543706f2543Smrg if (priv->fine) { 544706f2543Smrg /* The raise will generate an event near the center, 545706f2543Smrg * which is not where the cursor should be. So we 546706f2543Smrg * save the real position, do the raise, and move 547706f2543Smrg * the cursor here again after the raise generates 548706f2543Smrg * the event. */ 549706f2543Smrg raising = 1; 550706f2543Smrg raiseX = X.xcrossing.x; 551706f2543Smrg raiseY = X.xcrossing.y; 552706f2543Smrg XRaiseWindow(dpy, priv->window); 553706f2543Smrg } 554706f2543Smrg XSync(dpy, False); /* Not a backend display */ 555706f2543Smrg if (!X.xcrossing.x && !X.xcrossing.y) 556706f2543Smrg dmxConsoleMoveAbsolute(priv, priv->curX, priv->curY, 557706f2543Smrg priv->mou, motion, block); 558706f2543Smrg } 559706f2543Smrg break; 560706f2543Smrg case MotionNotify: 561706f2543Smrg if (priv->curX == X.xmotion.x && priv->curY == X.xmotion.y) 562706f2543Smrg continue; 563706f2543Smrg if (XPending(dpy)) { /* do motion compression */ 564706f2543Smrg XPeekEvent(dpy, &N); 565706f2543Smrg if (N.type == MotionNotify) continue; 566706f2543Smrg } 567706f2543Smrg DMXDBG2("dmxConsoleCollectEvents: Motion %d %d\n", 568706f2543Smrg X.xmotion.x, X.xmotion.y); 569706f2543Smrg if (raising) { 570706f2543Smrg raising = 0; 571706f2543Smrg dmxConsoleMoveAbsolute(priv, raiseX, raiseY, 572706f2543Smrg priv->mou, motion, block); 573706f2543Smrg } else { 574706f2543Smrg if (priv->fine) 575706f2543Smrg dmxConsoleMoveRelative(priv, X.xmotion.x, X.xmotion.y, 576706f2543Smrg priv->mou, motion, block); 577706f2543Smrg else 578706f2543Smrg dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y, 579706f2543Smrg priv->mou, motion, block); 580706f2543Smrg } 581706f2543Smrg break; 582706f2543Smrg case KeyPress: 583706f2543Smrg case KeyRelease: 584706f2543Smrg enqueue(priv->kbd, X.type, X.xkey.keycode, 0, NULL, block); 585706f2543Smrg break; 586706f2543Smrg default: 587706f2543Smrg /* Pass the whole event here, because 588706f2543Smrg * this may be an extension event. */ 589706f2543Smrg enqueue(priv->mou, X.type, X.xbutton.button, 0, &X, block); 590706f2543Smrg break; 591706f2543Smrg } 592706f2543Smrg } 593706f2543Smrg} 594706f2543Smrg 595706f2543Smrgstatic void dmxCloseConsole(myPrivate *priv) 596706f2543Smrg{ 597706f2543Smrg GETDMXINPUTFROMPRIV; 598706f2543Smrg dmxCommonRestoreState(priv); 599706f2543Smrg if (priv->display) { 600706f2543Smrg XFreeGC(priv->display, priv->gc); 601706f2543Smrg XFreeGC(priv->display, priv->gcDet); 602706f2543Smrg XFreeGC(priv->display, priv->gcRev); 603706f2543Smrg XFreeGC(priv->display, priv->gcCur); 604706f2543Smrg if (!dmxInput->console) XCloseDisplay(priv->display); 605706f2543Smrg } 606706f2543Smrg priv->display = NULL; 607706f2543Smrg} 608706f2543Smrg 609706f2543Smrgstatic Bool dmxCloseConsoleScreen(int idx, ScreenPtr pScreen) 610706f2543Smrg{ 611706f2543Smrg myPrivate *priv, *last; 612706f2543Smrg 613706f2543Smrg for (last = priv = (myPrivate *)dixLookupPrivate(&pScreen->devPrivates, 614706f2543Smrg dmxScreenPrivateKey); 615706f2543Smrg priv; 616706f2543Smrg priv = priv->next) dmxCloseConsole(last = priv); 617706f2543Smrg 618706f2543Smrg DMX_UNWRAP(CloseScreen, last, pScreen); 619706f2543Smrg return pScreen->CloseScreen(idx, pScreen); 620706f2543Smrg} 621706f2543Smrg 622706f2543Smrgstatic Cursor dmxConsoleCreateEmptyCursor(myPrivate *priv) 623706f2543Smrg{ 624706f2543Smrg char noCursorData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 625706f2543Smrg Pixmap pixmap; 626706f2543Smrg Cursor cursor; 627706f2543Smrg XColor color, tmpColor; 628706f2543Smrg Display *dpy = priv->display; 629706f2543Smrg 630706f2543Smrg /* Create empty cursor for window */ 631706f2543Smrg pixmap = XCreateBitmapFromData(priv->display, priv->window, 632706f2543Smrg noCursorData, 8, 8); 633706f2543Smrg if (!XAllocNamedColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), 634706f2543Smrg "black", 635706f2543Smrg &color, 636706f2543Smrg &tmpColor)) 637706f2543Smrg dmxLog(dmxFatal, "Cannot allocate color for cursor\n"); 638706f2543Smrg cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &color, &color, 0, 0); 639706f2543Smrg XFreePixmap(dpy, pixmap); 640706f2543Smrg return cursor; 641706f2543Smrg} 642706f2543Smrg 643706f2543Smrgstatic void dmxConsoleComputeWidthHeight(myPrivate *priv, 644706f2543Smrg int *width, int *height, 645706f2543Smrg double *xScale, double *yScale, 646706f2543Smrg int *consWidth, int *consHeight) 647706f2543Smrg{ 648706f2543Smrg int screen; 649706f2543Smrg Display *dpy = priv->display; 650706f2543Smrg 651706f2543Smrg *width = 0; 652706f2543Smrg *height = 0; 653706f2543Smrg *xScale = 1.0; 654706f2543Smrg *yScale = 1.0; 655706f2543Smrg 656706f2543Smrg screen = DefaultScreen(dpy); 657706f2543Smrg *consWidth = DisplayWidth(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; 658706f2543Smrg *consHeight = DisplayHeight(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; 659706f2543Smrg 660706f2543Smrg if (*consWidth < 1) *consWidth = 1; 661706f2543Smrg if (*consHeight < 1) *consHeight = 1; 662706f2543Smrg 663706f2543Smrg#if 1 664706f2543Smrg /* Always keep the console size similar 665706f2543Smrg * to the global bounding box. */ 666706f2543Smrg *width = dmxGlobalWidth; 667706f2543Smrg *height = dmxGlobalHeight; 668706f2543Smrg#else 669706f2543Smrg /* Make the console window as big as 670706f2543Smrg * possible by computing the visible 671706f2543Smrg * bounding box. */ 672706f2543Smrg for (i = 0; i < dmxNumScreens; i++) { 673706f2543Smrg if (screenInfo.screens[i]->x+screenInfo.screens[i]->width > *width) 674706f2543Smrg *width = screenInfo.screens[i]->x+screenInfo.screens[i]->width; 675706f2543Smrg 676706f2543Smrg if (screenInfo.screens[i]->y+screenInfo.screens[i]->height > *height) 677706f2543Smrg *height = screenInfo.screens[i]->y+screenInfo.screens[i]->height; 678706f2543Smrg } 679706f2543Smrg#endif 680706f2543Smrg 681706f2543Smrg if ((double)*consWidth / *width < (double)*consHeight / *height) 682706f2543Smrg *xScale = *yScale = (double)*consWidth / *width; 683706f2543Smrg else 684706f2543Smrg *xScale = *yScale = (double)*consHeight / *height; 685706f2543Smrg 686706f2543Smrg *consWidth = scalex(priv, *width); 687706f2543Smrg *consHeight = scaley(priv, *height); 688706f2543Smrg if (*consWidth < 1) *consWidth = 1; 689706f2543Smrg if (*consHeight < 1) *consHeight = 1; 690706f2543Smrg} 691706f2543Smrg 692706f2543Smrg/** Re-initialized the console device described by \a pDev (after a 693706f2543Smrg * reconfig). */ 694706f2543Smrgvoid dmxConsoleReInit(DevicePtr pDev) 695706f2543Smrg{ 696706f2543Smrg GETPRIVFROMPDEV; 697706f2543Smrg Display *dpy; 698706f2543Smrg 699706f2543Smrg if (!priv || !priv->initialized) return; 700706f2543Smrg dpy = priv->display; 701706f2543Smrg 702706f2543Smrg dmxConsoleComputeWidthHeight(priv, 703706f2543Smrg &priv->width, &priv->height, 704706f2543Smrg &priv->xScale, &priv->yScale, 705706f2543Smrg &priv->consWidth, &priv->consHeight); 706706f2543Smrg XResizeWindow(dpy, priv->window, priv->consWidth, priv->consHeight); 707706f2543Smrg XFreePixmap(dpy, priv->pixmap); 708706f2543Smrg priv->pixmap = XCreatePixmap(dpy, 709706f2543Smrg RootWindow(dpy, DefaultScreen(dpy)), 710706f2543Smrg priv->consWidth, 711706f2543Smrg priv->consHeight, 712706f2543Smrg DefaultDepth(dpy,DefaultScreen(dpy))); 713706f2543Smrg dmxConsoleDraw(priv, 1, 1); 714706f2543Smrg} 715706f2543Smrg 716706f2543Smrg/** Initialized the console device described by \a pDev. */ 717706f2543Smrgvoid dmxConsoleInit(DevicePtr pDev) 718706f2543Smrg{ 719706f2543Smrg GETPRIVFROMPDEV; 720706f2543Smrg DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; 721706f2543Smrg int screen; 722706f2543Smrg unsigned long mask; 723706f2543Smrg XSetWindowAttributes attribs; 724706f2543Smrg Display *dpy; 725706f2543Smrg Window win; 726706f2543Smrg XGCValues gcvals; 727706f2543Smrg XColor color; 728706f2543Smrg XClassHint class_hints; 729706f2543Smrg unsigned long tmp; 730706f2543Smrg 731706f2543Smrg if (dmxLocal->type == DMX_LOCAL_MOUSE) priv->mou = pDev; 732706f2543Smrg if (dmxLocal->type == DMX_LOCAL_KEYBOARD) priv->kbd = pDev; 733706f2543Smrg if (priv->initialized++) return; /* Only do once for mouse/keyboard pair */ 734706f2543Smrg 735706f2543Smrg if (!(dpy = priv->display = XOpenDisplay(dmxInput->name))) 736706f2543Smrg dmxLog(dmxFatal, 737706f2543Smrg "dmxOpenConsole: cannot open console display %s\n", 738706f2543Smrg dmxInput->name); 739706f2543Smrg 740706f2543Smrg /* Set up defaults */ 741706f2543Smrg dmxConsoleComputeWidthHeight(priv, 742706f2543Smrg &priv->width, &priv->height, 743706f2543Smrg &priv->xScale, &priv->yScale, 744706f2543Smrg &priv->consWidth, &priv->consHeight); 745706f2543Smrg 746706f2543Smrg /* Private initialization using computed values or constants. */ 747706f2543Smrg screen = DefaultScreen(dpy); 748706f2543Smrg priv->initPointerX = scalex(priv, priv->width / 2); 749706f2543Smrg priv->initPointerY = scaley(priv, priv->height / 2); 750706f2543Smrg priv->eventMask = (ButtonPressMask 751706f2543Smrg | ButtonReleaseMask 752706f2543Smrg | PointerMotionMask 753706f2543Smrg | EnterWindowMask 754706f2543Smrg | LeaveWindowMask 755706f2543Smrg | KeyPressMask 756706f2543Smrg | KeyReleaseMask 757706f2543Smrg | ExposureMask 758706f2543Smrg | ResizeRedirectMask); 759706f2543Smrg 760706f2543Smrg mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; 761706f2543Smrg attribs.colormap = DefaultColormap(dpy, screen); 762706f2543Smrg if (XParseColor(dpy, attribs.colormap, CONSOLE_BG_COLOR, &color) 763706f2543Smrg && XAllocColor(dpy, attribs.colormap, &color)) { 764706f2543Smrg attribs.background_pixel = color.pixel; 765706f2543Smrg } else 766706f2543Smrg attribs.background_pixel = WhitePixel(dpy, screen); 767706f2543Smrg 768706f2543Smrg attribs.event_mask = priv->eventMask; 769706f2543Smrg attribs.override_redirect = False; 770706f2543Smrg 771706f2543Smrg win = priv->window = XCreateWindow(dpy, 772706f2543Smrg RootWindow(dpy, screen), 773706f2543Smrg 0, 0, priv->consWidth, priv->consHeight, 774706f2543Smrg 0, 775706f2543Smrg DefaultDepth(dpy, screen), 776706f2543Smrg InputOutput, 777706f2543Smrg DefaultVisual(dpy, screen), 778706f2543Smrg mask, &attribs); 779706f2543Smrg priv->pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), 780706f2543Smrg priv->consWidth, priv->consHeight, 781706f2543Smrg DefaultDepth(dpy, screen)); 782706f2543Smrg 783706f2543Smrg /* Set up properties */ 784706f2543Smrg XStoreName(dpy, win, DMX_CONSOLE_NAME); 785706f2543Smrg class_hints.res_name = DMX_RES_NAME; 786706f2543Smrg class_hints.res_class = DMX_RES_CLASS; 787706f2543Smrg XSetClassHint(dpy, win, &class_hints); 788706f2543Smrg 789706f2543Smrg 790706f2543Smrg /* Map the window */ 791706f2543Smrg XMapWindow(dpy, win); 792706f2543Smrg 793706f2543Smrg /* Create cursors */ 794706f2543Smrg priv->cursorNormal = XCreateFontCursor(dpy, XC_circle); 795706f2543Smrg priv->cursorGrabbed = XCreateFontCursor(dpy, XC_spider); 796706f2543Smrg priv->cursorEmpty = dmxConsoleCreateEmptyCursor(priv); 797706f2543Smrg XDefineCursor(dpy, priv->window, priv->cursorNormal); 798706f2543Smrg 799706f2543Smrg /* Create GC */ 800706f2543Smrg mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground | 801706f2543Smrg GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | 802706f2543Smrg GCFillStyle | GCGraphicsExposures); 803706f2543Smrg gcvals.function = GXcopy; 804706f2543Smrg gcvals.plane_mask = AllPlanes; 805706f2543Smrg gcvals.clip_mask = None; 806706f2543Smrg if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_FG_COLOR, &color) 807706f2543Smrg && XAllocColor(dpy, attribs.colormap, &color)) { 808706f2543Smrg gcvals.foreground = color.pixel; 809706f2543Smrg } else 810706f2543Smrg gcvals.foreground = BlackPixel(dpy, screen); 811706f2543Smrg if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_BG_COLOR, &color) 812706f2543Smrg && XAllocColor(dpy, attribs.colormap, &color)) { 813706f2543Smrg gcvals.background = color.pixel; 814706f2543Smrg } else 815706f2543Smrg gcvals.background = WhitePixel(dpy, screen); 816706f2543Smrg gcvals.line_width = 0; 817706f2543Smrg gcvals.line_style = LineSolid; 818706f2543Smrg gcvals.cap_style = CapNotLast; 819706f2543Smrg gcvals.fill_style = FillSolid; 820706f2543Smrg gcvals.graphics_exposures = False; 821706f2543Smrg 822706f2543Smrg priv->gc = XCreateGC(dpy, win, mask, &gcvals); 823706f2543Smrg 824706f2543Smrg tmp = gcvals.foreground; 825706f2543Smrg if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_DET_COLOR, &color) 826706f2543Smrg && XAllocColor(dpy, attribs.colormap, &color)) { 827706f2543Smrg gcvals.foreground = color.pixel; 828706f2543Smrg } else 829706f2543Smrg gcvals.foreground = BlackPixel(dpy, screen); 830706f2543Smrg priv->gcDet = XCreateGC(dpy, win, mask, &gcvals); 831706f2543Smrg gcvals.foreground = tmp; 832706f2543Smrg 833706f2543Smrg tmp = gcvals.background; 834706f2543Smrg gcvals.background = gcvals.foreground; 835706f2543Smrg gcvals.foreground = tmp; 836706f2543Smrg priv->gcRev = XCreateGC(dpy, win, mask, &gcvals); 837706f2543Smrg 838706f2543Smrg gcvals.background = gcvals.foreground; 839706f2543Smrg if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_CUR_COLOR, &color) 840706f2543Smrg && XAllocColor(dpy, attribs.colormap, &color)) { 841706f2543Smrg gcvals.foreground = color.pixel; 842706f2543Smrg } else 843706f2543Smrg gcvals.foreground = BlackPixel(dpy, screen); 844706f2543Smrg priv->gcCur = XCreateGC(dpy, win, mask, &gcvals); 845706f2543Smrg 846706f2543Smrg dmxConsoleDraw(priv, 1, 1); 847706f2543Smrg 848706f2543Smrg if (dixLookupPrivate(&screenInfo.screens[0]->devPrivates, 849706f2543Smrg dmxScreenPrivateKey)) 850706f2543Smrg priv->next = dixLookupPrivate(&screenInfo.screens[0]->devPrivates, 851706f2543Smrg dmxScreenPrivateKey); 852706f2543Smrg else 853706f2543Smrg DMX_WRAP(CloseScreen, dmxCloseConsoleScreen, 854706f2543Smrg priv, screenInfo.screens[0]); 855706f2543Smrg dixSetPrivate(&screenInfo.screens[0]->devPrivates, dmxScreenPrivateKey, 856706f2543Smrg priv); 857706f2543Smrg} 858706f2543Smrg 859706f2543Smrg/** Fill in the \a info structure for the specified \a pDev. Only used 860706f2543Smrg * for pointers. */ 861706f2543Smrgvoid dmxConsoleMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) 862706f2543Smrg{ 863706f2543Smrg GETPRIVFROMPDEV; 864706f2543Smrg 865706f2543Smrg info->buttonClass = 1; 866706f2543Smrg dmxCommonMouGetMap(pDev, info->map, &info->numButtons); 867706f2543Smrg info->valuatorClass = 1; 868706f2543Smrg info->numRelAxes = 2; 869706f2543Smrg info->minval[0] = 0; 870706f2543Smrg info->minval[1] = 0; 871706f2543Smrg /* max possible console window size: */ 872706f2543Smrg info->maxval[0] = DisplayWidth(priv->display, DefaultScreen(priv->display)); 873706f2543Smrg info->maxval[1] = DisplayHeight(priv->display, DefaultScreen(priv->display)); 874706f2543Smrg info->res[0] = 1; 875706f2543Smrg info->minres[0] = 0; 876706f2543Smrg info->maxres[0] = 1; 877706f2543Smrg info->ptrFeedbackClass = 1; 878706f2543Smrg} 879706f2543Smrg 880706f2543Smrg/** Fill in the \a info structure for the specified \a pDev. Only used 881706f2543Smrg * for keyboard. */ 882706f2543Smrgvoid dmxConsoleKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) 883706f2543Smrg{ 884706f2543Smrg dmxCommonKbdGetInfo(pDev, info); 885706f2543Smrg info->keyboard = 1; 886706f2543Smrg info->keyClass = 1; 887706f2543Smrg dmxCommonKbdGetMap(pDev, &info->keySyms, info->modMap); 888706f2543Smrg info->freemap = 1; 889706f2543Smrg info->focusClass = 1; 890706f2543Smrg info->kbdFeedbackClass = 1; 891706f2543Smrg} 892706f2543Smrg 893706f2543Smrg/** Handle special console-only keys. */ 894706f2543Smrgint dmxConsoleFunctions(pointer private, DMXFunctionType function) 895706f2543Smrg{ 896706f2543Smrg GETONLYPRIVFROMPRIVATE; 897706f2543Smrg XRectangle rect; 898706f2543Smrg Display *dpy = priv->display; 899706f2543Smrg 900706f2543Smrg switch (function) { 901706f2543Smrg case DMX_FUNCTION_FINE: 902706f2543Smrg if (priv->fine) { 903706f2543Smrg priv->fine = 0; 904706f2543Smrg dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rect); 905706f2543Smrg XSetClipRectangles(dpy, priv->gc, 0, 0, &rect, 1, Unsorted); 906706f2543Smrg XCopyArea(dpy, priv->pixmap, priv->window, priv->gc, 907706f2543Smrg 0, 0, priv->consWidth, priv->consHeight, 0, 0); 908706f2543Smrg XSetClipMask(dpy, priv->gc, None); 909706f2543Smrg 910706f2543Smrg XDefineCursor(dpy, priv->window, 911706f2543Smrg priv->grabbed 912706f2543Smrg ? priv->cursorGrabbed 913706f2543Smrg : priv->cursorNormal); 914706f2543Smrg XWarpPointer(dpy, priv->window, priv->window, 915706f2543Smrg 0, 0, 0, 0, 916706f2543Smrg scalex(priv, priv->globalX), 917706f2543Smrg scaley(priv, priv->globalY)); 918706f2543Smrg XSync(dpy, False); /* Not a backend display */ 919706f2543Smrg } else { 920706f2543Smrg priv->fine = 1; 921706f2543Smrg XRaiseWindow(dpy, priv->window); 922706f2543Smrg XDefineCursor(dpy, priv->window, priv->cursorEmpty); 923706f2543Smrg dmxConsoleUpdateFineCursor(priv); 924706f2543Smrg } 925706f2543Smrg return 1; 926706f2543Smrg case DMX_FUNCTION_GRAB: 927706f2543Smrg if (priv->grabbed) { 928706f2543Smrg XUngrabKeyboard(dpy, CurrentTime); 929706f2543Smrg XUngrabPointer(dpy, CurrentTime); 930706f2543Smrg XDefineCursor(dpy, priv->window, 931706f2543Smrg priv->fine 932706f2543Smrg ? priv->cursorEmpty 933706f2543Smrg : priv->cursorNormal); 934706f2543Smrg } else { 935706f2543Smrg if (XGrabPointer(dpy, priv->window, True, 936706f2543Smrg 0, GrabModeAsync, GrabModeAsync, priv->window, 937706f2543Smrg None, CurrentTime)) { 938706f2543Smrg dmxLog(dmxError, "XGrabPointer failed\n"); 939706f2543Smrg return 0; 940706f2543Smrg } 941706f2543Smrg if (XGrabKeyboard(dpy, priv->window, True, 942706f2543Smrg GrabModeAsync, GrabModeAsync, CurrentTime)) { 943706f2543Smrg dmxLog(dmxError, "XGrabKeyboard failed\n"); 944706f2543Smrg XUngrabPointer(dpy, CurrentTime); 945706f2543Smrg return 0; 946706f2543Smrg } 947706f2543Smrg XDefineCursor(dpy, priv->window, 948706f2543Smrg priv->fine 949706f2543Smrg ? priv->cursorEmpty 950706f2543Smrg : priv->cursorGrabbed); 951706f2543Smrg } 952706f2543Smrg priv->grabbed = !priv->grabbed; 953706f2543Smrg if (priv->fine) dmxConsoleUpdateFineCursor(priv); 954706f2543Smrg return 1; 955706f2543Smrg case DMX_FUNCTION_TERMINATE: 956706f2543Smrg return 1; 957706f2543Smrg default: 958706f2543Smrg return 0; 959706f2543Smrg } 960706f2543Smrg} 961706f2543Smrg 962706f2543Smrgstatic void dmxDump(void) 963706f2543Smrg{ 964706f2543Smrg int i, j; 965706f2543Smrg DMXInputInfo *dmxInput; 966706f2543Smrg XEvent X; 967706f2543Smrg 968706f2543Smrg for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { 969706f2543Smrg for (j = 0; j < dmxInput->numDevs; j++) { 970706f2543Smrg DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; 971706f2543Smrg myPrivate *priv = dmxLocal->private; 972706f2543Smrg while (priv 973706f2543Smrg && priv->display 974706f2543Smrg && XCheckTypedEvent(priv->display, MotionNotify, &X)) { 975706f2543Smrg DMXDBG4("dmxDump: %s/%d threw event away %d %s\n", 976706f2543Smrg dmxInput->name, j, X.type, dmxEventName(X.type)); 977706f2543Smrg } 978706f2543Smrg } 979706f2543Smrg } 980706f2543Smrg} 981706f2543Smrg 982706f2543Smrg/** This routine is used to warp the pointer into the console window 983706f2543Smrg * from anywhere on the screen. It is used when backend and console 984706f2543Smrg * input are both being taken from the same X display. */ 985706f2543Smrgvoid dmxConsoleCapture(DMXInputInfo *dmxInput) 986706f2543Smrg{ 987706f2543Smrg int i; 988706f2543Smrg XEvent X; 989706f2543Smrg 990706f2543Smrg DMXDBG0("dmxConsoleCapture\n"); 991706f2543Smrg dmxSync(NULL, TRUE); 992706f2543Smrg for (i = 0; i < dmxInput->numDevs; i++) { 993706f2543Smrg DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 994706f2543Smrg myPrivate *priv = dmxLocal->private; 995706f2543Smrg if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; 996706f2543Smrg if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; 997706f2543Smrg if (priv->captured) continue; 998706f2543Smrg priv->captured = 2; /* Ungrab only after proximal events. */ 999706f2543Smrg XRaiseWindow(priv->display, priv->window); 1000706f2543Smrg XSync(priv->display, False); /* Not a backend display */ 1001706f2543Smrg while (XCheckTypedEvent(priv->display, MotionNotify, &X)) { 1002706f2543Smrg DMXDBG3(" Ignoring motion to %d %d after capture on %s\n", 1003706f2543Smrg X.xmotion.x, X.xmotion.y, dmxInput->name); 1004706f2543Smrg } 1005706f2543Smrg XWarpPointer(priv->display, None, 1006706f2543Smrg priv->window, 0, 0, 0, 0, priv->curX, priv->curY); 1007706f2543Smrg XSync(priv->display, False); /* Not a backend display */ 1008706f2543Smrg dmxDump(); 1009706f2543Smrg if (priv->fine) dmxConsoleUpdateFineCursor(priv); 1010706f2543Smrg } 1011706f2543Smrg} 1012706f2543Smrg 1013706f2543Smrg/** Undo the capture that was done by #dmxConsoleCapture. */ 1014706f2543Smrgvoid dmxConsoleUncapture(DMXInputInfo *dmxInput) 1015706f2543Smrg{ 1016706f2543Smrg int i; 1017706f2543Smrg 1018706f2543Smrg DMXDBG0("dmxConsoleUncapture\n"); 1019706f2543Smrg dmxSync(NULL, TRUE); 1020706f2543Smrg for (i = 0; i < dmxInput->numDevs; i++) { 1021706f2543Smrg DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 1022706f2543Smrg myPrivate *priv = dmxLocal->private; 1023706f2543Smrg if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; 1024706f2543Smrg if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; 1025706f2543Smrg if (!priv->captured) continue; 1026706f2543Smrg priv->captured = 0; 1027706f2543Smrg XSync(priv->display, False); /* Not a backend display */ 1028706f2543Smrg } 1029706f2543Smrg} 1030