display.c 8.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * DISPLAY driver
 *
 * Copyright 1998 Ulrich Weigand
 *
 */

#include "ts_xlib.h"
#include "ts_xresource.h"
#include "ts_xutil.h"

12 13 14
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
15 16 17
#include "windows.h"
#include "win.h"
#include "gdi.h"
18 19
#include "display.h"
#include "callback.h"
20 21 22
#include "heap.h"
#include "debug.h"
#include "debugtools.h"
23
#include "x11drv.h"
24

25 26 27 28
Cursor DISPLAY_XCursor = None;    /* Current X cursor */

BOOL32 DISPLAY_DisableWarpPointer = FALSE;  /* hack; see DISPLAY_MoveCursor */

29 30

/***********************************************************************
31
 *           DISPLAY_Inquire			(DISPLAY.101)
32
 */
33
WORD WINAPI DISPLAY_Inquire(LPCURSORINFO lpCursorInfo) 
34
{
35 36
    lpCursorInfo->wXMickeys = 1;
    lpCursorInfo->wYMickeys = 1;
37

38 39 40 41 42 43 44
    return sizeof(CURSORINFO);
}

/***********************************************************************
 *           DISPLAY_DoSetCursor
 */
static BOOL32 DISPLAY_DoSetCursor( CURSORICONINFO *ptr )
45
{
46 47 48
    Pixmap pixmapBits, pixmapMask, pixmapAll;
    XColor fg, bg;
    Cursor cursor = None;
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
    if (!ptr)  /* Create an empty cursor */
    {
        static const char data[] = { 0 };

        bg.red = bg.green = bg.blue = 0x0000;
        pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 );
        if (pixmapBits)
        {
            cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
                                          &bg, &bg, 0, 0 );
            XFreePixmap( display, pixmapBits );
        }
    }
    else  /* Create the X cursor from the bits */
    {
        XImage *image;

        if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
        {
            WARN(cursor, "Cursor has more than 1 bpp!\n" );
            return FALSE;
        }

        /* Create a pixmap and transfer all the bits to it */

        /* NOTE: Following hack works, but only because XFree depth
         *       1 images really use 1 bit/pixel (and so the same layout
         *       as the Windows cursor data). Perhaps use a more generic
         *       algorithm here.
         */
        pixmapAll = XCreatePixmap( display, rootWindow,
                                   ptr->nWidth, ptr->nHeight * 2, 1 );
        image = XCreateImage( display, DefaultVisualOfScreen(screen),
                              1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
                              ptr->nHeight * 2, 16, ptr->nWidthBytes);
        if (image)
        {
            image->byte_order = MSBFirst;
            image->bitmap_bit_order = MSBFirst;
            image->bitmap_unit = 16;
            _XInitImageFuncPtrs(image);
            if (pixmapAll)
                XPutImage( display, pixmapAll, BITMAP_monoGC, image,
                           0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
            image->data = NULL;
            XDestroyImage( image );
        }

        /* Now create the 2 pixmaps for bits and mask */

        pixmapBits = XCreatePixmap( display, rootWindow,
                                    ptr->nWidth, ptr->nHeight, 1 );
        pixmapMask = XCreatePixmap( display, rootWindow,
                                    ptr->nWidth, ptr->nHeight, 1 );

        /* Make sure everything went OK so far */

        if (pixmapBits && pixmapMask && pixmapAll)
        {
            /* We have to do some magic here, as cursors are not fully
             * compatible between Windows and X11. Under X11, there
             * are only 3 possible color cursor: black, white and
             * masked. So we map the 4th Windows color (invert the
             * bits on the screen) to black. This require some boolean
             * arithmetic:
             *
             *         Windows          |          X11
             * Xor    And      Result   |   Bits     Mask     Result
             *  0      0     black      |    0        1     background
             *  0      1     no change  |    X        0     no change
             *  1      0     white      |    1        1     foreground
             *  1      1     inverted   |    0        1     background
             *
             * which gives:
             *  Bits = 'Xor' and not 'And'
             *  Mask = 'Xor' or not 'And'
             *
             * FIXME: apparently some servers do support 'inverted' color.
             * I don't know if it's correct per the X spec, but maybe
             * we ought to take advantage of it.  -- AJ
             */
            XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
                       0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
            XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
                       0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
            XSetFunction( display, BITMAP_monoGC, GXandReverse );
            XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
                       0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
            XSetFunction( display, BITMAP_monoGC, GXorReverse );
            XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
                       0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
            XSetFunction( display, BITMAP_monoGC, GXcopy );
            fg.red = fg.green = fg.blue = 0xffff;
            bg.red = bg.green = bg.blue = 0x0000;
            cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
                                &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
        }

        /* Now free everything */

        if (pixmapAll) XFreePixmap( display, pixmapAll );
        if (pixmapBits) XFreePixmap( display, pixmapBits );
        if (pixmapMask) XFreePixmap( display, pixmapMask );
    }

    if (cursor == None) return FALSE;
    if (DISPLAY_XCursor != None) XFreeCursor( display, DISPLAY_XCursor );
    DISPLAY_XCursor = cursor;

    if (rootWindow != DefaultRootWindow(display) || !WIN_GetDesktop())
    {
        /* Set the cursor on the desktop window */
        XDefineCursor( display, rootWindow, cursor );
    }
    else
    {
        /* FIXME: this won't work correctly with native USER !*/

        /* Set the same cursor for all top-level windows */
        HWND32 hwnd = GetWindow32( GetDesktopWindow32(), GW_CHILD );
        while(hwnd)
        {
172
            Window win = X11DRV_WND_GetXWindow( hwnd );
173 174 175 176 177 178
            if (win && win!=DefaultRootWindow(display))
                XDefineCursor( display, win, cursor );
            hwnd = GetWindow32( hwnd, GW_HWNDNEXT );
        }
    }
    return TRUE;
179 180 181
}

