branch update for HEAD-2003050101
[reactos.git] / subsys / win32k / objects / gdiobj.c
1 /*
2  * GDIOBJ.C - GDI object manipulation routines
3  *
4  * $Id$
5  *
6  */
7
8 #undef WIN32_LEAN_AND_MEAN
9 #include <windows.h>
10 #include <ddk/ntddk.h>
11 #include <include/dce.h>
12 #include <win32k/gdiobj.h>
13 #include <win32k/brush.h>
14 #include <win32k/pen.h>
15 #include <win32k/text.h>
16 #include <win32k/dc.h>
17 #include <win32k/bitmaps.h>
18 #include <win32k/region.h>
19 #define NDEBUG
20 #include <win32k/debug1.h>
21
22 //  GDI stock objects
23
24 static LOGBRUSH WhiteBrush =
25 { BS_SOLID, RGB(255,255,255), 0 };
26
27 static LOGBRUSH LtGrayBrush =
28 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
29 { BS_SOLID, RGB(192,192,192), 0 };
30
31 static LOGBRUSH GrayBrush =
32 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
33 { BS_SOLID, RGB(128,128,128), 0 };
34
35 static LOGBRUSH DkGrayBrush =
36 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
37 /* NB_HATCH_STYLES is an index into HatchBrushes */
38 { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES };
39
40 static LOGBRUSH BlackBrush =
41 { BS_SOLID, RGB(0,0,0), 0 };
42
43 static LOGBRUSH NullBrush =
44 { BS_NULL, 0, 0 };
45
46 static LOGPEN WhitePen =
47 { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
48
49 static LOGPEN BlackPen =
50 { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
51
52 static LOGPEN NullPen =
53 { PS_NULL, { 0, 0 }, 0 };
54
55 static LOGFONTW OEMFixedFont =
56 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
57   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
58
59 /* Filler to make the location counter dword aligned again.  This is necessary
60    since (a) LOGFONT is packed, (b) gcc places initialised variables in the code
61    segment, and (c) Solaris assembler is stupid.  */
62 static UINT align_OEMFixedFont = 1;
63
64 static LOGFONTW AnsiFixedFont =
65 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
66   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
67
68 static UINT align_AnsiFixedFont = 1;
69
70 static LOGFONTW AnsiVarFont =
71 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
72   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
73
74 static UINT align_AnsiVarFont = 1;
75
76 static LOGFONTW SystemFont =
77 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
78   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"System" };
79
80 static UINT align_SystemFont = 1;
81
82 static LOGFONTW DeviceDefaultFont =
83 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
84   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"" };
85
86 static UINT align_DeviceDefaultFont = 1;
87
88 static LOGFONTW SystemFixedFont =
89 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
90   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
91
92 static UINT align_SystemFixedFont = 1;
93
94 /* FIXME: Is this correct? */
95 static LOGFONTW DefaultGuiFont =
96 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
97   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
98
99 static UINT align_DefaultGuiFont = 1;
100
101 static HGDIOBJ *StockObjects[NB_STOCK_OBJECTS]; // we dont assign these statically as WINE does because we might redesign
102                                                 // the way handles work, so it's more dynamic now
103
104
105 HBITMAP hPseudoStockBitmap; /*! 1x1 bitmap for memory DCs */
106
107 static PGDI_HANDLE_TABLE  HandleTable = 0;
108 static FAST_MUTEX  HandleTableMutex;
109 static FAST_MUTEX  RefCountHandling;
110
111 /*! Size of the GDI handle table
112  * per http://www.wd-mag.com/articles/1999/9902/9902b/9902b.htm?topic=articles
113  * gdi handle table can hold 0x4000 handles
114 */
115 #define GDI_HANDLE_NUMBER  0x4000
116
117 /*!
118  * Allocate GDI object table.
119  * \param       Size - number of entries in the object table.
120 */
121 static PGDI_HANDLE_TABLE
122 GDIOBJ_iAllocHandleTable (WORD Size)
123 {
124   PGDI_HANDLE_TABLE  handleTable;
125
126   ExAcquireFastMutexUnsafe (&HandleTableMutex);
127   handleTable = ExAllocatePool(PagedPool,
128                                sizeof (GDI_HANDLE_TABLE) +
129                                  sizeof (GDI_HANDLE_ENTRY) * Size);
130   ASSERT( handleTable );
131   memset (handleTable,
132           0,
133           sizeof (GDI_HANDLE_TABLE) + sizeof (GDI_HANDLE_ENTRY) * Size);
134   handleTable->wTableSize = Size;
135   ExReleaseFastMutexUnsafe (&HandleTableMutex);
136
137   return  handleTable;
138 }
139
140 /*!
141  * Returns the entry into the handle table by index.
142 */
143 static PGDI_HANDLE_ENTRY
144 GDIOBJ_iGetHandleEntryForIndex (WORD TableIndex)
145 {
146   //DPRINT("GDIOBJ_iGetHandleEntryForIndex: TableIndex: %d,\n handle: %x, ptr: %x\n", TableIndex, HandleTable->Handles [TableIndex], &(HandleTable->Handles [TableIndex])  );
147   //DPRINT("GIG: HandleTable: %x, Handles: %x, \n TableIndex: %x, pt: %x\n", HandleTable,  HandleTable->Handles, TableIndex, ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex));
148   //DPRINT("GIG: Hndl: %x, mag: %x\n", ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex), ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex)->wMagic);
149   return  ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex);
150 }
151
152 /*!
153  * Finds next free entry in the GDI handle table.
154  * \return      index into the table is successful, zero otherwise.
155 */
156 static WORD
157 GDIOBJ_iGetNextOpenHandleIndex (void)
158 {
159   WORD  tableIndex;
160
161   ExAcquireFastMutexUnsafe (&HandleTableMutex);
162   for (tableIndex = 1; tableIndex < HandleTable->wTableSize; tableIndex++)
163   {
164     if (HandleTable->Handles [tableIndex].wMagic == 0)
165     {
166       HandleTable->Handles [tableIndex].wMagic = GO_MAGIC_DONTCARE;
167       break;
168     }
169   }
170   ExReleaseFastMutexUnsafe (&HandleTableMutex);
171
172   return  (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
173 }
174
175 /*!
176  * Allocate memory for GDI object and return handle to it.
177  *
178  * \param Size - size of the GDI object. This shouldn't to include the size of GDIOBJHDR.
179  * The actual amount of allocated memory is sizeof(GDIOBJHDR)+Size
180  * \param Magic - object magic (see GDI Magic)
181  *
182  * \return Handle of the allocated object.
183  *
184  * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
185 */
186 HGDIOBJ GDIOBJ_AllocObj(WORD Size, WORD Magic)
187 {
188         PGDIOBJHDR  newObject;
189         PGDI_HANDLE_ENTRY  handleEntry;
190
191         DPRINT("GDIOBJ_AllocObj: size: %d, magic: %x\n", Size, Magic);
192         newObject = ExAllocatePool (PagedPool, Size + sizeof (GDIOBJHDR));
193         if (newObject == NULL)
194         {
195           DPRINT("GDIOBJ_AllocObj: failed\n");
196           return  NULL;
197         }
198         RtlZeroMemory (newObject, Size + sizeof (GDIOBJHDR));
199
200         newObject->wTableIndex = GDIOBJ_iGetNextOpenHandleIndex ();
201         newObject->dwCount = 0;
202         handleEntry = GDIOBJ_iGetHandleEntryForIndex (newObject->wTableIndex);
203         handleEntry->wMagic = Magic;
204         handleEntry->hProcessId = PsGetCurrentProcessId ();
205         handleEntry->pObject = newObject;
206         DPRINT("GDIOBJ_AllocObj: object handle %d\n", newObject->wTableIndex );
207         return  (HGDIOBJ) newObject->wTableIndex;
208 }
209
210 /*!
211  * Free memory allocated for the GDI object. For each object type this function calls the
212  * appropriate cleanup routine.
213  *
214  * \param hObj - handle of the object to be deleted.
215  * \param Magic - object magic or GO_MAGIC_DONTCARE.
216  * \param Flag - if set to GDIOBJFLAG_IGNOREPID then the routine doesn't check if the process that
217  * tries to delete the object is the same one that created it.
218  *
219  * \return Returns TRUE if succesful.
220  *
221  * \note You should only use GDIOBJFLAG_IGNOREPID if you are cleaning up after the process that terminated.
222  * \note This function deferres object deletion if it is still in use.
223 */
224 BOOL  GDIOBJ_FreeObj(HGDIOBJ hObj, WORD Magic, DWORD Flag)
225 {
226         PGDIOBJHDR  objectHeader;
227         PGDI_HANDLE_ENTRY  handleEntry;
228         PGDIOBJ         Obj;
229         BOOL    bRet = TRUE;
230
231         handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)hObj & 0xffff);
232         DPRINT("GDIOBJ_FreeObj: hObj: %d, magic: %x, handleEntry: %x\n", (WORD)hObj & 0xffff, Magic, handleEntry );
233
234         if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
235              || ((handleEntry->hProcessId != PsGetCurrentProcessId()) && !(Flag & GDIOBJFLAG_IGNOREPID))){
236
237           DPRINT("Can't Delete hObj: %d, magic: %x, pid:%d\n currpid:%d, flag:%d, hmm:%d\n",(WORD)hObj & 0xffff, handleEntry->wMagic, handleEntry->hProcessId, PsGetCurrentProcessId(), (Flag&GDIOBJFLAG_IGNOREPID), ((handleEntry->hProcessId != PsGetCurrentProcessId()) && !(Flag&GDIOBJFLAG_IGNOREPID)) );
238           return  FALSE;
239         }
240
241         objectHeader = (PGDIOBJHDR) handleEntry->pObject;
242         ASSERT(objectHeader);
243         DPRINT("FreeObj: locks: %x\n", objectHeader->dwCount );
244         if( !(Flag & GDIOBJFLAG_IGNORELOCK) ){
245                 // check that the reference count is zero. if not then set flag
246                 // and delete object when releaseobj is called
247                 ExAcquireFastMutex(&RefCountHandling);
248                 if( ( objectHeader->dwCount & ~0x80000000 ) > 0 ){
249                         DPRINT("GDIOBJ_FreeObj: delayed object deletion: count %d\n", objectHeader->dwCount);
250                         objectHeader->dwCount |= 0x80000000;
251                         ExReleaseFastMutex(&RefCountHandling);
252                         return TRUE;
253                 }
254                 ExReleaseFastMutex(&RefCountHandling);
255         }
256
257         //allow object to delete internal data
258         Obj = (PGDIOBJ)((PCHAR)handleEntry->pObject + sizeof(GDIOBJHDR));
259         switch( handleEntry->wMagic ){
260                 case GO_REGION_MAGIC:
261                         bRet = RGNDATA_InternalDelete( (PROSRGNDATA) Obj );
262                         break;
263                 case GO_BITMAP_MAGIC:
264                         bRet = Bitmap_InternalDelete( (PBITMAPOBJ) Obj );
265                         break;
266                 case GO_DC_MAGIC:
267                         bRet = DC_InternalDeleteDC( (PDC) Obj );
268                         break;
269                 case GO_PEN_MAGIC:
270                 case GO_PALETTE_MAGIC:
271                 case GO_DISABLED_DC_MAGIC:
272                 case GO_META_DC_MAGIC:
273                 case GO_METAFILE_MAGIC:
274                 case GO_METAFILE_DC_MAGIC:
275                 case GO_ENHMETAFILE_MAGIC:
276                 case GO_ENHMETAFILE_DC_MAGIC:
277
278                 case GO_BRUSH_MAGIC:
279                 case GO_FONT_MAGIC:
280                         break;
281                 case GO_DCE_MAGIC:
282                         bRet = DCE_InternalDelete( (PDCE) Obj );
283                         break;
284         }
285         handleEntry->hProcessId = 0;
286         ExFreePool (handleEntry->pObject);
287         handleEntry->pObject = 0;
288         handleEntry->wMagic = 0;
289
290         return  TRUE;
291 }
292
293 /*!
294  * Return pointer to the object by handle.
295  *
296  * \param hObj          Object handle
297  * \param Magic         one of the magic numbers defined in \ref GDI Magic
298  * \return                      Pointer to the object.
299  *
300  * \note Process can only get pointer to the objects it created or global objects.
301  *
302  * \todo Don't allow to lock the objects twice! Synchronization!
303 */
304 PGDIOBJ GDIOBJ_LockObj( HGDIOBJ hObj, WORD Magic )
305 {
306         PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
307         PGDIOBJHDR  objectHeader;
308
309         DPRINT("GDIOBJ_LockObj: hObj: %d, magic: %x, \n handleEntry: %x, mag %x\n", hObj, Magic, handleEntry, handleEntry->wMagic);
310         if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
311              || (handleEntry->hProcessId != (HANDLE)0xFFFFFFFF &&
312                  handleEntry->hProcessId != PsGetCurrentProcessId ())){
313           DPRINT("GDIBOJ_LockObj failed for %d, magic: %d, reqMagic\n",(WORD) hObj & 0xffff, handleEntry->wMagic, Magic);
314           return  NULL;
315         }
316
317         objectHeader = (PGDIOBJHDR) handleEntry->pObject;
318         ASSERT(objectHeader);
319         if( objectHeader->dwCount > 0 ){
320                 DbgPrint("Caution! GDIOBJ_LockObj trying to lock object second time\n" );
321                 DbgPrint("\t called from: %x\n", __builtin_return_address(0));
322         }
323
324         ExAcquireFastMutex(&RefCountHandling);
325         objectHeader->dwCount++;
326         ExReleaseFastMutex(&RefCountHandling);
327         return (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
328 }
329
330 /*!
331  * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be
332  * duplicates. You should use this function to avoid trying to lock the same object twice!
333  *
334  * \param       pList   pointer to the list that contains handles to the objects. You should set hObj and Magic fields.
335  * \param       nObj    number of objects to lock
336  * \return      for each entry in pList this function sets pObj field to point to the object.
337  *
338  * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
339 */
340 BOOL GDIOBJ_LockMultipleObj( PGDIMULTILOCK pList, INT nObj )
341 {
342         INT i, j;
343         ASSERT( pList );
344         //go through the list checking for duplicate objects
345         for( i = 0; i < nObj; i++ ){
346                 (pList+i)->pObj = NULL;
347                 for( j = 0; j < i; j++ ){
348                         if( ((pList+i)->hObj == (pList+j)->hObj)
349                           && ((pList+i)->Magic == (pList+j)->Magic) ){
350                                 //already locked, so just copy the pointer to the object
351                                 (pList+i)->pObj = (pList+j)->pObj;
352                                 break;
353                         }
354                 }
355                 if( (pList+i)->pObj == NULL ){
356                         //object hasn't been locked, so lock it.
357                         (pList+i)->pObj = GDIOBJ_LockObj( (pList+i)->hObj, (pList+i)->Magic );
358                 }
359         }
360         return TRUE;
361 }
362
363 /*!
364  * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
365  * as soon as you don't need to have access to it's data.
366
367  * \param hObj          Object handle
368  * \param Magic         one of the magic numbers defined in \ref GDI Magic
369  *
370  * \note This function performs delayed cleanup. If the object is locked when GDI_FreeObj() is called
371  * then \em this function frees the object when reference count is zero.
372  *
373  * \todo Change synchronization algorithm.
374 */
375 BOOL GDIOBJ_UnlockObj( HGDIOBJ hObj, WORD Magic )
376 {
377         PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
378         PGDIOBJHDR  objectHeader;
379
380         DPRINT("GDIOBJ_UnlockObj: hObj: %d, magic: %x, \n handleEntry: %x\n", hObj, Magic, handleEntry);
381         if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
382               || (handleEntry->hProcessId != (HANDLE)0xFFFFFFFF &&
383                  handleEntry->hProcessId != PsGetCurrentProcessId ())){
384           DPRINT( "GDIOBJ_UnLockObj: failed\n");
385           return  FALSE;
386         }
387
388         objectHeader = (PGDIOBJHDR) handleEntry->pObject;
389         ASSERT(objectHeader);
390
391         ExAcquireFastMutex(&RefCountHandling);
392         if( ( objectHeader->dwCount & ~0x80000000 ) == 0 ){
393                 ExReleaseFastMutex(&RefCountHandling);
394                 DPRINT( "GDIOBJ_UnLockObj: unlock object that is not locked\n" );
395                 return FALSE;
396         }
397
398         objectHeader = (PGDIOBJHDR) handleEntry->pObject;
399         ASSERT(objectHeader);
400         objectHeader->dwCount--;
401
402         if( objectHeader->dwCount  == 0x80000000 ){
403                 //delayed object release
404                 objectHeader->dwCount = 0;
405                 ExReleaseFastMutex(&RefCountHandling);
406                 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
407                 return GDIOBJ_FreeObj( hObj, Magic, GDIOBJFLAG_DEFAULT );
408         }
409         ExReleaseFastMutex(&RefCountHandling);
410         return TRUE;
411 }
412
413
414 /*!
415  * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be
416  * duplicates.
417  *
418  * \param       pList   pointer to the list that contains handles to the objects. You should set hObj and Magic fields.
419  * \param       nObj    number of objects to lock
420  *
421  * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
422 */
423 BOOL GDIOBJ_UnlockMultipleObj( PGDIMULTILOCK pList, INT nObj )
424 {
425         INT i, j;
426         ASSERT( pList );
427         //go through the list checking for duplicate objects
428         for( i = 0; i < nObj; i++ ){
429                 if( (pList+i)->pObj != NULL ){
430                         for( j = i+1; j < nObj; j++ ){
431                                 if( ((pList+i)->pObj == (pList+j)->pObj) ){
432                                         //set the pointer to zero for all duplicates
433                                         (pList+j)->pObj = NULL;
434                                 }
435                         }
436                         GDIOBJ_UnlockObj( (pList+i)->hObj, (pList+i)->Magic );
437                         (pList+i)->pObj = NULL;
438                 }
439         }
440         return TRUE;
441 }
442
443 /*!
444  * Marks the object as global. (Creator process ID is set to 0xFFFFFFFF). Global objects may be
445  * accessed by any process.
446  * \param       ObjectHandle - handle of the object to make global.
447  *
448  * \note        Only stock objects should be marked global.
449 */
450 VOID GDIOBJ_MarkObjectGlobal(HGDIOBJ ObjectHandle)
451 {
452   PGDI_HANDLE_ENTRY  handleEntry;
453
454   if (ObjectHandle == NULL)
455     return;
456
457   handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
458   if (handleEntry == 0)
459     return;
460
461   handleEntry->hProcessId = (HANDLE)0xFFFFFFFF;
462 }
463
464 /*!
465  * Get the type (magic value) of the object.
466  * \param       ObjectHandle - handle of the object.
467  * \return      GDI Magic value.
468 */
469 WORD  GDIOBJ_GetHandleMagic (HGDIOBJ ObjectHandle)
470 {
471   PGDI_HANDLE_ENTRY  handleEntry;
472
473   if (ObjectHandle == NULL)
474     return  0;
475
476   handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
477   if (handleEntry == 0 ||
478       (handleEntry->hProcessId != (HANDLE)0xFFFFFFFF &&
479        handleEntry->hProcessId != PsGetCurrentProcessId ()))
480     return  0;
481
482   return  handleEntry->wMagic;
483 }
484
485 /*!
486  * Initialization of the GDI object engine.
487 */
488 VOID
489 InitGdiObjectHandleTable (void)
490 {
491   DPRINT ("InitGdiObjectHandleTable\n");
492   ExInitializeFastMutex (&HandleTableMutex);
493   ExInitializeFastMutex (&RefCountHandling);
494
495   HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_NUMBER);
496   DPRINT("HandleTable: %x\n", HandleTable );
497
498   InitEngHandleTable();
499 }
500
501 /*!
502  * Creates a bunch of stock objects: brushes, pens, fonts.
503 */
504 VOID CreateStockObjects(void)
505 {
506   // Create GDI Stock Objects from the logical structures we've defined
507
508   StockObjects[WHITE_BRUSH] =  W32kCreateBrushIndirect(&WhiteBrush);
509   GDIOBJ_MarkObjectGlobal(StockObjects[WHITE_BRUSH]);
510   StockObjects[LTGRAY_BRUSH] = W32kCreateBrushIndirect(&LtGrayBrush);
511   GDIOBJ_MarkObjectGlobal(StockObjects[LTGRAY_BRUSH]);
512   StockObjects[GRAY_BRUSH] =   W32kCreateBrushIndirect(&GrayBrush);
513   GDIOBJ_MarkObjectGlobal(StockObjects[GRAY_BRUSH]);
514   StockObjects[DKGRAY_BRUSH] = W32kCreateBrushIndirect(&DkGrayBrush);
515   GDIOBJ_MarkObjectGlobal(StockObjects[DKGRAY_BRUSH]);
516   StockObjects[BLACK_BRUSH] =  W32kCreateBrushIndirect(&BlackBrush);
517   GDIOBJ_MarkObjectGlobal(StockObjects[BLACK_BRUSH]);
518   StockObjects[NULL_BRUSH] =   W32kCreateBrushIndirect(&NullBrush);
519   GDIOBJ_MarkObjectGlobal(StockObjects[NULL_BRUSH]);
520
521   StockObjects[WHITE_PEN] = W32kCreatePenIndirect(&WhitePen);
522   GDIOBJ_MarkObjectGlobal(StockObjects[WHITE_PEN]);
523   StockObjects[BLACK_PEN] = W32kCreatePenIndirect(&BlackPen);
524   GDIOBJ_MarkObjectGlobal(StockObjects[BLACK_PEN]);
525   StockObjects[NULL_PEN] =  W32kCreatePenIndirect(&NullPen);
526   GDIOBJ_MarkObjectGlobal(StockObjects[NULL_PEN]);
527
528   (void) TextIntCreateFontIndirect(&OEMFixedFont, &StockObjects[OEM_FIXED_FONT]);
529   GDIOBJ_MarkObjectGlobal(StockObjects[OEM_FIXED_FONT]);
530   (void) TextIntCreateFontIndirect(&AnsiFixedFont, &StockObjects[ANSI_FIXED_FONT]);
531   GDIOBJ_MarkObjectGlobal(StockObjects[ANSI_FIXED_FONT]);
532   (void) TextIntCreateFontIndirect(&SystemFont, &StockObjects[SYSTEM_FONT]);
533   GDIOBJ_MarkObjectGlobal(StockObjects[SYSTEM_FONT]);
534   (void) TextIntCreateFontIndirect(&DeviceDefaultFont, &StockObjects[DEVICE_DEFAULT_FONT]);
535   GDIOBJ_MarkObjectGlobal(StockObjects[DEVICE_DEFAULT_FONT]);
536   (void) TextIntCreateFontIndirect(&SystemFixedFont, &StockObjects[SYSTEM_FIXED_FONT]);
537   GDIOBJ_MarkObjectGlobal(StockObjects[SYSTEM_FIXED_FONT]);
538   (void) TextIntCreateFontIndirect(&DefaultGuiFont, &StockObjects[DEFAULT_GUI_FONT]);
539   GDIOBJ_MarkObjectGlobal(StockObjects[DEFAULT_GUI_FONT]);
540
541   StockObjects[DEFAULT_PALETTE] = (HGDIOBJ*)PALETTE_Init();
542 }
543
544 /*!
545  * Return stock object.
546  * \param       Object - stock object id.
547  * \return      Handle to the object.
548 */
549 HGDIOBJ STDCALL  W32kGetStockObject(INT  Object)
550 {
551   // check when adding new objects
552   if( (Object < 0) || (Object >= NB_STOCK_OBJECTS)  )
553         return NULL;
554   return StockObjects[Object];
555 }
556
557 /*!
558  * Delete GDI object
559  * \param       hObject object handle
560  * \return      if the function fails the returned value is NULL.
561 */
562 BOOL STDCALL  W32kDeleteObject(HGDIOBJ hObject)
563 {
564   return GDIOBJ_FreeObj( hObject, GO_MAGIC_DONTCARE, GDIOBJFLAG_DEFAULT );
565 }
566
567 /*!
568  * Internal function. Called when the process is destroyed to free the remaining GDI handles.
569  * \param       Process - PID of the process that was destroyed.
570 */
571 BOOL STDCALL W32kCleanupForProcess( INT Process )
572 {
573         DWORD i;
574         PGDI_HANDLE_ENTRY handleEntry;
575         PGDIOBJHDR  objectHeader;
576
577         for( i=1; i < GDI_HANDLE_NUMBER; i++ ){
578                 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) i & 0xffff);
579                 if( handleEntry && handleEntry->wMagic != 0 && handleEntry->hProcessId == Process){
580                         objectHeader = (PGDIOBJHDR) handleEntry->pObject;
581                         DPRINT("\nW32kCleanup: %d, magic: %x \n process: %d, locks: %d", i, handleEntry->wMagic, handleEntry->hProcessId, objectHeader->dwCount);
582                         GDIOBJ_FreeObj( (WORD) i & 0xffff, GO_MAGIC_DONTCARE, GDIOBJFLAG_IGNOREPID|GDIOBJFLAG_IGNORELOCK );
583                 }
584         }
585         return TRUE;
586 }
587
588 /*!
589  *      Internal function. Dumps all the objects for the given process.
590  * \param       If process == 0 dump all the objects.
591  *
592 */
593 VOID STDCALL W32kDumpGdiObjects( INT Process )
594 {
595         DWORD i;
596         PGDI_HANDLE_ENTRY handleEntry;
597         PGDIOBJHDR  objectHeader;
598
599         for( i=1; i < GDI_HANDLE_NUMBER; i++ ){
600                 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) i & 0xffff);
601                 if( handleEntry && handleEntry->wMagic != 0 ){
602                         objectHeader = (PGDIOBJHDR) handleEntry->pObject;
603                         DPRINT("\nHandle: %d, magic: %x \n process: %d, locks: %d", i, handleEntry->wMagic, handleEntry->hProcessId, objectHeader->dwCount);
604                 }
605         }
606
607 }