Release 980329
[wine] / windows / user.c
1 /*
2  * Misc. USER functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  *           1996 Alex Korobka 
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include "windows.h"
11 #include "resource.h"
12 #include "heap.h"
13 #include "gdi.h"
14 #include "user.h"
15 #include "task.h"
16 #include "queue.h"
17 #include "win.h"
18 #include "clipboard.h"
19 #include "hook.h"
20 #include "debug.h"
21 #include "toolhelp.h"
22 #include "message.h"
23 #include "shell.h"
24
25 WORD USER_HeapSel = 0;
26
27 extern BOOL32 MENU_PatchResidentPopup( HQUEUE16, WND* );
28 extern void QUEUE_FlushMessages(HQUEUE16);
29
30 /***********************************************************************
31  *           GetFreeSystemResources   (USER.284)
32  */
33 WORD WINAPI GetFreeSystemResources( WORD resType )
34 {
35     int userPercent, gdiPercent;
36
37     switch(resType)
38     {
39     case GFSR_USERRESOURCES:
40         userPercent = (int)LOCAL_CountFree( USER_HeapSel ) * 100 /
41                                LOCAL_HeapSize( USER_HeapSel );
42         gdiPercent  = 100;
43         break;
44
45     case GFSR_GDIRESOURCES:
46         gdiPercent  = (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
47                                LOCAL_HeapSize( GDI_HeapSel );
48         userPercent = 100;
49         break;
50
51     case GFSR_SYSTEMRESOURCES:
52         userPercent = (int)LOCAL_CountFree( USER_HeapSel ) * 100 /
53                                LOCAL_HeapSize( USER_HeapSel );
54         gdiPercent  = (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
55                                LOCAL_HeapSize( GDI_HeapSel );
56         break;
57
58     default:
59         return 0;
60     }
61     return (WORD)MIN( userPercent, gdiPercent );
62 }
63
64
65 /***********************************************************************
66  *           SystemHeapInfo   (TOOLHELP.71)
67  */
68 BOOL16 WINAPI SystemHeapInfo( SYSHEAPINFO *pHeapInfo )
69 {
70     pHeapInfo->wUserFreePercent = GetFreeSystemResources( GFSR_USERRESOURCES );
71     pHeapInfo->wGDIFreePercent  = GetFreeSystemResources( GFSR_GDIRESOURCES );
72     pHeapInfo->hUserSegment = USER_HeapSel;
73     pHeapInfo->hGDISegment  = GDI_HeapSel;
74     return TRUE;
75 }
76
77
78 /***********************************************************************
79  *           TimerCount   (TOOLHELP.80)
80  */
81 BOOL16 WINAPI TimerCount( TIMERINFO *pTimerInfo )
82 {
83     /* FIXME
84      * In standard mode, dwmsSinceStart = dwmsThisVM 
85      *
86      * I tested this, under Windows in enhanced mode, and
87      * if you never switch VM (ie start/stop DOS) these
88      * values should be the same as well. 
89      *
90      * Also, Wine should adjust for the hardware timer
91      * to reduce the amount of error to ~1ms. 
92      * I can't be bothered, can you?
93      */
94     pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
95     return TRUE;
96 }
97
98 static RESOURCEHANDLER16 __r16loader = NULL;
99
100 /**********************************************************************
101  *           USER_CallDefaultRsrcHandler
102  *
103  * Called by the LoadDIBIcon/CursorHandler().
104  */
105 HGLOBAL16 USER_CallDefaultRsrcHandler( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
106 {
107     return __r16loader( hMemObj, hModule, hRsrc );
108 }
109
110 /**********************************************************************
111  *           USER_InstallRsrcHandler
112  */
113 static void USER_InstallRsrcHandler( HINSTANCE16 hInstance )
114 {
115     FARPROC16 proc;
116
117     /* SetResourceHandler() returns previous function which is set
118      * when a module's resource table is loaded. */
119
120     proc = SetResourceHandler( hInstance, RT_ICON, (FARPROC32)LoadDIBIconHandler );
121     if(!__r16loader ) 
122         __r16loader = (RESOURCEHANDLER16)proc;
123     proc = SetResourceHandler( hInstance, RT_CURSOR, (FARPROC32)LoadDIBCursorHandler );
124     if(!__r16loader )
125         __r16loader = (RESOURCEHANDLER16)proc;
126 }
127
128 /**********************************************************************
129  *           InitApp   (USER.5)
130  */
131 INT16 WINAPI InitApp( HINSTANCE16 hInstance )
132 {
133     int queueSize;
134
135       /* InitTask() calls LibMain()'s of implicitly loaded DLLs 
136        * prior to InitApp() so there is no clean way to do
137        * SetTaskSignalHandler() in time. So, broken Windows bypasses 
138        * a pTask->userhandler on startup and simply calls a global 
139        * function pointer to the default USER signal handler.
140        */
141
142     USER_InstallRsrcHandler( hInstance );
143
144       /* Create task message queue */
145     queueSize = GetProfileInt32A( "windows", "DefaultQueueSize", 8 );
146     if (!SetMessageQueue32( queueSize )) return 0;
147
148     return 1;
149 }
150
151 /**********************************************************************
152  *           USER_ModuleUnload
153  */
154 static void USER_ModuleUnload( HMODULE16 hModule )
155 {
156     HOOK_FreeModuleHooks( hModule );
157     CLASS_FreeModuleClasses( hModule );
158 }
159
160 /**********************************************************************
161  *           USER_AppExit
162  */
163 static void USER_AppExit( HTASK16 hTask, HINSTANCE16 hInstance, HQUEUE16 hQueue )
164 {
165     /* FIXME: empty clipboard if needed, maybe destroy menus (Windows
166      *        only complains about them but does nothing);
167      */
168
169     WND* desktop = WIN_GetDesktop();
170
171     /* Patch desktop window */
172     if( desktop->hmemTaskQ == hQueue )
173         desktop->hmemTaskQ = GetTaskQueue(TASK_GetNextTask(hTask));
174
175     /* Patch resident popup menu window */
176     MENU_PatchResidentPopup( hQueue, NULL );
177
178     TIMER_RemoveQueueTimers( hQueue );
179
180     QUEUE_FlushMessages( hQueue );
181     HOOK_FreeQueueHooks( hQueue );
182
183     QUEUE_SetExitingQueue( hQueue );
184     WIN_ResetQueueWindows( desktop, hQueue, (HQUEUE16)0);
185     CLIPBOARD_ResetLock( hQueue, 0 );
186     QUEUE_SetExitingQueue( 0 );
187
188     /* Free the message queue */
189
190     QUEUE_DeleteMsgQueue( hQueue );
191
192     /* ModuleUnload() in "Internals" */
193
194     hInstance = GetExePtr( hInstance );
195     if( GetModuleUsage( hInstance ) <= 1 ) 
196         USER_ModuleUnload( hInstance );
197 }
198
199
200 /***********************************************************************
201  *           USER_ExitWindows
202  *
203  * Clean-up everything and exit the Wine process.
204  * This is the back-end of ExitWindows(), called when all windows
205  * have agreed to be terminated.
206  */
207 void USER_ExitWindows(void)
208 {
209     /* Do the clean-up stuff */
210
211     WriteOutProfiles();
212     SHELL_SaveRegistry();
213
214     exit(0);
215 }
216
217
218 /***********************************************************************
219  *           USER_SignalProc (USER.314)
220  */
221 void WINAPI USER_SignalProc( HANDLE16 hTaskOrModule, UINT16 uCode,
222                              UINT16 uExitFn, HINSTANCE16 hInstance,
223                              HQUEUE16 hQueue )
224 {
225     switch( uCode )
226     {
227         case USIG_GPF:
228         case USIG_TERMINATION:
229              USER_AppExit( hTaskOrModule, hInstance, hQueue ); /* task */
230              break;
231
232         case USIG_DLL_LOAD:
233              USER_InstallRsrcHandler( hTaskOrModule ); /* module */
234              break;
235
236         case USIG_DLL_UNLOAD:
237              USER_ModuleUnload( hTaskOrModule ); /* module */
238              break;
239
240         default:
241              fprintf(stderr,"Unimplemented USER signal: %i\n", (int)uCode );
242     }
243 }
244
245
246 /***********************************************************************
247  *           ExitWindows16   (USER.7)
248  */
249 BOOL16 WINAPI ExitWindows16( DWORD dwReturnCode, UINT16 wReserved )
250 {
251     return ExitWindowsEx( EWX_LOGOFF, 0xffffffff );
252 }
253
254
255 /***********************************************************************
256  *           ExitWindowsExec16   (USER.246)
257  */
258 BOOL16 WINAPI ExitWindowsExec16( LPCSTR lpszExe, LPCSTR lpszParams )
259 {
260     fprintf(stderr, "ExitWindowsExec() : Should run the following in DOS-mode :\n\t\"%s %s\"\n",
261         lpszExe, lpszParams);
262     return ExitWindowsEx( EWX_LOGOFF, 0xffffffff );
263 }
264
265
266 /***********************************************************************
267  *           ExitWindowsEx   (USER32.195)
268  */
269 BOOL32 WINAPI ExitWindowsEx( UINT32 flags, DWORD reserved )
270 {
271     int i;
272     BOOL32 result;
273     WND **list, **ppWnd;
274         
275     /* We have to build a list of all windows first, as in EnumWindows */
276
277     if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) return FALSE;
278
279     /* Send a WM_QUERYENDSESSION message to every window */
280
281     for (ppWnd = list, i = 0; *ppWnd; ppWnd++, i++)
282     {
283         /* Make sure that the window still exists */
284         if (!IsWindow32( (*ppWnd)->hwndSelf )) continue;
285         if (!SendMessage16( (*ppWnd)->hwndSelf, WM_QUERYENDSESSION, 0, 0 ))
286             break;
287     }
288     result = !(*ppWnd);
289
290     /* Now notify all windows that got a WM_QUERYENDSESSION of the result */
291
292     for (ppWnd = list; i > 0; i--, ppWnd++)
293     {
294         if (!IsWindow32( (*ppWnd)->hwndSelf )) continue;
295         SendMessage16( (*ppWnd)->hwndSelf, WM_ENDSESSION, result, 0 );
296     }
297     HeapFree( SystemHeap, 0, list );
298
299     if (result) USER_ExitWindows();
300     return FALSE;
301 }
302
303 /***********************************************************************
304  *           EnumDisplaySettingsA   (USER32.592)
305  */
306 BOOL32 WINAPI EnumDisplaySettings32A(LPCSTR name,DWORD n,LPDEVMODE32A devmode) {
307         fprintf(stderr,"EnumDisplaySettings32A(%s,%ld,%p)\n",name,n,devmode);
308         if (n==0) {
309                 devmode->dmBitsPerPel = DefaultDepthOfScreen(screen);
310                 devmode->dmPelsHeight = screenHeight;
311                 devmode->dmPelsWidth = screenWidth;
312                 return TRUE;
313         }
314         return FALSE;
315 }
316
317
318 /***********************************************************************
319  *           SetEventHook   (USER.321)
320  *
321  *      Used by Turbo Debugger for Windows
322  */
323 FARPROC16 SetEventHook(FARPROC16 lpfnEventHook)
324 {
325         fprintf(stderr, "SetEventHook(lpfnEventHook = %08x): stub !\n", (UINT32)lpfnEventHook);
326         return NULL;
327 }
328
329 /***********************************************************************
330  *           UserSeeUserDo   (USER.216)
331  */
332 DWORD WINAPI UserSeeUserDo(WORD wReqType, WORD wParam1, WORD wParam2, WORD wParam3)
333 {
334     switch (wReqType)
335     {
336     case USUD_LOCALALLOC:
337         return LOCAL_Alloc(USER_HeapSel, wParam1, wParam3);
338     case USUD_LOCALFREE:
339         return LOCAL_Free(USER_HeapSel, wParam1);
340     case USUD_LOCALCOMPACT:
341         return LOCAL_Compact(USER_HeapSel, wParam3, 0);
342     case USUD_LOCALHEAP:
343         return USER_HeapSel;
344     case USUD_FIRSTCLASS:
345         FIXME(local, "return a pointer to the first window class.\n"); 
346         return (DWORD)-1;
347     default:
348         WARN(local, "wReqType %04x (unknown)", wReqType);
349         return (DWORD)-1;
350     }
351 }
352