a43e680da731cdb0129fb7da8845fa68f7bcc5e2
[reactos.git] / reactos / base / applications / devmgmt / mainwnd.c
1 /*
2 * PROJECT: ReactOS Device Managment
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/devmgmt/mainwnd.c
5 * PURPOSE: Main window message handler
6 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
7 *
8 */
9
10 #include "precomp.h"
11
12 static const TCHAR szMainWndClass[] = TEXT("DevMgmtWndClass");
13
14
15 /* Toolbar buttons */
16 TBBUTTON Buttons [] =
17 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
18 {TBICON_PROP, IDC_PROP, TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0}, /* properties */
19 {TBICON_REFRESH, IDC_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, /* refresh */
20
21 /* Note: First item for a seperator is its width in pixels */
22 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0}, /* separator */
23
24 {TBICON_HELP, IDC_PROGHELP,TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, /* help */
25 {TBICON_EXIT, IDC_EXIT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, /* exit */
26
27 };
28
29
30 /* menu hints */
31 static const MENU_HINT MainMenuHintTable[] = {
32 /* File Menu */
33 {IDC_EXIT, IDS_HINT_EXIT},
34
35 /* Action Menu */
36 {IDC_REFRESH, IDS_HINT_REFRESH},
37 {IDC_PROP, IDS_HINT_PROP},
38
39 /* Help Menu */
40 {IDC_PROGHELP, IDS_HINT_HELP},
41 {IDC_ABOUT, IDS_HINT_ABOUT}
42 };
43
44 /* system menu hints */
45 static const MENU_HINT SystemMenuHintTable[] = {
46 {SC_RESTORE, IDS_HINT_SYS_RESTORE},
47 {SC_MOVE, IDS_HINT_SYS_MOVE},
48 {SC_SIZE, IDS_HINT_SYS_SIZE},
49 {SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE},
50 {SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE},
51 {SC_CLOSE, IDS_HINT_SYS_CLOSE},
52 };
53
54
55 static BOOL
56 MainWndMenuHint(PMAIN_WND_INFO Info,
57 WORD CmdId,
58 const MENU_HINT *HintArray,
59 DWORD HintsCount,
60 UINT DefHintId)
61 {
62 BOOL Found = FALSE;
63 const MENU_HINT *LastHint;
64 UINT HintId = DefHintId;
65
66 LastHint = HintArray + HintsCount;
67 while (HintArray != LastHint)
68 {
69 if (HintArray->CmdId == CmdId)
70 {
71 HintId = HintArray->HintId;
72 Found = TRUE;
73 break;
74 }
75 HintArray++;
76 }
77
78 StatusBarLoadString(Info->hStatus,
79 SB_SIMPLEID,
80 hInstance,
81 HintId);
82
83 return Found;
84 }
85
86
87 static VOID
88 UpdateMainStatusBar(PMAIN_WND_INFO Info)
89 {
90 if (Info->hStatus != NULL)
91 {
92 SendMessage(Info->hStatus,
93 SB_SIMPLE,
94 (WPARAM)Info->InMenuLoop,
95 0);
96 }
97 }
98
99
100 static BOOL
101 CreateToolbar(PMAIN_WND_INFO Info)
102 {
103 INT NumButtons = sizeof(Buttons) / sizeof(Buttons[0]);
104
105 Info->hTool = CreateWindowEx(0,
106 TOOLBARCLASSNAME,
107 NULL,
108 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
109 0, 0, 0, 0,
110 Info->hMainWnd,
111 (HMENU)IDC_TOOLBAR,
112 hInstance,
113 NULL);
114 if(Info->hTool != NULL)
115 {
116 HIMAGELIST hImageList;
117
118 SendMessage(Info->hTool,
119 TB_SETEXTENDEDSTYLE,
120 0,
121 TBSTYLE_EX_HIDECLIPPEDBUTTONS);
122
123 SendMessage(Info->hTool,
124 TB_BUTTONSTRUCTSIZE,
125 sizeof(Buttons[0]),
126 0);
127
128 hImageList = InitImageList(IDB_PROP,
129 IDB_EXIT,
130 16,
131 16);
132 if (hImageList == NULL)
133 return FALSE;
134
135 ImageList_Destroy((HIMAGELIST)SendMessage(Info->hTool,
136 TB_SETIMAGELIST,
137 0,
138 (LPARAM)hImageList));
139
140 SendMessage(Info->hTool,
141 TB_ADDBUTTONS,
142 NumButtons,
143 (LPARAM)Buttons);
144
145 return TRUE;
146 }
147
148 return FALSE;
149 }
150
151
152 static BOOL
153 CreateTreeView(PMAIN_WND_INFO Info)
154 {
155 Info->hTreeView = CreateWindowEx(0,
156 WC_TREEVIEW,
157 NULL,
158 WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES |
159 TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_LINESATROOT,
160 0, 0, 0, 0,
161 Info->hMainWnd,
162 (HMENU)IDC_TREEVIEW,
163 hInstance,
164 NULL);
165 if (Info->hTreeView == NULL)
166 {
167 DisplayString(_T("Could not create TreeView."));
168 return FALSE;
169 }
170
171 return TRUE;
172 }
173
174 static BOOL
175 CreateStatusBar(PMAIN_WND_INFO Info)
176 {
177 INT StatWidths[] = {110, -1}; /* widths of status bar */
178
179 Info->hStatus = CreateWindowEx(0,
180 STATUSCLASSNAME,
181 NULL,
182 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
183 0, 0, 0, 0,
184 Info->hMainWnd,
185 (HMENU)IDC_STATUSBAR,
186 hInstance,
187 NULL);
188 if(Info->hStatus == NULL)
189 return FALSE;
190
191
192 SendMessage(Info->hStatus,
193 SB_SETPARTS,
194 sizeof(StatWidths) / sizeof(INT),
195 (LPARAM)StatWidths);
196
197 return TRUE;
198 }
199
200
201 static DWORD WINAPI
202 DeviceEnumThread(LPVOID lpParameter)
203 {
204 HTREEITEM hRoot;
205 HWND *hTreeView;
206
207 hTreeView = (HWND *)lpParameter;
208
209 if (*hTreeView)
210 FreeDeviceStrings(*hTreeView);
211
212 hRoot = InitTreeView(*hTreeView);
213 if (hRoot)
214 {
215 ListDevicesByType(*hTreeView, hRoot);
216 return 0;
217 }
218
219 return -1;
220 }
221
222
223 static BOOL
224 InitMainWnd(PMAIN_WND_INFO Info)
225 {
226 HANDLE DevEnumThread;
227 HMENU hMenu;
228
229 if (!CreateToolbar(Info))
230 DisplayString(_T("error creating toolbar"));
231
232 if (!CreateTreeView(Info))
233 {
234 DisplayString(_T("error creating list view"));
235 return FALSE;
236 }
237
238 if (!CreateStatusBar(Info))
239 DisplayString(_T("error creating status bar"));
240
241 /* make 'properties' bold */
242 hMenu = GetMenu(Info->hMainWnd);
243 hMenu = GetSubMenu(hMenu, 1);
244 SetMenuDefaultItem(hMenu, IDC_PROP, FALSE);
245
246 /* Create Popup Menu */
247 Info->hShortcutMenu = LoadMenu(hInstance,
248 MAKEINTRESOURCE(IDR_POPUP));
249 Info->hShortcutMenu = GetSubMenu(Info->hShortcutMenu,
250 0);
251 SetMenuDefaultItem(Info->hShortcutMenu, IDC_PROP, FALSE);
252
253 /* create seperate thread to emum devices */
254 DevEnumThread = CreateThread(NULL,
255 0,
256 DeviceEnumThread,
257 &Info->hTreeView,
258 0,
259 NULL);
260 if (!DevEnumThread)
261 {
262 DisplayString(_T("Failed to enumerate devices"));
263 return FALSE;
264 }
265
266 CloseHandle(DevEnumThread);
267 return TRUE;
268 }
269
270
271 static VOID
272 OnContext(PMAIN_WND_INFO Info,
273 LPARAM lParam)
274 {
275 HTREEITEM hSelected;
276 POINT pt;
277 RECT rc;
278
279 INT xPos = GET_X_LPARAM(lParam);
280 INT yPos = GET_Y_LPARAM(lParam);
281
282 hSelected = TreeView_GetSelection(Info->hTreeView);
283
284 if (TreeView_GetItemRect(Info->hTreeView,
285 hSelected,
286 &rc,
287 TRUE))
288 {
289 if (GetCursorPos(&pt) &&
290 ScreenToClient(Info->hTreeView, &pt) &&
291 PtInRect(&rc, pt))
292 {
293 TrackPopupMenuEx(Info->hShortcutMenu,
294 TPM_RIGHTBUTTON,
295 xPos,
296 yPos,
297 Info->hMainWnd,
298 NULL);
299 }
300 }
301 }
302
303
304 static VOID
305 OnNotify(PMAIN_WND_INFO Info,
306 LPARAM lParam)
307 {
308 LPNMHDR pnmhdr = (LPNMHDR)lParam;
309
310 switch (pnmhdr->code)
311 {
312 case TVN_SELCHANGED:
313 {
314 LPNM_TREEVIEW pnmtv = (LPNM_TREEVIEW)lParam;
315
316 if (!TreeView_GetChild(Info->hTreeView,
317 pnmtv->itemNew.hItem))
318 {
319 SendMessage(Info->hTool,
320 TB_SETSTATE,
321 IDC_PROP,
322 (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
323
324 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_ENABLED);
325 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_ENABLED);
326 }
327 else
328 {
329 SendMessage(Info->hTool,
330 TB_SETSTATE,
331 IDC_PROP,
332 (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
333
334 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_GRAYED);
335 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_GRAYED);
336 }
337 }
338 break;
339
340 case NM_DBLCLK:
341 {
342 HTREEITEM hSelected = TreeView_GetSelection(Info->hTreeView);
343
344 if (!TreeView_GetChild(Info->hTreeView,
345 hSelected))
346 {
347 OpenPropSheet(Info->hTreeView,
348 hSelected);
349 }
350 }
351 break;
352
353 case NM_RCLICK:
354 {
355 TV_HITTESTINFO HitTest;
356
357 if (GetCursorPos(&HitTest.pt) &&
358 ScreenToClient(Info->hTreeView, &HitTest.pt))
359 {
360 if (TreeView_HitTest(Info->hTreeView, &HitTest))
361 (void)TreeView_SelectItem(Info->hTreeView, HitTest.hItem);
362 }
363 }
364 break;
365
366 case TTN_GETDISPINFO:
367 {
368 LPTOOLTIPTEXT lpttt;
369 UINT idButton;
370
371 lpttt = (LPTOOLTIPTEXT)lParam;
372
373 idButton = (UINT)lpttt->hdr.idFrom;
374 switch (idButton)
375 {
376 case IDC_PROP:
377 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PROP);
378 break;
379
380 case IDC_REFRESH:
381 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_REFRESH);
382 break;
383
384 case IDC_PROGHELP:
385 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_HELP);
386 break;
387
388 case IDC_EXIT:
389 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EXIT);
390 break;
391 }
392 }
393 break;
394 }
395 }
396
397
398 static VOID
399 MainWndCommand(PMAIN_WND_INFO Info,
400 WORD CmdId,
401 HWND hControl)
402 {
403 UNREFERENCED_PARAMETER(hControl);
404
405 switch (CmdId)
406 {
407 case IDC_PROP:
408 {
409 HTREEITEM hSelected = TreeView_GetSelection(Info->hTreeView);
410 OpenPropSheet(Info->hTreeView,
411 hSelected);
412 }
413 break;
414
415 case IDC_REFRESH:
416 {
417 HANDLE DevEnumThread;
418
419 SendMessage(Info->hTool,
420 TB_SETSTATE,
421 IDC_PROP,
422 (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
423
424 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_GRAYED);
425 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_GRAYED);
426
427 /* create seperate thread to emum devices */
428 DevEnumThread = CreateThread(NULL,
429 0,
430 DeviceEnumThread,
431 &Info->hTreeView,
432 0,
433 NULL);
434 if (!DevEnumThread)
435 {
436 DisplayString(_T("Failed to enumerate devices"));
437 break;
438 }
439
440 CloseHandle(DevEnumThread);
441 }
442 break;
443
444 case IDC_PROGHELP:
445 {
446 DisplayString(_T("Help is not yet implemented\n"));
447 SetFocus(Info->hTreeView);
448 }
449 break;
450
451 case IDC_EXIT:
452 {
453 PostMessage(Info->hMainWnd,
454 WM_CLOSE,
455 0,
456 0);
457 }
458 break;
459
460 case IDC_ABOUT:
461 {
462 DialogBox(hInstance,
463 MAKEINTRESOURCE(IDD_ABOUTBOX),
464 Info->hMainWnd,
465 (DLGPROC)AboutDialogProc);
466
467 SetFocus(Info->hTreeView);
468 }
469 break;
470
471 }
472 }
473
474
475 static VOID CALLBACK
476 MainWndResize(PMAIN_WND_INFO Info,
477 WORD cx,
478 WORD cy)
479 {
480 RECT rcClient, rcTool, rcStatus;
481 int lvHeight, iToolHeight, iStatusHeight;
482
483 /* Size toolbar and get height */
484 SendMessage(Info->hTool, TB_AUTOSIZE, 0, 0);
485 GetWindowRect(Info->hTool, &rcTool);
486 iToolHeight = rcTool.bottom - rcTool.top;
487
488 /* Size status bar and get height */
489 SendMessage(Info->hStatus, WM_SIZE, 0, 0);
490 GetWindowRect(Info->hStatus, &rcStatus);
491 iStatusHeight = rcStatus.bottom - rcStatus.top;
492
493 /* Calculate remaining height and size list view */
494 GetClientRect(Info->hMainWnd, &rcClient);
495 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
496 SetWindowPos(Info->hTreeView,
497 NULL,
498 0,
499 iToolHeight,
500 rcClient.right,
501 lvHeight,
502 SWP_NOZORDER);
503 }
504
505
506 static LRESULT CALLBACK
507 MainWndProc(HWND hwnd,
508 UINT msg,
509 WPARAM wParam,
510 LPARAM lParam)
511 {
512 PMAIN_WND_INFO Info;
513 LRESULT Ret = 0;
514
515 /* Get the window context */
516 Info = (PMAIN_WND_INFO)GetWindowLongPtr(hwnd,
517 GWLP_USERDATA);
518 if (Info == NULL && msg != WM_CREATE)
519 {
520 goto HandleDefaultMessage;
521 }
522
523 switch(msg)
524 {
525 case WM_CREATE:
526 {
527 Info = (PMAIN_WND_INFO)(((LPCREATESTRUCT)lParam)->lpCreateParams);
528
529 /* Initialize the main window context */
530 Info->hMainWnd = hwnd;
531
532 SetWindowLongPtr(hwnd,
533 GWLP_USERDATA,
534 (LONG_PTR)Info);
535
536 if (!InitMainWnd(Info))
537 SendMessage(hwnd, WM_CLOSE, 0, 0);
538
539 /* Show the window */
540 ShowWindow(hwnd,
541 Info->nCmdShow);
542
543 }
544 break;
545
546 case WM_SIZE:
547 {
548 MainWndResize(Info,
549 LOWORD(lParam),
550 HIWORD(lParam));
551 }
552 break;
553
554 case WM_NOTIFY:
555 {
556 OnNotify(Info, lParam);
557 }
558 break;
559
560 case WM_CONTEXTMENU:
561 {
562 OnContext(Info, lParam);
563 }
564 break;
565
566 case WM_COMMAND:
567 {
568 MainWndCommand(Info,
569 LOWORD(wParam),
570 (HWND)lParam);
571 goto HandleDefaultMessage;
572 }
573
574 case WM_MENUSELECT:
575 {
576 if (Info->hStatus != NULL)
577 {
578 if (!MainWndMenuHint(Info,
579 LOWORD(wParam),
580 MainMenuHintTable,
581 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
582 IDS_HINT_BLANK))
583 {
584 MainWndMenuHint(Info,
585 LOWORD(wParam),
586 SystemMenuHintTable,
587 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
588 IDS_HINT_BLANK);
589 }
590 }
591 }
592 break;
593
594 case WM_ENTERMENULOOP:
595 {
596 Info->InMenuLoop = TRUE;
597 UpdateMainStatusBar(Info);
598 break;
599 }
600
601 case WM_EXITMENULOOP:
602 {
603 Info->InMenuLoop = FALSE;
604 UpdateMainStatusBar(Info);
605 break;
606 }
607
608 case WM_CLOSE:
609 {
610 FreeDeviceStrings(Info->hTreeView);
611 DestroyMenu(Info->hShortcutMenu);
612 DestroyWindow(hwnd);
613 }
614 break;
615
616 case WM_DESTROY:
617 {
618 HeapFree(ProcessHeap,
619 0,
620 Info);
621 SetWindowLongPtr(hwnd,
622 GWLP_USERDATA,
623 0);
624
625 /* Break the message queue loop */
626 PostQuitMessage(0);
627 }
628 break;
629
630 default:
631 {
632 HandleDefaultMessage:
633
634 Ret = DefWindowProc(hwnd,
635 msg,
636 wParam,
637 lParam);
638 }
639 break;
640 }
641 return Ret;
642 }
643
644
645
646 HWND
647 CreateMainWindow(LPCTSTR lpCaption,
648 int nCmdShow)
649 {
650 PMAIN_WND_INFO Info;
651 HWND hMainWnd = NULL;
652
653 Info = (PMAIN_WND_INFO)HeapAlloc(ProcessHeap,
654 HEAP_ZERO_MEMORY,
655 sizeof(MAIN_WND_INFO));
656
657 if (Info != NULL)
658 {
659 Info->nCmdShow = nCmdShow;
660
661 hMainWnd = CreateWindowEx(WS_EX_WINDOWEDGE,
662 szMainWndClass,
663 lpCaption,
664 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
665 CW_USEDEFAULT,
666 CW_USEDEFAULT,
667 600,
668 450,
669 NULL,
670 NULL,
671 hInstance,
672 Info);
673 if (hMainWnd == NULL)
674 {
675 GetError();
676 HeapFree(ProcessHeap,
677 0,
678 Info);
679 }
680 }
681
682 return hMainWnd;
683 }
684
685 BOOL
686 InitMainWindowImpl(VOID)
687 {
688 WNDCLASSEX wc = {0};
689
690 wc.cbSize = sizeof(WNDCLASSEX);
691 wc.lpfnWndProc = MainWndProc;
692 wc.hInstance = hInstance;
693 wc.hIcon = LoadIcon(hInstance,
694 MAKEINTRESOURCE(IDI_MAIN_ICON));
695 wc.hCursor = LoadCursor(NULL,
696 IDC_ARROW);
697 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
698 wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
699 wc.lpszClassName = szMainWndClass;
700 wc.hIconSm = (HICON)LoadImage(hInstance,
701 MAKEINTRESOURCE(IDI_MAIN_ICON),
702 IMAGE_ICON,
703 16,
704 16,
705 LR_SHARED);
706
707 return RegisterClassEx(&wc) != (ATOM)0;
708 }
709
710
711 VOID
712 UninitMainWindowImpl(VOID)
713 {
714 UnregisterClass(szMainWndClass,
715 hInstance);
716 }
717
718