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 )
491 csi
.ciCharset
= ANSI_CHARSET
;
492 if ( !translate_charset_info( ULongToPtr(ansi_cp
.CodePage
), &csi
, TCI_SRCCODEPAGE
) )
494 FIXME( "unhandled codepage %u - use ANSI_CHARSET for default stock objects\n", ansi_cp
.CodePage
);
498 return csi
.ciCharset
;
502 /***********************************************************************
505 * Retrieve the reference count of a GDI object.
506 * Note: the object must be locked otherwise the count is meaningless.
508 UINT
GDI_get_ref_count( HGDIOBJ handle
)
510 GDI_HANDLE_ENTRY
*entry
;
513 pthread_mutex_lock( &gdi_lock
);
514 if ((entry
= handle_entry( handle
))) ret
= entry_obj( entry
)->selcount
;
515 pthread_mutex_unlock( &gdi_lock
);
520 /***********************************************************************
523 * Increment the reference count of a GDI object.
525 HGDIOBJ
GDI_inc_ref_count( HGDIOBJ handle
)
527 GDI_HANDLE_ENTRY
*entry
;
529 pthread_mutex_lock( &gdi_lock
);
530 if ((entry
= handle_entry( handle
))) entry_obj( entry
)->selcount
++;
532 pthread_mutex_unlock( &gdi_lock
);
537 /***********************************************************************
540 * Decrement the reference count of a GDI object.
542 BOOL
GDI_dec_ref_count( HGDIOBJ handle
)
544 GDI_HANDLE_ENTRY
*entry
;
546 pthread_mutex_lock( &gdi_lock
);
547 if ((entry
= handle_entry( handle
)))
549 assert( entry_obj( entry
)->selcount
);
550 if (!--entry_obj( entry
)->selcount
&& entry_obj( entry
)->deleted
)
552 /* handle delayed DeleteObject*/
553 entry_obj( entry
)->deleted
= 0;
554 pthread_mutex_unlock( &gdi_lock
);
555 TRACE( "executing delayed DeleteObject for %p\n", handle
);
556 NtGdiDeleteObjectApp( handle
);
560 pthread_mutex_unlock( &gdi_lock
);
561 return entry
!= NULL
;
565 static HFONT
create_font( const LOGFONTW
*deffont
)
569 memset( &lf
, 0, sizeof(lf
) );
570 lf
.elfEnumLogfontEx
.elfLogFont
= *deffont
;
571 return NtGdiHfontCreate( &lf
, sizeof(lf
), 0, 0, NULL
);
574 static HFONT
create_scaled_font( const LOGFONTW
*deffont
, unsigned int dpi
)
579 lf
.lfHeight
= muldiv( lf
.lfHeight
, dpi
, 96 );
580 return create_font( &lf
);
583 static void init_gdi_shared(void)
585 SIZE_T size
= sizeof(*gdi_shared
);
587 if (NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&gdi_shared
, 0, &size
,
588 MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
))
590 next_unused
= gdi_shared
->Handles
+ FIRST_GDI_HANDLE
;
593 if (NtCurrentTeb()->GdiBatchCount
)
595 TEB64
*teb64
= (TEB64
*)(UINT_PTR
)NtCurrentTeb()->GdiBatchCount
;
596 PEB64
*peb64
= (PEB64
*)(UINT_PTR
)teb64
->Peb
;
597 peb64
->GdiSharedHandleTable
= (UINT_PTR
)gdi_shared
;
601 /* NOTE: Windows uses 32-bit for 32-bit kernel */
602 NtCurrentTeb()->Peb
->GdiSharedHandleTable
= gdi_shared
;
605 HGDIOBJ
get_stock_object( INT obj
)
607 assert( obj
>= 0 && obj
<= STOCK_LAST
+ 1 && obj
!= 9 );
612 if (get_system_dpi() != 96) obj
= 9;
615 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 2;
617 case SYSTEM_FIXED_FONT
:
618 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 3;
620 case DEFAULT_GUI_FONT
:
621 if (get_system_dpi() != 96) obj
= STOCK_LAST
+ 4;
625 return entry_to_handle( handle_entry( ULongToHandle( obj
+ FIRST_GDI_HANDLE
)));
628 static void init_stock_objects( unsigned int dpi
)
630 const struct DefaultFontInfo
*deffonts
;
634 /* Create stock objects in order matching stock object macros,
635 * so that they use predictable handle slots. Our GetStockObject
637 create_brush( &WhiteBrush
);
638 create_brush( &LtGrayBrush
);
639 create_brush( &GrayBrush
);
640 create_brush( &DkGrayBrush
);
641 create_brush( &BlackBrush
);
642 create_brush( &NullBrush
);
644 create_pen( PS_SOLID
, 0, RGB(255,255,255) );
645 create_pen( PS_SOLID
, 0, RGB(0,0,0) );
646 create_pen( PS_NULL
, 0, RGB(0,0,0) );
648 /* slot 9 is not used for non-scaled stock objects */
649 create_scaled_font( &OEMFixedFont
, dpi
);
651 /* language-independent stock fonts */
652 create_font( &OEMFixedFont
);
653 create_font( &AnsiFixedFont
);
654 create_font( &AnsiVarFont
);
656 /* language-dependent stock fonts */
657 deffonts
= get_default_fonts(get_default_charset());
658 create_font( &deffonts
->SystemFont
);
659 create_font( &deffonts
->DeviceDefaultFont
);
663 create_font( &deffonts
->SystemFixedFont
);
664 create_font( &deffonts
->DefaultGuiFont
);
666 create_brush( &DCBrush
);
667 NtGdiCreatePen( PS_SOLID
, 0, RGB(0,0,0), NULL
);
669 obj
= NtGdiCreateBitmap( 1, 1, 1, 1, NULL
);
671 assert( (HandleToULong( obj
) & 0xffff) == FIRST_GDI_HANDLE
+ DEFAULT_BITMAP
);
673 create_scaled_font( &deffonts
->SystemFont
, dpi
);
674 create_scaled_font( &deffonts
->SystemFixedFont
, dpi
);
675 create_scaled_font( &deffonts
->DefaultGuiFont
, dpi
);
677 /* clear the NOSYSTEM bit on all stock objects*/
678 for (i
= 0; i
< STOCK_LAST
+ 5; i
++)
680 GDI_HANDLE_ENTRY
*entry
= &gdi_shared
->Handles
[FIRST_GDI_HANDLE
+ i
];
681 entry_obj( entry
)->system
= TRUE
;
682 entry
->StockFlag
= 1;
687 static const char *gdi_obj_type( unsigned type
)
691 case NTGDI_OBJ_PEN
: return "NTGDI_OBJ_PEN";
692 case NTGDI_OBJ_BRUSH
: return "NTGDI_OBJ_BRUSH";
693 case NTGDI_OBJ_DC
: return "NTGDI_OBJ_DC";
694 case NTGDI_OBJ_METADC
: return "NTGDI_OBJ_METADC";
695 case NTGDI_OBJ_PAL
: return "NTGDI_OBJ_PAL";
696 case NTGDI_OBJ_FONT
: return "NTGDI_OBJ_FONT";
697 case NTGDI_OBJ_BITMAP
: return "NTGDI_OBJ_BITMAP";
698 case NTGDI_OBJ_REGION
: return "NTGDI_OBJ_REGION";
699 case NTGDI_OBJ_METAFILE
: return "NTGDI_OBJ_METAFILE";
700 case NTGDI_OBJ_MEMDC
: return "NTGDI_OBJ_MEMDC";
701 case NTGDI_OBJ_EXTPEN
: return "NTGDI_OBJ_EXTPEN";
702 case NTGDI_OBJ_ENHMETADC
: return "NTGDI_OBJ_ENHMETADC";
703 case NTGDI_OBJ_ENHMETAFILE
: return "NTGDI_OBJ_ENHMETAFILE";
704 default: return "UNKNOWN";
708 static void dump_gdi_objects( void )
710 GDI_HANDLE_ENTRY
*entry
;
712 TRACE( "%u objects:\n", GDI_MAX_HANDLE_COUNT
);
714 pthread_mutex_lock( &gdi_lock
);
715 for (entry
= gdi_shared
->Handles
; entry
< next_unused
; entry
++)
718 TRACE( "handle %p FREE\n", entry_to_handle( entry
));
720 TRACE( "handle %p obj %s type %s selcount %u deleted %u\n",
721 entry_to_handle( entry
), wine_dbgstr_longlong( entry
->Object
),
722 gdi_obj_type( entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
),
723 entry_obj( entry
)->selcount
, entry_obj( entry
)->deleted
);
725 pthread_mutex_unlock( &gdi_lock
);
728 /***********************************************************************
731 * Allocate a GDI handle for an object, which must have been allocated on the process heap.
733 HGDIOBJ
alloc_gdi_handle( struct gdi_obj_header
*obj
, DWORD type
, const struct gdi_obj_funcs
*funcs
)
735 GDI_HANDLE_ENTRY
*entry
;
738 assert( type
); /* type 0 is reserved to mark free entries */
740 pthread_mutex_lock( &gdi_lock
);
744 next_free
= (GDI_HANDLE_ENTRY
*)(UINT_PTR
)entry
->Object
;
745 else if (next_unused
< gdi_shared
->Handles
+ GDI_MAX_HANDLE_COUNT
)
746 entry
= next_unused
++;
749 pthread_mutex_unlock( &gdi_lock
);
750 ERR( "out of GDI object handles, expect a crash\n" );
751 if (TRACE_ON(gdi
)) dump_gdi_objects();
758 entry
->Object
= (UINT_PTR
)obj
;
759 entry
->ExtType
= type
>> NTGDI_HANDLE_TYPE_SHIFT
;
760 entry
->Type
= entry
->ExtType
& 0x1f;
761 if (++entry
->Generation
== 0xff) entry
->Generation
= 1;
762 ret
= entry_to_handle( entry
);
763 pthread_mutex_unlock( &gdi_lock
);
764 TRACE( "allocated %s %p %u/%u\n", gdi_obj_type(type
), ret
,
765 InterlockedIncrement( &debug_count
), GDI_MAX_HANDLE_COUNT
);
770 /***********************************************************************
773 * Free a GDI handle and return a pointer to the object.
775 void *free_gdi_handle( HGDIOBJ handle
)
778 GDI_HANDLE_ENTRY
*entry
;
780 pthread_mutex_lock( &gdi_lock
);
781 if ((entry
= handle_entry( handle
)))
783 TRACE( "freed %s %p %u/%u\n", gdi_obj_type( entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
),
784 handle
, InterlockedDecrement( &debug_count
) + 1, GDI_MAX_HANDLE_COUNT
);
785 object
= entry_obj( entry
);
787 entry
->Object
= (UINT_PTR
)next_free
;
790 pthread_mutex_unlock( &gdi_lock
);
794 DWORD
get_gdi_object_type( HGDIOBJ obj
)
796 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
797 return entry
? entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
: 0;
800 void set_gdi_client_ptr( HGDIOBJ obj
, void *ptr
)
802 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
803 if (entry
) entry
->UserPointer
= (UINT_PTR
)ptr
;
806 /***********************************************************************
809 * Return a pointer to, and the type of, the GDI object
810 * associated with the handle.
811 * The object must be released with GDI_ReleaseObj.
813 void *get_any_obj_ptr( HGDIOBJ handle
, DWORD
*type
)
816 GDI_HANDLE_ENTRY
*entry
;
818 pthread_mutex_lock( &gdi_lock
);
820 if ((entry
= handle_entry( handle
)))
822 ptr
= entry_obj( entry
);
823 *type
= entry
->ExtType
<< NTGDI_HANDLE_TYPE_SHIFT
;
826 if (!ptr
) pthread_mutex_unlock( &gdi_lock
);
830 /***********************************************************************
833 * Return a pointer to the GDI object associated with the handle.
834 * Return NULL if the object has the wrong type.
835 * The object must be released with GDI_ReleaseObj.
837 void *GDI_GetObjPtr( HGDIOBJ handle
, DWORD type
)
840 void *ptr
= get_any_obj_ptr( handle
, &ret_type
);
841 if (ptr
&& ret_type
!= type
)
843 GDI_ReleaseObj( handle
);
849 /***********************************************************************
853 void GDI_ReleaseObj( HGDIOBJ handle
)
855 pthread_mutex_unlock( &gdi_lock
);
859 /***********************************************************************
860 * NtGdiDeleteObjectApp (win32u.@)
862 * Delete a Gdi object.
865 * obj [I] Gdi object to delete
868 * Success: TRUE. If obj was not returned from GetStockObject(), any resources
869 * it consumed are released.
870 * Failure: FALSE, if obj is not a valid Gdi object, or is currently selected
873 BOOL WINAPI
NtGdiDeleteObjectApp( HGDIOBJ obj
)
875 GDI_HANDLE_ENTRY
*entry
;
876 const struct gdi_obj_funcs
*funcs
= NULL
;
877 struct gdi_obj_header
*header
;
879 pthread_mutex_lock( &gdi_lock
);
880 if (!(entry
= handle_entry( obj
)))
882 pthread_mutex_unlock( &gdi_lock
);
886 header
= entry_obj( entry
);
889 TRACE("Preserving system object %p\n", obj
);
890 pthread_mutex_unlock( &gdi_lock
);
894 obj
= entry_to_handle( entry
); /* make it a full handle */
896 if (header
->selcount
)
898 TRACE("delayed for %p because object in use, count %u\n", obj
, header
->selcount
);
899 header
->deleted
= 1; /* mark for delete */
901 else funcs
= header
->funcs
;
903 pthread_mutex_unlock( &gdi_lock
);
907 if (funcs
&& funcs
->pDeleteObject
) return funcs
->pDeleteObject( obj
);
911 /***********************************************************************
912 * NtGdiCreateClientObj (win32u.@)
914 HANDLE WINAPI
NtGdiCreateClientObj( ULONG type
)
916 struct gdi_obj_header
*obj
;
919 if (!(obj
= malloc( sizeof(*obj
) )))
922 handle
= alloc_gdi_handle( obj
, type
, NULL
);
923 if (!handle
) free( obj
);
927 /***********************************************************************
928 * NtGdiDeleteClientObj (win32u.@)
930 BOOL WINAPI
NtGdiDeleteClientObj( HGDIOBJ handle
)
933 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
939 /***********************************************************************
940 * NtGdiExtGetObjectW (win32u.@)
942 INT WINAPI
NtGdiExtGetObjectW( HGDIOBJ handle
, INT count
, void *buffer
)
944 GDI_HANDLE_ENTRY
*entry
;
945 const struct gdi_obj_funcs
*funcs
= NULL
;
948 TRACE("%p %d %p\n", handle
, count
, buffer
);
950 pthread_mutex_lock( &gdi_lock
);
951 if ((entry
= handle_entry( handle
)))
953 funcs
= entry_obj( entry
)->funcs
;
954 handle
= entry_to_handle( entry
); /* make it a full handle */
956 pthread_mutex_unlock( &gdi_lock
);
958 if (funcs
&& funcs
->pGetObjectW
)
960 if (buffer
&& ((ULONG_PTR
)buffer
>> 16) == 0) /* catch apps getting argument order wrong */
961 SetLastError( ERROR_NOACCESS
);
963 result
= funcs
->pGetObjectW( handle
, count
, buffer
);
968 /***********************************************************************
969 * NtGdiGetDCObject (win32u.@)
971 * Get the currently selected object of a given type in a device context.
973 HANDLE WINAPI
NtGdiGetDCObject( HDC hdc
, UINT type
)
978 if (!(dc
= get_dc_ptr( hdc
))) return 0;
982 case NTGDI_OBJ_EXTPEN
: /* fall through */
983 case NTGDI_OBJ_PEN
: ret
= dc
->hPen
; break;
984 case NTGDI_OBJ_BRUSH
: ret
= dc
->hBrush
; break;
985 case NTGDI_OBJ_PAL
: ret
= dc
->hPalette
; break;
986 case NTGDI_OBJ_FONT
: ret
= dc
->hFont
; break;
987 case NTGDI_OBJ_SURF
: ret
= dc
->hBitmap
; break;
989 FIXME( "(%p, %d): unknown type.\n", hdc
, type
);
992 release_dc_ptr( dc
);
997 /***********************************************************************
998 * NtGdiUnrealizeObject (win32u.@)
1000 BOOL WINAPI
NtGdiUnrealizeObject( HGDIOBJ obj
)
1002 const struct gdi_obj_funcs
*funcs
= NULL
;
1003 GDI_HANDLE_ENTRY
*entry
;
1005 pthread_mutex_lock( &gdi_lock
);
1006 if ((entry
= handle_entry( obj
)))
1008 funcs
= entry_obj( entry
)->funcs
;
1009 obj
= entry_to_handle( entry
); /* make it a full handle */
1011 pthread_mutex_unlock( &gdi_lock
);
1013 if (funcs
&& funcs
->pUnrealizeObject
) return funcs
->pUnrealizeObject( obj
);
1014 return funcs
!= NULL
;
1018 /***********************************************************************
1019 * NtGdiFlush (win32u.@)
1021 BOOL WINAPI
NtGdiFlush(void)
1023 return TRUE
; /* FIXME */
1027 /*******************************************************************
1028 * NtGdiGetColorAdjustment (win32u.@)
1030 BOOL WINAPI
NtGdiGetColorAdjustment( HDC hdc
, COLORADJUSTMENT
*ca
)
1036 /*******************************************************************
1037 * NtGdiSetColorAdjustment (win32u.@)
1039 BOOL WINAPI
NtGdiSetColorAdjustment( HDC hdc
, const COLORADJUSTMENT
*ca
)
1046 static struct unix_funcs unix_funcs
=
1056 NtGdiComputeXformCoefficients
,
1057 NtGdiCreateCompatibleBitmap
,
1058 NtGdiCreateCompatibleDC
,
1059 NtGdiCreateDIBitmapInternal
,
1060 NtGdiCreateMetafileDC
,
1061 NtGdiDdDDICheckVidPnExclusiveOwnership
,
1062 NtGdiDdDDICreateDCFromMemory
,
1063 NtGdiDdDDIDestroyDCFromMemory
,
1064 NtGdiDdDDIDestroyDevice
,
1066 NtGdiDdDDISetVidPnSourceOwner
,
1067 NtGdiDeleteObjectApp
,
1074 NtGdiExcludeClipRect
,
1078 NtGdiExtSelectClipRgn
,
1083 NtGdiGetAndSetDCDword
,
1086 NtGdiGetCharABCWidthsW
,
1088 NtGdiGetCharWidthInfo
,
1089 NtGdiGetDIBitsInternal
,
1091 NtGdiGetDeviceGammaRamp
,
1093 NtGdiGetFontUnicodeRanges
,
1094 NtGdiGetGlyphIndicesW
,
1095 NtGdiGetGlyphOutline
,
1096 NtGdiGetKerningPairs
,
1097 NtGdiGetNearestColor
,
1098 NtGdiGetOutlineTextMetricsInternalW
,
1101 NtGdiGetRasterizerCaps
,
1102 NtGdiGetRealizationInfo
,
1103 NtGdiGetTextCharsetInfo
,
1104 NtGdiGetTextExtentExW
,
1106 NtGdiGetTextMetricsW
,
1108 NtGdiIntersectClipRect
,
1112 NtGdiModifyWorldTransform
,
1127 NtGdiScaleViewportExtEx
,
1128 NtGdiScaleWindowExtEx
,
1131 NtGdiSelectClipPath
,
1135 NtGdiSetDIBitsToDeviceInternal
,
1136 NtGdiSetDeviceGammaRamp
,
1139 NtGdiSetSystemPaletteUse
,
1143 NtGdiStretchDIBitsInternal
,
1144 NtGdiStrokeAndFillPath
,
1146 NtGdiTransparentBlt
,
1147 NtGdiUnrealizeObject
,
1150 NtUserActivateKeyboardLayout
,
1153 NtUserCallHwndParam
,
1154 NtUserCallNextHookEx
,
1158 NtUserChangeDisplaySettings
,
1160 NtUserCloseClipboard
,
1161 NtUserCountClipboardFormats
,
1162 NtUserCreateWindowEx
,
1163 NtUserDeferWindowPosAndBand
,
1164 NtUserDestroyCursor
,
1166 NtUserDestroyWindow
,
1167 NtUserDispatchMessage
,
1169 NtUserEndDeferWindowPosEx
,
1171 NtUserEnumDisplayDevices
,
1172 NtUserEnumDisplayMonitors
,
1173 NtUserEnumDisplaySettings
,
1174 NtUserFlashWindowEx
,
1175 NtUserGetAsyncKeyState
,
1176 NtUserGetClassInfoEx
,
1177 NtUserGetCursorInfo
,
1179 NtUserGetDisplayConfigBufferSizes
,
1181 NtUserGetKeyNameText
,
1182 NtUserGetKeyboardLayoutList
,
1184 NtUserGetPriorityClipboardFormat
,
1185 NtUserGetQueueStatus
,
1186 NtUserGetUpdateRect
,
1188 NtUserGetUpdatedClipboardFormats
,
1189 NtUserIsClipboardFormatAvailable
,
1190 NtUserMapVirtualKeyEx
,
1193 NtUserMsgWaitForMultipleObjectsEx
,
1196 NtUserPostThreadMessage
,
1198 NtUserRegisterClassExWOW
,
1199 NtUserRegisterHotKey
,
1202 NtUserSelectPalette
,
1204 NtUserSetActiveWindow
,
1207 NtUserSetClassLongPtr
,
1210 NtUserSetCursorIconData
,
1213 NtUserSetLayeredWindowAttributes
,
1216 NtUserSetWindowLong
,
1217 NtUserSetWindowLongPtr
,
1220 NtUserSetWindowWord
,
1223 NtUserShowWindowAsync
,
1224 NtUserSystemParametersInfo
,
1225 NtUserSystemParametersInfoForDpi
,
1227 NtUserUnregisterClass
,
1228 NtUserUnregisterHotKey
,
1229 NtUserUpdateLayeredWindow
,
1231 NtUserWaitForInputIdle
,
1232 NtUserWindowFromPoint
,
1235 __wine_get_brush_bitmap_info
,
1236 __wine_get_file_outline_text_metric
,
1237 __wine_get_icm_profile
,
1238 __wine_get_vulkan_driver
,
1239 __wine_get_wgl_driver
,
1241 __wine_set_user_driver
,
1244 NTSTATUS
gdi_init(void)
1246 pthread_mutexattr_t attr
;
1249 pthread_mutexattr_init( &attr
);
1250 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
1251 pthread_mutex_init( &gdi_lock
, &attr
);
1252 pthread_mutexattr_destroy( &attr
);
1254 NtQuerySystemInformation( SystemBasicInformation
, &system_info
, sizeof(system_info
), NULL
);
1256 if (!gdi_shared
) return STATUS_NO_MEMORY
;
1259 init_stock_objects( dpi
);
1263 NTSTATUS
callbacks_init( void *args
)
1265 user_callbacks
= *(const struct user_callbacks
**)args
;
1266 *(const struct unix_funcs
**)args
= &unix_funcs
;