4 * Copyright 1998 Ulrich Weigand
5 * Copyright 2007 Henri Verbeet
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
26 #include <X11/cursorfont.h>
29 #ifdef SONAME_LIBXCURSOR
30 # include <X11/Xcursor/Xcursor.h>
31 static void *xcursor_handle
;
32 # define MAKE_FUNCPTR(f) static typeof(f) * p##f
33 MAKE_FUNCPTR(XcursorImageCreate
);
34 MAKE_FUNCPTR(XcursorImageDestroy
);
35 MAKE_FUNCPTR(XcursorImageLoadCursor
);
36 MAKE_FUNCPTR(XcursorImagesCreate
);
37 MAKE_FUNCPTR(XcursorImagesDestroy
);
38 MAKE_FUNCPTR(XcursorImagesLoadCursor
);
39 MAKE_FUNCPTR(XcursorLibraryLoadCursor
);
41 #endif /* SONAME_LIBXCURSOR */
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
51 #include "wine/server.h"
52 #include "wine/library.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(cursor
);
58 /**********************************************************************/
61 #define Button6Mask (1<<13)
64 #define Button7Mask (1<<14)
67 #define NB_BUTTONS 9 /* Windows can handle 5 buttons and the wheel too */
69 static const UINT button_down_flags
[NB_BUTTONS
] =
72 MOUSEEVENTF_MIDDLEDOWN
,
73 MOUSEEVENTF_RIGHTDOWN
,
76 MOUSEEVENTF_XDOWN
, /* FIXME: horizontal wheel */
82 static const UINT button_up_flags
[NB_BUTTONS
] =
95 static HWND cursor_window
;
96 static DWORD last_time_modified
;
97 static XContext cursor_context
;
98 static Cursor
create_cursor( HANDLE handle
);
100 BOOL CDECL
X11DRV_SetCursorPos( INT x
, INT y
);
103 /***********************************************************************
104 * X11DRV_Xcursor_Init
106 * Load the Xcursor library for use.
108 void X11DRV_Xcursor_Init(void)
110 #ifdef SONAME_LIBXCURSOR
111 xcursor_handle
= wine_dlopen(SONAME_LIBXCURSOR
, RTLD_NOW
, NULL
, 0);
112 if (!xcursor_handle
) /* wine_dlopen failed. */
114 WARN("Xcursor failed to load. Using fallback code.\n");
117 #define LOAD_FUNCPTR(f) \
118 p##f = wine_dlsym(xcursor_handle, #f, NULL, 0)
120 LOAD_FUNCPTR(XcursorImageCreate
);
121 LOAD_FUNCPTR(XcursorImageDestroy
);
122 LOAD_FUNCPTR(XcursorImageLoadCursor
);
123 LOAD_FUNCPTR(XcursorImagesCreate
);
124 LOAD_FUNCPTR(XcursorImagesDestroy
);
125 LOAD_FUNCPTR(XcursorImagesLoadCursor
);
126 LOAD_FUNCPTR(XcursorLibraryLoadCursor
);
128 #endif /* SONAME_LIBXCURSOR */
132 /***********************************************************************
135 static Cursor
get_empty_cursor(void)
137 static Cursor cursor
;
138 static const char data
[] = { 0 };
146 bg
.red
= bg
.green
= bg
.blue
= 0x0000;
147 pixmap
= XCreateBitmapFromData( gdi_display
, root_window
, data
, 1, 1 );
150 cursor
= XCreatePixmapCursor( gdi_display
, pixmap
, pixmap
, &bg
, &bg
, 0, 0 );
151 XFreePixmap( gdi_display
, pixmap
);
158 /***********************************************************************
161 void set_window_cursor( struct x11drv_win_data
*data
, HCURSOR handle
)
166 if (!handle
) cursor
= get_empty_cursor();
167 else if (!cursor_context
|| XFindContext( gdi_display
, (XID
)handle
, cursor_context
, (char **)&cursor
))
169 /* try to create it */
171 if (!(cursor
= create_cursor( handle
))) return;
174 if (!cursor_context
) cursor_context
= XUniqueContext();
175 if (!XFindContext( gdi_display
, (XID
)handle
, cursor_context
, (char **)&prev
))
177 /* someone else was here first */
178 XFreeCursor( gdi_display
, cursor
);
183 XSaveContext( gdi_display
, (XID
)handle
, cursor_context
, (char *)cursor
);
184 TRACE( "cursor %p created %lx\n", handle
, cursor
);
188 XDefineCursor( gdi_display
, data
->whole_window
, cursor
);
189 /* make the change take effect immediately */
190 XFlush( gdi_display
);
191 data
->cursor
= handle
;
195 /***********************************************************************
198 void sync_window_cursor( struct x11drv_win_data
*data
)
202 SERVER_START_REQ( set_cursor
)
205 wine_server_call( req
);
206 cursor
= reply
->prev_count
>= 0 ? wine_server_ptr_handle( reply
->prev_handle
) : 0;
210 if (data
->cursor
!= cursor
) set_window_cursor( data
, cursor
);
213 /***********************************************************************
216 * Update the various window states on a mouse event.
218 static HWND
update_mouse_state( HWND hwnd
, Window window
, int x
, int y
, unsigned int state
, POINT
*pt
)
220 struct x11drv_win_data
*data
= X11DRV_get_win_data( hwnd
);
224 if (window
== data
->whole_window
)
226 x
+= data
->whole_rect
.left
- data
->client_rect
.left
;
227 y
+= data
->whole_rect
.top
- data
->client_rect
.top
;
229 if (window
== root_window
)
231 x
+= virtual_screen_rect
.left
;
232 y
+= virtual_screen_rect
.top
;
236 if (GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
237 pt
->x
= data
->client_rect
.right
- data
->client_rect
.left
- 1 - pt
->x
;
238 MapWindowPoints( hwnd
, 0, pt
, 1 );
240 if (InterlockedExchangePointer( (void **)&cursor_window
, hwnd
) != hwnd
||
241 GetTickCount() - last_time_modified
> 100)
243 cursor_window
= hwnd
;
244 sync_window_cursor( data
);
246 if (hwnd
!= GetDesktopWindow()) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
248 /* update the wine server Z-order */
250 if (window
!= x11drv_thread_data()->grab_window
&&
251 /* ignore event if a button is pressed, since the mouse is then grabbed too */
252 !(state
& (Button1Mask
|Button2Mask
|Button3Mask
|Button4Mask
|Button5Mask
|Button6Mask
|Button7Mask
)))
255 SetRect( &rect
, pt
->x
, pt
->y
, pt
->x
+ 1, pt
->y
+ 1 );
256 MapWindowPoints( 0, hwnd
, (POINT
*)&rect
, 2 );
258 SERVER_START_REQ( update_window_zorder
)
260 req
->window
= wine_server_user_handle( hwnd
);
261 req
->rect
.left
= rect
.left
;
262 req
->rect
.top
= rect
.top
;
263 req
->rect
.right
= rect
.right
;
264 req
->rect
.bottom
= rect
.bottom
;
265 wine_server_call( req
);
273 /***********************************************************************
274 * X11DRV_send_mouse_input
276 static void X11DRV_send_mouse_input( HWND hwnd
, DWORD flags
, int x
, int y
, DWORD data
, DWORD time
)
280 last_time_modified
= GetTickCount();
282 input
.type
= INPUT_MOUSE
;
285 input
.u
.mi
.mouseData
= data
;
286 input
.u
.mi
.dwFlags
= flags
;
287 input
.u
.mi
.time
= time
;
288 input
.u
.mi
.dwExtraInfo
= 0;
290 __wine_send_input( hwnd
, &input
);
293 #ifdef SONAME_LIBXCURSOR
295 /***********************************************************************
296 * create_xcursor_frame
298 * Use Xcursor to create a frame of an X cursor from a Windows one.
300 static XcursorImage
*create_xcursor_frame( HDC hdc
, const ICONINFOEXW
*iinfo
, HANDLE icon
,
301 HBITMAP hbmColor
, unsigned char *color_bits
, int color_size
,
302 HBITMAP hbmMask
, unsigned char *mask_bits
, int mask_size
,
303 int width
, int height
, int istep
)
305 XcursorImage
*image
, *ret
= NULL
;
306 int x
, y
, i
, has_alpha
;
310 image
= pXcursorImageCreate( width
, height
);
314 ERR("X11 failed to produce a cursor frame!\n");
318 image
->xhot
= iinfo
->xHotspot
;
319 image
->yhot
= iinfo
->yHotspot
;
320 image
->delay
= 100; /* TODO: find a way to get the proper delay */
322 /* draw the cursor frame to a temporary buffer then copy it into the XcursorImage */
323 memset( color_bits
, 0x00, color_size
);
324 SelectObject( hdc
, hbmColor
);
325 if (!DrawIconEx( hdc
, 0, 0, icon
, width
, height
, istep
, NULL
, DI_NORMAL
))
327 TRACE("Could not draw frame %d (walk past end of frames).\n", istep
);
330 memcpy( image
->pixels
, color_bits
, color_size
);
332 /* check if the cursor frame was drawn with an alpha channel */
333 for (i
= 0, ptr
= image
->pixels
; i
< width
* height
; i
++, ptr
++)
334 if ((has_alpha
= (*ptr
& 0xff000000) != 0)) break;
336 /* if no alpha channel was drawn then generate it from the mask */
339 unsigned int width_bytes
= (width
+ 31) / 32 * 4;
341 /* draw the cursor mask to a temporary buffer */
342 memset( mask_bits
, 0xFF, mask_size
);
343 SelectObject( hdc
, hbmMask
);
344 if (!DrawIconEx( hdc
, 0, 0, icon
, width
, height
, istep
, NULL
, DI_MASK
))
346 ERR("Failed to draw frame mask %d.\n", istep
);
349 /* use the buffer to directly modify the XcursorImage alpha channel */
350 for (y
= 0, ptr
= image
->pixels
; y
< height
; y
++)
351 for (x
= 0; x
< width
; x
++, ptr
++)
352 if (!((mask_bits
[y
* width_bytes
+ x
/ 8] << (x
% 8)) & 0x80))
358 if (ret
== NULL
) pXcursorImageDestroy( image
);
362 /***********************************************************************
363 * create_xcursor_cursor
365 * Use Xcursor to create an X cursor from a Windows one.
367 static Cursor
create_xcursor_cursor( HDC hdc
, const ICONINFOEXW
*iinfo
, HANDLE icon
, int width
, int height
)
369 unsigned char *color_bits
, *mask_bits
;
370 HBITMAP hbmColor
= 0, hbmMask
= 0;
371 XcursorImage
**imgs
, *image
;
372 int color_size
, mask_size
;
373 BITMAPINFO
*info
= NULL
;
374 XcursorImages
*images
;
378 if (!(imgs
= HeapAlloc( GetProcessHeap(), 0, sizeof(XcursorImage
*) ))) return 0;
380 /* Allocate all of the resources necessary to obtain a cursor frame */
381 if (!(info
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )))) goto cleanup
;
382 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
383 info
->bmiHeader
.biWidth
= width
;
384 info
->bmiHeader
.biHeight
= -height
;
385 info
->bmiHeader
.biPlanes
= 1;
386 info
->bmiHeader
.biCompression
= BI_RGB
;
387 info
->bmiHeader
.biXPelsPerMeter
= 0;
388 info
->bmiHeader
.biYPelsPerMeter
= 0;
389 info
->bmiHeader
.biClrUsed
= 0;
390 info
->bmiHeader
.biClrImportant
= 0;
391 info
->bmiHeader
.biBitCount
= 32;
392 color_size
= width
* height
* 4;
393 info
->bmiHeader
.biSizeImage
= color_size
;
394 hbmColor
= CreateDIBSection( hdc
, info
, DIB_RGB_COLORS
, (VOID
**) &color_bits
, NULL
, 0);
397 ERR("Failed to create DIB section for cursor color data!\n");
400 info
->bmiHeader
.biBitCount
= 1;
401 mask_size
= ((width
+ 31) / 32 * 4) * height
; /* width_bytes * height */
402 info
->bmiHeader
.biSizeImage
= mask_size
;
403 hbmMask
= CreateDIBSection( hdc
, info
, DIB_RGB_COLORS
, (VOID
**) &mask_bits
, NULL
, 0);
406 ERR("Failed to create DIB section for cursor mask data!\n");
410 /* Create an XcursorImage for each frame of the cursor */
413 XcursorImage
**imgstmp
;
415 image
= create_xcursor_frame( hdc
, iinfo
, icon
,
416 hbmColor
, color_bits
, color_size
,
417 hbmMask
, mask_bits
, mask_size
,
418 width
, height
, nFrames
);
419 if (!image
) break; /* no more drawable frames */
421 imgs
[nFrames
++] = image
;
422 if (!(imgstmp
= HeapReAlloc( GetProcessHeap(), 0, imgs
, (nFrames
+1)*sizeof(XcursorImage
*) ))) goto cleanup
;
426 /* Build an X cursor out of all of the frames */
427 if (!(images
= pXcursorImagesCreate( nFrames
))) goto cleanup
;
428 for (images
->nimage
= 0; images
->nimage
< nFrames
; images
->nimage
++)
429 images
->images
[images
->nimage
] = imgs
[images
->nimage
];
431 cursor
= pXcursorImagesLoadCursor( gdi_display
, images
);
433 pXcursorImagesDestroy( images
); /* Note: this frees each individual frame (calls XcursorImageDestroy) */
434 HeapFree( GetProcessHeap(), 0, imgs
);
440 /* Failed to produce a cursor, free previously allocated frames */
441 for (nFrames
--; nFrames
>= 0; nFrames
--)
442 pXcursorImageDestroy( imgs
[nFrames
] );
443 HeapFree( GetProcessHeap(), 0, imgs
);
445 /* Cleanup all of the resources used to obtain the frame data */
446 if (hbmColor
) DeleteObject( hbmColor
);
447 if (hbmMask
) DeleteObject( hbmMask
);
448 HeapFree( GetProcessHeap(), 0, info
);
453 struct system_cursors
459 static const struct system_cursors user32_cursors
[] =
461 { OCR_NORMAL
, "left_ptr" },
462 { OCR_IBEAM
, "xterm" },
463 { OCR_WAIT
, "watch" },
464 { OCR_CROSS
, "cross" },
465 { OCR_UP
, "center_ptr" },
466 { OCR_SIZE
, "fleur" },
467 { OCR_SIZEALL
, "fleur" },
468 { OCR_ICON
, "icon" },
469 { OCR_SIZENWSE
, "nwse-resize" },
470 { OCR_SIZENESW
, "nesw-resize" },
471 { OCR_SIZEWE
, "ew-resize" },
472 { OCR_SIZENS
, "ns-resize" },
473 { OCR_NO
, "not-allowed" },
474 { OCR_HAND
, "hand2" },
475 { OCR_APPSTARTING
, "left_ptr_watch" },
476 { OCR_HELP
, "question_arrow" },
480 static const struct system_cursors comctl32_cursors
[] =
485 { 106, "row-resize" },
486 { 107, "row-resize" },
488 { 135, "col-resize" },
492 static const struct system_cursors ole32_cursors
[] =
501 static const struct system_cursors riched20_cursors
[] =
504 { 107, "right_ptr" },
513 const struct system_cursors
*cursors
;
517 { user32_cursors
, {'u','s','e','r','3','2','.','d','l','l',0} },
518 { comctl32_cursors
, {'c','o','m','c','t','l','3','2','.','d','l','l',0} },
519 { ole32_cursors
, {'o','l','e','3','2','.','d','l','l',0} },
520 { riched20_cursors
, {'r','i','c','h','e','d','2','0','.','d','l','l',0} }
523 /***********************************************************************
524 * create_xcursor_system_cursor
526 * Create an X cursor for a system cursor.
528 static Cursor
create_xcursor_system_cursor( const ICONINFOEXW
*info
)
530 static const WCHAR idW
[] = {'%','h','u',0};
531 const struct system_cursors
*cursors
;
536 WCHAR
*p
, name
[MAX_PATH
* 2], valueW
[64];
540 if (!pXcursorLibraryLoadCursor
) return 0;
541 if (!info
->szModName
[0]) return 0;
543 p
= strrchrW( info
->szModName
, '\\' );
544 strcpyW( name
, p
? p
+ 1 : info
->szModName
);
545 p
= name
+ strlenW( name
);
547 if (info
->szResName
[0]) strcpyW( p
, info
->szResName
);
548 else sprintfW( p
, idW
, info
->wResID
);
551 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver\Cursors */
552 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\X11 Driver\\Cursors", &key
))
554 size
= sizeof(valueW
) / sizeof(WCHAR
);
555 ret
= RegQueryValueExW( key
, name
, NULL
, NULL
, (BYTE
*)valueW
, &size
);
559 if (!valueW
[0]) return 0; /* force standard cursor */
560 if (!WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, sizeof(valueA
), NULL
, NULL
))
566 if (info
->szResName
[0]) goto done
; /* only integer resources are supported here */
567 if (!(module
= GetModuleHandleW( info
->szModName
))) goto done
;
569 for (i
= 0; i
< sizeof(module_cursors
)/sizeof(module_cursors
[0]); i
++)
570 if (GetModuleHandleW( module_cursors
[i
].name
) == module
) break;
571 if (i
== sizeof(module_cursors
)/sizeof(module_cursors
[0])) goto done
;
573 cursors
= module_cursors
[i
].cursors
;
574 for (i
= 0; cursors
[i
].id
; i
++)
575 if (cursors
[i
].id
== info
->wResID
)
577 strcpy( valueA
, cursors
[i
].name
);
585 cursor
= pXcursorLibraryLoadCursor( gdi_display
, valueA
);
587 if (!cursor
) WARN( "no system cursor found for %s mapped to %s\n",
588 debugstr_w(name
), debugstr_a(valueA
) );
590 else WARN( "no system cursor found for %s\n", debugstr_w(name
) );
594 #endif /* SONAME_LIBXCURSOR */
597 /***********************************************************************
598 * create_cursor_from_bitmaps
600 * Create an X11 cursor from source bitmaps.
602 static Cursor
create_cursor_from_bitmaps( HBITMAP src_xor
, HBITMAP src_and
, int width
, int height
,
603 int xor_y
, int and_y
, XColor
*fg
, XColor
*bg
,
604 int hotspot_x
, int hotspot_y
)
606 HDC src
= 0, dst
= 0;
607 HBITMAP bits
= 0, mask
= 0, mask_inv
= 0;
610 if (!(src
= CreateCompatibleDC( 0 ))) goto done
;
611 if (!(dst
= CreateCompatibleDC( 0 ))) goto done
;
613 if (!(bits
= CreateBitmap( width
, height
, 1, 1, NULL
))) goto done
;
614 if (!(mask
= CreateBitmap( width
, height
, 1, 1, NULL
))) goto done
;
615 if (!(mask_inv
= CreateBitmap( width
, height
, 1, 1, NULL
))) goto done
;
617 /* We have to do some magic here, as cursors are not fully
618 * compatible between Windows and X11. Under X11, there are
619 * only 3 possible color cursor: black, white and masked. So
620 * we map the 4th Windows color (invert the bits on the screen)
621 * to black and an additional white bit on an other place
622 * (+1,+1). This require some boolean arithmetic:
625 * And Xor Result | Bits Mask Result
626 * 0 0 black | 0 1 background
627 * 0 1 white | 1 1 foreground
628 * 1 0 no change | X 0 no change
629 * 1 1 inverted | 0 1 background
632 * Bits = not 'And' and 'Xor' or 'And2' and 'Xor2'
633 * Mask = not 'And' or 'Xor' or 'And2' and 'Xor2'
635 SelectObject( src
, src_and
);
636 SelectObject( dst
, bits
);
637 BitBlt( dst
, 0, 0, width
, height
, src
, 0, and_y
, SRCCOPY
);
638 SelectObject( dst
, mask
);
639 BitBlt( dst
, 0, 0, width
, height
, src
, 0, and_y
, SRCCOPY
);
640 SelectObject( dst
, mask_inv
);
641 BitBlt( dst
, 0, 0, width
, height
, src
, 0, and_y
, SRCCOPY
);
642 SelectObject( src
, src_xor
);
643 BitBlt( dst
, 0, 0, width
, height
, src
, 0, xor_y
, SRCAND
/* src & dst */ );
644 SelectObject( dst
, bits
);
645 BitBlt( dst
, 0, 0, width
, height
, src
, 0, xor_y
, SRCERASE
/* src & ~dst */ );
646 SelectObject( dst
, mask
);
647 BitBlt( dst
, 0, 0, width
, height
, src
, 0, xor_y
, 0xdd0228 /* src | ~dst */ );
648 /* additional white */
649 SelectObject( src
, mask_inv
);
650 BitBlt( dst
, 1, 1, width
, height
, src
, 0, 0, SRCPAINT
/* src | dst */);
651 SelectObject( dst
, bits
);
652 BitBlt( dst
, 1, 1, width
, height
, src
, 0, 0, SRCPAINT
/* src | dst */ );
655 cursor
= XCreatePixmapCursor( gdi_display
, X11DRV_get_pixmap(bits
), X11DRV_get_pixmap(mask
),
656 fg
, bg
, hotspot_x
, hotspot_y
);
662 DeleteObject( bits
);
663 DeleteObject( mask
);
664 DeleteObject( mask_inv
);
668 /***********************************************************************
671 * Create an X cursor from a Windows one.
673 static Cursor
create_xlib_cursor( HDC hdc
, const ICONINFOEXW
*icon
, int width
, int height
)
676 Cursor cursor
= None
;
677 HBITMAP xor_bitmap
= 0;
679 unsigned int *color_bits
= NULL
, *ptr
;
680 unsigned char *mask_bits
= NULL
, *xor_bits
= NULL
;
681 int i
, x
, y
, has_alpha
= 0;
682 int rfg
, gfg
, bfg
, rbg
, gbg
, bbg
, fgBits
, bgBits
;
683 unsigned int width_bytes
= (width
+ 31) / 32 * 4;
685 if (!(info
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] ))))
687 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
688 info
->bmiHeader
.biWidth
= width
;
689 info
->bmiHeader
.biHeight
= -height
;
690 info
->bmiHeader
.biPlanes
= 1;
691 info
->bmiHeader
.biBitCount
= 1;
692 info
->bmiHeader
.biCompression
= BI_RGB
;
693 info
->bmiHeader
.biSizeImage
= width_bytes
* height
;
694 info
->bmiHeader
.biXPelsPerMeter
= 0;
695 info
->bmiHeader
.biYPelsPerMeter
= 0;
696 info
->bmiHeader
.biClrUsed
= 0;
697 info
->bmiHeader
.biClrImportant
= 0;
699 if (!(mask_bits
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
))) goto done
;
700 if (!GetDIBits( hdc
, icon
->hbmMask
, 0, height
, mask_bits
, info
, DIB_RGB_COLORS
)) goto done
;
702 info
->bmiHeader
.biBitCount
= 32;
703 info
->bmiHeader
.biSizeImage
= width
* height
* 4;
704 if (!(color_bits
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
))) goto done
;
705 if (!(xor_bits
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, width_bytes
* height
))) goto done
;
706 GetDIBits( hdc
, icon
->hbmColor
, 0, height
, color_bits
, info
, DIB_RGB_COLORS
);
708 /* compute fg/bg color and xor bitmap based on average of the color values */
710 if (!(xor_bitmap
= CreateBitmap( width
, height
, 1, 1, NULL
))) goto done
;
711 rfg
= gfg
= bfg
= rbg
= gbg
= bbg
= fgBits
= 0;
712 for (y
= 0, ptr
= color_bits
; y
< height
; y
++)
714 for (x
= 0; x
< width
; x
++, ptr
++)
716 int red
= (*ptr
>> 16) & 0xff;
717 int green
= (*ptr
>> 8) & 0xff;
718 int blue
= (*ptr
>> 0) & 0xff;
719 if (red
+ green
+ blue
> 0x40)
725 xor_bits
[y
* width_bytes
+ x
/ 8] |= 0x80 >> (x
% 8);
737 fg
.red
= rfg
* 257 / fgBits
;
738 fg
.green
= gfg
* 257 / fgBits
;
739 fg
.blue
= bfg
* 257 / fgBits
;
741 else fg
.red
= fg
.green
= fg
.blue
= 0;
742 bgBits
= width
* height
- fgBits
;
745 bg
.red
= rbg
* 257 / bgBits
;
746 bg
.green
= gbg
* 257 / bgBits
;
747 bg
.blue
= bbg
* 257 / bgBits
;
749 else bg
.red
= bg
.green
= bg
.blue
= 0;
751 info
->bmiHeader
.biBitCount
= 1;
752 info
->bmiHeader
.biSizeImage
= width_bytes
* height
;
753 SetDIBits( hdc
, xor_bitmap
, 0, height
, xor_bits
, info
, DIB_RGB_COLORS
);
755 /* generate mask from the alpha channel if we have one */
757 for (i
= 0, ptr
= color_bits
; i
< width
* height
; i
++, ptr
++)
758 if ((has_alpha
= (*ptr
& 0xff000000) != 0)) break;
762 memset( mask_bits
, 0, width_bytes
* height
);
763 for (y
= 0, ptr
= color_bits
; y
< height
; y
++)
764 for (x
= 0; x
< width
; x
++, ptr
++)
765 if ((*ptr
>> 24) > 25) /* more than 10% alpha */
766 mask_bits
[y
* width_bytes
+ x
/ 8] |= 0x80 >> (x
% 8);
768 info
->bmiHeader
.biBitCount
= 1;
769 info
->bmiHeader
.biSizeImage
= width_bytes
* height
;
770 SetDIBits( hdc
, icon
->hbmMask
, 0, height
, mask_bits
, info
, DIB_RGB_COLORS
);
773 cursor
= XCreatePixmapCursor( gdi_display
,
774 X11DRV_get_pixmap(xor_bitmap
),
775 X11DRV_get_pixmap(icon
->hbmMask
),
776 &fg
, &bg
, icon
->xHotspot
, icon
->yHotspot
);
781 cursor
= create_cursor_from_bitmaps( xor_bitmap
, icon
->hbmMask
, width
, height
, 0, 0,
782 &fg
, &bg
, icon
->xHotspot
, icon
->yHotspot
);
786 DeleteObject( xor_bitmap
);
787 HeapFree( GetProcessHeap(), 0, info
);
788 HeapFree( GetProcessHeap(), 0, color_bits
);
789 HeapFree( GetProcessHeap(), 0, xor_bits
);
790 HeapFree( GetProcessHeap(), 0, mask_bits
);
794 /***********************************************************************
797 * Create an X cursor from a Windows one.
799 static Cursor
create_cursor( HANDLE handle
)
805 if (!handle
) return get_empty_cursor();
807 info
.cbSize
= sizeof(info
);
808 if (!GetIconInfoExW( handle
, &info
)) return 0;
810 #ifdef SONAME_LIBXCURSOR
811 if (use_system_cursors
&& (cursor
= create_xcursor_system_cursor( &info
)))
813 DeleteObject( info
.hbmColor
);
814 DeleteObject( info
.hbmMask
);
819 GetObjectW( info
.hbmMask
, sizeof(bm
), &bm
);
820 if (!info
.hbmColor
) bm
.bmHeight
/= 2;
822 /* make sure hotspot is valid */
823 if (info
.xHotspot
>= bm
.bmWidth
|| info
.yHotspot
>= bm
.bmHeight
)
825 info
.xHotspot
= bm
.bmWidth
/ 2;
826 info
.yHotspot
= bm
.bmHeight
/ 2;
831 HDC hdc
= CreateCompatibleDC( 0 );
834 #ifdef SONAME_LIBXCURSOR
835 if (pXcursorImagesLoadCursor
)
836 cursor
= create_xcursor_cursor( hdc
, &info
, handle
, bm
.bmWidth
, bm
.bmHeight
);
838 if (!cursor
) cursor
= create_xlib_cursor( hdc
, &info
, bm
.bmWidth
, bm
.bmHeight
);
840 DeleteObject( info
.hbmColor
);
846 fg
.red
= fg
.green
= fg
.blue
= 0xffff;
847 bg
.red
= bg
.green
= bg
.blue
= 0;
848 cursor
= create_cursor_from_bitmaps( info
.hbmMask
, info
.hbmMask
, bm
.bmWidth
, bm
.bmHeight
,
849 bm
.bmHeight
, 0, &fg
, &bg
, info
.xHotspot
, info
.yHotspot
);
852 DeleteObject( info
.hbmMask
);
856 /***********************************************************************
857 * DestroyCursorIcon (X11DRV.@)
859 void CDECL
X11DRV_DestroyCursorIcon( HCURSOR handle
)
864 if (cursor_context
&& !XFindContext( gdi_display
, (XID
)handle
, cursor_context
, (char **)&cursor
))
866 TRACE( "%p xid %lx\n", handle
, cursor
);
867 XFreeCursor( gdi_display
, cursor
);
868 XDeleteContext( gdi_display
, (XID
)handle
, cursor_context
);
873 /***********************************************************************
874 * SetCursor (X11DRV.@)
876 void CDECL
X11DRV_SetCursor( HCURSOR handle
)
878 if (cursor_window
) SendNotifyMessageW( cursor_window
, WM_X11DRV_SET_CURSOR
, 0, (LPARAM
)handle
);
881 /***********************************************************************
882 * SetCursorPos (X11DRV.@)
884 BOOL CDECL
X11DRV_SetCursorPos( INT x
, INT y
)
886 Display
*display
= thread_init_display();
888 TRACE( "warping to (%d,%d)\n", x
, y
);
891 XWarpPointer( display
, root_window
, root_window
, 0, 0, 0, 0,
892 x
- virtual_screen_rect
.left
, y
- virtual_screen_rect
.top
);
893 XFlush( display
); /* avoids bad mouse lag in games that do their own mouse warping */
898 /***********************************************************************
899 * GetCursorPos (X11DRV.@)
901 BOOL CDECL
X11DRV_GetCursorPos(LPPOINT pos
)
903 Display
*display
= thread_init_display();
905 int rootX
, rootY
, winX
, winY
;
910 ret
= XQueryPointer( display
, root_window
, &root
, &child
, &rootX
, &rootY
, &winX
, &winY
, &xstate
);
913 pos
->x
= winX
+ virtual_screen_rect
.left
;
914 pos
->y
= winY
+ virtual_screen_rect
.top
;
915 TRACE("pointer at (%d,%d)\n", pos
->x
, pos
->y
);
922 /***********************************************************************
925 void X11DRV_ButtonPress( HWND hwnd
, XEvent
*xev
)
927 XButtonEvent
*event
= &xev
->xbutton
;
928 int buttonNum
= event
->button
- 1;
932 if (buttonNum
>= NB_BUTTONS
) return;
940 wData
= -WHEEL_DELTA
;
956 update_user_time( event
->time
);
957 hwnd
= update_mouse_state( hwnd
, event
->window
, event
->x
, event
->y
, event
->state
, &pt
);
960 X11DRV_send_mouse_input( hwnd
, button_down_flags
[buttonNum
] | MOUSEEVENTF_ABSOLUTE
| MOUSEEVENTF_MOVE
,
961 pt
.x
, pt
.y
, wData
, EVENT_x11_time_to_win32_time(event
->time
) );
965 /***********************************************************************
966 * X11DRV_ButtonRelease
968 void X11DRV_ButtonRelease( HWND hwnd
, XEvent
*xev
)
970 XButtonEvent
*event
= &xev
->xbutton
;
971 int buttonNum
= event
->button
- 1;
975 if (buttonNum
>= NB_BUTTONS
|| !button_up_flags
[buttonNum
]) return;
993 hwnd
= update_mouse_state( hwnd
, event
->window
, event
->x
, event
->y
, event
->state
, &pt
);
996 X11DRV_send_mouse_input( hwnd
, button_up_flags
[buttonNum
] | MOUSEEVENTF_ABSOLUTE
| MOUSEEVENTF_MOVE
,
997 pt
.x
, pt
.y
, wData
, EVENT_x11_time_to_win32_time(event
->time
) );
1001 /***********************************************************************
1002 * X11DRV_MotionNotify
1004 void X11DRV_MotionNotify( HWND hwnd
, XEvent
*xev
)
1006 XMotionEvent
*event
= &xev
->xmotion
;
1009 TRACE("hwnd %p, event->is_hint %d\n", hwnd
, event
->is_hint
);
1011 hwnd
= update_mouse_state( hwnd
, event
->window
, event
->x
, event
->y
, event
->state
, &pt
);
1014 X11DRV_send_mouse_input( hwnd
, MOUSEEVENTF_MOVE
| MOUSEEVENTF_ABSOLUTE
,
1015 pt
.x
, pt
.y
, 0, EVENT_x11_time_to_win32_time(event
->time
) );
1019 /***********************************************************************
1020 * X11DRV_EnterNotify
1022 void X11DRV_EnterNotify( HWND hwnd
, XEvent
*xev
)
1024 XCrossingEvent
*event
= &xev
->xcrossing
;
1027 TRACE("hwnd %p, event->detail %d\n", hwnd
, event
->detail
);
1029 if (event
->detail
== NotifyVirtual
|| event
->detail
== NotifyNonlinearVirtual
) return;
1030 if (event
->window
== x11drv_thread_data()->grab_window
) return;
1032 /* simulate a mouse motion event */
1033 hwnd
= update_mouse_state( hwnd
, event
->window
, event
->x
, event
->y
, event
->state
, &pt
);
1036 X11DRV_send_mouse_input( hwnd
, MOUSEEVENTF_MOVE
| MOUSEEVENTF_ABSOLUTE
,
1037 pt
.x
, pt
.y
, 0, EVENT_x11_time_to_win32_time(event
->time
) );