/***********************************************************************
182
 *           DISPLAY_SetCursor			(DISPLAY.102)
183
 */
184
VOID WINAPI DISPLAY_SetCursor( CURSORICONINFO *lpCursor )
185
{
186 187 188
    EnterCriticalSection( &X11DRV_CritSection );
    CALL_LARGE_STACK( DISPLAY_DoSetCursor, lpCursor );
    LeaveCriticalSection( &X11DRV_CritSection );
189 190 191
}

/***********************************************************************
192
 *           DISPLAY_MoveCursor			(DISPLAY.103)
193
 */
194
VOID WINAPI DISPLAY_MoveCursor( WORD wAbsX, WORD wAbsY )
195
{
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    /* 
     * We do not want the to create MotionNotify events here, 
     * otherwise we will get an endless recursion:
     * XMotionEvent -> MOUSEEVENTF_MOVE -> mouse_event -> DisplayMoveCursor
     * -> XWarpPointer -> XMotionEvent -> ...
     *
     * Unfortunately, the XWarpPointer call does create a MotionNotify
     * event. So, we use a hack: before MOUSE_SendEvent calls the mouse event
     * procedure, it sets a global flag. If this flag is set, we skip the
     * XWarpPointer call.  If we are *not* called from within MOUSE_SendEvent,
     * we will call XWarpPointer, which will create a MotionNotify event.
     * Strictly speaking, this is also wrong, but that should normally not
     * have any negative effects ...
     *
     * But first of all, we check whether we already are at the position
     * are supposed to move to; if so, we don't need to do anything.
     */

    Window root, child;
    int rootX, rootY, winX, winY;
    unsigned int xstate;

    if (DISPLAY_DisableWarpPointer) return;

    if (!TSXQueryPointer( display, rootWindow, &root, &child,
                          &rootX, &rootY, &winX, &winY, &xstate ))
        return;

    if ( winX == wAbsX && winY == wAbsY )
        return;

    TRACE( cursor, "(%d,%d): moving from (%d,%d)\n", wAbsX, wAbsY, winX, winY );

    TSXWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, wAbsX, wAbsY );
230 231 232
}

/***********************************************************************
233
 *           DISPLAY_CheckCursor                  (DISPLAY.104)
234
 */
235
VOID WINAPI DISPLAY_CheckCursor()
236
{
237
    FIXME( cursor, "stub\n" );
238 239 240
}

/***********************************************************************
241
 *           UserRepaintDisable			(DISPLAY.500)
242 243 244
 */
VOID WINAPI UserRepaintDisable( BOOL16 disable )
{
245
    TRACE( cursor, "(%d): stub\n", disable );
246 247
}