Add a note about WinPrinters.
[wine.git] / windows / display.c
blobc34a145425178c40f2bc9cea179e44fc332e3de2
1 /*
2 * DISPLAY driver
4 * Copyright 1998 Ulrich Weigand
6 */
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include "ts_xlib.h"
12 #include "ts_xresource.h"
13 #include "ts_xutil.h"
15 #include "windows.h"
16 #include "win.h"
17 #include "gdi.h"
18 #include "display.h"
19 #include "callback.h"
20 #include "heap.h"
21 #include "debug.h"
22 #include "debugtools.h"
23 #include "x11drv.h"
25 Cursor DISPLAY_XCursor = None; /* Current X cursor */
27 BOOL32 DISPLAY_DisableWarpPointer = FALSE; /* hack; see DISPLAY_MoveCursor */
30 /***********************************************************************
31 * DISPLAY_Inquire (DISPLAY.101)
33 WORD WINAPI DISPLAY_Inquire(LPCURSORINFO lpCursorInfo)
35 lpCursorInfo->wXMickeys = 1;
36 lpCursorInfo->wYMickeys = 1;
38 return sizeof(CURSORINFO);
41 /***********************************************************************
42 * DISPLAY_DoSetCursor
44 static BOOL32 DISPLAY_DoSetCursor( CURSORICONINFO *ptr )
46 Pixmap pixmapBits, pixmapMask, pixmapAll;
47 XColor fg, bg;
48 Cursor cursor = None;
50 if (!ptr) /* Create an empty cursor */
52 static const char data[] = { 0 };
54 bg.red = bg.green = bg.blue = 0x0000;
55 pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 );
56 if (pixmapBits)
58 cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
59 &bg, &bg, 0, 0 );
60 XFreePixmap( display, pixmapBits );
63 else /* Create the X cursor from the bits */
65 XImage *image;
67 if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
69 WARN(cursor, "Cursor has more than 1 bpp!\n" );
70 return FALSE;
73 /* Create a pixmap and transfer all the bits to it */
75 /* NOTE: Following hack works, but only because XFree depth
76 * 1 images really use 1 bit/pixel (and so the same layout
77 * as the Windows cursor data). Perhaps use a more generic
78 * algorithm here.
80 pixmapAll = XCreatePixmap( display, rootWindow,
81 ptr->nWidth, ptr->nHeight * 2, 1 );
82 image = XCreateImage( display, DefaultVisualOfScreen(screen),
83 1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
84 ptr->nHeight * 2, 16, ptr->nWidthBytes);
85 if (image)
87 image->byte_order = MSBFirst;
88 image->bitmap_bit_order = MSBFirst;
89 image->bitmap_unit = 16;
90 _XInitImageFuncPtrs(image);
91 if (pixmapAll)
92 XPutImage( display, pixmapAll, BITMAP_monoGC, image,
93 0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
94 image->data = NULL;
95 XDestroyImage( image );
98 /* Now create the 2 pixmaps for bits and mask */
100 pixmapBits = XCreatePixmap( display, rootWindow,
101 ptr->nWidth, ptr->nHeight, 1 );
102 pixmapMask = XCreatePixmap( display, rootWindow,
103 ptr->nWidth, ptr->nHeight, 1 );
105 /* Make sure everything went OK so far */
107 if (pixmapBits && pixmapMask && pixmapAll)
109 /* We have to do some magic here, as cursors are not fully
110 * compatible between Windows and X11. Under X11, there
111 * are only 3 possible color cursor: black, white and
112 * masked. So we map the 4th Windows color (invert the
113 * bits on the screen) to black. This require some boolean
114 * arithmetic:
116 * Windows | X11
117 * Xor And Result | Bits Mask Result
118 * 0 0 black | 0 1 background
119 * 0 1 no change | X 0 no change
120 * 1 0 white | 1 1 foreground
121 * 1 1 inverted | 0 1 background
123 * which gives:
124 * Bits = 'Xor' and not 'And'
125 * Mask = 'Xor' or not 'And'
127 * FIXME: apparently some servers do support 'inverted' color.
128 * I don't know if it's correct per the X spec, but maybe
129 * we ought to take advantage of it. -- AJ
131 XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
132 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
133 XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
134 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
135 XSetFunction( display, BITMAP_monoGC, GXandReverse );
136 XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
137 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
138 XSetFunction( display, BITMAP_monoGC, GXorReverse );
139 XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
140 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
141 XSetFunction( display, BITMAP_monoGC, GXcopy );
142 fg.red = fg.green = fg.blue = 0xffff;
143 bg.red = bg.green = bg.blue = 0x0000;
144 cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
145 &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
148 /* Now free everything */
150 if (pixmapAll) XFreePixmap( display, pixmapAll );
151 if (pixmapBits) XFreePixmap( display, pixmapBits );
152 if (pixmapMask) XFreePixmap( display, pixmapMask );
155 if (cursor == None) return FALSE;
156 if (DISPLAY_XCursor != None) XFreeCursor( display, DISPLAY_XCursor );
157 DISPLAY_XCursor = cursor;
159 if (rootWindow != DefaultRootWindow(display) || !WIN_GetDesktop())
161 /* Set the cursor on the desktop window */
162 XDefineCursor( display, rootWindow, cursor );
164 else
166 /* FIXME: this won't work correctly with native USER !*/
168 /* Set the same cursor for all top-level windows */
169 HWND32 hwnd = GetWindow32( GetDesktopWindow32(), GW_CHILD );
170 while(hwnd)
172 Window win = WIN_GetXWindow( hwnd );
173 if (win && win!=DefaultRootWindow(display))
174 XDefineCursor( display, win, cursor );
175 hwnd = GetWindow32( hwnd, GW_HWNDNEXT );
178 return TRUE;
181 /***********************************************************************
182 * DISPLAY_SetCursor (DISPLAY.102)
184 VOID WINAPI DISPLAY_SetCursor( CURSORICONINFO *lpCursor )
186 EnterCriticalSection( &X11DRV_CritSection );
187 CALL_LARGE_STACK( DISPLAY_DoSetCursor, lpCursor );
188 LeaveCriticalSection( &X11DRV_CritSection );
191 /***********************************************************************
192 * DISPLAY_MoveCursor (DISPLAY.103)
194 VOID WINAPI DISPLAY_MoveCursor( WORD wAbsX, WORD wAbsY )
197 * We do not want the to create MotionNotify events here,
198 * otherwise we will get an endless recursion:
199 * XMotionEvent -> MOUSEEVENTF_MOVE -> mouse_event -> DisplayMoveCursor
200 * -> XWarpPointer -> XMotionEvent -> ...
202 * Unfortunately, the XWarpPointer call does create a MotionNotify
203 * event. So, we use a hack: before MOUSE_SendEvent calls the mouse event
204 * procedure, it sets a global flag. If this flag is set, we skip the
205 * XWarpPointer call. If we are *not* called from within MOUSE_SendEvent,
206 * we will call XWarpPointer, which will create a MotionNotify event.
207 * Strictly speaking, this is also wrong, but that should normally not
208 * have any negative effects ...
210 * But first of all, we check whether we already are at the position
211 * are supposed to move to; if so, we don't need to do anything.
214 Window root, child;
215 int rootX, rootY, winX, winY;
216 unsigned int xstate;
218 if (DISPLAY_DisableWarpPointer) return;
220 if (!TSXQueryPointer( display, rootWindow, &root, &child,
221 &rootX, &rootY, &winX, &winY, &xstate ))
222 return;
224 if ( winX == wAbsX && winY == wAbsY )
225 return;
227 TRACE( cursor, "(%d,%d): moving from (%d,%d)\n", wAbsX, wAbsY, winX, winY );
229 TSXWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, wAbsX, wAbsY );
232 /***********************************************************************
233 * DISPLAY_CheckCursor (DISPLAY.104)
235 VOID WINAPI DISPLAY_CheckCursor()
237 FIXME( cursor, "stub\n" );
240 /***********************************************************************
241 * UserRepaintDisable (DISPLAY.500)
243 VOID WINAPI UserRepaintDisable( BOOL16 disable )
245 TRACE( cursor, "(%d): stub\n", disable );