Release 940405
[wine.git] / windows / mdi.c
blob1912295176350fffc4a39db72af6872a36e880f6
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
5 * This file contains routines to support MDI features.
6 */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include "windows.h"
10 #include "win.h"
11 #include "mdi.h"
12 #include "user.h"
14 /* #define DEBUG_MDI /* */
16 /**********************************************************************
17 * MDIRecreateMenuList
19 void
20 MDIRecreateMenuList(MDICLIENTINFO *ci)
22 MDICHILDINFO *chi;
23 char buffer[128];
24 int id, n, index;
26 #ifdef DEBUG_MDI
27 fprintf(stderr, "MDIRecreateMenuList: hWindowMenu %04.4x\n",
28 ci->hWindowMenu);
29 #endif
31 id = ci->idFirstChild;
32 while (DeleteMenu(ci->hWindowMenu, id, MF_BYCOMMAND))
33 id++;
35 #ifdef DEBUG_MDI
36 fprintf(stderr, "MDIRecreateMenuList: id %04.4x, idFirstChild %04.4x\n",
37 id, ci->idFirstChild);
38 #endif
40 if (!ci->flagMenuAltered)
42 ci->flagMenuAltered = TRUE;
43 AppendMenu(ci->hWindowMenu, MF_SEPARATOR, 0, NULL);
46 id = ci->idFirstChild;
47 index = 1;
48 for (chi = ci->infoActiveChildren; chi != NULL; chi = chi->next)
50 n = sprintf(buffer, "%d ", index++);
51 GetWindowText(chi->hwnd, buffer + n, sizeof(buffer) - n - 1);
53 #ifdef DEBUG_MDI
54 fprintf(stderr, "MDIRecreateMenuList: id %04.4x, '%s'\n",
55 id, buffer);
56 #endif
58 AppendMenu(ci->hWindowMenu, MF_STRING, id++, buffer);
62 /**********************************************************************
63 * MDICreateClient
65 HWND
66 MDICreateClient(WND *w, MDICLIENTINFO *ci, HWND parent, LPMDICREATESTRUCT cs)
68 HWND hwnd;
71 * Create child window
73 cs->style &= (WS_MINIMIZE | WS_MAXIMIZE | WS_HSCROLL | WS_VSCROLL);
75 hwnd = CreateWindowEx(0, cs->szClass, cs->szTitle,
76 WS_CHILD | WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS |
77 WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
78 WS_THICKFRAME | WS_VISIBLE | cs->style,
79 cs->x, cs->y, cs->cx, cs->cy, parent, (HMENU) 0,
80 w->hInstance, cs->lParam);
82 if (hwnd)
84 HANDLE h = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(MDICHILDINFO));
85 MDICHILDINFO *child_info = USER_HEAP_ADDR(h);
86 if (!h)
88 DestroyWindow(hwnd);
89 return 0;
92 ci->nActiveChildren++;
94 child_info->next = ci->infoActiveChildren;
95 child_info->prev = NULL;
96 child_info->hwnd = hwnd;
98 if (ci->infoActiveChildren)
99 ci->infoActiveChildren->prev = child_info;
101 ci->infoActiveChildren = child_info;
103 SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
106 return hwnd;
109 /**********************************************************************
110 * MDIDestroyClient
112 HWND
113 MDIDestroyClient(WND *w_parent, MDICLIENTINFO *ci, HWND parent, HWND child,
114 BOOL flagDestroy)
116 MDICHILDINFO *chi;
118 chi = ci->infoActiveChildren;
119 while (chi && chi->hwnd != child)
120 chi = chi->next;
122 if (chi)
124 if (chi->prev)
125 chi->prev->next = chi->next;
126 if (chi->next)
127 chi->next->prev = chi->prev;
128 if (ci->infoActiveChildren == chi)
129 ci->infoActiveChildren = chi->next;
131 ci->nActiveChildren--;
133 if (chi->hwnd == ci->hwndActiveChild)
134 SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
136 USER_HEAP_FREE((HANDLE) chi);
138 if (flagDestroy)
139 DestroyWindow(child);
142 return 0;
145 /**********************************************************************
146 * MDIBringChildToTop
148 void MDIBringChildToTop(HWND parent, WORD id, WORD by_id)
150 MDICHILDINFO *chi;
151 MDICLIENTINFO *ci;
152 WND *w;
153 int i;
155 w = WIN_FindWndPtr(parent);
156 ci = (MDICLIENTINFO *) w->wExtra;
158 #ifdef DEBUG_MDI
159 fprintf(stderr, "MDIBringToTop: id %04.4x, by_id %d\n", id, by_id);
160 #endif
162 if (by_id)
163 id -= ci->idFirstChild;
164 if (!by_id || id < ci->nActiveChildren)
166 chi = ci->infoActiveChildren;
168 if (by_id)
170 for (i = 0; i < id; i++)
171 chi = chi->next;
173 else
175 while (chi && chi->hwnd != id)
176 chi = chi->next;
179 if (!chi)
180 return;
182 #ifdef DEBUG_MDI
183 fprintf(stderr, "MDIBringToTop: child %04.4x\n", chi->hwnd);
184 #endif
185 if (chi != ci->infoActiveChildren)
187 SetWindowPos(chi->hwnd, HWND_TOP, 0, 0, 0, 0,
188 SWP_NOMOVE | SWP_NOSIZE );
190 if (chi->next)
191 chi->next->prev = chi->prev;
193 if (chi->prev)
194 chi->prev->next = chi->next;
196 chi->prev = NULL;
197 chi->next = ci->infoActiveChildren;
198 chi->next->prev = chi;
199 ci->infoActiveChildren = chi;
201 SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
204 #ifdef DEBUG_MDI
205 fprintf(stderr, "MDIBringToTop: pos %04.4x, hwnd %04.4x\n",
206 id, chi->hwnd);
207 #endif
211 /**********************************************************************
212 * MDIChildActivated
214 LONG MDIChildActivated(WND *w, MDICLIENTINFO *ci, HWND parent)
216 MDICHILDINFO *chi;
217 HWND deact_hwnd;
218 HWND act_hwnd;
219 LONG lParam;
221 #ifdef DEBUG_MDI
222 fprintf(stderr, "MDIChildActivate: top %04.4x\n", w->hwndChild);
223 #endif
225 chi = ci->infoActiveChildren;
226 if (chi)
228 deact_hwnd = ci->hwndActiveChild;
229 act_hwnd = chi->hwnd;
230 lParam = ((LONG) deact_hwnd << 16) | act_hwnd;
232 #ifdef DEBUG_MDI
233 fprintf(stderr, "MDIChildActivate: deact %04.4x, act %04.4x\n",
234 deact_hwnd, act_hwnd);
235 #endif
237 ci->hwndActiveChild = act_hwnd;
239 if (deact_hwnd != act_hwnd)
241 MDIRecreateMenuList(ci);
242 SendMessage(deact_hwnd, WM_NCACTIVATE, FALSE, 0);
243 SendMessage(deact_hwnd, WM_MDIACTIVATE, FALSE, lParam);
246 SendMessage(act_hwnd, WM_NCACTIVATE, TRUE, 0);
247 SendMessage(act_hwnd, WM_MDIACTIVATE, TRUE, lParam);
250 if (chi || ci->nActiveChildren == 0)
252 MDIRecreateMenuList(ci);
253 DrawMenuBar(GetParent(parent));
256 return 0;
259 /**********************************************************************
260 * MDICascade
262 LONG MDICascade(HWND parent, MDICLIENTINFO *ci)
264 MDICHILDINFO *chi;
265 RECT rect;
266 int spacing, xsize, ysize;
267 int x, y;
269 GetClientRect(parent, &rect);
270 spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
271 ysize = abs(rect.bottom - rect.top) - 8 * spacing;
272 xsize = abs(rect.right - rect.left) - 8 * spacing;
274 #ifdef DEBUG_MDI
275 fprintf(stderr,
276 "MDICascade: Client wnd at (%d,%d) - (%d,%d), spacing %d\n",
277 rect.left, rect.top, rect.right, rect.bottom, spacing);
278 fprintf(stderr, "MDICascade: searching for last child\n");
279 #endif
280 for (chi = ci->infoActiveChildren; chi->next != NULL; chi = chi->next)
283 #ifdef DEBUG_MDI
284 fprintf(stderr, "MDICascade: last child is %04.4x\n", chi->hwnd);
285 #endif
286 x = 0;
287 y = 0;
288 for ( ; chi != NULL; chi = chi->prev)
290 #ifdef DEBUG_MDI
291 fprintf(stderr, "MDICascade: move %04.4x to (%d,%d) size [%d,%d]\n",
292 chi->hwnd, x, y, xsize, ysize);
293 #endif
294 SetWindowPos(chi->hwnd, 0, x, y, xsize, ysize,
295 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
297 x += spacing;
298 y += spacing;
301 return 0;
304 /**********************************************************************
305 * MDIClientWndProc
307 * This function is the handler for all MDI requests.
309 LONG
310 MDIClientWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
312 LPCREATESTRUCT cs;
313 LPCLIENTCREATESTRUCT ccs;
314 MDICLIENTINFO *ci;
315 WND *w;
316 RECT rect;
318 w = WIN_FindWndPtr(hwnd);
319 ci = (MDICLIENTINFO *) w->wExtra;
321 switch (message)
323 case WM_CHILDACTIVATE:
324 return MDIChildActivated(w, ci, hwnd);
326 case WM_CREATE:
327 cs = (LPCREATESTRUCT) lParam;
328 ccs = (LPCLIENTCREATESTRUCT) cs->lpCreateParams;
329 ci->hWindowMenu = ccs->hWindowMenu;
330 ci->idFirstChild = ccs->idFirstChild;
331 ci->infoActiveChildren = NULL;
332 ci->flagMenuAltered = FALSE;
333 ci->flagChildMaximized = FALSE;
334 w->dwStyle |= WS_CLIPCHILDREN;
336 GetClientRect(w->hwndParent, &rect);
337 MoveWindow(hwnd, 0, 0, rect.right, rect.bottom, 1);
339 return 0;
341 case WM_MDIACTIVATE:
342 MDIBringChildToTop(hwnd, wParam, FALSE);
343 return 0;
345 case WM_MDICASCADE:
346 return MDICascade(hwnd, ci);
348 case WM_MDICREATE:
349 return MDICreateClient(w, ci, hwnd, (LPMDICREATESTRUCT) lParam);
351 case WM_MDIDESTROY:
352 return MDIDestroyClient(w, ci, hwnd, wParam, TRUE);
354 case WM_MDIGETACTIVE:
355 return ((LONG) ci->hwndActiveChild |
356 ((LONG) ci->flagChildMaximized << 16));
358 case WM_MDIICONARRANGE:
359 /* return MDIIconArrange(...) */
360 break;
362 case WM_MDIMAXIMIZE:
363 ci->flagChildMaximized = TRUE;
364 MDIBringChildToTop(hwnd, wParam, FALSE);
365 return 0;
367 case WM_NCACTIVATE:
368 SendMessage(ci->hwndActiveChild, message, wParam, lParam);
369 break;
371 case WM_PARENTNOTIFY:
372 if (wParam == WM_DESTROY)
373 return MDIDestroyClient(w, ci, hwnd, LOWORD(lParam), FALSE);
374 else if (wParam == WM_LBUTTONDOWN)
375 MDIBringChildToTop(hwnd, ci->hwndHitTest, FALSE);
376 break;
380 return DefWindowProc(hwnd, message, wParam, lParam);
383 /**********************************************************************
384 * DefFrameProc (USER.445)
387 LONG
388 DefFrameProc(HWND hwnd, HWND hwndMDIClient, WORD message,
389 WORD wParam, LONG lParam)
391 switch (message)
393 case WM_COMMAND:
394 MDIBringChildToTop(hwndMDIClient, wParam, TRUE);
395 break;
397 case WM_NCACTIVATE:
398 SendMessage(hwndMDIClient, message, wParam, lParam);
399 break;
401 case WM_SETFOCUS:
402 SendMessage(hwndMDIClient, WM_SETFOCUS, wParam, lParam);
403 break;
405 case WM_SIZE:
406 MoveWindow(hwndMDIClient, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
407 break;
411 return DefWindowProc(hwnd, message, wParam, lParam);
414 /**********************************************************************
415 * DefMDIChildProc (USER.447)
418 LONG
419 DefMDIChildProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
421 MDICLIENTINFO *ci;
422 WND *w;
424 w = WIN_FindWndPtr(GetParent(hwnd));
425 ci = (MDICLIENTINFO *) w->wExtra;
427 switch (message)
429 case WM_NCHITTEST:
430 ci->hwndHitTest = hwnd;
431 break;
433 case WM_NCPAINT:
434 return NC_DoNCPaint(hwnd, (HRGN)1,
435 hwnd == ci->hwndActiveChild);
438 return DefWindowProc(hwnd, message, wParam, lParam);
441 /**********************************************************************
442 * TranslateMDISysAccel (USER.451)
445 BOOL TranslateMDISysAccel(HWND hwndClient, LPMSG msg)
447 return 0;