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