comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / win32u / gdiobj.c
blobf8a1bd96f8f1d386b01956ee626d54f9bc0bcf65
1 /*
2 * GDI functions
4 * Copyright 1993 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <pthread.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winreg.h"
35 #include "winnls.h"
36 #include "winerror.h"
37 #include "winternl.h"
39 #include "ntgdi_private.h"
40 #include "wine/debug.h"
41 #include "wine/unixlib.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
45 #define FIRST_GDI_HANDLE 32
47 static GDI_SHARED_MEMORY *gdi_shared;
48 static GDI_HANDLE_ENTRY *next_free;
49 static GDI_HANDLE_ENTRY *next_unused;
50 static LONG debug_count;
51 SYSTEM_BASIC_INFORMATION system_info;
53 static inline HGDIOBJ entry_to_handle( GDI_HANDLE_ENTRY *entry )
55 unsigned int idx = entry - gdi_shared->Handles;
56 return ULongToHandle( idx | (entry->Unique << NTGDI_HANDLE_TYPE_SHIFT) );
59 static inline GDI_HANDLE_ENTRY *handle_entry( HGDIOBJ handle )
61 unsigned int idx = LOWORD(handle);
63 if (idx < GDI_MAX_HANDLE_COUNT && gdi_shared->Handles[idx].Type)
65 if (!HIWORD( handle ) || HIWORD( handle ) == gdi_shared->Handles[idx].Unique)
66 return &gdi_shared->Handles[idx];
68 if (handle) WARN( "invalid handle %p\n", handle );
69 return NULL;
72 static inline struct gdi_obj_header *entry_obj( GDI_HANDLE_ENTRY *entry )
74 return (struct gdi_obj_header *)(ULONG_PTR)entry->Object;
77 /***********************************************************************
78 * GDI stock objects
81 static const LOGBRUSH WhiteBrush = { BS_SOLID, RGB(255,255,255), 0 };
82 static const LOGBRUSH BlackBrush = { BS_SOLID, RGB(0,0,0), 0 };
83 static const LOGBRUSH NullBrush = { BS_NULL, 0, 0 };
85 static const LOGBRUSH LtGrayBrush = { BS_SOLID, RGB(192,192,192), 0 };
86 static const LOGBRUSH GrayBrush = { BS_SOLID, RGB(128,128,128), 0 };
87 static const LOGBRUSH DkGrayBrush = { BS_SOLID, RGB(64,64,64), 0 };
89 static const LOGBRUSH DCBrush = { BS_SOLID, RGB(255,255,255), 0 };
91 static pthread_mutex_t gdi_lock;
94 /****************************************************************************
96 * language-independent stock fonts
100 static const LOGFONTW OEMFixedFont =
101 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
102 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN };
104 static const LOGFONTW AnsiFixedFont =
105 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
106 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
107 {'C','o','u','r','i','e','r'} };
109 static const LOGFONTW AnsiVarFont =
110 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
111 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
112 {'M','S',' ','S','a','n','s',' ','S','e','r','i','f'} };
114 /******************************************************************************
116 * language-dependent stock fonts
118 * 'ANSI' charset and 'DEFAULT' charset is not same.
119 * The chars in CP_ACP should be drawn with 'DEFAULT' charset.
120 * 'ANSI' charset seems to be identical with ISO-8859-1.
121 * 'DEFAULT' charset is a language-dependent charset.
123 * 'System' font seems to be an alias for language-dependent font.
127 * language-dependent stock fonts for all known charsets
128 * please see TranslateCharsetInfo (dlls/gdi/font.c) and
129 * CharsetBindingInfo (dlls/x11drv/xfont.c),
130 * and modify entries for your language if needed.
132 struct DefaultFontInfo
134 UINT charset;
135 LOGFONTW SystemFont;
136 LOGFONTW DeviceDefaultFont;
137 LOGFONTW SystemFixedFont;
138 LOGFONTW DefaultGuiFont;
141 static const struct DefaultFontInfo default_fonts[] =
143 { ANSI_CHARSET,
144 { /* System */
145 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
146 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
147 {'S','y','s','t','e','m'}
149 { /* Device Default */
150 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
151 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
152 {'S','y','s','t','e','m'}
154 { /* System Fixed */
155 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
156 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
157 {'C','o','u','r','i','e','r'}
159 { /* DefaultGuiFont */
160 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
161 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
162 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
165 { EASTEUROPE_CHARSET,
166 { /* System */
167 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
168 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
169 {'S','y','s','t','e','m'}
171 { /* Device Default */
172 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
173 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
174 {'S','y','s','t','e','m'}
176 { /* System Fixed */
177 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
178 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
179 {'C','o','u','r','i','e','r'}
181 { /* DefaultGuiFont */
182 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
183 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
184 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
187 { RUSSIAN_CHARSET,
188 { /* System */
189 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
190 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
191 {'S','y','s','t','e','m'}
193 { /* Device Default */
194 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
195 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
196 {'S','y','s','t','e','m'}
198 { /* System Fixed */
199 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
200 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
201 {'C','o','u','r','i','e','r'}
203 { /* DefaultGuiFont */
204 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
205 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
206 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
209 { GREEK_CHARSET,
210 { /* System */
211 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, GREEK_CHARSET,
212 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
213 {'S','y','s','t','e','m'}
215 { /* Device Default */
216 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, GREEK_CHARSET,
217 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
218 {'S','y','s','t','e','m'}
220 { /* System Fixed */
221 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
222 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
223 {'C','o','u','r','i','e','r'}
225 { /* DefaultGuiFont */
226 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
227 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
228 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
231 { TURKISH_CHARSET,
232 { /* System */
233 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, TURKISH_CHARSET,
234 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
235 {'S','y','s','t','e','m'}
237 { /* Device Default */
238 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, TURKISH_CHARSET,
239 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
240 {'S','y','s','t','e','m'}
242 { /* System Fixed */
243 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
244 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
245 {'C','o','u','r','i','e','r'}
247 { /* DefaultGuiFont */
248 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
249 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
250 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
253 { HEBREW_CHARSET,
254 { /* System */
255 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, HEBREW_CHARSET,
256 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
257 {'S','y','s','t','e','m'}
259 { /* Device Default */
260 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, HEBREW_CHARSET,
261 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
262 {'S','y','s','t','e','m'}
264 { /* System Fixed */
265 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
266 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
267 {'C','o','u','r','i','e','r'}
269 { /* DefaultGuiFont */
270 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
271 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
272 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
275 { ARABIC_CHARSET,
276 { /* System */
277 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ARABIC_CHARSET,
278 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
279 {'S','y','s','t','e','m'}
281 { /* Device Default */
282 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ARABIC_CHARSET,
283 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
284 {'S','y','s','t','e','m'}
286 { /* System Fixed */
287 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
288 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
289 {'C','o','u','r','i','e','r'}
291 { /* DefaultGuiFont */
292 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
293 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
294 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
297 { BALTIC_CHARSET,
298 { /* System */
299 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, BALTIC_CHARSET,
300 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
301 {'S','y','s','t','e','m'}
303 { /* Device Default */
304 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, BALTIC_CHARSET,
305 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
306 {'S','y','s','t','e','m'}
308 { /* System Fixed */
309 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
310 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
311 {'C','o','u','r','i','e','r'}
313 { /* DefaultGuiFont */
314 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
315 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
316 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
319 { THAI_CHARSET,
320 { /* System */
321 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, THAI_CHARSET,
322 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
323 {'S','y','s','t','e','m'}
325 { /* Device Default */
326 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, THAI_CHARSET,
327 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
328 {'S','y','s','t','e','m'}
330 { /* System Fixed */
331 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
332 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
333 {'C','o','u','r','i','e','r'}
335 { /* DefaultGuiFont */
336 -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
337 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
338 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
341 { SHIFTJIS_CHARSET,
342 { /* System */
343 18, 8, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
344 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
345 {'S','y','s','t','e','m'}
347 { /* Device Default */
348 18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
349 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
350 {'S','y','s','t','e','m'}
352 { /* System Fixed */
353 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
354 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
355 {'C','o','u','r','i','e','r'}
357 { /* DefaultGuiFont */
358 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
359 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
360 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
363 { GB2312_CHARSET,
364 { /* System */
365 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, GB2312_CHARSET,
366 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
367 {'S','y','s','t','e','m'}
369 { /* Device Default */
370 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, GB2312_CHARSET,
371 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
372 {'S','y','s','t','e','m'}
374 { /* System Fixed */
375 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
376 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
377 {'C','o','u','r','i','e','r'}
379 { /* DefaultGuiFont */
380 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
381 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
382 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
385 { HANGEUL_CHARSET,
386 { /* System */
387 16, 8, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
388 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
389 {'S','y','s','t','e','m'}
391 { /* Device Default */
392 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
393 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
394 {'S','y','s','t','e','m'}
396 { /* System Fixed */
397 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
398 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
399 {'C','o','u','r','i','e','r'}
401 { /* DefaultGuiFont */
402 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
403 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
404 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
407 { CHINESEBIG5_CHARSET,
408 { /* System */
409 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
410 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
411 {'S','y','s','t','e','m'}
413 { /* Device Default */
414 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
415 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
416 {'S','y','s','t','e','m'}
418 { /* System Fixed */
419 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
420 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
421 {'C','o','u','r','i','e','r'}
423 { /* DefaultGuiFont */
424 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
425 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
426 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
429 { JOHAB_CHARSET,
430 { /* System */
431 16, 7, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, JOHAB_CHARSET,
432 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
433 {'S','y','s','t','e','m'}
435 { /* Device Default */
436 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, JOHAB_CHARSET,
437 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
438 {'S','y','s','t','e','m'}
440 { /* System Fixed */
441 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
442 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
443 {'C','o','u','r','i','e','r'}
445 { /* DefaultGuiFont */
446 -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
447 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
448 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
453 void make_gdi_object_system( HGDIOBJ handle, BOOL set)
455 GDI_HANDLE_ENTRY *entry;
457 pthread_mutex_lock( &gdi_lock );
458 if ((entry = handle_entry( handle ))) entry_obj( entry )->system = !!set;
459 pthread_mutex_unlock( &gdi_lock );
462 /******************************************************************************
463 * get_default_fonts
465 static const struct DefaultFontInfo* get_default_fonts(void)
467 unsigned int n;
468 CHARSETINFO csi;
470 if (ansi_cp.CodePage == CP_UTF8) return &default_fonts[0];
472 csi.ciCharset = ANSI_CHARSET;
473 translate_charset_info( ULongToPtr(ansi_cp.CodePage), &csi, TCI_SRCCODEPAGE );
475 for(n = 0; n < ARRAY_SIZE( default_fonts ); n++)
476 if ( default_fonts[n].charset == csi.ciCharset )
477 return &default_fonts[n];
479 FIXME( "unhandled charset 0x%08x - use ANSI_CHARSET for default stock objects\n", csi.ciCharset );
480 return &default_fonts[0];
484 /***********************************************************************
485 * GDI_get_ref_count
487 * Retrieve the reference count of a GDI object.
488 * Note: the object must be locked otherwise the count is meaningless.
490 UINT GDI_get_ref_count( HGDIOBJ handle )
492 GDI_HANDLE_ENTRY *entry;
493 UINT ret = 0;
495 pthread_mutex_lock( &gdi_lock );
496 if ((entry = handle_entry( handle ))) ret = entry_obj( entry )->selcount;
497 pthread_mutex_unlock( &gdi_lock );
498 return ret;
502 /***********************************************************************
503 * GDI_inc_ref_count
505 * Increment the reference count of a GDI object.
507 HGDIOBJ GDI_inc_ref_count( HGDIOBJ handle )
509 GDI_HANDLE_ENTRY *entry;
511 pthread_mutex_lock( &gdi_lock );
512 if ((entry = handle_entry( handle ))) entry_obj( entry )->selcount++;
513 else handle = 0;
514 pthread_mutex_unlock( &gdi_lock );
515 return handle;
519 /***********************************************************************
520 * GDI_dec_ref_count
522 * Decrement the reference count of a GDI object.
524 BOOL GDI_dec_ref_count( HGDIOBJ handle )
526 GDI_HANDLE_ENTRY *entry;
528 pthread_mutex_lock( &gdi_lock );
529 if ((entry = handle_entry( handle )))
531 assert( entry_obj( entry )->selcount );
532 if (!--entry_obj( entry )->selcount && entry_obj( entry )->deleted)
534 /* handle delayed DeleteObject*/
535 entry_obj( entry )->deleted = 0;
536 pthread_mutex_unlock( &gdi_lock );
537 TRACE( "executing delayed DeleteObject for %p\n", handle );
538 NtGdiDeleteObjectApp( handle );
539 return TRUE;
542 pthread_mutex_unlock( &gdi_lock );
543 return entry != NULL;
547 static HFONT create_font( const LOGFONTW *deffont )
549 ENUMLOGFONTEXDVW lf;
551 memset( &lf, 0, sizeof(lf) );
552 lf.elfEnumLogfontEx.elfLogFont = *deffont;
553 return NtGdiHfontCreate( &lf, sizeof(lf), 0, 0, NULL );
556 static HFONT create_scaled_font( const LOGFONTW *deffont, unsigned int dpi )
558 LOGFONTW lf;
560 lf = *deffont;
561 lf.lfHeight = muldiv( lf.lfHeight, dpi, 96 );
562 return create_font( &lf );
565 static void init_gdi_shared(void)
567 SIZE_T size = sizeof(*gdi_shared);
569 if (NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&gdi_shared, zero_bits(),
570 &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ))
571 return;
572 next_unused = gdi_shared->Handles + FIRST_GDI_HANDLE;
574 #ifndef _WIN64
575 if (NtCurrentTeb()->GdiBatchCount)
577 TEB64 *teb64 = (TEB64 *)(UINT_PTR)NtCurrentTeb()->GdiBatchCount;
578 PEB64 *peb64 = (PEB64 *)(UINT_PTR)teb64->Peb;
579 peb64->GdiSharedHandleTable = (UINT_PTR)gdi_shared;
580 return;
582 #endif
583 /* NOTE: Windows uses 32-bit for 32-bit kernel */
584 NtCurrentTeb()->Peb->GdiSharedHandleTable = gdi_shared;
587 /***********************************************************************
588 * GetStockObject (win32u.so)
590 HGDIOBJ WINAPI GetStockObject( INT obj )
592 assert( obj >= 0 && obj <= STOCK_LAST + 1 && obj != 9 );
594 switch (obj)
596 case OEM_FIXED_FONT:
597 if (get_system_dpi() != 96) obj = 9;
598 break;
599 case SYSTEM_FONT:
600 if (get_system_dpi() != 96) obj = STOCK_LAST + 2;
601 break;
602 case SYSTEM_FIXED_FONT:
603 if (get_system_dpi() != 96) obj = STOCK_LAST + 3;
604 break;
605 case DEFAULT_GUI_FONT:
606 if (get_system_dpi() != 96) obj = STOCK_LAST + 4;
607 break;
610 return entry_to_handle( handle_entry( ULongToHandle( obj + FIRST_GDI_HANDLE )));
613 static void init_stock_objects( unsigned int dpi )
615 const struct DefaultFontInfo *deffonts;
616 unsigned int i;
617 HGDIOBJ obj;
619 /* Create stock objects in order matching stock object macros,
620 * so that they use predictable handle slots. Our GetStockObject
621 * depends on it. */
622 create_brush( &WhiteBrush );
623 create_brush( &LtGrayBrush );
624 create_brush( &GrayBrush );
625 create_brush( &DkGrayBrush );
626 create_brush( &BlackBrush );
627 create_brush( &NullBrush );
629 create_pen( PS_SOLID, 0, RGB(255,255,255) );
630 create_pen( PS_SOLID, 0, RGB(0,0,0) );
631 create_pen( PS_NULL, 0, RGB(0,0,0) );
633 /* slot 9 is not used for non-scaled stock objects */
634 create_scaled_font( &OEMFixedFont, dpi );
636 /* language-independent stock fonts */
637 create_font( &OEMFixedFont );
638 create_font( &AnsiFixedFont );
639 create_font( &AnsiVarFont );
641 /* language-dependent stock fonts */
642 deffonts = get_default_fonts();
643 create_font( &deffonts->SystemFont );
644 create_font( &deffonts->DeviceDefaultFont );
646 PALETTE_Init();
648 create_font( &deffonts->SystemFixedFont );
649 create_font( &deffonts->DefaultGuiFont );
651 create_brush( &DCBrush );
652 NtGdiCreatePen( PS_SOLID, 0, RGB(0,0,0), NULL );
654 obj = NtGdiCreateBitmap( 1, 1, 1, 1, NULL );
656 assert( (HandleToULong( obj ) & 0xffff) == FIRST_GDI_HANDLE + DEFAULT_BITMAP );
658 create_scaled_font( &deffonts->SystemFont, dpi );
659 create_scaled_font( &deffonts->SystemFixedFont, dpi );
660 create_scaled_font( &deffonts->DefaultGuiFont, dpi );
662 /* clear the NOSYSTEM bit on all stock objects*/
663 for (i = 0; i < STOCK_LAST + 5; i++)
665 GDI_HANDLE_ENTRY *entry = &gdi_shared->Handles[FIRST_GDI_HANDLE + i];
666 entry_obj( entry )->system = TRUE;
667 entry->StockFlag = 1;
672 static const char *gdi_obj_type( unsigned type )
674 switch ( type )
676 case NTGDI_OBJ_PEN: return "NTGDI_OBJ_PEN";
677 case NTGDI_OBJ_BRUSH: return "NTGDI_OBJ_BRUSH";
678 case NTGDI_OBJ_DC: return "NTGDI_OBJ_DC";
679 case NTGDI_OBJ_METADC: return "NTGDI_OBJ_METADC";
680 case NTGDI_OBJ_PAL: return "NTGDI_OBJ_PAL";
681 case NTGDI_OBJ_FONT: return "NTGDI_OBJ_FONT";
682 case NTGDI_OBJ_BITMAP: return "NTGDI_OBJ_BITMAP";
683 case NTGDI_OBJ_REGION: return "NTGDI_OBJ_REGION";
684 case NTGDI_OBJ_METAFILE: return "NTGDI_OBJ_METAFILE";
685 case NTGDI_OBJ_MEMDC: return "NTGDI_OBJ_MEMDC";
686 case NTGDI_OBJ_EXTPEN: return "NTGDI_OBJ_EXTPEN";
687 case NTGDI_OBJ_ENHMETADC: return "NTGDI_OBJ_ENHMETADC";
688 case NTGDI_OBJ_ENHMETAFILE: return "NTGDI_OBJ_ENHMETAFILE";
689 default: return "UNKNOWN";
693 static void dump_gdi_objects( void )
695 GDI_HANDLE_ENTRY *entry;
697 TRACE( "%u objects:\n", GDI_MAX_HANDLE_COUNT );
699 pthread_mutex_lock( &gdi_lock );
700 for (entry = gdi_shared->Handles; entry < next_unused; entry++)
702 if (!entry->Type)
703 TRACE( "handle %p FREE\n", entry_to_handle( entry ));
704 else
705 TRACE( "handle %p obj %s type %s selcount %u deleted %u\n",
706 entry_to_handle( entry ), wine_dbgstr_longlong( entry->Object ),
707 gdi_obj_type( entry->ExtType << NTGDI_HANDLE_TYPE_SHIFT ),
708 entry_obj( entry )->selcount, entry_obj( entry )->deleted );
710 pthread_mutex_unlock( &gdi_lock );
713 /***********************************************************************
714 * alloc_gdi_handle
716 * Allocate a GDI handle for an object, which must have been allocated on the process heap.
718 HGDIOBJ alloc_gdi_handle( struct gdi_obj_header *obj, DWORD type, const struct gdi_obj_funcs *funcs )
720 GDI_HANDLE_ENTRY *entry;
721 HGDIOBJ ret;
723 assert( type ); /* type 0 is reserved to mark free entries */
725 pthread_mutex_lock( &gdi_lock );
727 entry = next_free;
728 if (entry)
729 next_free = (GDI_HANDLE_ENTRY *)(UINT_PTR)entry->Object;
730 else if (next_unused < gdi_shared->Handles + GDI_MAX_HANDLE_COUNT)
731 entry = next_unused++;
732 else
734 pthread_mutex_unlock( &gdi_lock );
735 ERR( "out of GDI object handles, expect a crash\n" );
736 if (TRACE_ON(gdi)) dump_gdi_objects();
737 return 0;
739 obj->funcs = funcs;
740 obj->selcount = 0;
741 obj->system = 0;
742 obj->deleted = 0;
743 entry->Object = (UINT_PTR)obj;
744 entry->ExtType = type >> NTGDI_HANDLE_TYPE_SHIFT;
745 entry->Type = entry->ExtType & 0x1f;
746 if (++entry->Generation == 0xff) entry->Generation = 1;
747 ret = entry_to_handle( entry );
748 pthread_mutex_unlock( &gdi_lock );
749 TRACE( "allocated %s %p %u/%u\n", gdi_obj_type(type), ret,
750 InterlockedIncrement( &debug_count ), GDI_MAX_HANDLE_COUNT );
751 return ret;
755 /***********************************************************************
756 * free_gdi_handle
758 * Free a GDI handle and return a pointer to the object.
760 void *free_gdi_handle( HGDIOBJ handle )
762 void *object = NULL;
763 GDI_HANDLE_ENTRY *entry;
765 pthread_mutex_lock( &gdi_lock );
766 if ((entry = handle_entry( handle )))
768 TRACE( "freed %s %p %u/%u\n", gdi_obj_type( entry->ExtType << NTGDI_HANDLE_TYPE_SHIFT ),
769 handle, InterlockedDecrement( &debug_count ) + 1, GDI_MAX_HANDLE_COUNT );
770 object = entry_obj( entry );
771 entry->Type = 0;
772 entry->Object = (UINT_PTR)next_free;
773 next_free = entry;
775 pthread_mutex_unlock( &gdi_lock );
776 return object;
779 DWORD get_gdi_object_type( HGDIOBJ obj )
781 GDI_HANDLE_ENTRY *entry = handle_entry( obj );
782 return entry ? entry->ExtType << NTGDI_HANDLE_TYPE_SHIFT : 0;
785 void set_gdi_client_ptr( HGDIOBJ obj, void *ptr )
787 GDI_HANDLE_ENTRY *entry = handle_entry( obj );
788 if (entry) entry->UserPointer = (UINT_PTR)ptr;
791 /***********************************************************************
792 * get_any_obj_ptr
794 * Return a pointer to, and the type of, the GDI object
795 * associated with the handle.
796 * The object must be released with GDI_ReleaseObj.
798 void *get_any_obj_ptr( HGDIOBJ handle, DWORD *type )
800 void *ptr = NULL;
801 GDI_HANDLE_ENTRY *entry;
803 pthread_mutex_lock( &gdi_lock );
805 if ((entry = handle_entry( handle )))
807 ptr = entry_obj( entry );
808 *type = entry->ExtType << NTGDI_HANDLE_TYPE_SHIFT;
811 if (!ptr) pthread_mutex_unlock( &gdi_lock );
812 return ptr;
815 /***********************************************************************
816 * GDI_GetObjPtr
818 * Return a pointer to the GDI object associated with the handle.
819 * Return NULL if the object has the wrong type.
820 * The object must be released with GDI_ReleaseObj.
822 void *GDI_GetObjPtr( HGDIOBJ handle, DWORD type )
824 DWORD ret_type;
825 void *ptr = get_any_obj_ptr( handle, &ret_type );
826 if (ptr && ret_type != type)
828 GDI_ReleaseObj( handle );
829 ptr = NULL;
831 return ptr;
834 /***********************************************************************
835 * GDI_ReleaseObj
838 void GDI_ReleaseObj( HGDIOBJ handle )
840 pthread_mutex_unlock( &gdi_lock );
844 /***********************************************************************
845 * NtGdiDeleteObjectApp (win32u.@)
847 * Delete a Gdi object.
849 * PARAMS
850 * obj [I] Gdi object to delete
852 * RETURNS
853 * Success: TRUE. If obj was not returned from GetStockObject(), any resources
854 * it consumed are released.
855 * Failure: FALSE, if obj is not a valid Gdi object, or is currently selected
856 * into a DC.
858 BOOL WINAPI NtGdiDeleteObjectApp( HGDIOBJ obj )
860 GDI_HANDLE_ENTRY *entry;
861 const struct gdi_obj_funcs *funcs = NULL;
862 struct gdi_obj_header *header;
864 pthread_mutex_lock( &gdi_lock );
865 if (!(entry = handle_entry( obj )))
867 pthread_mutex_unlock( &gdi_lock );
868 return FALSE;
871 header = entry_obj( entry );
872 if (header->system)
874 TRACE("Preserving system object %p\n", obj);
875 pthread_mutex_unlock( &gdi_lock );
876 return TRUE;
879 obj = entry_to_handle( entry ); /* make it a full handle */
881 if (header->selcount)
883 TRACE("delayed for %p because object in use, count %u\n", obj, header->selcount );
884 header->deleted = 1; /* mark for delete */
886 else funcs = header->funcs;
888 pthread_mutex_unlock( &gdi_lock );
890 TRACE("%p\n", obj );
892 if (funcs && funcs->pDeleteObject) return funcs->pDeleteObject( obj );
893 return TRUE;
896 /***********************************************************************
897 * NtGdiCreateClientObj (win32u.@)
899 HANDLE WINAPI NtGdiCreateClientObj( ULONG type )
901 struct gdi_obj_header *obj;
902 HGDIOBJ handle;
904 if (!(obj = malloc( sizeof(*obj) )))
905 return 0;
907 handle = alloc_gdi_handle( obj, type, NULL );
908 if (!handle) free( obj );
909 return handle;
912 /***********************************************************************
913 * NtGdiDeleteClientObj (win32u.@)
915 BOOL WINAPI NtGdiDeleteClientObj( HGDIOBJ handle )
917 void *obj;
918 if (!(obj = free_gdi_handle( handle ))) return FALSE;
919 free( obj );
920 return TRUE;
924 /***********************************************************************
925 * NtGdiExtGetObjectW (win32u.@)
927 INT WINAPI NtGdiExtGetObjectW( HGDIOBJ handle, INT count, void *buffer )
929 GDI_HANDLE_ENTRY *entry;
930 const struct gdi_obj_funcs *funcs = NULL;
931 INT result = 0;
933 TRACE("%p %d %p\n", handle, count, buffer );
935 pthread_mutex_lock( &gdi_lock );
936 if ((entry = handle_entry( handle )))
938 funcs = entry_obj( entry )->funcs;
939 handle = entry_to_handle( entry ); /* make it a full handle */
941 pthread_mutex_unlock( &gdi_lock );
943 if (funcs && funcs->pGetObjectW)
945 if (buffer && ((ULONG_PTR)buffer >> 16) == 0) /* catch apps getting argument order wrong */
946 RtlSetLastWin32Error( ERROR_NOACCESS );
947 else
948 result = funcs->pGetObjectW( handle, count, buffer );
950 return result;
953 /***********************************************************************
954 * NtGdiGetDCObject (win32u.@)
956 * Get the currently selected object of a given type in a device context.
958 HANDLE WINAPI NtGdiGetDCObject( HDC hdc, UINT type )
960 HGDIOBJ ret = 0;
961 DC *dc;
963 if (!(dc = get_dc_ptr( hdc ))) return 0;
965 switch (type)
967 case NTGDI_OBJ_EXTPEN: /* fall through */
968 case NTGDI_OBJ_PEN: ret = dc->hPen; break;
969 case NTGDI_OBJ_BRUSH: ret = dc->hBrush; break;
970 case NTGDI_OBJ_PAL: ret = dc->hPalette; break;
971 case NTGDI_OBJ_FONT: ret = dc->hFont; break;
972 case NTGDI_OBJ_SURF: ret = dc->hBitmap; break;
973 default:
974 FIXME( "(%p, %d): unknown type.\n", hdc, type );
975 break;
977 release_dc_ptr( dc );
978 return ret;
982 /***********************************************************************
983 * NtGdiUnrealizeObject (win32u.@)
985 BOOL WINAPI NtGdiUnrealizeObject( HGDIOBJ obj )
987 const struct gdi_obj_funcs *funcs = NULL;
988 GDI_HANDLE_ENTRY *entry;
990 pthread_mutex_lock( &gdi_lock );
991 if ((entry = handle_entry( obj )))
993 funcs = entry_obj( entry )->funcs;
994 obj = entry_to_handle( entry ); /* make it a full handle */
996 pthread_mutex_unlock( &gdi_lock );
998 if (funcs && funcs->pUnrealizeObject) return funcs->pUnrealizeObject( obj );
999 return funcs != NULL;
1003 /***********************************************************************
1004 * NtGdiFlush (win32u.@)
1006 BOOL WINAPI NtGdiFlush(void)
1008 return TRUE; /* FIXME */
1012 /*******************************************************************
1013 * NtGdiGetColorAdjustment (win32u.@)
1015 BOOL WINAPI NtGdiGetColorAdjustment( HDC hdc, COLORADJUSTMENT *ca )
1017 FIXME( "stub\n" );
1018 return FALSE;
1021 /*******************************************************************
1022 * NtGdiSetColorAdjustment (win32u.@)
1024 BOOL WINAPI NtGdiSetColorAdjustment( HDC hdc, const COLORADJUSTMENT *ca )
1026 FIXME( "stub\n" );
1027 return FALSE;
1031 static struct unix_funcs unix_funcs =
1033 NtGdiAbortDoc,
1034 NtGdiAbortPath,
1035 NtGdiAlphaBlend,
1036 NtGdiAngleArc,
1037 NtGdiArcInternal,
1038 NtGdiBeginPath,
1039 NtGdiBitBlt,
1040 NtGdiCloseFigure,
1041 NtGdiComputeXformCoefficients,
1042 NtGdiCreateCompatibleBitmap,
1043 NtGdiCreateCompatibleDC,
1044 NtGdiCreateDIBitmapInternal,
1045 NtGdiCreateMetafileDC,
1046 NtGdiDdDDICheckVidPnExclusiveOwnership,
1047 NtGdiDdDDICloseAdapter,
1048 NtGdiDdDDICreateDCFromMemory,
1049 NtGdiDdDDIDestroyDCFromMemory,
1050 NtGdiDdDDIDestroyDevice,
1051 NtGdiDdDDIEscape,
1052 NtGdiDdDDIOpenAdapterFromDeviceName,
1053 NtGdiDdDDIOpenAdapterFromLuid,
1054 NtGdiDdDDIQueryVideoMemoryInfo,
1055 NtGdiDdDDISetVidPnSourceOwner,
1056 NtGdiDeleteObjectApp,
1057 NtGdiDoPalette,
1058 NtGdiEllipse,
1059 NtGdiEndDoc,
1060 NtGdiEndPath,
1061 NtGdiEndPage,
1062 NtGdiEnumFonts,
1063 NtGdiExcludeClipRect,
1064 NtGdiExtEscape,
1065 NtGdiExtFloodFill,
1066 NtGdiExtTextOutW,
1067 NtGdiExtSelectClipRgn,
1068 NtGdiFillPath,
1069 NtGdiFillRgn,
1070 NtGdiFontIsLinked,
1071 NtGdiFrameRgn,
1072 NtGdiGetAndSetDCDword,
1073 NtGdiGetAppClipBox,
1074 NtGdiGetBoundsRect,
1075 NtGdiGetCharABCWidthsW,
1076 NtGdiGetCharWidthW,
1077 NtGdiGetCharWidthInfo,
1078 NtGdiGetDIBitsInternal,
1079 NtGdiGetDeviceCaps,
1080 NtGdiGetDeviceGammaRamp,
1081 NtGdiGetFontData,
1082 NtGdiGetFontUnicodeRanges,
1083 NtGdiGetGlyphIndicesW,
1084 NtGdiGetGlyphOutline,
1085 NtGdiGetKerningPairs,
1086 NtGdiGetNearestColor,
1087 NtGdiGetOutlineTextMetricsInternalW,
1088 NtGdiGetPixel,
1089 NtGdiGetRandomRgn,
1090 NtGdiGetRasterizerCaps,
1091 NtGdiGetRealizationInfo,
1092 NtGdiGetTextCharsetInfo,
1093 NtGdiGetTextExtentExW,
1094 NtGdiGetTextFaceW,
1095 NtGdiGetTextMetricsW,
1096 NtGdiGradientFill,
1097 NtGdiIntersectClipRect,
1098 NtGdiInvertRgn,
1099 NtGdiLineTo,
1100 NtGdiMaskBlt,
1101 NtGdiModifyWorldTransform,
1102 NtGdiMoveTo,
1103 NtGdiOffsetClipRgn,
1104 NtGdiOpenDCW,
1105 NtGdiPatBlt,
1106 NtGdiPlgBlt,
1107 NtGdiPolyDraw,
1108 NtGdiPolyPolyDraw,
1109 NtGdiPtVisible,
1110 NtGdiRectVisible,
1111 NtGdiRectangle,
1112 NtGdiResetDC,
1113 NtGdiResizePalette,
1114 NtGdiRestoreDC,
1115 NtGdiRoundRect,
1116 NtGdiScaleViewportExtEx,
1117 NtGdiScaleWindowExtEx,
1118 NtGdiSelectBitmap,
1119 NtGdiSelectBrush,
1120 NtGdiSelectClipPath,
1121 NtGdiSelectFont,
1122 NtGdiSelectPen,
1123 NtGdiSetBoundsRect,
1124 NtGdiSetDIBitsToDeviceInternal,
1125 NtGdiSetDeviceGammaRamp,
1126 NtGdiSetLayout,
1127 NtGdiSetPixel,
1128 NtGdiSetSystemPaletteUse,
1129 NtGdiStartDoc,
1130 NtGdiStartPage,
1131 NtGdiStretchBlt,
1132 NtGdiStretchDIBitsInternal,
1133 NtGdiStrokeAndFillPath,
1134 NtGdiStrokePath,
1135 NtGdiTransparentBlt,
1136 NtGdiUnrealizeObject,
1137 NtGdiUpdateColors,
1138 NtGdiWidenPath,
1139 NtUserDrawCaptionTemp,
1140 NtUserDrawMenuBarTemp,
1141 NtUserEndPaint,
1142 NtUserExcludeUpdateRgn,
1143 NtUserReleaseDC,
1144 NtUserScrollDC,
1145 NtUserSelectPalette,
1146 NtUserUpdateLayeredWindow,
1148 SetDIBits,
1149 __wine_get_brush_bitmap_info,
1150 __wine_get_file_outline_text_metric,
1151 __wine_get_icm_profile,
1152 __wine_get_wgl_driver,
1153 __wine_send_input,
1156 void gdi_init(void)
1158 pthread_mutexattr_t attr;
1159 unsigned int dpi;
1161 pthread_mutexattr_init( &attr );
1162 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
1163 pthread_mutex_init( &gdi_lock, &attr );
1164 pthread_mutexattr_destroy( &attr );
1166 NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL );
1167 init_gdi_shared();
1168 if (!gdi_shared) return;
1170 dpi = font_init();
1171 init_stock_objects( dpi );
1174 NTSTATUS callbacks_init( void *args )
1176 *(const struct unix_funcs **)args = &unix_funcs;
1177 return 0;