Prevent from crashing/hanging in Windows 95 OSR2.
[wine] / programs / progman / main.c
1 /*
2  * Program Manager
3  *
4  * Copyright 1996 Ulrich Schmid
5  * Copyright 2002 Sylvain Petreolle
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include "windows.h"
25 #include "windowsx.h"
26 #include "license.h"
27 #include "progman.h"
28
29 GLOBALS Globals;
30
31 static VOID MAIN_CreateGroups(void);
32 static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
33 static ATOM MAIN_RegisterMainWinClass(void);
34 static VOID MAIN_CreateMainWindow(void);
35 static VOID MAIN_CreateMDIWindow(void);
36 static VOID MAIN_AutoStart(void);
37
38 #define BUFFER_SIZE 1000
39
40 /***********************************************************************
41  *
42  *           WinMain
43  */
44
45 int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
46 {
47   MSG      msg;
48
49   Globals.lpszIniFile         = "progman.ini";
50   Globals.lpszIcoFile         = "progman.ico";
51
52   Globals.hInstance           = hInstance;
53   Globals.hGroups             = 0;
54   Globals.hActiveGroup        = 0;
55
56   /* Read Options from `progman.ini' */
57   Globals.bAutoArrange =
58     GetPrivateProfileInt("Settings", "AutoArrange", 0, Globals.lpszIniFile);
59   Globals.bMinOnRun =
60     GetPrivateProfileInt("Settings", "MinOnRun", 0, Globals.lpszIniFile);
61   Globals.bSaveSettings =
62     GetPrivateProfileInt("Settings", "SaveSettings", 0, Globals.lpszIniFile);
63
64   /* Load default icons */
65   Globals.hMainIcon    = ExtractIcon(Globals.hInstance, Globals.lpszIcoFile, 0);
66   Globals.hGroupIcon   = ExtractIcon(Globals.hInstance, Globals.lpszIcoFile, 0);
67   Globals.hDefaultIcon = ExtractIcon(Globals.hInstance, Globals.lpszIcoFile, 0);
68   if (!Globals.hMainIcon)    Globals.hMainIcon = LoadIcon(0, MAKEINTRESOURCE(DEFAULTICON));
69   if (!Globals.hGroupIcon)   Globals.hGroupIcon = LoadIcon(0, MAKEINTRESOURCE(DEFAULTICON));
70   if (!Globals.hDefaultIcon) Globals.hDefaultIcon = LoadIcon(0, MAKEINTRESOURCE(DEFAULTICON));
71
72   /* Register classes */
73   if (!prev)
74     {
75       if (!MAIN_RegisterMainWinClass()) return(FALSE);
76       if (!GROUP_RegisterGroupWinClass()) return(FALSE);
77       if (!PROGRAM_RegisterProgramWinClass()) return(FALSE);
78     }
79
80   /* Create main window */
81   MAIN_CreateMainWindow();
82   Globals.hAccel = LoadAccelerators(Globals.hInstance, STRING_ACCEL);
83
84   /* Setup menu, stringtable and resourcenames */
85   STRING_LoadMenus();
86
87   MAIN_CreateMDIWindow();
88
89   /* Initialize groups */
90   MAIN_CreateGroups();
91
92   /* Start initial applications */
93   MAIN_AutoStart();
94
95   /* Message loop */
96   while (GetMessage (&msg, 0, 0, 0))
97     if (!TranslateAccelerator(Globals.hMainWnd, Globals.hAccel, &msg))
98       {
99         TranslateMessage (&msg);
100         DispatchMessage (&msg);
101       }
102   return 0;
103 }
104
105 /***********************************************************************
106  *
107  *           MAIN_CreateGroups
108  */
109
110 static VOID MAIN_CreateGroups()
111 {
112   CHAR buffer[BUFFER_SIZE];
113   CHAR szPath[MAX_PATHNAME_LEN];
114   CHAR key[20], *ptr;
115
116   /* Initialize groups according the `Order' entry of `progman.ini' */
117   GetPrivateProfileString("Settings", "Order", "", buffer, sizeof(buffer), Globals.lpszIniFile);
118   ptr = buffer;
119   while (ptr < buffer + sizeof(buffer))
120     {
121       int num, skip, ret;
122       ret = sscanf(ptr, "%d%n", &num, &skip);
123       if (ret == 0)
124         MAIN_MessageBoxIDS_s(IDS_FILE_READ_ERROR_s, Globals.lpszIniFile, IDS_ERROR, MB_OK);
125       if (ret != 1) break;
126
127       sprintf(key, "Group%d", num);
128       GetPrivateProfileString("Groups", key, "", szPath,
129                               sizeof(szPath), Globals.lpszIniFile);
130       if (!szPath[0]) continue;
131
132       GRPFILE_ReadGroupFile(szPath);
133
134       ptr += skip;
135     }
136   /* FIXME initialize other groups, not enumerated by `Order' */
137 }
138
139 /***********************************************************************
140  *
141  *           MAIN_AutoStart
142  */
143
144 VOID MAIN_AutoStart()
145 {
146   CHAR buffer[BUFFER_SIZE];
147   HLOCAL hGroup, hProgram;
148
149   GetPrivateProfileString("Settings", "AutoStart", "Autostart", buffer,
150                           sizeof(buffer), Globals.lpszIniFile);
151
152   for (hGroup = GROUP_FirstGroup(); hGroup; hGroup = GROUP_NextGroup(hGroup))
153     if (!lstrcmp(buffer, GROUP_GroupName(hGroup)))
154       for (hProgram = PROGRAM_FirstProgram(hGroup); hProgram;
155            hProgram = PROGRAM_NextProgram(hProgram))
156         PROGRAM_ExecuteProgram(hProgram);
157 }
158
159 /***********************************************************************
160  *
161  *           MAIN_MainWndProc
162  */
163
164 static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT msg,
165                                  WPARAM wParam, LPARAM lParam)
166 {
167 #if 0
168   printf("M %4.4x %4.4x\n", msg, wParam);
169 #endif
170   switch (msg)
171     {
172     case WM_INITMENU:
173       CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
174                     MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
175       CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
176                     MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
177       CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
178                     MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
179       break;
180
181     case WM_COMMAND:
182       if (wParam < PM_FIRST_CHILD){
183         MAIN_MenuCommand(hWnd, wParam, lParam);
184       }
185       break;
186
187     case WM_DESTROY:
188       PostQuitMessage (0);
189       break;
190     }
191   return(DefFrameProc(hWnd, Globals.hMDIWnd, msg, wParam, lParam));
192 }
193
194 /***********************************************************************
195  *
196  *           MAIN_MenuCommand
197  */
198
199 static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
200 {
201   HLOCAL hActiveGroup    = GROUP_ActiveGroup();
202   HLOCAL hActiveProgram  = PROGRAM_ActiveProgram(hActiveGroup);
203   HWND   hActiveGroupWnd = GROUP_GroupWnd(hActiveGroup);
204
205   switch(wParam)
206     {
207       /* Menu File */
208     case PM_NEW:
209       switch (DIALOG_New((hActiveGroupWnd && !IsIconic(hActiveGroupWnd)) ?
210                          PM_NEW_PROGRAM : PM_NEW_GROUP))
211       {
212       case PM_NEW_PROGRAM:
213         if (hActiveGroup) PROGRAM_NewProgram(hActiveGroup);
214         break;
215
216       case PM_NEW_GROUP:
217         GROUP_NewGroup();
218         break;
219       }
220       break;
221
222     case PM_OPEN:
223       if (hActiveProgram)
224         PROGRAM_ExecuteProgram(hActiveProgram);
225       else if (hActiveGroupWnd)
226         OpenIcon(hActiveGroupWnd);
227       break;
228
229     case PM_MOVE:
230     case PM_COPY:
231       if (hActiveProgram)
232         PROGRAM_CopyMoveProgram(hActiveProgram, wParam == PM_MOVE);
233       break;
234
235     case PM_DELETE:
236       if (hActiveProgram)
237         {
238         if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, PROGRAM_ProgramName(hActiveProgram)))
239           PROGRAM_DeleteProgram(hActiveProgram, TRUE);
240         }
241       else if (hActiveGroup)
242         {
243         if (DIALOG_Delete(IDS_DELETE_GROUP_s, GROUP_GroupName(hActiveGroup)))
244           GROUP_DeleteGroup(hActiveGroup);
245         }
246       break;
247
248     case PM_ATTRIBUTES:
249       if (hActiveProgram)
250         PROGRAM_ModifyProgram(hActiveProgram);
251       else if (hActiveGroup)
252         GROUP_ModifyGroup(hActiveGroup);
253       break;
254
255     case PM_EXECUTE:
256       DIALOG_Execute();
257       break;
258
259     case PM_EXIT:
260       PostQuitMessage(0);
261       break;
262
263       /* Menu Options */
264     case PM_AUTO_ARRANGE:
265       Globals.bAutoArrange = !Globals.bAutoArrange;
266       CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
267                     MF_BYCOMMAND | (Globals.bAutoArrange ?
268                                     MF_CHECKED : MF_UNCHECKED));
269       WritePrivateProfileString("Settings", "AutoArrange",
270                                 Globals.bAutoArrange ? "1" : "0",
271                                 Globals.lpszIniFile);
272       WritePrivateProfileString(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
273       break;
274
275     case PM_MIN_ON_RUN:
276       Globals.bMinOnRun = !Globals.bMinOnRun;
277       CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
278                     MF_BYCOMMAND | (Globals.bMinOnRun ?
279                                     MF_CHECKED : MF_UNCHECKED));
280       WritePrivateProfileString("Settings", "MinOnRun",
281                                 Globals.bMinOnRun ? "1" : "0",
282                                 Globals.lpszIniFile);
283       WritePrivateProfileString(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
284       break;
285
286     case PM_SAVE_SETTINGS:
287       Globals.bSaveSettings = !Globals.bSaveSettings;
288       CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
289                     MF_BYCOMMAND | (Globals.bSaveSettings ?
290                                     MF_CHECKED : MF_UNCHECKED));
291       WritePrivateProfileString("Settings", "SaveSettings",
292                                 Globals.bSaveSettings ? "1" : "0",
293                                 Globals.lpszIniFile);
294       WritePrivateProfileString(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
295       break;
296
297       /* Menu Windows */
298     case PM_ARRANGE:
299
300       if (hActiveGroupWnd && !IsIconic(hActiveGroupWnd))
301         ArrangeIconicWindows(hActiveGroupWnd);
302       else
303         SendMessage(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
304       break;
305
306       /* Menu Help */
307     case PM_CONTENTS:
308       if (!WinHelp(Globals.hMainWnd, "progman.hlp", HELP_CONTENTS, 0))
309         MAIN_MessageBoxIDS(IDS_WINHELP_ERROR, IDS_ERROR, MB_OK);
310       break;
311
312     case PM_HELPONHELP:
313       if (!WinHelp(Globals.hMainWnd, "progman.hlp", HELP_HELPONHELP, 0))
314         MAIN_MessageBoxIDS(IDS_WINHELP_ERROR, IDS_ERROR, MB_OK);
315       break;
316
317     case PM_TUTORIAL:
318       WinExec("wintutor.exe", SW_SHOWNORMAL);
319       break;
320
321     case PM_LICENSE:
322       WineLicense(Globals.hMainWnd);
323       break;
324
325     case PM_NO_WARRANTY:
326       WineWarranty(Globals.hMainWnd);
327       break;
328
329     case PM_ABOUT_WINE:
330       ShellAbout(hWnd, "WINE", "Program Manager", 0);
331       break;
332
333     default:
334         MAIN_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
335       break;
336     }
337 }
338
339 /***********************************************************************
340  *
341  *           MAIN_RegisterMainWinClass
342  */
343
344 static ATOM MAIN_RegisterMainWinClass()
345 {
346   WNDCLASS class;
347
348   class.style         = CS_HREDRAW | CS_VREDRAW;
349   class.lpfnWndProc   = MAIN_MainWndProc;
350   class.cbClsExtra    = 0;
351   class.cbWndExtra    = 0;
352   class.hInstance     = Globals.hInstance;
353   class.hIcon         = Globals.hMainIcon;
354   class.hCursor       = LoadCursor (0, IDC_ARROW);
355   class.hbrBackground = GetStockObject (NULL_BRUSH);
356   class.lpszMenuName  = 0;
357   class.lpszClassName = STRING_MAIN_WIN_CLASS_NAME;
358
359   return RegisterClass(&class);
360 }
361
362 /***********************************************************************
363  *
364  *           MAIN_CreateMainWindow
365  */
366
367 static VOID MAIN_CreateMainWindow()
368 {
369   INT  left , top, right, bottom, width, height, show;
370   CHAR buffer[100];
371
372   Globals.hMDIWnd   = 0;
373   Globals.hMainMenu = 0;
374
375   /* Get the geometry of the main window */
376   GetPrivateProfileString("Settings", "Window", "",
377                           buffer, sizeof(buffer), Globals.lpszIniFile);
378   if (5 == sscanf(buffer, "%d %d %d %d %d", &left, &top, &right, &bottom, &show))
379   {
380     width  = right - left;
381     height = bottom - top;
382   }
383   else
384   {
385     left = top = width = height = CW_USEDEFAULT;
386     show = SW_SHOWNORMAL;
387   }
388
389   /* Create main Window */
390   Globals.hMainWnd =
391     CreateWindow (STRING_MAIN_WIN_CLASS_NAME, "",
392                   WS_OVERLAPPEDWINDOW, left, top, width, height,
393                   0, 0, Globals.hInstance, 0);
394
395   ShowWindow (Globals.hMainWnd, show);
396   UpdateWindow (Globals.hMainWnd);
397 }
398
399 /***********************************************************************
400  *
401  *           MAIN_CreateMDIWindow
402  */
403
404 static VOID MAIN_CreateMDIWindow()
405 {
406   CLIENTCREATESTRUCT ccs;
407   RECT rect;
408
409   /* Get the geometry of the MDI window */
410   GetClientRect(Globals.hMainWnd, &rect);
411
412   ccs.hWindowMenu  = Globals.hWindowsMenu;
413   ccs.idFirstChild = PM_FIRST_CHILD;
414
415   /* Create MDI Window */
416   Globals.hMDIWnd =
417     CreateWindow (STRING_MDI_WIN_CLASS_NAME, "",
418                   WS_CHILD, rect.left, rect.top,
419                   rect.right - rect.left, rect.bottom - rect.top,
420                   Globals.hMainWnd, 0,
421                   Globals.hInstance, &ccs);
422
423   ShowWindow (Globals.hMDIWnd, SW_SHOW);
424   UpdateWindow (Globals.hMDIWnd);
425 }
426
427 /**********************************************************************/
428 /***********************************************************************
429  *
430  *           MAIN_MessageBoxIDS
431  */
432 INT MAIN_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
433 {
434   CHAR text[MAX_STRING_LEN];
435   CHAR title[MAX_STRING_LEN];
436
437   LoadString(Globals.hInstance, ids_text, text, sizeof(text));
438   LoadString(Globals.hInstance, ids_title, title, sizeof(title));
439
440   return(MessageBox(Globals.hMainWnd, text, title, type));
441 }
442
443 /***********************************************************************
444  *
445  *           MAIN_MessageBoxIDS_s
446  */
447 INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
448 {
449   CHAR text[MAX_STRING_LEN];
450   CHAR title[MAX_STRING_LEN];
451   CHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
452
453   LoadString(Globals.hInstance, ids_text, text, sizeof(text));
454   LoadString(Globals.hInstance, ids_title, title, sizeof(title));
455   wsprintf(newtext, text, str);
456
457   return(MessageBox(Globals.hMainWnd, newtext, title, type));
458 }
459
460 /***********************************************************************
461  *
462  *           MAIN_ReplaceString
463  */
464
465 VOID MAIN_ReplaceString(HLOCAL *handle, LPSTR replace)
466 {
467   HLOCAL newhandle = LocalAlloc(LMEM_FIXED, strlen(replace) + 1);
468   if (newhandle)
469     {
470       LPSTR  newstring = LocalLock(newhandle);
471       lstrcpy(newstring, replace);
472       LocalFree(*handle);
473       *handle = newhandle;
474     }
475   else MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK);
476 }
477
478 /* Local Variables:    */
479 /* c-file-style: "GNU" */
480 /* End:                */