* Sync up to trunk head (r65426).
[reactos.git] / base / applications / rapps / winmain.c
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/rapps/winmain.c
5 * PURPOSE: Main program
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
7 */
8
9 #include "rapps.h"
10
11 #include <shellapi.h>
12
13 #define SEARCH_TIMER_ID 'SR'
14
15 HWND hMainWnd;
16 HINSTANCE hInst;
17 HIMAGELIST hImageTreeView = NULL;
18 INT SelectedEnumType = ENUM_ALL_COMPONENTS;
19 SETTINGS_INFO SettingsInfo;
20
21 WCHAR szSearchPattern[MAX_STR_LEN] = L"";
22 BOOL SearchEnabled = TRUE;
23
24 BOOL
25 SearchPatternMatch(PCWSTR szHaystack, PCWSTR szNeedle)
26 {
27 if (!*szNeedle)
28 return TRUE;
29 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
30 return StrStrIW(szHaystack, szNeedle) != NULL;
31 }
32
33 VOID
34 FillDefaultSettings(PSETTINGS_INFO pSettingsInfo)
35 {
36 pSettingsInfo->bSaveWndPos = TRUE;
37 pSettingsInfo->bUpdateAtStart = FALSE;
38 pSettingsInfo->bLogEnabled = TRUE;
39 StringCbCopyW(pSettingsInfo->szDownloadDir,
40 sizeof(pSettingsInfo->szDownloadDir),
41 L"C:\\Downloads");
42 pSettingsInfo->bDelInstaller = FALSE;
43
44 pSettingsInfo->Maximized = FALSE;
45 pSettingsInfo->Left = 0;
46 pSettingsInfo->Top = 0;
47 pSettingsInfo->Right = 680;
48 pSettingsInfo->Bottom = 450;
49 }
50
51 static BOOL
52 LoadSettings(VOID)
53 {
54 HKEY hKey;
55 DWORD dwSize;
56
57 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\ReactOS\\rapps", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
58 {
59 dwSize = sizeof(SETTINGS_INFO);
60 if (RegQueryValueExW(hKey, L"Settings", NULL, NULL, (LPBYTE)&SettingsInfo, &dwSize) == ERROR_SUCCESS)
61 {
62 RegCloseKey(hKey);
63 return TRUE;
64 }
65
66 RegCloseKey(hKey);
67 }
68
69 return FALSE;
70 }
71
72 VOID
73 SaveSettings(HWND hwnd)
74 {
75 WINDOWPLACEMENT wp;
76 HKEY hKey;
77
78 if (SettingsInfo.bSaveWndPos)
79 {
80 wp.length = sizeof(WINDOWPLACEMENT);
81 GetWindowPlacement(hwnd, &wp);
82
83 SettingsInfo.Left = wp.rcNormalPosition.left;
84 SettingsInfo.Top = wp.rcNormalPosition.top;
85 SettingsInfo.Right = wp.rcNormalPosition.right;
86 SettingsInfo.Bottom = wp.rcNormalPosition.bottom;
87 SettingsInfo.Maximized = (IsZoomed(hwnd) || (wp.flags & WPF_RESTORETOMAXIMIZED));
88 }
89
90 if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\ReactOS\\rapps", 0, NULL,
91 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
92 {
93 RegSetValueExW(hKey, L"Settings", 0, REG_BINARY, (LPBYTE)&SettingsInfo, sizeof(SETTINGS_INFO));
94 RegCloseKey(hKey);
95 }
96 }
97
98 VOID
99 FreeInstalledAppList(VOID)
100 {
101 INT Count = ListView_GetItemCount(hListView) - 1;
102 PINSTALLED_INFO Info;
103
104 while (Count >= 0)
105 {
106 Info = ListViewGetlParam(Count);
107 if (Info)
108 {
109 RegCloseKey(Info->hSubKey);
110 HeapFree(GetProcessHeap(), 0, Info);
111 }
112 Count--;
113 }
114 }
115
116 BOOL
117 CALLBACK
118 EnumInstalledAppProc(INT ItemIndex, LPWSTR lpName, PINSTALLED_INFO Info)
119 {
120 PINSTALLED_INFO ItemInfo;
121 WCHAR szText[MAX_PATH];
122 INT Index;
123
124 if (!SearchPatternMatch(lpName, szSearchPattern))
125 return TRUE;
126
127 ItemInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(INSTALLED_INFO));
128 if (!ItemInfo) return FALSE;
129
130 RtlCopyMemory(ItemInfo, Info, sizeof(INSTALLED_INFO));
131
132 Index = ListViewAddItem(ItemIndex, 0, lpName, (LPARAM)ItemInfo);
133
134 /* Get version info */
135 GetApplicationString(ItemInfo->hSubKey, L"DisplayVersion", szText);
136 ListView_SetItemText(hListView, Index, 1, szText);
137 /* Get comments */
138 GetApplicationString(ItemInfo->hSubKey, L"Comments", szText);
139 ListView_SetItemText(hListView, Index, 2, szText);
140
141 return TRUE;
142 }
143
144 VOID
145 FreeAvailableAppList(VOID)
146 {
147 INT Count = ListView_GetItemCount(hListView) - 1;
148 PVOID Info;
149
150 while (Count >= 0)
151 {
152 Info = ListViewGetlParam(Count);
153 if (Info)
154 HeapFree(GetProcessHeap(), 0, Info);
155 Count--;
156 }
157 }
158
159 BOOL
160 CALLBACK
161 EnumAvailableAppProc(PAPPLICATION_INFO Info)
162 {
163 PAPPLICATION_INFO ItemInfo;
164 INT Index;
165
166 if (!SearchPatternMatch(Info->szName, szSearchPattern) &&
167 !SearchPatternMatch(Info->szDesc, szSearchPattern))
168 {
169 return TRUE;
170 }
171
172 /* Only add a ListView entry if...
173 - no RegName was supplied (so we cannot determine whether the application is installed or not) or
174 - a RegName was supplied and the application is not installed
175 */
176 if (!*Info->szRegName || (!IsInstalledApplication(Info->szRegName, FALSE) && !IsInstalledApplication(Info->szRegName, TRUE)))
177 {
178 ItemInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(APPLICATION_INFO));
179 if (!ItemInfo) return FALSE;
180
181 RtlCopyMemory(ItemInfo, Info, sizeof(APPLICATION_INFO));
182
183 Index = ListViewAddItem(Info->Category, 0, Info->szName, (LPARAM)ItemInfo);
184 ListView_SetItemText(hListView, Index, 1, Info->szVersion);
185 ListView_SetItemText(hListView, Index, 2, Info->szDesc);
186 }
187
188 return TRUE;
189 }
190
191 VOID
192 UpdateApplicationsList(INT EnumType)
193 {
194 WCHAR szBuffer1[MAX_STR_LEN], szBuffer2[MAX_STR_LEN];
195 HICON hIcon;
196 HIMAGELIST hImageListView;
197
198 (VOID) ListView_DeleteAllItems(hListView);
199
200 /* Create image list */
201 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
202 LISTVIEW_ICON_SIZE,
203 GetSystemColorDepth() | ILC_MASK,
204 0, 1);
205
206 hIcon = LoadImage(hInst,
207 MAKEINTRESOURCE(IDI_MAIN),
208 IMAGE_ICON,
209 LISTVIEW_ICON_SIZE,
210 LISTVIEW_ICON_SIZE,
211 LR_CREATEDIBSECTION);
212
213 ImageList_AddIcon(hImageListView, hIcon);
214 DestroyIcon(hIcon);
215
216 if (EnumType == -1) EnumType = SelectedEnumType;
217
218 if (IS_INSTALLED_ENUM(SelectedEnumType))
219 FreeInstalledAppList();
220 else if (IS_AVAILABLE_ENUM(SelectedEnumType))
221 FreeAvailableAppList();
222
223 if (IS_INSTALLED_ENUM(EnumType))
224 {
225 /* Enum installed applications and updates */
226 EnumInstalledApplications(EnumType, TRUE, EnumInstalledAppProc);
227 EnumInstalledApplications(EnumType, FALSE, EnumInstalledAppProc);
228 }
229 else if (IS_AVAILABLE_ENUM(EnumType))
230 {
231 /* Enum availabled applications */
232 EnumAvailableApplications(EnumType, EnumAvailableAppProc);
233 }
234
235 /* Set image list for ListView */
236 hImageListView = ListView_SetImageList(hListView, hImageListView, LVSIL_SMALL);
237
238 /* Destroy old image list */
239 if (hImageListView)
240 ImageList_Destroy(hImageListView);
241
242 SelectedEnumType = EnumType;
243
244 LoadStringW(hInst, IDS_APPS_COUNT, szBuffer2, sizeof(szBuffer2) / sizeof(WCHAR));
245 StringCbPrintfW(szBuffer1, sizeof(szBuffer1),
246 szBuffer2,
247 ListView_GetItemCount(hListView));
248 SetStatusBarText(szBuffer1);
249
250 SetWelcomeText();
251 }
252
253 VOID
254 InitApplicationsList(VOID)
255 {
256 WCHAR szText[MAX_STR_LEN];
257
258 /* Add columns to ListView */
259 LoadStringW(hInst, IDS_APP_NAME, szText, sizeof(szText) / sizeof(WCHAR));
260 ListViewAddColumn(0, szText, 200, LVCFMT_LEFT);
261
262 LoadStringW(hInst, IDS_APP_INST_VERSION, szText, sizeof(szText) / sizeof(WCHAR));
263 ListViewAddColumn(1, szText, 90, LVCFMT_RIGHT);
264
265 LoadStringW(hInst, IDS_APP_DESCRIPTION, szText, sizeof(szText) / sizeof(WCHAR));
266 ListViewAddColumn(3, szText, 250, LVCFMT_LEFT);
267
268 UpdateApplicationsList(ENUM_ALL_COMPONENTS);
269 }
270
271 HTREEITEM
272 AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
273 {
274 WCHAR szText[MAX_STR_LEN];
275 INT Index;
276 HICON hIcon;
277
278 hIcon = LoadImage(hInst,
279 MAKEINTRESOURCE(IconIndex),
280 IMAGE_ICON,
281 TREEVIEW_ICON_SIZE,
282 TREEVIEW_ICON_SIZE,
283 LR_CREATEDIBSECTION);
284
285 Index = ImageList_AddIcon(hImageTreeView, hIcon);
286 DestroyIcon(hIcon);
287
288 LoadStringW(hInst, TextIndex, szText, sizeof(szText) / sizeof(TCHAR));
289
290 return TreeViewAddItem(hRootItem, szText, Index, Index, TextIndex);
291 }
292
293 VOID
294 InitCategoriesList(VOID)
295 {
296 HTREEITEM hRootItem1, hRootItem2;
297
298 /* Create image list */
299 hImageTreeView = ImageList_Create(TREEVIEW_ICON_SIZE,
300 TREEVIEW_ICON_SIZE,
301 GetSystemColorDepth() | ILC_MASK,
302 0, 1);
303
304 hRootItem1 = AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY);
305 AddCategory(hRootItem1, IDS_APPLICATIONS, IDI_APPS);
306 AddCategory(hRootItem1, IDS_UPDATES, IDI_APPUPD);
307
308 hRootItem2 = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
309 AddCategory(hRootItem2, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
310 AddCategory(hRootItem2, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
311 AddCategory(hRootItem2, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
312 AddCategory(hRootItem2, IDS_CAT_GAMES, IDI_CAT_GAMES);
313 AddCategory(hRootItem2, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
314 AddCategory(hRootItem2, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
315 AddCategory(hRootItem2, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
316 AddCategory(hRootItem2, IDS_CAT_EDU, IDI_CAT_EDU);
317 AddCategory(hRootItem2, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
318 AddCategory(hRootItem2, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
319 AddCategory(hRootItem2, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
320 AddCategory(hRootItem2, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
321 AddCategory(hRootItem2, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
322 AddCategory(hRootItem2, IDS_CAT_LIBS, IDI_CAT_LIBS);
323 AddCategory(hRootItem2, IDS_CAT_OTHER, IDI_CAT_OTHER);
324
325 (VOID) TreeView_SetImageList(hTreeView, hImageTreeView, TVSIL_NORMAL);
326
327 (VOID) TreeView_Expand(hTreeView, hRootItem2, TVE_EXPAND);
328 (VOID) TreeView_Expand(hTreeView, hRootItem1, TVE_EXPAND);
329
330 (VOID) TreeView_SelectItem(hTreeView, hRootItem1);
331 }
332
333 BOOL
334 InitControls(HWND hwnd)
335 {
336 if (SettingsInfo.bSaveWndPos)
337 {
338 MoveWindow(hwnd, SettingsInfo.Left, SettingsInfo.Top,
339 SettingsInfo.Right - SettingsInfo.Left,
340 SettingsInfo.Bottom - SettingsInfo.Top, TRUE);
341
342 if (SettingsInfo.Maximized) ShowWindow(hwnd, SW_MAXIMIZE);
343 }
344
345 if (CreateStatusBar(hwnd) &&
346 CreateToolBar(hwnd) &&
347 CreateListView(hwnd) &&
348 CreateTreeView(hwnd) &&
349 CreateRichEdit(hwnd) &&
350 CreateVSplitBar(hwnd) &&
351 CreateHSplitBar(hwnd))
352 {
353 WCHAR szBuffer1[MAX_STR_LEN], szBuffer2[MAX_STR_LEN];
354
355 InitApplicationsList();
356
357 InitCategoriesList();
358
359 LoadStringW(hInst, IDS_APPS_COUNT, szBuffer2, sizeof(szBuffer2) / sizeof(WCHAR));
360 StringCbPrintfW(szBuffer1, sizeof(szBuffer1),
361 szBuffer2,
362 ListView_GetItemCount(hListView));
363 SetStatusBarText(szBuffer1);
364 return TRUE;
365 }
366
367 return FALSE;
368 }
369
370 VOID CALLBACK
371 SearchTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
372 {
373 KillTimer(hwnd, SEARCH_TIMER_ID);
374 UpdateApplicationsList(-1);
375 }
376
377 VOID
378 MainWndOnCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
379 {
380 WORD wCommand = LOWORD(wParam);
381
382 if (lParam == (LPARAM)hSearchBar)
383 {
384 WCHAR szBuf[MAX_STR_LEN];
385
386 switch (HIWORD(wParam))
387 {
388 case EN_SETFOCUS:
389 {
390 WCHAR szWndText[MAX_STR_LEN];
391
392 LoadStringW(hInst, IDS_SEARCH_TEXT, szBuf, sizeof(szBuf) / sizeof(WCHAR));
393 GetWindowTextW(hSearchBar, szWndText, MAX_STR_LEN);
394 if (wcscmp(szBuf, szWndText) == 0)
395 {
396 SearchEnabled = FALSE;
397 SetWindowTextW(hSearchBar, L"");
398 }
399 }
400 break;
401
402 case EN_KILLFOCUS:
403 {
404 GetWindowTextW(hSearchBar, szBuf, MAX_STR_LEN);
405 if (wcslen(szBuf) < 1)
406 {
407 LoadStringW(hInst, IDS_SEARCH_TEXT, szBuf, sizeof(szBuf) / sizeof(WCHAR));
408 SearchEnabled = FALSE;
409 SetWindowTextW(hSearchBar, szBuf);
410 }
411 }
412 break;
413
414 case EN_CHANGE:
415 {
416 WCHAR szWndText[MAX_STR_LEN];
417
418 if (!SearchEnabled)
419 {
420 SearchEnabled = TRUE;
421 break;
422 }
423
424 LoadStringW(hInst, IDS_SEARCH_TEXT, szBuf, sizeof(szBuf) / sizeof(WCHAR));
425 GetWindowTextW(hSearchBar, szWndText, MAX_STR_LEN);
426 if (wcscmp(szBuf, szWndText) != 0)
427 {
428 StringCbCopy(szSearchPattern, sizeof(szSearchPattern),
429 szWndText);
430 }
431 else
432 {
433 szSearchPattern[0] = UNICODE_NULL;
434 }
435
436 SetTimer(hwnd, SEARCH_TIMER_ID, 250, SearchTimerProc);
437 }
438 break;
439 }
440
441 return;
442 }
443
444 switch (wCommand)
445 {
446 case ID_OPEN_LINK:
447 ShellExecuteW(hwnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
448 HeapFree(GetProcessHeap(), 0, pLink);
449 break;
450
451 case ID_COPY_LINK:
452 CopyTextToClipboard(pLink);
453 HeapFree(GetProcessHeap(), 0, pLink);
454 break;
455
456 case ID_SETTINGS:
457 CreateSettingsDlg(hwnd);
458 break;
459
460 case ID_EXIT:
461 PostMessageW(hwnd, WM_CLOSE, 0, 0);
462 break;
463
464 case ID_INSTALL:
465 if (DownloadApplication(-1))
466 /* TODO: Implement install dialog
467 * if (InstallApplication(-1))
468 */
469 UpdateApplicationsList(-1);
470 break;
471
472 case ID_UNINSTALL:
473 if (UninstallApplication(-1, FALSE))
474 UpdateApplicationsList(-1);
475 break;
476
477 case ID_MODIFY:
478 if (UninstallApplication(-1, TRUE))
479 UpdateApplicationsList(-1);
480 break;
481
482 case ID_REGREMOVE:
483 RemoveAppFromRegistry(-1);
484 break;
485
486 case ID_REFRESH:
487 UpdateApplicationsList(-1);
488 break;
489
490 case ID_RESETDB:
491 UpdateAppsDB();
492 UpdateApplicationsList(-1);
493 break;
494
495 case ID_HELP:
496 MessageBoxW(hwnd, L"Help not implemented yet", NULL, MB_OK);
497 break;
498
499 case ID_ABOUT:
500 ShowAboutDialog();
501 break;
502 }
503 }
504
505 VOID
506 MainWndOnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
507 {
508 HDWP hdwp = BeginDeferWindowPos(5);
509 INT SearchBarWidth = GetWindowWidth(hSearchBar);
510 INT RichPos = GetWindowHeight(hRichEdit);
511 INT NewPos = HIWORD(lParam) - (RichPos + SPLIT_WIDTH + GetWindowHeight(hStatusBar));
512 INT VSplitterPos;
513
514 /* Size status bar */
515 SendMessage(hStatusBar, WM_SIZE, 0, 0);
516
517 /* Size tool bar */
518 SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
519
520 /* Size SearchBar */
521 MoveWindow(hSearchBar, LOWORD(lParam) - SearchBarWidth - 4, 5, SearchBarWidth, 22, TRUE);
522
523 /*
524 * HIWORD(lParam) - Height of main window
525 * LOWORD(lParam) - Width of main window
526 */
527
528 /* Size vertical splitter bar */
529 DeferWindowPos(hdwp,
530 hVSplitter,
531 0,
532 (VSplitterPos = GetWindowWidth(hTreeView)),
533 GetWindowHeight(hToolBar),
534 SPLIT_WIDTH,
535 HIWORD(lParam) - GetWindowHeight(hToolBar) - GetWindowHeight(hStatusBar),
536 SWP_NOZORDER|SWP_NOACTIVATE);
537
538 /* Size TreeView */
539 DeferWindowPos(hdwp,
540 hTreeView,
541 0,
542 0,
543 GetWindowHeight(hToolBar),
544 VSplitterPos,
545 HIWORD(lParam) - GetWindowHeight(hToolBar) - GetWindowHeight(hStatusBar),
546 SWP_NOZORDER|SWP_NOACTIVATE);
547
548 if(wParam != SIZE_MINIMIZED)
549 {
550 while (NewPos < SPLIT_WIDTH + GetWindowHeight(hToolBar))
551 {
552 RichPos--;
553 NewPos = HIWORD(lParam) - (RichPos +
554 SPLIT_WIDTH + GetWindowHeight(hStatusBar));
555 }
556 }
557 SetHSplitterPos(NewPos);
558
559 /* Size ListView */
560 DeferWindowPos(hdwp,
561 hListView,
562 0,
563 VSplitterPos + SPLIT_WIDTH,
564 GetWindowHeight(hToolBar),
565 LOWORD(lParam) - (VSplitterPos + SPLIT_WIDTH),
566 GetHSplitterPos() - GetWindowHeight(hToolBar),
567 SWP_NOZORDER|SWP_NOACTIVATE);
568
569 /* Size RichEdit */
570 DeferWindowPos(hdwp,
571 hRichEdit,
572 0,
573 VSplitterPos + SPLIT_WIDTH,
574 GetHSplitterPos() + SPLIT_WIDTH,
575 LOWORD(lParam) - (VSplitterPos + SPLIT_WIDTH),
576 RichPos,
577 SWP_NOZORDER|SWP_NOACTIVATE);
578
579 /* Size horizontal splitter bar */
580 DeferWindowPos(hdwp,
581 hHSplitter,
582 0,
583 VSplitterPos + SPLIT_WIDTH,
584 GetHSplitterPos(),
585 LOWORD(lParam) - (VSplitterPos + SPLIT_WIDTH),
586 SPLIT_WIDTH,
587 SWP_NOZORDER|SWP_NOACTIVATE);
588
589 EndDeferWindowPos(hdwp);
590 }
591
592 BOOL IsSelectedNodeInstalled(void)
593 {
594 HTREEITEM hSelectedItem = TreeView_GetSelection(hTreeView);
595 TV_ITEM tItem;
596
597 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
598 tItem.hItem = hSelectedItem;
599 TreeView_GetItem(hTreeView, &tItem);
600 switch (tItem.lParam)
601 {
602 case IDS_INSTALLED:
603 case IDS_APPLICATIONS:
604 case IDS_UPDATES:
605 return TRUE;
606 default:
607 return FALSE;
608 }
609 }
610
611 LRESULT CALLBACK
612 MainWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
613 {
614 switch (Msg)
615 {
616 case WM_CREATE:
617 if (!InitControls(hwnd))
618 PostMessage(hwnd, WM_CLOSE, 0, 0);
619
620 break;
621
622 case WM_COMMAND:
623 MainWndOnCommand(hwnd, wParam, lParam);
624 break;
625
626 case WM_NOTIFY:
627 {
628 LPNMHDR data = (LPNMHDR)lParam;
629
630 switch (data->code)
631 {
632 case TVN_SELCHANGED:
633 {
634 if (data->hwndFrom == hTreeView)
635 {
636 switch (((LPNMTREEVIEW)lParam)->itemNew.lParam)
637 {
638 case IDS_INSTALLED:
639 UpdateApplicationsList(ENUM_ALL_COMPONENTS);
640 break;
641
642 case IDS_APPLICATIONS:
643 UpdateApplicationsList(ENUM_APPLICATIONS);
644 break;
645
646 case IDS_UPDATES:
647 UpdateApplicationsList(ENUM_UPDATES);
648 break;
649
650 case IDS_AVAILABLEFORINST:
651 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
652 break;
653
654 case IDS_CAT_AUDIO:
655 UpdateApplicationsList(ENUM_CAT_AUDIO);
656 break;
657
658 case IDS_CAT_DEVEL:
659 UpdateApplicationsList(ENUM_CAT_DEVEL);
660 break;
661
662 case IDS_CAT_DRIVERS:
663 UpdateApplicationsList(ENUM_CAT_DRIVERS);
664 break;
665
666 case IDS_CAT_EDU:
667 UpdateApplicationsList(ENUM_CAT_EDU);
668 break;
669
670 case IDS_CAT_ENGINEER:
671 UpdateApplicationsList(ENUM_CAT_ENGINEER);
672 break;
673
674 case IDS_CAT_FINANCE:
675 UpdateApplicationsList(ENUM_CAT_FINANCE);
676 break;
677
678 case IDS_CAT_GAMES:
679 UpdateApplicationsList(ENUM_CAT_GAMES);
680 break;
681
682 case IDS_CAT_GRAPHICS:
683 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
684 break;
685
686 case IDS_CAT_INTERNET:
687 UpdateApplicationsList(ENUM_CAT_INTERNET);
688 break;
689
690 case IDS_CAT_LIBS:
691 UpdateApplicationsList(ENUM_CAT_LIBS);
692 break;
693
694 case IDS_CAT_OFFICE:
695 UpdateApplicationsList(ENUM_CAT_OFFICE);
696 break;
697
698 case IDS_CAT_OTHER:
699 UpdateApplicationsList(ENUM_CAT_OTHER);
700 break;
701
702 case IDS_CAT_SCIENCE:
703 UpdateApplicationsList(ENUM_CAT_SCIENCE);
704 break;
705
706 case IDS_CAT_TOOLS:
707 UpdateApplicationsList(ENUM_CAT_TOOLS);
708 break;
709
710 case IDS_CAT_VIDEO:
711 UpdateApplicationsList(ENUM_CAT_VIDEO);
712 break;
713 }
714 }
715
716 /* Disable/enable items based on treeview selection */
717 if (IsSelectedNodeInstalled())
718 {
719 EnableMenuItem(GetMenu(hwnd), ID_REGREMOVE, MF_ENABLED);
720 EnableMenuItem(GetMenu(hwnd), ID_INSTALL, MF_GRAYED);
721 EnableMenuItem(GetMenu(hwnd), ID_UNINSTALL, MF_ENABLED);
722 EnableMenuItem(GetMenu(hwnd), ID_MODIFY, MF_ENABLED);
723
724 EnableMenuItem(GetMenu(hListView), ID_REGREMOVE, MF_ENABLED);
725 EnableMenuItem(GetMenu(hListView), ID_INSTALL, MF_GRAYED);
726 EnableMenuItem(GetMenu(hListView), ID_UNINSTALL, MF_ENABLED);
727 EnableMenuItem(GetMenu(hListView), ID_MODIFY, MF_ENABLED);
728
729 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
730 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_INSTALL, FALSE);
731 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
732 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_MODIFY, TRUE);
733 }
734 else
735 {
736 EnableMenuItem(GetMenu(hwnd), ID_REGREMOVE, MF_GRAYED);
737 EnableMenuItem(GetMenu(hwnd), ID_INSTALL, MF_ENABLED);
738 EnableMenuItem(GetMenu(hwnd), ID_UNINSTALL, MF_GRAYED);
739 EnableMenuItem(GetMenu(hwnd), ID_MODIFY, MF_GRAYED);
740
741 EnableMenuItem(GetMenu(hListView), ID_REGREMOVE, MF_GRAYED);
742 EnableMenuItem(GetMenu(hListView), ID_INSTALL, MF_ENABLED);
743 EnableMenuItem(GetMenu(hListView), ID_UNINSTALL, MF_GRAYED);
744 EnableMenuItem(GetMenu(hListView), ID_MODIFY, MF_GRAYED);
745
746 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
747 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_INSTALL, TRUE);
748 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
749 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_MODIFY, FALSE);
750 }
751 }
752 break;
753
754 case LVN_ITEMCHANGED:
755 {
756 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
757
758 if (pnic->hdr.hwndFrom == hListView)
759 {
760 /* Check if this is a valid item
761 * (technically, it can be also an unselect) */
762 INT ItemIndex = pnic->iItem;
763 if (ItemIndex == -1 ||
764 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
765 {
766 break;
767 }
768
769 /* Check if the focus has been moved to another item */
770 if ((pnic->uChanged & LVIF_STATE) &&
771 (pnic->uNewState & LVIS_FOCUSED) &&
772 !(pnic->uOldState & LVIS_FOCUSED))
773 {
774 if (IS_INSTALLED_ENUM(SelectedEnumType))
775 ShowInstalledAppInfo(ItemIndex);
776 if (IS_AVAILABLE_ENUM(SelectedEnumType))
777 ShowAvailableAppInfo(ItemIndex);
778 }
779 }
780 }
781 break;
782
783 case LVN_COLUMNCLICK:
784 {
785 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
786
787 (VOID) ListView_SortItems(hListView, ListViewCompareFunc, pnmv->iSubItem);
788 bAscending = !bAscending;
789 }
790 break;
791
792 case NM_CLICK:
793 {
794 if (data->hwndFrom == hListView && ((LPNMLISTVIEW)lParam)->iItem != -1)
795 {
796 if (IS_INSTALLED_ENUM(SelectedEnumType))
797 ShowInstalledAppInfo(-1);
798 if (IS_AVAILABLE_ENUM(SelectedEnumType))
799 ShowAvailableAppInfo(-1);
800 }
801 }
802 break;
803
804 case NM_DBLCLK:
805 {
806 if (data->hwndFrom == hListView && ((LPNMLISTVIEW)lParam)->iItem != -1)
807 {
808 SendMessage(hwnd, WM_COMMAND, ID_INSTALL, 0); //Won't do anything if the program is already installed
809 }
810 }
811 break;
812
813 case NM_RCLICK:
814 {
815 if (data->hwndFrom == hListView && ((LPNMLISTVIEW)lParam)->iItem != -1)
816 {
817 ShowPopupMenu(hListView, 0, ID_INSTALL);
818 }
819 }
820 break;
821
822 case EN_LINK:
823 RichEditOnLink(hwnd, (ENLINK*)lParam);
824 break;
825
826 case TTN_GETDISPINFO:
827 ToolBarOnGetDispInfo((LPTOOLTIPTEXT)lParam);
828 break;
829 }
830 }
831 break;
832
833 case WM_PAINT:
834 break;
835
836 case WM_SIZE:
837 {
838 if ((GetClientWindowHeight(hMainWnd) - GetWindowHeight(hStatusBar) - SPLIT_WIDTH) < GetHSplitterPos())
839 {
840 INT NewSplitPos = GetClientWindowHeight(hwnd) - 100 - GetWindowHeight(hStatusBar) - SPLIT_WIDTH;
841 if (NewSplitPos > GetWindowHeight(hToolBar) + SPLIT_WIDTH)
842 SetHSplitterPos(NewSplitPos);
843 }
844
845 MainWndOnSize(hwnd, wParam, lParam);
846 }
847 break;
848
849 case WM_SIZING:
850 {
851 int RichEditHeight = GetWindowHeight(hRichEdit);
852 LPRECT pRect = (LPRECT)lParam;
853
854 while (RichEditHeight <= 100)
855 {
856 if (GetHSplitterPos() - 1 < GetWindowHeight(hToolBar) + GetWindowHeight(hListView) + SPLIT_WIDTH)
857 break;
858 SetHSplitterPos(GetHSplitterPos() - 1);
859 RichEditHeight++;
860 }
861
862 if (pRect->right-pRect->left < 565)
863 pRect->right = pRect->left + 565;
864
865 if (pRect->bottom-pRect->top < 300)
866 pRect->bottom = pRect->top + 300;
867 return TRUE;
868 }
869
870 case WM_SYSCOLORCHANGE:
871 {
872 /* Forward WM_SYSCOLORCHANGE to common controls */
873 SendMessage(hListView, WM_SYSCOLORCHANGE, 0, 0);
874 SendMessage(hTreeView, WM_SYSCOLORCHANGE, 0, 0);
875 SendMessage(hToolBar, WM_SYSCOLORCHANGE, 0, 0);
876 SendMessageW(hRichEdit, EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
877 }
878 break;
879
880 case WM_DESTROY:
881 {
882 ShowWindow(hwnd, SW_HIDE);
883 SaveSettings(hwnd);
884
885 FreeLogs();
886
887 if (IS_AVAILABLE_ENUM(SelectedEnumType))
888 FreeAvailableAppList();
889 if (IS_INSTALLED_ENUM(SelectedEnumType))
890 FreeInstalledAppList();
891 if (hImageTreeView) ImageList_Destroy(hImageTreeView);
892
893 PostQuitMessage(0);
894 return 0;
895 }
896 break;
897 }
898
899 return DefWindowProc(hwnd, Msg, wParam, lParam);
900 }
901
902 int WINAPI
903 wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
904 {
905 WNDCLASSEXW WndClass = {0};
906 WCHAR szWindowClass[] = L"ROSAPPMGR";
907 WCHAR szWindowName[MAX_STR_LEN];
908 HANDLE hMutex = NULL;
909 MSG Msg;
910
911 switch (GetUserDefaultUILanguage())
912 {
913 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
914 SetProcessDefaultLayout(LAYOUT_RTL);
915 break;
916
917 default:
918 break;
919 }
920
921 hInst = hInstance;
922
923 hMutex = CreateMutexW(NULL, FALSE, szWindowClass);
924 if ((!hMutex) || (GetLastError() == ERROR_ALREADY_EXISTS))
925 {
926 /* If already started, it is found its window */
927 HWND hWindow = FindWindowW(szWindowClass, NULL);
928
929 /* Activate window */
930 ShowWindow(hWindow, SW_SHOWNORMAL);
931 SetForegroundWindow(hWindow);
932 return 1;
933 }
934
935 if (!LoadSettings())
936 {
937 FillDefaultSettings(&SettingsInfo);
938 }
939
940 InitLogs();
941
942 InitCommonControls();
943
944 /* Create the window */
945 WndClass.cbSize = sizeof(WNDCLASSEXW);
946 WndClass.lpszClassName = szWindowClass;
947 WndClass.lpfnWndProc = MainWindowProc;
948 WndClass.hInstance = hInstance;
949 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
950 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
951 WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
952 WndClass.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
953
954 if (RegisterClassExW(&WndClass) == (ATOM)0) goto Exit;
955
956 LoadStringW(hInst, IDS_APPTITLE, szWindowName, sizeof(szWindowName) / sizeof(WCHAR));
957
958 hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE,
959 szWindowClass,
960 szWindowName,
961 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
962 CW_USEDEFAULT,
963 CW_USEDEFAULT,
964 680,
965 450,
966 NULL,
967 NULL,
968 hInstance,
969 NULL);
970
971 if (!hMainWnd) goto Exit;
972
973 /* Show it */
974 ShowWindow(hMainWnd, nShowCmd);
975 UpdateWindow(hMainWnd);
976
977 if (SettingsInfo.bUpdateAtStart)
978 UpdateAppsDB();
979
980 /* Message Loop */
981 while (GetMessage(&Msg, NULL, 0, 0))
982 {
983 TranslateMessage(&Msg);
984 DispatchMessage(&Msg);
985 }
986
987 Exit:
988 if (hMutex) CloseHandle(hMutex);
989
990 return 0;
991 }