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
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
);
72 static inline struct gdi_obj_header
*entry_obj( GDI_HANDLE_ENTRY
*entry
)
74 return (struct gdi_obj_header
*)(ULONG_PTR
)entry
->Object
;
77 /***********************************************************************
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
136 LOGFONTW DeviceDefaultFont
;
137 LOGFONTW SystemFixedFont
;
138 LOGFONTW DefaultGuiFont
;
141 static const struct DefaultFontInfo default_fonts
[] =
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'}
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
,
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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'}
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
,
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'}
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'}
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'}
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 /******************************************************************************
465 static const struct DefaultFontInfo
* get_default_fonts(void)
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 /***********************************************************************
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
;
495 pthread_mutex_lock( &gdi_lock
);
496 if ((entry
= handle_entry( handle
))) ret
= entry_obj( entry
)->selcount
;
497 pthread_mutex_unlock( &gdi_lock
);
502 /***********************************************************************
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
++;
514 pthread_mutex_unlock( &gdi_lock
);
519 /***********************************************************************
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
);
542 pthread_mutex_unlock( &gdi_lock
);
543 return entry
!= NULL
;
547 static HFONT
create_font( const LOGFONTW
*deffont
)
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
)
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
))
572 next_unused
= gdi_shared
->Handles
+ FIRST_GDI_HANDLE
;
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
;
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 );
597 if (get_system_dpi() != 96) obj
= 9;
600 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 2;
602 case SYSTEM_FIXED_FONT
:
603 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 3;
605 case DEFAULT_GUI_FONT
:
606 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 4;
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
;
619 /* Create stock objects in order matching stock object macros,
620 * so that they use predictable handle slots. Our GetStockObject
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
);
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
)
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
++)
703 TRACE( "handle %p FREE\n", entry_to_handle( entry
));
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 /***********************************************************************
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
;
723 assert( type
); /* type 0 is reserved to mark free entries */
725 pthread_mutex_lock( &gdi_lock
);
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
++;
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();
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
);
755 /***********************************************************************
758 * Free a GDI handle and return a pointer to the object.
760 void *free_gdi_handle( HGDIOBJ handle
)
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
);
772 entry
->Object
= (UINT_PTR
)next_free
;
775 pthread_mutex_unlock( &gdi_lock
);
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 /***********************************************************************
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
)
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
);
815 /***********************************************************************
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
)
825 void *ptr
= get_any_obj_ptr( handle
, &ret_type
);
826 if (ptr
&& ret_type
!= type
)
828 GDI_ReleaseObj( handle
);
834 /***********************************************************************
838 void GDI_ReleaseObj( HGDIOBJ handle
)
840 pthread_mutex_unlock( &gdi_lock
);
844 /***********************************************************************
845 * NtGdiDeleteObjectApp (win32u.@)
847 * Delete a Gdi object.
850 * obj [I] Gdi object to delete
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
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
);
871 header
= entry_obj( entry
);
874 TRACE("Preserving system object %p\n", obj
);
875 pthread_mutex_unlock( &gdi_lock
);
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
);
892 if (funcs
&& funcs
->pDeleteObject
) return funcs
->pDeleteObject( obj
);
896 /***********************************************************************
897 * NtGdiCreateClientObj (win32u.@)
899 HANDLE WINAPI
NtGdiCreateClientObj( ULONG type
)
901 struct gdi_obj_header
*obj
;
904 if (!(obj
= malloc( sizeof(*obj
) )))
907 handle
= alloc_gdi_handle( obj
, type
, NULL
);
908 if (!handle
) free( obj
);
912 /***********************************************************************
913 * NtGdiDeleteClientObj (win32u.@)
915 BOOL WINAPI
NtGdiDeleteClientObj( HGDIOBJ handle
)
918 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
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
;
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
);
948 result
= funcs
->pGetObjectW( handle
, count
, buffer
);
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
)
963 if (!(dc
= get_dc_ptr( hdc
))) return 0;
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;
974 FIXME( "(%p, %d): unknown type.\n", hdc
, type
);
977 release_dc_ptr( dc
);
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
)
1021 /*******************************************************************
1022 * NtGdiSetColorAdjustment (win32u.@)
1024 BOOL WINAPI
NtGdiSetColorAdjustment( HDC hdc
, const COLORADJUSTMENT
*ca
)
1032 pthread_mutexattr_t attr
;
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
);
1042 if (!gdi_shared
) return;
1045 init_stock_objects( dpi
);