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 const struct user_callbacks
*user_callbacks
= NULL
;
55 static inline HGDIOBJ
entry_to_handle( GDI_HANDLE_ENTRY
*entry
)
57 unsigned int idx
= entry
- gdi_shared
->Handles
;
58 return ULongToHandle( idx
| (entry
->Unique
<< NTGDI_HANDLE_TYPE_SHIFT
) );
61 static inline GDI_HANDLE_ENTRY
*handle_entry( HGDIOBJ handle
)
63 unsigned int idx
= LOWORD(handle
);
65 if (idx
< GDI_MAX_HANDLE_COUNT
&& gdi_shared
->Handles
[idx
].Type
)
67 if (!HIWORD( handle
) || HIWORD( handle
) == gdi_shared
->Handles
[idx
].Unique
)
68 return &gdi_shared
->Handles
[idx
];
70 if (handle
) WARN( "invalid handle %p\n", handle
);
74 static inline struct gdi_obj_header
*entry_obj( GDI_HANDLE_ENTRY
*entry
)
76 return (struct gdi_obj_header
*)(ULONG_PTR
)entry
->Object
;
79 /***********************************************************************
83 static const LOGBRUSH WhiteBrush
= { BS_SOLID
, RGB(255,255,255), 0 };
84 static const LOGBRUSH BlackBrush
= { BS_SOLID
, RGB(0,0,0), 0 };
85 static const LOGBRUSH NullBrush
= { BS_NULL
, 0, 0 };
87 static const LOGBRUSH LtGrayBrush
= { BS_SOLID
, RGB(192,192,192), 0 };
88 static const LOGBRUSH GrayBrush
= { BS_SOLID
, RGB(128,128,128), 0 };
89 static const LOGBRUSH DkGrayBrush
= { BS_SOLID
, RGB(64,64,64), 0 };
91 static const LOGBRUSH DCBrush
= { BS_SOLID
, RGB(255,255,255), 0 };
93 static pthread_mutex_t gdi_lock
;
96 /****************************************************************************
98 * language-independent stock fonts
102 static const LOGFONTW OEMFixedFont
=
103 { 12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, OEM_CHARSET
,
104 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
};
106 static const LOGFONTW AnsiFixedFont
=
107 { 12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
108 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
109 {'C','o','u','r','i','e','r'} };
111 static const LOGFONTW AnsiVarFont
=
112 { 12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
113 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
114 {'M','S',' ','S','a','n','s',' ','S','e','r','i','f'} };
116 /******************************************************************************
118 * language-dependent stock fonts
120 * 'ANSI' charset and 'DEFAULT' charset is not same.
121 * The chars in CP_ACP should be drawn with 'DEFAULT' charset.
122 * 'ANSI' charset seems to be identical with ISO-8859-1.
123 * 'DEFAULT' charset is a language-dependent charset.
125 * 'System' font seems to be an alias for language-dependent font.
129 * language-dependent stock fonts for all known charsets
130 * please see TranslateCharsetInfo (dlls/gdi/font.c) and
131 * CharsetBindingInfo (dlls/x11drv/xfont.c),
132 * and modify entries for your language if needed.
134 struct DefaultFontInfo
138 LOGFONTW DeviceDefaultFont
;
139 LOGFONTW SystemFixedFont
;
140 LOGFONTW DefaultGuiFont
;
143 static const struct DefaultFontInfo default_fonts
[] =
147 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
148 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
149 {'S','y','s','t','e','m'}
151 { /* Device Default */
152 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
153 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
154 {'S','y','s','t','e','m'}
157 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
158 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
159 {'C','o','u','r','i','e','r'}
161 { /* DefaultGuiFont */
162 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
163 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
164 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
167 { EASTEUROPE_CHARSET
,
169 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, EASTEUROPE_CHARSET
,
170 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
171 {'S','y','s','t','e','m'}
173 { /* Device Default */
174 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, EASTEUROPE_CHARSET
,
175 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
176 {'S','y','s','t','e','m'}
179 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, EASTEUROPE_CHARSET
,
180 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
181 {'C','o','u','r','i','e','r'}
183 { /* DefaultGuiFont */
184 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, EASTEUROPE_CHARSET
,
185 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
186 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
191 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, RUSSIAN_CHARSET
,
192 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
193 {'S','y','s','t','e','m'}
195 { /* Device Default */
196 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, RUSSIAN_CHARSET
,
197 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
198 {'S','y','s','t','e','m'}
201 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, RUSSIAN_CHARSET
,
202 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
203 {'C','o','u','r','i','e','r'}
205 { /* DefaultGuiFont */
206 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, RUSSIAN_CHARSET
,
207 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
208 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
213 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, GREEK_CHARSET
,
214 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
215 {'S','y','s','t','e','m'}
217 { /* Device Default */
218 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, GREEK_CHARSET
,
219 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
220 {'S','y','s','t','e','m'}
223 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, GREEK_CHARSET
,
224 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
225 {'C','o','u','r','i','e','r'}
227 { /* DefaultGuiFont */
228 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, GREEK_CHARSET
,
229 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
230 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
235 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, TURKISH_CHARSET
,
236 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
237 {'S','y','s','t','e','m'}
239 { /* Device Default */
240 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, TURKISH_CHARSET
,
241 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
242 {'S','y','s','t','e','m'}
245 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, TURKISH_CHARSET
,
246 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
247 {'C','o','u','r','i','e','r'}
249 { /* DefaultGuiFont */
250 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, TURKISH_CHARSET
,
251 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
252 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
257 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, HEBREW_CHARSET
,
258 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
259 {'S','y','s','t','e','m'}
261 { /* Device Default */
262 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, HEBREW_CHARSET
,
263 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
264 {'S','y','s','t','e','m'}
267 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, HEBREW_CHARSET
,
268 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
269 {'C','o','u','r','i','e','r'}
271 { /* DefaultGuiFont */
272 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, HEBREW_CHARSET
,
273 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
274 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
279 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, ARABIC_CHARSET
,
280 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
281 {'S','y','s','t','e','m'}
283 { /* Device Default */
284 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, ARABIC_CHARSET
,
285 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
286 {'S','y','s','t','e','m'}
289 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ARABIC_CHARSET
,
290 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
291 {'C','o','u','r','i','e','r'}
293 { /* DefaultGuiFont */
294 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ARABIC_CHARSET
,
295 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
296 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
301 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, BALTIC_CHARSET
,
302 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
303 {'S','y','s','t','e','m'}
305 { /* Device Default */
306 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, BALTIC_CHARSET
,
307 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
308 {'S','y','s','t','e','m'}
311 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, BALTIC_CHARSET
,
312 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
313 {'C','o','u','r','i','e','r'}
315 { /* DefaultGuiFont */
316 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, BALTIC_CHARSET
,
317 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
318 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
323 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, THAI_CHARSET
,
324 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
325 {'S','y','s','t','e','m'}
327 { /* Device Default */
328 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, THAI_CHARSET
,
329 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
330 {'S','y','s','t','e','m'}
333 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, THAI_CHARSET
,
334 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
335 {'C','o','u','r','i','e','r'}
337 { /* DefaultGuiFont */
338 -11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, THAI_CHARSET
,
339 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
340 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
345 18, 8, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, SHIFTJIS_CHARSET
,
346 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
347 {'S','y','s','t','e','m'}
349 { /* Device Default */
350 18, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, SHIFTJIS_CHARSET
,
351 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
352 {'S','y','s','t','e','m'}
355 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, SHIFTJIS_CHARSET
,
356 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
357 {'C','o','u','r','i','e','r'}
359 { /* DefaultGuiFont */
360 -12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, SHIFTJIS_CHARSET
,
361 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
362 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
367 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, GB2312_CHARSET
,
368 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
369 {'S','y','s','t','e','m'}
371 { /* Device Default */
372 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, GB2312_CHARSET
,
373 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
374 {'S','y','s','t','e','m'}
377 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, GB2312_CHARSET
,
378 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
379 {'C','o','u','r','i','e','r'}
381 { /* DefaultGuiFont */
382 -12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, GB2312_CHARSET
,
383 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
384 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
389 16, 8, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, HANGEUL_CHARSET
,
390 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
391 {'S','y','s','t','e','m'}
393 { /* Device Default */
394 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, HANGEUL_CHARSET
,
395 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
396 {'S','y','s','t','e','m'}
399 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, HANGEUL_CHARSET
,
400 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
401 {'C','o','u','r','i','e','r'}
403 { /* DefaultGuiFont */
404 -12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, HANGEUL_CHARSET
,
405 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
406 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
409 { CHINESEBIG5_CHARSET
,
411 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, CHINESEBIG5_CHARSET
,
412 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
413 {'S','y','s','t','e','m'}
415 { /* Device Default */
416 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, CHINESEBIG5_CHARSET
,
417 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
418 {'S','y','s','t','e','m'}
421 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, CHINESEBIG5_CHARSET
,
422 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
423 {'C','o','u','r','i','e','r'}
425 { /* DefaultGuiFont */
426 -12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, CHINESEBIG5_CHARSET
,
427 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
428 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
433 16, 7, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, JOHAB_CHARSET
,
434 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
435 {'S','y','s','t','e','m'}
437 { /* Device Default */
438 16, 0, 0, 0, FW_BOLD
, FALSE
, FALSE
, FALSE
, JOHAB_CHARSET
,
439 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
440 {'S','y','s','t','e','m'}
443 16, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, JOHAB_CHARSET
,
444 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
,
445 {'C','o','u','r','i','e','r'}
447 { /* DefaultGuiFont */
448 -12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, JOHAB_CHARSET
,
449 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
,
450 {'M','S',' ','S','h','e','l','l',' ','D','l','g'}
455 void make_gdi_object_system( HGDIOBJ handle
, BOOL set
)
457 GDI_HANDLE_ENTRY
*entry
;
459 pthread_mutex_lock( &gdi_lock
);
460 if ((entry
= handle_entry( handle
))) entry_obj( entry
)->system
= !!set
;
461 pthread_mutex_unlock( &gdi_lock
);
464 /******************************************************************************
467 static const struct DefaultFontInfo
* get_default_fonts(UINT charset
)
471 for(n
= 0; n
< ARRAY_SIZE( default_fonts
); n
++)
473 if ( default_fonts
[n
].charset
== charset
)
474 return &default_fonts
[n
];
477 FIXME( "unhandled charset 0x%08x - use ANSI_CHARSET for default stock objects\n", charset
);
478 return &default_fonts
[0];
482 /******************************************************************************
483 * get_default_charset (internal)
485 * get the language-dependent charset that can handle CP_ACP correctly.
487 static UINT
get_default_charset( void )
493 csi
.ciCharset
= ANSI_CHARSET
;
494 if ( !translate_charset_info( ULongToPtr(uACP
), &csi
, TCI_SRCCODEPAGE
) )
496 FIXME( "unhandled codepage %u - use ANSI_CHARSET for default stock objects\n", uACP
);
500 return csi
.ciCharset
;
504 /***********************************************************************
507 * Retrieve the reference count of a GDI object.
508 * Note: the object must be locked otherwise the count is meaningless.
510 UINT
GDI_get_ref_count( HGDIOBJ handle
)
512 GDI_HANDLE_ENTRY
*entry
;
515 pthread_mutex_lock( &gdi_lock
);
516 if ((entry
= handle_entry( handle
))) ret
= entry_obj( entry
)->selcount
;
517 pthread_mutex_unlock( &gdi_lock
);
522 /***********************************************************************
525 * Increment the reference count of a GDI object.
527 HGDIOBJ
GDI_inc_ref_count( HGDIOBJ handle
)
529 GDI_HANDLE_ENTRY
*entry
;
531 pthread_mutex_lock( &gdi_lock
);
532 if ((entry
= handle_entry( handle
))) entry_obj( entry
)->selcount
++;
534 pthread_mutex_unlock( &gdi_lock
);
539 /***********************************************************************
542 * Decrement the reference count of a GDI object.
544 BOOL
GDI_dec_ref_count( HGDIOBJ handle
)
546 GDI_HANDLE_ENTRY
*entry
;
548 pthread_mutex_lock( &gdi_lock
);
549 if ((entry
= handle_entry( handle
)))
551 assert( entry_obj( entry
)->selcount
);
552 if (!--entry_obj( entry
)->selcount
&& entry_obj( entry
)->deleted
)
554 /* handle delayed DeleteObject*/
555 entry_obj( entry
)->deleted
= 0;
556 pthread_mutex_unlock( &gdi_lock
);
557 TRACE( "executing delayed DeleteObject for %p\n", handle
);
558 NtGdiDeleteObjectApp( handle
);
562 pthread_mutex_unlock( &gdi_lock
);
563 return entry
!= NULL
;
567 static HFONT
create_font( const LOGFONTW
*deffont
)
571 memset( &lf
, 0, sizeof(lf
) );
572 lf
.elfEnumLogfontEx
.elfLogFont
= *deffont
;
573 return NtGdiHfontCreate( &lf
, sizeof(lf
), 0, 0, NULL
);
576 static HFONT
create_scaled_font( const LOGFONTW
*deffont
, unsigned int dpi
)
581 lf
.lfHeight
= muldiv( lf
.lfHeight
, dpi
, 96 );
582 return create_font( &lf
);
585 static void init_gdi_shared(void)
587 SIZE_T size
= sizeof(*gdi_shared
);
589 if (NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&gdi_shared
, 0, &size
,
590 MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
))
592 next_unused
= gdi_shared
->Handles
+ FIRST_GDI_HANDLE
;
595 if (NtCurrentTeb()->GdiBatchCount
)
597 TEB64
*teb64
= (TEB64
*)(UINT_PTR
)NtCurrentTeb()->GdiBatchCount
;
598 PEB64
*peb64
= (PEB64
*)(UINT_PTR
)teb64
->Peb
;
599 peb64
->GdiSharedHandleTable
= (UINT_PTR
)gdi_shared
;
603 /* NOTE: Windows uses 32-bit for 32-bit kernel */
604 NtCurrentTeb()->Peb
->GdiSharedHandleTable
= gdi_shared
;
607 HGDIOBJ
get_stock_object( INT obj
)
609 assert( obj
>= 0 && obj
<= STOCK_LAST
+ 1 && obj
!= 9 );
614 if (get_system_dpi() != 96) obj
= 9;
617 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 2;
619 case SYSTEM_FIXED_FONT
:
620 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 3;
622 case DEFAULT_GUI_FONT
:
623 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 4;
627 return entry_to_handle( handle_entry( ULongToHandle( obj
+ FIRST_GDI_HANDLE
)));
630 static void init_stock_objects( unsigned int dpi
)
632 const struct DefaultFontInfo
*deffonts
;
636 /* Create stock objects in order matching stock object macros,
637 * so that they use predictable handle slots. Our GetStockObject
639 create_brush( &WhiteBrush
);
640 create_brush( &LtGrayBrush
);
641 create_brush( &GrayBrush
);
642 create_brush( &DkGrayBrush
);
643 create_brush( &BlackBrush
);
644 create_brush( &NullBrush
);
646 create_pen( PS_SOLID
, 0, RGB(255,255,255) );
647 create_pen( PS_SOLID
, 0, RGB(0,0,0) );
648 create_pen( PS_NULL
, 0, RGB(0,0,0) );
650 /* slot 9 is not used for non-scaled stock objects */
651 create_scaled_font( &OEMFixedFont
, dpi
);
653 /* language-independent stock fonts */
654 create_font( &OEMFixedFont
);
655 create_font( &AnsiFixedFont
);
656 create_font( &AnsiVarFont
);
658 /* language-dependent stock fonts */
659 deffonts
= get_default_fonts(get_default_charset());
660 create_font( &deffonts
->SystemFont
);
661 create_font( &deffonts
->DeviceDefaultFont
);
665 create_font( &deffonts
->SystemFixedFont
);
666 create_font( &deffonts
->DefaultGuiFont
);
668 create_brush( &DCBrush
);
669 NtGdiCreatePen( PS_SOLID
, 0, RGB(0,0,0), NULL
);
671 obj
= NtGdiCreateBitmap( 1, 1, 1, 1, NULL
);
673 assert( (HandleToULong( obj
) & 0xffff) == FIRST_GDI_HANDLE
+ DEFAULT_BITMAP
);
675 create_scaled_font( &deffonts
->SystemFont
, dpi
);
676 create_scaled_font( &deffonts
->SystemFixedFont
, dpi
);
677 create_scaled_font( &deffonts
->DefaultGuiFont
, dpi
);
679 /* clear the NOSYSTEM bit on all stock objects*/
680 for (i
= 0; i
< STOCK_LAST
+ 5; i
++)
682 GDI_HANDLE_ENTRY
*entry
= &gdi_shared
->Handles
[FIRST_GDI_HANDLE
+ i
];
683 entry_obj( entry
)->system
= TRUE
;
684 entry
->StockFlag
= 1;
689 static const char *gdi_obj_type( unsigned type
)
693 case NTGDI_OBJ_PEN
: return "NTGDI_OBJ_PEN";
694 case NTGDI_OBJ_BRUSH
: return "NTGDI_OBJ_BRUSH";
695 case NTGDI_OBJ_DC
: return "NTGDI_OBJ_DC";
696 case NTGDI_OBJ_METADC
: return "NTGDI_OBJ_METADC";
697 case NTGDI_OBJ_PAL
: return "NTGDI_OBJ_PAL";
698 case NTGDI_OBJ_FONT
: return "NTGDI_OBJ_FONT";
699 case NTGDI_OBJ_BITMAP
: return "NTGDI_OBJ_BITMAP";
700 case NTGDI_OBJ_REGION
: return "NTGDI_OBJ_REGION";
701 case NTGDI_OBJ_METAFILE
: return "NTGDI_OBJ_METAFILE";
702 case NTGDI_OBJ_MEMDC
: return "NTGDI_OBJ_MEMDC";
703 case NTGDI_OBJ_EXTPEN
: return "NTGDI_OBJ_EXTPEN";
704 case NTGDI_OBJ_ENHMETADC
: return "NTGDI_OBJ_ENHMETADC";
705 case NTGDI_OBJ_ENHMETAFILE
: return "NTGDI_OBJ_ENHMETAFILE";
706 default: return "UNKNOWN";
710 static void dump_gdi_objects( void )
712 GDI_HANDLE_ENTRY
*entry
;
714 TRACE( "%u objects:\n", GDI_MAX_HANDLE_COUNT
);
716 pthread_mutex_lock( &gdi_lock
);
717 for (entry
= gdi_shared
->Handles
; entry
< next_unused
; entry
++)
720 TRACE( "handle %p FREE\n", entry_to_handle( entry
));
722 TRACE( "handle %p obj %s type %s selcount %u deleted %u\n",
723 entry_to_handle( entry
), wine_dbgstr_longlong( entry
->Object
),
724 gdi_obj_type( entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
),
725 entry_obj( entry
)->selcount
, entry_obj( entry
)->deleted
);
727 pthread_mutex_unlock( &gdi_lock
);
730 /***********************************************************************
733 * Allocate a GDI handle for an object, which must have been allocated on the process heap.
735 HGDIOBJ
alloc_gdi_handle( struct gdi_obj_header
*obj
, DWORD type
, const struct gdi_obj_funcs
*funcs
)
737 GDI_HANDLE_ENTRY
*entry
;
740 assert( type
); /* type 0 is reserved to mark free entries */
742 pthread_mutex_lock( &gdi_lock
);
746 next_free
= (GDI_HANDLE_ENTRY
*)(UINT_PTR
)entry
->Object
;
747 else if (next_unused
< gdi_shared
->Handles
+ GDI_MAX_HANDLE_COUNT
)
748 entry
= next_unused
++;
751 pthread_mutex_unlock( &gdi_lock
);
752 ERR( "out of GDI object handles, expect a crash\n" );
753 if (TRACE_ON(gdi
)) dump_gdi_objects();
760 entry
->Object
= (UINT_PTR
)obj
;
761 entry
->ExtType
= type
>> NTGDI_HANDLE_TYPE_SHIFT
;
762 entry
->Type
= entry
->ExtType
& 0x1f;
763 if (++entry
->Generation
== 0xff) entry
->Generation
= 1;
764 ret
= entry_to_handle( entry
);
765 pthread_mutex_unlock( &gdi_lock
);
766 TRACE( "allocated %s %p %u/%u\n", gdi_obj_type(type
), ret
,
767 InterlockedIncrement( &debug_count
), GDI_MAX_HANDLE_COUNT
);
772 /***********************************************************************
775 * Free a GDI handle and return a pointer to the object.
777 void *free_gdi_handle( HGDIOBJ handle
)
780 GDI_HANDLE_ENTRY
*entry
;
782 pthread_mutex_lock( &gdi_lock
);
783 if ((entry
= handle_entry( handle
)))
785 TRACE( "freed %s %p %u/%u\n", gdi_obj_type( entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
),
786 handle
, InterlockedDecrement( &debug_count
) + 1, GDI_MAX_HANDLE_COUNT
);
787 object
= entry_obj( entry
);
789 entry
->Object
= (UINT_PTR
)next_free
;
792 pthread_mutex_unlock( &gdi_lock
);
796 DWORD
get_gdi_object_type( HGDIOBJ obj
)
798 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
799 return entry
? entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
: 0;
802 void set_gdi_client_ptr( HGDIOBJ obj
, void *ptr
)
804 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
805 if (entry
) entry
->UserPointer
= (UINT_PTR
)ptr
;
808 /***********************************************************************
811 * Return a pointer to, and the type of, the GDI object
812 * associated with the handle.
813 * The object must be released with GDI_ReleaseObj.
815 void *get_any_obj_ptr( HGDIOBJ handle
, DWORD
*type
)
818 GDI_HANDLE_ENTRY
*entry
;
820 pthread_mutex_lock( &gdi_lock
);
822 if ((entry
= handle_entry( handle
)))
824 ptr
= entry_obj( entry
);
825 *type
= entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
;
828 if (!ptr
) pthread_mutex_unlock( &gdi_lock
);
832 /***********************************************************************
835 * Return a pointer to the GDI object associated with the handle.
836 * Return NULL if the object has the wrong type.
837 * The object must be released with GDI_ReleaseObj.
839 void *GDI_GetObjPtr( HGDIOBJ handle
, DWORD type
)
842 void *ptr
= get_any_obj_ptr( handle
, &ret_type
);
843 if (ptr
&& ret_type
!= type
)
845 GDI_ReleaseObj( handle
);
851 /***********************************************************************
855 void GDI_ReleaseObj( HGDIOBJ handle
)
857 pthread_mutex_unlock( &gdi_lock
);
861 /***********************************************************************
862 * NtGdiDeleteObjectApp (win32u.@)
864 * Delete a Gdi object.
867 * obj [I] Gdi object to delete
870 * Success: TRUE. If obj was not returned from GetStockObject(), any resources
871 * it consumed are released.
872 * Failure: FALSE, if obj is not a valid Gdi object, or is currently selected
875 BOOL WINAPI
NtGdiDeleteObjectApp( HGDIOBJ obj
)
877 GDI_HANDLE_ENTRY
*entry
;
878 const struct gdi_obj_funcs
*funcs
= NULL
;
879 struct gdi_obj_header
*header
;
881 pthread_mutex_lock( &gdi_lock
);
882 if (!(entry
= handle_entry( obj
)))
884 pthread_mutex_unlock( &gdi_lock
);
888 header
= entry_obj( entry
);
891 TRACE("Preserving system object %p\n", obj
);
892 pthread_mutex_unlock( &gdi_lock
);
896 obj
= entry_to_handle( entry
); /* make it a full handle */
898 if (header
->selcount
)
900 TRACE("delayed for %p because object in use, count %u\n", obj
, header
->selcount
);
901 header
->deleted
= 1; /* mark for delete */
903 else funcs
= header
->funcs
;
905 pthread_mutex_unlock( &gdi_lock
);
909 if (funcs
&& funcs
->pDeleteObject
) return funcs
->pDeleteObject( obj
);
913 /***********************************************************************
914 * NtGdiCreateClientObj (win32u.@)
916 HANDLE WINAPI
NtGdiCreateClientObj( ULONG type
)
918 struct gdi_obj_header
*obj
;
921 if (!(obj
= malloc( sizeof(*obj
) )))
924 handle
= alloc_gdi_handle( obj
, type
, NULL
);
925 if (!handle
) free( obj
);
929 /***********************************************************************
930 * NtGdiDeleteClientObj (win32u.@)
932 BOOL WINAPI
NtGdiDeleteClientObj( HGDIOBJ handle
)
935 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
941 /***********************************************************************
942 * NtGdiExtGetObjectW (win32u.@)
944 INT WINAPI
NtGdiExtGetObjectW( HGDIOBJ handle
, INT count
, void *buffer
)
946 GDI_HANDLE_ENTRY
*entry
;
947 const struct gdi_obj_funcs
*funcs
= NULL
;
950 TRACE("%p %d %p\n", handle
, count
, buffer
);
952 pthread_mutex_lock( &gdi_lock
);
953 if ((entry
= handle_entry( handle
)))
955 funcs
= entry_obj( entry
)->funcs
;
956 handle
= entry_to_handle( entry
); /* make it a full handle */
958 pthread_mutex_unlock( &gdi_lock
);
960 if (funcs
&& funcs
->pGetObjectW
)
962 if (buffer
&& ((ULONG_PTR
)buffer
>> 16) == 0) /* catch apps getting argument order wrong */
963 SetLastError( ERROR_NOACCESS
);
965 result
= funcs
->pGetObjectW( handle
, count
, buffer
);
970 /***********************************************************************
971 * NtGdiGetDCObject (win32u.@)
973 * Get the currently selected object of a given type in a device context.
975 HANDLE WINAPI
NtGdiGetDCObject( HDC hdc
, UINT type
)
980 if (!(dc
= get_dc_ptr( hdc
))) return 0;
984 case NTGDI_OBJ_EXTPEN
: /* fall through */
985 case NTGDI_OBJ_PEN
: ret
= dc
->hPen
; break;
986 case NTGDI_OBJ_BRUSH
: ret
= dc
->hBrush
; break;
987 case NTGDI_OBJ_PAL
: ret
= dc
->hPalette
; break;
988 case NTGDI_OBJ_FONT
: ret
= dc
->hFont
; break;
989 case NTGDI_OBJ_SURF
: ret
= dc
->hBitmap
; break;
991 FIXME( "(%p, %d): unknown type.\n", hdc
, type
);
994 release_dc_ptr( dc
);
999 /***********************************************************************
1000 * NtGdiUnrealizeObject (win32u.@)
1002 BOOL WINAPI
NtGdiUnrealizeObject( HGDIOBJ obj
)
1004 const struct gdi_obj_funcs
*funcs
= NULL
;
1005 GDI_HANDLE_ENTRY
*entry
;
1007 pthread_mutex_lock( &gdi_lock
);
1008 if ((entry
= handle_entry( obj
)))
1010 funcs
= entry_obj( entry
)->funcs
;
1011 obj
= entry_to_handle( entry
); /* make it a full handle */
1013 pthread_mutex_unlock( &gdi_lock
);
1015 if (funcs
&& funcs
->pUnrealizeObject
) return funcs
->pUnrealizeObject( obj
);
1016 return funcs
!= NULL
;
1020 /***********************************************************************
1021 * NtGdiFlush (win32u.@)
1023 BOOL WINAPI
NtGdiFlush(void)
1025 return TRUE
; /* FIXME */
1029 /*******************************************************************
1030 * NtGdiGetColorAdjustment (win32u.@)
1032 BOOL WINAPI
NtGdiGetColorAdjustment( HDC hdc
, COLORADJUSTMENT
*ca
)
1038 /*******************************************************************
1039 * NtGdiSetColorAdjustment (win32u.@)
1041 BOOL WINAPI
NtGdiSetColorAdjustment( HDC hdc
, const COLORADJUSTMENT
*ca
)
1048 static struct unix_funcs unix_funcs
=
1058 NtGdiComputeXformCoefficients
,
1059 NtGdiCreateCompatibleBitmap
,
1060 NtGdiCreateCompatibleDC
,
1061 NtGdiCreateDIBitmapInternal
,
1062 NtGdiCreateMetafileDC
,
1063 NtGdiDdDDICheckVidPnExclusiveOwnership
,
1064 NtGdiDdDDICreateDCFromMemory
,
1065 NtGdiDdDDIDestroyDCFromMemory
,
1066 NtGdiDdDDIDestroyDevice
,
1068 NtGdiDdDDISetVidPnSourceOwner
,
1069 NtGdiDeleteObjectApp
,
1076 NtGdiExcludeClipRect
,
1080 NtGdiExtSelectClipRgn
,
1085 NtGdiGetAndSetDCDword
,
1088 NtGdiGetCharABCWidthsW
,
1090 NtGdiGetCharWidthInfo
,
1091 NtGdiGetDIBitsInternal
,
1093 NtGdiGetDeviceGammaRamp
,
1095 NtGdiGetFontUnicodeRanges
,
1096 NtGdiGetGlyphIndicesW
,
1097 NtGdiGetGlyphOutline
,
1098 NtGdiGetKerningPairs
,
1099 NtGdiGetNearestColor
,
1100 NtGdiGetOutlineTextMetricsInternalW
,
1103 NtGdiGetRasterizerCaps
,
1104 NtGdiGetRealizationInfo
,
1105 NtGdiGetTextCharsetInfo
,
1106 NtGdiGetTextExtentExW
,
1108 NtGdiGetTextMetricsW
,
1110 NtGdiIntersectClipRect
,
1114 NtGdiModifyWorldTransform
,
1129 NtGdiScaleViewportExtEx
,
1130 NtGdiScaleWindowExtEx
,
1133 NtGdiSelectClipPath
,
1137 NtGdiSetDIBitsToDeviceInternal
,
1138 NtGdiSetDeviceGammaRamp
,
1141 NtGdiSetSystemPaletteUse
,
1145 NtGdiStretchDIBitsInternal
,
1146 NtGdiStrokeAndFillPath
,
1148 NtGdiTransparentBlt
,
1149 NtGdiUnrealizeObject
,
1152 NtUserActivateKeyboardLayout
,
1155 NtUserChangeDisplaySettings
,
1156 NtUserCountClipboardFormats
,
1157 NtUserEnumDisplayDevices
,
1158 NtUserEnumDisplayMonitors
,
1159 NtUserEnumDisplaySettings
,
1160 NtUserGetDisplayConfigBufferSizes
,
1161 NtUserGetKeyNameText
,
1162 NtUserGetKeyboardLayoutList
,
1163 NtUserGetPriorityClipboardFormat
,
1164 NtUserGetUpdatedClipboardFormats
,
1165 NtUserIsClipboardFormatAvailable
,
1166 NtUserMapVirtualKeyEx
,
1168 NtUserSelectPalette
,
1171 NtUserSystemParametersInfo
,
1172 NtUserSystemParametersInfoForDpi
,
1174 NtUserUnregisterHotKey
,
1181 __wine_get_brush_bitmap_info
,
1182 __wine_get_file_outline_text_metric
,
1183 __wine_get_icm_profile
,
1184 __wine_get_vulkan_driver
,
1185 __wine_get_wgl_driver
,
1186 __wine_set_display_driver
,
1187 __wine_set_visible_region
,
1190 NTSTATUS
gdi_init(void)
1192 pthread_mutexattr_t attr
;
1195 pthread_mutexattr_init( &attr
);
1196 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
1197 pthread_mutex_init( &gdi_lock
, &attr
);
1198 pthread_mutexattr_destroy( &attr
);
1200 NtQuerySystemInformation( SystemBasicInformation
, &system_info
, sizeof(system_info
), NULL
);
1202 if (!gdi_shared
) return STATUS_NO_MEMORY
;
1205 init_stock_objects( dpi
);
1209 NTSTATUS
callbacks_init( void *args
)
1211 user_callbacks
= *(const struct user_callbacks
**)args
;
1212 *(const struct unix_funcs
**)args
= &unix_funcs
;