windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / win32u / gdiobj.c
blob057988e99e94dcf8cdd58f424d6a4555017c797e
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 (int)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, (int)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;
1030 void gdi_init(void)
1032 pthread_mutexattr_t attr;
1033 unsigned int dpi;
1035 pthread_mutexattr_init( &attr );
1036 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
1037 pthread_mutex_init( &gdi_lock, &attr );
1038 pthread_mutexattr_destroy( &attr );
1040 NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL );
1041 init_gdi_shared();
1042 if (!gdi_shared) return;
1044 dpi = font_init();
1045 init_stock_objects( dpi );