Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Cursor and icon support |
| 3 | * |
| 4 | * Copyright 1995 Alexandre Julliard |
| 5 | */ |
| 6 | |
| 7 | /* |
| 8 | * Theory: |
| 9 | * |
| 10 | * Cursors and icons are stored in a global heap block, with the |
| 11 | * following layout: |
| 12 | * |
| 13 | * CURSORICONINFO info; |
| 14 | * BYTE[] ANDbits; |
| 15 | * BYTE[] XORbits; |
| 16 | * |
| 17 | * The bits structures are in the format of a device-dependent bitmap. |
| 18 | * |
| 19 | * This layout is very sub-optimal, as the bitmap bits are stored in |
| 20 | * the X client instead of in the server like other bitmaps; however, |
| 21 | * some programs (notably Paint Brush) expect to be able to manipulate |
| 22 | * the bits directly :-( |
| 23 | */ |
| 24 | |
| 25 | #include <string.h> |
| 26 | #include <stdlib.h> |
| 27 | #include "windows.h" |
| 28 | #include "bitmap.h" |
| 29 | #include "callback.h" |
| 30 | #include "cursoricon.h" |
| 31 | #include "sysmetrics.h" |
| 32 | #include "win.h" |
| 33 | #include "stddebug.h" |
| 34 | #include "debug.h" |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 35 | #include "xmalloc.h" |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 36 | #include "task.h" |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 37 | |
| 38 | |
| 39 | Cursor CURSORICON_XCursor = None; /* Current X cursor */ |
| 40 | static HCURSOR hActiveCursor = 0; /* Active cursor */ |
| 41 | static int CURSOR_ShowCount = 0; /* Cursor display count */ |
| 42 | static RECT CURSOR_ClipRect; /* Cursor clipping rect */ |
| 43 | |
| 44 | /********************************************************************** |
| 45 | * CURSORICON_FindBestIcon |
| 46 | * |
| 47 | * Find the icon closest to the requested size and number of colors. |
| 48 | */ |
| 49 | static ICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, |
| 50 | int height, int colors ) |
| 51 | { |
| 52 | int i, maxcolors, maxwidth, maxheight; |
| 53 | ICONDIRENTRY *entry, *bestEntry = NULL; |
| 54 | |
| 55 | if (dir->idCount < 1) |
| 56 | { |
| 57 | fprintf( stderr, "Icon: empty directory!\n" ); |
| 58 | return NULL; |
| 59 | } |
| 60 | if (dir->idCount == 1) return &dir->idEntries[0].icon; /* No choice... */ |
| 61 | |
| 62 | /* First find the exact size with less colors */ |
| 63 | |
| 64 | maxcolors = 0; |
| 65 | for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++) |
| 66 | if ((entry->bWidth == width) && (entry->bHeight == height) && |
| 67 | (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors)) |
| 68 | { |
| 69 | bestEntry = entry; |
| 70 | maxcolors = entry->bColorCount; |
| 71 | } |
| 72 | if (bestEntry) return bestEntry; |
| 73 | |
| 74 | /* First find the exact size with more colors */ |
| 75 | |
| 76 | maxcolors = 255; |
| 77 | for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++) |
| 78 | if ((entry->bWidth == width) && (entry->bHeight == height) && |
| 79 | (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors)) |
| 80 | { |
| 81 | bestEntry = entry; |
| 82 | maxcolors = entry->bColorCount; |
| 83 | } |
| 84 | if (bestEntry) return bestEntry; |
| 85 | |
| 86 | /* Now find a smaller one with less colors */ |
| 87 | |
| 88 | maxcolors = maxwidth = maxheight = 0; |
| 89 | for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++) |
| 90 | if ((entry->bWidth <= width) && (entry->bHeight <= height) && |
| 91 | (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) && |
| 92 | (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors)) |
| 93 | { |
| 94 | bestEntry = entry; |
| 95 | maxwidth = entry->bWidth; |
| 96 | maxheight = entry->bHeight; |
| 97 | maxcolors = entry->bColorCount; |
| 98 | } |
| 99 | if (bestEntry) return bestEntry; |
| 100 | |
| 101 | /* Now find a smaller one with more colors */ |
| 102 | |
| 103 | maxcolors = 255; |
| 104 | maxwidth = maxheight = 0; |
| 105 | for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++) |
| 106 | if ((entry->bWidth <= width) && (entry->bHeight <= height) && |
| 107 | (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) && |
| 108 | (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors)) |
| 109 | { |
| 110 | bestEntry = entry; |
| 111 | maxwidth = entry->bWidth; |
| 112 | maxheight = entry->bHeight; |
| 113 | maxcolors = entry->bColorCount; |
| 114 | } |
| 115 | if (bestEntry) return bestEntry; |
| 116 | |
| 117 | /* Now find a larger one with less colors */ |
| 118 | |
| 119 | maxcolors = 0; |
| 120 | maxwidth = maxheight = 255; |
| 121 | for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++) |
| 122 | if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) && |
| 123 | (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors)) |
| 124 | { |
| 125 | bestEntry = entry; |
| 126 | maxwidth = entry->bWidth; |
| 127 | maxheight = entry->bHeight; |
| 128 | maxcolors = entry->bColorCount; |
| 129 | } |
| 130 | if (bestEntry) return bestEntry; |
| 131 | |
| 132 | /* Now find a larger one with more colors */ |
| 133 | |
| 134 | maxcolors = maxwidth = maxheight = 255; |
| 135 | for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++) |
| 136 | if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) && |
| 137 | (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors)) |
| 138 | { |
| 139 | bestEntry = entry; |
| 140 | maxwidth = entry->bWidth; |
| 141 | maxheight = entry->bHeight; |
| 142 | maxcolors = entry->bColorCount; |
| 143 | } |
| 144 | |
| 145 | return bestEntry; |
| 146 | } |
| 147 | |
| 148 | |
| 149 | /********************************************************************** |
| 150 | * CURSORICON_FindBestCursor |
| 151 | * |
| 152 | * Find the cursor closest to the requested size. |
| 153 | */ |
| 154 | static CURSORDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, |
| 155 | int width, int height ) |
| 156 | { |
| 157 | int i, maxwidth, maxheight; |
| 158 | CURSORDIRENTRY *entry, *bestEntry = NULL; |
| 159 | |
| 160 | if (dir->idCount < 1) |
| 161 | { |
| 162 | fprintf( stderr, "Cursor: empty directory!\n" ); |
| 163 | return NULL; |
| 164 | } |
| 165 | if (dir->idCount == 1) return &dir->idEntries[0].cursor; /* No choice... */ |
| 166 | |
| 167 | /* First find the largest one smaller than or equal to the requested size*/ |
| 168 | |
| 169 | maxwidth = maxheight = 0; |
| 170 | for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++) |
| 171 | if ((entry->wWidth <= width) && (entry->wHeight <= height) && |
| 172 | (entry->wWidth > maxwidth) && (entry->wHeight > maxheight)) |
| 173 | { |
| 174 | bestEntry = entry; |
| 175 | maxwidth = entry->wWidth; |
| 176 | maxheight = entry->wHeight; |
| 177 | } |
| 178 | if (bestEntry) return bestEntry; |
| 179 | |
| 180 | /* Now find the smallest one larger than the requested size */ |
| 181 | |
| 182 | maxwidth = maxheight = 255; |
| 183 | for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++) |
| 184 | if ((entry->wWidth < maxwidth) && (entry->wHeight < maxheight)) |
| 185 | { |
| 186 | bestEntry = entry; |
| 187 | maxwidth = entry->wWidth; |
| 188 | maxheight = entry->wHeight; |
| 189 | } |
| 190 | |
| 191 | return bestEntry; |
| 192 | } |
| 193 | |
| 194 | |
| 195 | /********************************************************************** |
| 196 | * CURSORICON_LoadDirEntry |
| 197 | * |
| 198 | * Load the icon/cursor directory for a given resource name and find the |
| 199 | * best matching entry. |
| 200 | */ |
| 201 | static BOOL CURSORICON_LoadDirEntry(HANDLE hInstance, SEGPTR name, |
| 202 | int width, int height, int colors, |
| 203 | BOOL fCursor, CURSORICONDIRENTRY *dirEntry) |
| 204 | { |
| 205 | HRSRC hRsrc; |
| 206 | HANDLE hMem; |
| 207 | CURSORICONDIR *dir; |
| 208 | CURSORICONDIRENTRY *entry = NULL; |
| 209 | |
| 210 | if (!(hRsrc = FindResource( hInstance, name, |
| 211 | fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON ))) |
| 212 | return FALSE; |
| 213 | if (!(hMem = LoadResource( hInstance, hRsrc ))) return FALSE; |
| 214 | if ((dir = (CURSORICONDIR *)LockResource( hMem ))) |
| 215 | { |
| 216 | if (fCursor) |
| 217 | entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir, |
| 218 | width, height ); |
| 219 | else |
| 220 | entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir, |
| 221 | width, height, colors ); |
| 222 | if (entry) *dirEntry = *entry; |
| 223 | } |
| 224 | FreeResource( hMem ); |
| 225 | return (entry != NULL); |
| 226 | } |
| 227 | |
| 228 | |
| 229 | /********************************************************************** |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 230 | * CURSORICON_LoadHandler |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 231 | * |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 232 | * Create a cursor or icon from a resource. |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 233 | */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 234 | static HANDLE CURSORICON_LoadHandler( HANDLE handle, HINSTANCE hInstance, |
| 235 | BOOL fCursor ) |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 236 | { |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 237 | HANDLE hAndBits, hXorBits; |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 238 | HDC hdc; |
| 239 | int size, sizeAnd, sizeXor; |
| 240 | POINT hotspot = { 0 ,0 }; |
| 241 | BITMAPOBJ *bmpXor, *bmpAnd; |
| 242 | BITMAPINFO *bmi, *pInfo; |
| 243 | CURSORICONINFO *info; |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 244 | char *bits; |
| 245 | |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 246 | if (fCursor) /* If cursor, get the hotspot */ |
| 247 | { |
| 248 | POINT *pt = (POINT *)LockResource( handle ); |
| 249 | hotspot = *pt; |
| 250 | bmi = (BITMAPINFO *)(pt + 1); |
| 251 | } |
| 252 | else bmi = (BITMAPINFO *)LockResource( handle ); |
| 253 | |
| 254 | /* Create a copy of the bitmap header */ |
| 255 | |
| 256 | size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS ); |
| 257 | /* Make sure we have room for the monochrome bitmap later on */ |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 258 | size = MAX( size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD) ); |
| 259 | pInfo = (BITMAPINFO *)xmalloc( size ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 260 | memcpy( pInfo, bmi, size ); |
| 261 | |
| 262 | if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) |
| 263 | { |
| 264 | if (pInfo->bmiHeader.biCompression != BI_RGB) |
| 265 | { |
| 266 | fprintf(stderr,"Unknown size for compressed icon bitmap.\n"); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 267 | free( pInfo ); |
| 268 | return 0; |
| 269 | } |
| 270 | pInfo->bmiHeader.biHeight /= 2; |
| 271 | } |
| 272 | else if (pInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) |
| 273 | { |
| 274 | BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)pInfo; |
| 275 | core->bcHeight /= 2; |
| 276 | } |
| 277 | else |
| 278 | { |
| 279 | fprintf( stderr, "CURSORICON_Load: Unknown bitmap length %ld!\n", |
| 280 | pInfo->bmiHeader.biSize ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 281 | free( pInfo ); |
| 282 | return 0; |
| 283 | } |
| 284 | |
| 285 | /* Create the XOR bitmap */ |
| 286 | |
| 287 | if (!(hdc = GetDC( 0 ))) |
| 288 | { |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 289 | free( pInfo ); |
| 290 | return 0; |
| 291 | } |
| 292 | |
| 293 | hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader, CBM_INIT, |
| 294 | (char*)bmi + size, pInfo, DIB_RGB_COLORS ); |
| 295 | |
| 296 | /* Fix the bitmap header to load the monochrome mask */ |
| 297 | |
| 298 | if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) |
| 299 | { |
| 300 | BITMAPINFOHEADER *bih = &pInfo->bmiHeader; |
| 301 | RGBQUAD *rgb = pInfo->bmiColors; |
| 302 | bits = (char *)bmi + size + |
| 303 | DIB_GetImageWidthBytes(bih->biWidth,bih->biBitCount)*bih->biHeight; |
| 304 | bih->biBitCount = 1; |
| 305 | bih->biClrUsed = bih->biClrImportant = 2; |
| 306 | rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00; |
| 307 | rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff; |
| 308 | rgb[0].rgbReserved = rgb[1].rgbReserved = 0; |
| 309 | } |
| 310 | else |
| 311 | { |
| 312 | BITMAPCOREHEADER *bch = (BITMAPCOREHEADER *)pInfo; |
| 313 | RGBTRIPLE *rgb = (RGBTRIPLE *)(bch + 1); |
| 314 | bits = (char *)bmi + size + |
| 315 | DIB_GetImageWidthBytes(bch->bcWidth,bch->bcBitCount)*bch->bcHeight; |
| 316 | bch->bcBitCount = 1; |
| 317 | rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00; |
| 318 | rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff; |
| 319 | } |
| 320 | |
| 321 | /* Create the AND bitmap */ |
| 322 | |
| 323 | hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader, CBM_INIT, |
| 324 | bits, pInfo, DIB_RGB_COLORS ); |
| 325 | ReleaseDC( 0, hdc ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 326 | |
| 327 | /* Now create the CURSORICONINFO structure */ |
| 328 | |
| 329 | bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC ); |
| 330 | bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC ); |
| 331 | sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes; |
| 332 | sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes; |
| 333 | |
| 334 | if (!(handle = GlobalAlloc( GMEM_MOVEABLE, |
| 335 | sizeof(CURSORICONINFO) + sizeXor + sizeAnd))) |
| 336 | { |
| 337 | DeleteObject( hXorBits ); |
| 338 | DeleteObject( hAndBits ); |
| 339 | return 0; |
| 340 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 341 | |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 342 | /* Make it owned by the module */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 343 | if (hInstance) FarSetOwner( handle, (WORD)(DWORD)GetExePtr(hInstance) ); |
| 344 | |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 345 | info = (CURSORICONINFO *)GlobalLock( handle ); |
| 346 | info->ptHotSpot.x = hotspot.x; |
| 347 | info->ptHotSpot.y = hotspot.y; |
| 348 | info->nWidth = bmpXor->bitmap.bmWidth; |
| 349 | info->nHeight = bmpXor->bitmap.bmHeight; |
| 350 | info->nWidthBytes = bmpXor->bitmap.bmWidthBytes; |
| 351 | info->bPlanes = bmpXor->bitmap.bmPlanes; |
| 352 | info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel; |
| 353 | |
| 354 | /* Transfer the bitmap bits to the CURSORICONINFO structure */ |
| 355 | |
| 356 | GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) ); |
| 357 | GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd ); |
| 358 | DeleteObject( hXorBits ); |
| 359 | DeleteObject( hAndBits ); |
| 360 | GlobalUnlock( handle ); |
| 361 | return handle; |
| 362 | } |
| 363 | |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 364 | /********************************************************************** |
| 365 | * CURSORICON_Load |
| 366 | * |
| 367 | * Load a cursor or icon. |
| 368 | */ |
| 369 | static HANDLE CURSORICON_Load( HANDLE hInstance, SEGPTR name, int width, |
| 370 | int height, int colors, BOOL fCursor ) |
| 371 | { |
| 372 | HANDLE handle,hRet; |
| 373 | HRSRC hRsrc; |
| 374 | CURSORICONDIRENTRY dirEntry; |
| 375 | |
| 376 | if (!hInstance) /* OEM cursor/icon */ |
| 377 | { |
| 378 | if (HIWORD(name)) /* Check for '#xxx' name */ |
| 379 | { |
| 380 | char *ptr = PTR_SEG_TO_LIN( name ); |
| 381 | if (ptr[0] != '#') return 0; |
| 382 | if (!(name = (SEGPTR)atoi( ptr + 1 ))) return 0; |
| 383 | } |
| 384 | return OBM_LoadCursorIcon( LOWORD(name), fCursor ); |
| 385 | } |
| 386 | |
| 387 | /* Find the best entry in the directory */ |
| 388 | |
| 389 | if (!CURSORICON_LoadDirEntry( hInstance, name, width, height, |
| 390 | colors, fCursor, &dirEntry )) return 0; |
| 391 | |
| 392 | /* Load the resource */ |
| 393 | |
| 394 | if (!(hRsrc = FindResource( hInstance, |
| 395 | MAKEINTRESOURCE( dirEntry.icon.wResId ), |
| 396 | fCursor ? RT_CURSOR : RT_ICON ))) return 0; |
| 397 | if (!(handle = LoadResource( hInstance, hRsrc ))) return 0; |
| 398 | |
| 399 | hRet = CURSORICON_LoadHandler( handle, hInstance, fCursor ); |
| 400 | FreeResource(handle); |
| 401 | return hRet; |
| 402 | } |
| 403 | |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 404 | |
| 405 | /*********************************************************************** |
| 406 | * CURSORICON_Copy |
| 407 | * |
| 408 | * Make a copy of a cursor or icon. |
| 409 | */ |
| 410 | static HANDLE CURSORICON_Copy( HANDLE hInstance, HANDLE handle ) |
| 411 | { |
| 412 | char *ptrOld, *ptrNew; |
| 413 | int size; |
| 414 | HANDLE hNew; |
| 415 | |
| 416 | if (!(ptrOld = (char *)GlobalLock( handle ))) return 0; |
| 417 | if (!(hInstance = GetExePtr( hInstance ))) return 0; |
| 418 | size = GlobalSize( handle ); |
| 419 | hNew = GlobalAlloc( GMEM_MOVEABLE, size ); |
Alexandre Julliard | d7d4fdf | 1995-12-26 15:05:24 +0000 | [diff] [blame] | 420 | FarSetOwner( hNew, (WORD)(DWORD)hInstance ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 421 | ptrNew = (char *)GlobalLock( hNew ); |
| 422 | memcpy( ptrNew, ptrOld, size ); |
| 423 | GlobalUnlock( handle ); |
| 424 | GlobalUnlock( hNew ); |
| 425 | return hNew; |
| 426 | } |
| 427 | |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 428 | /*********************************************************************** |
| 429 | * CURSORICON_IconToCursor |
| 430 | * |
| 431 | * Should convert bitmap to mono and truncate if too large |
| 432 | * FIXME: if icon is passed returns a copy of OCR_DRAGOBJECT cursor |
| 433 | * but should actually convert icon to cursor. |
| 434 | */ |
| 435 | HCURSOR CURSORICON_IconToCursor(HICON hIcon) |
| 436 | { |
| 437 | CURSORICONINFO *ptr = NULL; |
| 438 | |
| 439 | if(hIcon) |
| 440 | if (!(ptr = (CURSORICONINFO*)GlobalLock( hIcon ))) return FALSE; |
| 441 | if (ptr->bPlanes * ptr->bBitsPerPixel == 1) |
| 442 | { |
| 443 | return hIcon; /* assuming it's a cursor */ |
| 444 | } |
| 445 | else |
| 446 | { |
| 447 | /* kludge */ |
| 448 | |
| 449 | HTASK hTask = GetCurrentTask(); |
| 450 | TDB* pTask = (TDB *)GlobalLock(hTask); |
| 451 | |
| 452 | if(!pTask) return 0; |
| 453 | |
| 454 | fprintf( stdnimp, "IconToCursor: Icons are not supported, returning default!\n"); |
| 455 | return CURSORICON_Copy( pTask->hInstance , |
| 456 | CURSORICON_Load(0,MAKEINTRESOURCE(OCR_DRAGOBJECT), |
| 457 | SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE) ); |
| 458 | } |
| 459 | |
| 460 | return 0; |
| 461 | } |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 462 | |
| 463 | /*********************************************************************** |
| 464 | * LoadCursor (USER.173) |
| 465 | */ |
| 466 | HCURSOR LoadCursor( HANDLE hInstance, SEGPTR name ) |
| 467 | { |
| 468 | if (HIWORD(name)) |
| 469 | dprintf_cursor( stddeb, "LoadCursor: "NPFMT" '%s'\n", |
| 470 | hInstance, (char *)PTR_SEG_TO_LIN( name ) ); |
| 471 | else |
| 472 | dprintf_cursor( stddeb, "LoadCursor: "NPFMT" %04x\n", |
| 473 | hInstance, LOWORD(name) ); |
| 474 | |
| 475 | return CURSORICON_Load( hInstance, name, |
| 476 | SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE); |
| 477 | } |
| 478 | |
| 479 | |
| 480 | /*********************************************************************** |
| 481 | * LoadIcon (USER.174) |
| 482 | */ |
| 483 | HICON LoadIcon( HANDLE hInstance, SEGPTR name ) |
| 484 | { |
| 485 | if (HIWORD(name)) |
| 486 | dprintf_icon( stddeb, "LoadIcon: "NPFMT" '%s'\n", |
| 487 | hInstance, (char *)PTR_SEG_TO_LIN( name ) ); |
| 488 | else |
| 489 | dprintf_icon( stddeb, "LoadIcon: "NPFMT" %04x\n", |
| 490 | hInstance, LOWORD(name) ); |
| 491 | |
| 492 | return CURSORICON_Load( hInstance, name, |
| 493 | SYSMETRICS_CXICON, SYSMETRICS_CYICON, |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 494 | MIN( 16, 1 << screenDepth ), FALSE ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 495 | } |
| 496 | |
| 497 | |
| 498 | /*********************************************************************** |
| 499 | * CreateCursor (USER.406) |
| 500 | */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 501 | HCURSOR CreateCursor( HINSTANCE hInstance, INT xHotSpot, INT yHotSpot, |
| 502 | INT nWidth, INT nHeight, LPVOID lpANDbits, LPVOID lpXORbits) |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 503 | { |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 504 | CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 }; |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 505 | |
| 506 | dprintf_cursor( stddeb, "CreateCursor: %dx%d spot=%d,%d xor=%p and=%p\n", |
| 507 | nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits); |
| 508 | return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits ); |
| 509 | } |
| 510 | |
| 511 | |
| 512 | /*********************************************************************** |
| 513 | * CreateIcon (USER.407) |
| 514 | */ |
| 515 | HICON CreateIcon( HANDLE hInstance, INT nWidth, INT nHeight, BYTE bPlanes, |
| 516 | BYTE bBitsPixel, LPSTR lpANDbits, LPSTR lpXORbits) |
| 517 | { |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 518 | CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel }; |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 519 | |
| 520 | dprintf_icon( stddeb, "CreateIcon: %dx%dx%d, xor=%p, and=%p\n", |
| 521 | nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits); |
| 522 | return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits ); |
| 523 | } |
| 524 | |
| 525 | |
| 526 | /*********************************************************************** |
| 527 | * CreateCursorIconIndirect (USER.408) |
| 528 | */ |
| 529 | HANDLE CreateCursorIconIndirect( HANDLE hInstance, CURSORICONINFO *info, |
| 530 | LPSTR lpANDbits, LPSTR lpXORbits ) |
| 531 | { |
| 532 | HANDLE handle; |
| 533 | char *ptr; |
| 534 | int sizeAnd, sizeXor; |
| 535 | |
| 536 | hInstance = GetExePtr( hInstance ); /* Make it a module handle */ |
| 537 | if (!hInstance || !lpXORbits || !lpANDbits || info->bPlanes != 1) return 0; |
| 538 | info->nWidthBytes = (info->nWidth * info->bBitsPerPixel + 15) / 16 * 2; |
| 539 | sizeXor = info->nHeight * info->nWidthBytes; |
| 540 | sizeAnd = info->nHeight * ((info->nWidth + 15) / 16 * 2); |
| 541 | if (!(handle = DirectResAlloc(hInstance, 0x10, |
| 542 | sizeof(CURSORICONINFO) + sizeXor + sizeAnd))) |
| 543 | return 0; |
| 544 | ptr = (char *)GlobalLock( handle ); |
| 545 | memcpy( ptr, info, sizeof(*info) ); |
| 546 | memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd ); |
| 547 | memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor ); |
| 548 | GlobalUnlock( handle ); |
| 549 | return handle; |
| 550 | } |
| 551 | |
| 552 | |
| 553 | /*********************************************************************** |
| 554 | * CopyIcon (USER.368) |
| 555 | */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 556 | #ifdef WINELIB32 |
| 557 | HICON CopyIcon( HICON hIcon ) |
| 558 | { |
| 559 | dprintf_icon( stddeb, "CopyIcon: "NPFMT"\n", hIcon ); |
| 560 | return CURSORICON_Copy( 0, hIcon ); |
| 561 | } |
| 562 | #else |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 563 | HICON CopyIcon( HANDLE hInstance, HICON hIcon ) |
| 564 | { |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 565 | dprintf_icon( stddeb, "CopyIcon: "NPFMT" "NPFMT"\n", hInstance, hIcon ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 566 | return CURSORICON_Copy( hInstance, hIcon ); |
| 567 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 568 | #endif |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 569 | |
| 570 | |
| 571 | /*********************************************************************** |
| 572 | * CopyCursor (USER.369) |
| 573 | */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 574 | #ifdef WINELIB32 |
| 575 | HCURSOR CopyCursor( HCURSOR hCursor ) |
| 576 | { |
| 577 | dprintf_cursor( stddeb, "CopyCursor: "NPFMT"\n", hCursor ); |
| 578 | return CURSORICON_Copy( 0, hCursor ); |
| 579 | } |
| 580 | #else |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 581 | HCURSOR CopyCursor( HANDLE hInstance, HCURSOR hCursor ) |
| 582 | { |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 583 | dprintf_cursor( stddeb, "CopyCursor: "NPFMT" "NPFMT"\n", hInstance, hCursor ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 584 | return CURSORICON_Copy( hInstance, hCursor ); |
| 585 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 586 | #endif |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 587 | |
| 588 | |
| 589 | /*********************************************************************** |
| 590 | * DestroyIcon (USER.457) |
| 591 | */ |
| 592 | BOOL DestroyIcon( HICON hIcon ) |
| 593 | { |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 594 | dprintf_icon( stddeb, "DestroyIcon: "NPFMT"\n", hIcon ); |
| 595 | /* FIXME: should check for OEM icon here */ |
| 596 | return (GlobalFree( hIcon ) != 0); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 597 | } |
| 598 | |
| 599 | |
| 600 | /*********************************************************************** |
| 601 | * DestroyCursor (USER.458) |
| 602 | */ |
| 603 | BOOL DestroyCursor( HCURSOR hCursor ) |
| 604 | { |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 605 | dprintf_cursor( stddeb, "DestroyCursor: "NPFMT"\n", hCursor ); |
| 606 | /* FIXME: should check for OEM cursor here */ |
| 607 | return (GlobalFree( hCursor ) != 0); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 608 | } |
| 609 | |
| 610 | |
| 611 | /*********************************************************************** |
| 612 | * DrawIcon (USER.84) |
| 613 | */ |
| 614 | BOOL DrawIcon( HDC hdc, short x, short y, HICON hIcon ) |
| 615 | { |
| 616 | CURSORICONINFO *ptr; |
| 617 | HDC hMemDC; |
| 618 | HBITMAP hXorBits, hAndBits; |
| 619 | COLORREF oldFg, oldBg; |
| 620 | |
| 621 | if (!(ptr = (CURSORICONINFO *)GlobalLock( hIcon ))) return FALSE; |
| 622 | if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE; |
| 623 | hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1, (char *)(ptr+1)); |
| 624 | hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes, |
| 625 | ptr->bBitsPerPixel, (char *)(ptr + 1) |
| 626 | + ptr->nHeight * ((ptr->nWidth + 15) / 16 * 2) ); |
| 627 | oldFg = SetTextColor( hdc, RGB(0,0,0) ); |
| 628 | oldBg = SetBkColor( hdc, RGB(255,255,255) ); |
| 629 | |
| 630 | if (hXorBits && hAndBits) |
| 631 | { |
| 632 | HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits ); |
| 633 | BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND ); |
| 634 | SelectObject( hMemDC, hXorBits ); |
| 635 | BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCINVERT); |
| 636 | SelectObject( hMemDC, hBitTemp ); |
| 637 | } |
| 638 | DeleteDC( hMemDC ); |
| 639 | if (hXorBits) DeleteObject( hXorBits ); |
| 640 | if (hAndBits) DeleteObject( hAndBits ); |
| 641 | GlobalUnlock( hIcon ); |
| 642 | SetTextColor( hdc, oldFg ); |
| 643 | SetBkColor( hdc, oldBg ); |
| 644 | return TRUE; |
| 645 | } |
| 646 | |
| 647 | |
| 648 | /*********************************************************************** |
| 649 | * DumpIcon (USER.459) |
| 650 | */ |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 651 | DWORD DumpIcon( SEGPTR pInfo, WORD *lpLen, |
| 652 | SEGPTR *lpXorBits, SEGPTR *lpAndBits ) |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 653 | { |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 654 | CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 655 | int sizeAnd, sizeXor; |
| 656 | |
| 657 | if (!info) return 0; |
| 658 | sizeXor = info->nHeight * info->nWidthBytes; |
| 659 | sizeAnd = info->nHeight * ((info->nWidth + 15) / 16 * 2); |
Alexandre Julliard | ade697e | 1995-11-26 13:59:11 +0000 | [diff] [blame] | 660 | if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO); |
| 661 | if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd; |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 662 | if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor; |
| 663 | return MAKELONG( sizeXor, sizeXor ); |
| 664 | } |
| 665 | |
| 666 | |
| 667 | /*********************************************************************** |
| 668 | * CURSORICON_SetCursor |
| 669 | * |
| 670 | * Change the X cursor. Helper function for SetCursor() and ShowCursor(). |
| 671 | */ |
| 672 | static BOOL CURSORICON_SetCursor( HCURSOR hCursor ) |
| 673 | { |
| 674 | Pixmap pixmapBits, pixmapMask, pixmapAll; |
| 675 | XColor fg, bg; |
| 676 | Cursor cursor = None; |
| 677 | |
| 678 | if (!hCursor) /* Create an empty cursor */ |
| 679 | { |
| 680 | static const char data[] = { 0 }; |
| 681 | |
| 682 | bg.red = bg.green = bg.blue = 0x0000; |
| 683 | pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 ); |
| 684 | if (pixmapBits) |
| 685 | { |
| 686 | cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits, |
| 687 | &bg, &bg, 0, 0 ); |
| 688 | XFreePixmap( display, pixmapBits ); |
| 689 | } |
| 690 | } |
| 691 | else /* Create the X cursor from the bits */ |
| 692 | { |
| 693 | CURSORICONINFO *ptr; |
| 694 | XImage *image; |
| 695 | |
| 696 | if (!(ptr = (CURSORICONINFO*)GlobalLock( hCursor ))) return FALSE; |
| 697 | if (ptr->bPlanes * ptr->bBitsPerPixel != 1) |
| 698 | { |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 699 | fprintf( stderr, "Cursor "NPFMT" has more than 1 bpp!\n", hCursor ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 700 | return FALSE; |
| 701 | } |
| 702 | |
| 703 | /* Create a pixmap and transfer all the bits to it */ |
| 704 | |
| 705 | pixmapAll = XCreatePixmap( display, rootWindow, |
| 706 | ptr->nWidth, ptr->nHeight * 2, 1 ); |
| 707 | image = XCreateImage( display, DefaultVisualOfScreen(screen), |
| 708 | 1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth, |
| 709 | ptr->nHeight * 2, 16, ptr->nWidthBytes); |
| 710 | if (image) |
| 711 | { |
| 712 | extern void _XInitImageFuncPtrs( XImage* ); |
| 713 | image->byte_order = MSBFirst; |
| 714 | image->bitmap_bit_order = MSBFirst; |
| 715 | image->bitmap_unit = 16; |
| 716 | _XInitImageFuncPtrs(image); |
| 717 | if (pixmapAll) |
| 718 | CallTo32_LargeStack( XPutImage, 10, |
| 719 | display, pixmapAll, BITMAP_monoGC, image, |
| 720 | 0, 0, 0, 0, ptr->nWidth, ptr->nHeight*2 ); |
| 721 | image->data = NULL; |
| 722 | XDestroyImage( image ); |
| 723 | } |
| 724 | |
| 725 | /* Now create the 2 pixmaps for bits and mask */ |
| 726 | |
| 727 | pixmapBits = XCreatePixmap( display, rootWindow, |
| 728 | ptr->nWidth, ptr->nHeight, 1 ); |
| 729 | pixmapMask = XCreatePixmap( display, rootWindow, |
| 730 | ptr->nWidth, ptr->nHeight, 1 ); |
| 731 | |
| 732 | /* Make sure everything went OK so far */ |
| 733 | |
| 734 | if (pixmapBits && pixmapMask && pixmapAll) |
| 735 | { |
| 736 | /* We have to do some magic here, as cursors are not fully |
| 737 | * compatible between Windows and X11. Under X11, there |
| 738 | * are only 3 possible color cursor: black, white and |
| 739 | * masked. So we map the 4th Windows color (invert the |
| 740 | * bits on the screen) to black. This require some boolean |
| 741 | * arithmetic: |
| 742 | * |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 743 | * Windows | X11 |
| 744 | * Xor And Result | Bits Mask Result |
| 745 | * 0 0 black | 0 1 background |
| 746 | * 0 1 no change | X 0 no change |
| 747 | * 1 0 white | 1 1 foreground |
| 748 | * 1 1 inverted | 0 1 background |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 749 | * |
| 750 | * which gives: |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 751 | * Bits = 'Xor' and not 'And' |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 752 | * Mask = 'Xor' or not 'And' |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 753 | * |
| 754 | * FIXME: apparently some servers do support 'inverted' color. |
| 755 | * I don't know if it's correct per the X spec, but maybe |
| 756 | * we ought to take advantage of it. -- AJ |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 757 | */ |
| 758 | XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC, |
| 759 | 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 ); |
| 760 | XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC, |
| 761 | 0, 0, ptr->nWidth, ptr->nHeight, 0, 0 ); |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 762 | XSetFunction( display, BITMAP_monoGC, GXandReverse ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 763 | XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC, |
| 764 | 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 ); |
| 765 | XSetFunction( display, BITMAP_monoGC, GXorReverse ); |
| 766 | XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC, |
| 767 | 0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 ); |
| 768 | XSetFunction( display, BITMAP_monoGC, GXcopy ); |
| 769 | fg.red = fg.green = fg.blue = 0xffff; |
| 770 | bg.red = bg.green = bg.blue = 0x0000; |
| 771 | cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask, |
| 772 | &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y ); |
| 773 | } |
| 774 | |
| 775 | /* Now free everything */ |
| 776 | |
| 777 | if (pixmapAll) XFreePixmap( display, pixmapAll ); |
| 778 | if (pixmapBits) XFreePixmap( display, pixmapBits ); |
| 779 | if (pixmapMask) XFreePixmap( display, pixmapMask ); |
| 780 | GlobalUnlock( hCursor ); |
| 781 | } |
| 782 | |
| 783 | if (cursor == None) return FALSE; |
| 784 | if (CURSORICON_XCursor != None) XFreeCursor( display, CURSORICON_XCursor ); |
| 785 | CURSORICON_XCursor = cursor; |
| 786 | |
| 787 | if (rootWindow != DefaultRootWindow(display)) |
| 788 | { |
| 789 | /* Set the cursor on the desktop window */ |
| 790 | XDefineCursor( display, rootWindow, cursor ); |
| 791 | } |
| 792 | else |
| 793 | { |
| 794 | /* Set the same cursor for all top-level windows */ |
| 795 | HWND hwnd = GetWindow( GetDesktopWindow(), GW_CHILD ); |
| 796 | while(hwnd) |
| 797 | { |
| 798 | Window win = WIN_GetXWindow( hwnd ); |
| 799 | if (win) XDefineCursor( display, win, cursor ); |
| 800 | hwnd = GetWindow( hwnd, GW_HWNDNEXT ); |
| 801 | } |
| 802 | } |
| 803 | return TRUE; |
| 804 | } |
| 805 | |
| 806 | |
| 807 | /*********************************************************************** |
| 808 | * SetCursor (USER.69) |
| 809 | */ |
| 810 | HCURSOR SetCursor( HCURSOR hCursor ) |
| 811 | { |
| 812 | HCURSOR hOldCursor; |
| 813 | |
| 814 | if (hCursor == hActiveCursor) return hActiveCursor; /* No change */ |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 815 | dprintf_cursor( stddeb, "SetCursor: "NPFMT"\n", hCursor ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 816 | hOldCursor = hActiveCursor; |
| 817 | hActiveCursor = hCursor; |
| 818 | /* Change the cursor shape only if it is visible */ |
| 819 | if (CURSOR_ShowCount >= 0) CURSORICON_SetCursor( hActiveCursor ); |
| 820 | return hOldCursor; |
| 821 | } |
| 822 | |
| 823 | |
| 824 | /*********************************************************************** |
| 825 | * SetCursorPos (USER.70) |
| 826 | */ |
| 827 | void SetCursorPos( short x, short y ) |
| 828 | { |
| 829 | dprintf_cursor( stddeb, "SetCursorPos: x=%d y=%d\n", x, y ); |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 830 | XWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, x, y ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 831 | } |
| 832 | |
| 833 | |
| 834 | /*********************************************************************** |
| 835 | * ShowCursor (USER.71) |
| 836 | */ |
| 837 | int ShowCursor( BOOL bShow ) |
| 838 | { |
| 839 | dprintf_cursor( stddeb, "ShowCursor: %d, count=%d\n", |
| 840 | bShow, CURSOR_ShowCount ); |
| 841 | |
| 842 | if (bShow) |
| 843 | { |
| 844 | if (++CURSOR_ShowCount == 0) |
| 845 | CURSORICON_SetCursor( hActiveCursor ); /* Show it */ |
| 846 | } |
| 847 | else |
| 848 | { |
| 849 | if (--CURSOR_ShowCount == -1) |
| 850 | CURSORICON_SetCursor( 0 ); /* Hide it */ |
| 851 | } |
| 852 | return CURSOR_ShowCount; |
| 853 | } |
| 854 | |
| 855 | |
| 856 | /*********************************************************************** |
| 857 | * GetCursor (USER.247) |
| 858 | */ |
| 859 | HCURSOR GetCursor(void) |
| 860 | { |
| 861 | return hActiveCursor; |
| 862 | } |
| 863 | |
| 864 | |
| 865 | /*********************************************************************** |
| 866 | * ClipCursor (USER.16) |
| 867 | */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 868 | BOOL ClipCursor( RECT *rect ) |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 869 | { |
| 870 | if (!rect) SetRectEmpty( &CURSOR_ClipRect ); |
| 871 | else CopyRect( &CURSOR_ClipRect, rect ); |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 872 | return TRUE; |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 873 | } |
| 874 | |
| 875 | |
| 876 | /*********************************************************************** |
| 877 | * GetCursorPos (USER.17) |
| 878 | */ |
| 879 | void GetCursorPos( POINT *pt ) |
| 880 | { |
| 881 | Window root, child; |
| 882 | int rootX, rootY, childX, childY; |
| 883 | unsigned int mousebut; |
| 884 | |
| 885 | if (!pt) return; |
| 886 | if (!XQueryPointer( display, rootWindow, &root, &child, |
| 887 | &rootX, &rootY, &childX, &childY, &mousebut )) |
| 888 | pt->x = pt->y = 0; |
| 889 | else |
| 890 | { |
| 891 | pt->x = rootX + desktopX; |
| 892 | pt->y = rootY + desktopY; |
| 893 | } |
Alexandre Julliard | 902da69 | 1995-11-05 14:39:02 +0000 | [diff] [blame] | 894 | dprintf_cursor(stddeb, "GetCursorPos: ret=%ld,%ld\n", (LONG)pt->x, |
| 895 | (LONG)pt->y ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 896 | } |
| 897 | |
| 898 | |
| 899 | /*********************************************************************** |
| 900 | * GetClipCursor (USER.309) |
| 901 | */ |
| 902 | void GetClipCursor( RECT *rect ) |
| 903 | { |
| 904 | if (rect) CopyRect( rect, &CURSOR_ClipRect ); |
| 905 | } |
| 906 | |
| 907 | |
| 908 | /********************************************************************** |
| 909 | * GetIconID (USER.455) |
| 910 | */ |
| 911 | WORD GetIconID( HANDLE hResource, DWORD resType ) |
| 912 | { |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 913 | CURSORICONDIR *lpDir = LockResource(hResource); |
| 914 | |
| 915 | if (!lpDir || lpDir->idReserved || |
| 916 | ((lpDir->idType != 1) && (lpDir->idType != 2))) |
| 917 | { |
| 918 | dprintf_cursor(stddeb,"GetIconID: invalid resource directory\n"); |
| 919 | return 0; |
| 920 | } |
| 921 | |
| 922 | dprintf_cursor( stddeb, "GetIconID: hRes="NPFMT", entries=%i\n", |
| 923 | hResource, lpDir->idCount ); |
| 924 | |
| 925 | switch(resType) |
| 926 | { |
| 927 | case 1: /* cursor */ |
| 928 | { |
| 929 | CURSORDIRENTRY *entry = CURSORICON_FindBestCursor( lpDir, |
| 930 | SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR ); |
| 931 | return entry ? entry->wResId : 0; |
| 932 | } |
| 933 | case 3: /* icon */ |
| 934 | { |
| 935 | ICONDIRENTRY *entry = CURSORICON_FindBestIcon( lpDir, |
| 936 | SYSMETRICS_CXICON, SYSMETRICS_CYICON, |
| 937 | MIN( 16, 1 << screenDepth ) ); |
| 938 | return entry ? entry->wResId : 0; |
| 939 | } |
| 940 | } |
| 941 | fprintf( stderr, "GetIconID: invalid res type %ld\n", resType ); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 942 | return 0; |
| 943 | } |
| 944 | |
| 945 | |
| 946 | /********************************************************************** |
| 947 | * LoadIconHandler (USER.456) |
| 948 | */ |
| 949 | HICON LoadIconHandler( HANDLE hResource, BOOL bNew ) |
| 950 | { |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame^] | 951 | dprintf_cursor(stddeb,"LoadIconHandler: hRes="NPFMT"\n",hResource); |
| 952 | |
| 953 | if( !bNew ) |
| 954 | { |
| 955 | fprintf(stdnimp,"LoadIconHandler: 2.xx resources are not supported\n"); |
| 956 | return 0; |
| 957 | } |
| 958 | return CURSORICON_LoadHandler( hResource, 0, FALSE); |
Alexandre Julliard | af0bae5 | 1995-10-03 17:06:08 +0000 | [diff] [blame] | 959 | } |