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