[RAPPS] unuglify icons. CORE-10642
[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(SETTINGS_INFO);
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(WINDOWPLACEMENT);
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(SETTINGS_INFO));
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 availabled 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 DeferWindowPos(hdwp,
521 hVSplitter,
522 0,
523 (VSplitterPos = GetWindowWidth(hTreeView)),
524 GetWindowHeight(hToolBar),
525 SPLIT_WIDTH,
526 HIWORD(lParam) - GetWindowHeight(hToolBar) - GetWindowHeight(hStatusBar),
527 SWP_NOZORDER|SWP_NOACTIVATE);
528
529 /* Size TreeView */
530 DeferWindowPos(hdwp,
531 hTreeView,
532 0,
533 0,
534 GetWindowHeight(hToolBar),
535 VSplitterPos,
536 HIWORD(lParam) - GetWindowHeight(hToolBar) - GetWindowHeight(hStatusBar),
537 SWP_NOZORDER|SWP_NOACTIVATE);
538
539 if(wParam != SIZE_MINIMIZED)
540 {
541 while (NewPos < SPLIT_WIDTH + GetWindowHeight(hToolBar))
542 {
543 RichPos--;
544 NewPos = HIWORD(lParam) - (RichPos +
545 SPLIT_WIDTH + GetWindowHeight(hStatusBar));
546 }
547 }
548 SetHSplitterPos(NewPos);
549
550 /* Size ListView */
551 DeferWindowPos(hdwp,
552 hListView,
553 0,
554 VSplitterPos + SPLIT_WIDTH,
555 GetWindowHeight(hToolBar),
556 LOWORD(lParam) - (VSplitterPos + SPLIT_WIDTH),
557 GetHSplitterPos() - GetWindowHeight(hToolBar),
558 SWP_NOZORDER|SWP_NOACTIVATE);
559
560 /* Size RichEdit */
561 DeferWindowPos(hdwp,
562 hRichEdit,
563 0,
564 VSplitterPos + SPLIT_WIDTH,
565 GetHSplitterPos() + SPLIT_WIDTH,
566 LOWORD(lParam) - (VSplitterPos + SPLIT_WIDTH),
567 RichPos,
568 SWP_NOZORDER|SWP_NOACTIVATE);
569
570 /* Size horizontal splitter bar */
571 DeferWindowPos(hdwp,
572 hHSplitter,
573 0,
574 VSplitterPos + SPLIT_WIDTH,
575 GetHSplitterPos(),
576 LOWORD(lParam) - (VSplitterPos + SPLIT_WIDTH),
577 SPLIT_WIDTH,
578 SWP_NOZORDER|SWP_NOACTIVATE);
579
580 EndDeferWindowPos(hdwp);
581 }
582
583 BOOL IsSelectedNodeInstalled(void)
584 {
585 HTREEITEM hSelectedItem = TreeView_GetSelection(hTreeView);
586 TV_ITEM tItem;
587
588 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
589 tItem.hItem = hSelectedItem;
590 TreeView_GetItem(hTreeView, &tItem);
591 switch (tItem.lParam)
592 {
593 case IDS_INSTALLED:
594 case IDS_APPLICATIONS:
595 case IDS_UPDATES:
596 return TRUE;
597 default:
598 return FALSE;
599 }
600 }
601
602 LRESULT CALLBACK
603 MainWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
604 {
605
606 switch (Msg)
607 {
608 case WM_CREATE:
609 if (!InitControls(hwnd))
610 PostMessage(hwnd, WM_CLOSE, 0, 0);
611 break;
612
613 case WM_COMMAND:
614 MainWndOnCommand(hwnd, wParam, lParam);
615 break;
616
617 case WM_NOTIFY:
618 {
619 LPNMHDR data = (LPNMHDR)lParam;
620
621 switch (data->code)
622 {
623 case TVN_SELCHANGED:
624 {
625 if (data->hwndFrom == hTreeView)
626 {
627 switch (((LPNMTREEVIEW)lParam)->itemNew.lParam)
628 {
629 case IDS_INSTALLED:
630 UpdateApplicationsList(ENUM_ALL_COMPONENTS);
631 break;
632
633 case IDS_APPLICATIONS:
634 UpdateApplicationsList(ENUM_APPLICATIONS);
635 break;
636
637 case IDS_UPDATES:
638 UpdateApplicationsList(ENUM_UPDATES);
639 break;
640
641 case IDS_AVAILABLEFORINST:
642 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
643 break;
644
645 case IDS_CAT_AUDIO:
646 UpdateApplicationsList(ENUM_CAT_AUDIO);
647 break;
648
649 case IDS_CAT_DEVEL:
650 UpdateApplicationsList(ENUM_CAT_DEVEL);
651 break;
652
653 case IDS_CAT_DRIVERS:
654 UpdateApplicationsList(ENUM_CAT_DRIVERS);
655 break;
656
657 case IDS_CAT_EDU:
658 UpdateApplicationsList(ENUM_CAT_EDU);
659 break;
660
661 case IDS_CAT_ENGINEER:
662 UpdateApplicationsList(ENUM_CAT_ENGINEER);
663 break;
664
665 case IDS_CAT_FINANCE:
666 UpdateApplicationsList(ENUM_CAT_FINANCE);
667 break;
668
669 case IDS_CAT_GAMES:
670 UpdateApplicationsList(ENUM_CAT_GAMES);
671 break;
672
673 case IDS_CAT_GRAPHICS:
674 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
675 break;
676
677 case IDS_CAT_INTERNET:
678 UpdateApplicationsList(ENUM_CAT_INTERNET);
679 break;
680
681 case IDS_CAT_LIBS:
682 UpdateApplicationsList(ENUM_CAT_LIBS);
683 break;
684
685 case IDS_CAT_OFFICE:
686 UpdateApplicationsList(ENUM_CAT_OFFICE);
687 break;
688
689 case IDS_CAT_OTHER:
690 UpdateApplicationsList(ENUM_CAT_OTHER);
691 break;
692
693 case IDS_CAT_SCIENCE:
694 UpdateApplicationsList(ENUM_CAT_SCIENCE);
695 break;
696
697 case IDS_CAT_TOOLS:
698 UpdateApplicationsList(ENUM_CAT_TOOLS);
699 break;
700
701 case IDS_CAT_VIDEO:
702 UpdateApplicationsList(ENUM_CAT_VIDEO);
703 break;
704 }
705 }
706
707 /* Disable/enable items based on treeview selection */
708 if (IsSelectedNodeInstalled())
709 {
710 EnableMenuItem(GetMenu(hwnd), ID_REGREMOVE, MF_ENABLED);
711 EnableMenuItem(GetMenu(hwnd), ID_INSTALL, MF_GRAYED);
712 EnableMenuItem(GetMenu(hwnd), ID_UNINSTALL, MF_ENABLED);
713 EnableMenuItem(GetMenu(hwnd), ID_MODIFY, MF_ENABLED);
714
715 EnableMenuItem(GetMenu(hListView), ID_REGREMOVE, MF_ENABLED);
716 EnableMenuItem(GetMenu(hListView), ID_INSTALL, MF_GRAYED);
717 EnableMenuItem(GetMenu(hListView), ID_UNINSTALL, MF_ENABLED);
718 EnableMenuItem(GetMenu(hListView), ID_MODIFY, MF_ENABLED);
719
720 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
721 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_INSTALL, FALSE);
722 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
723 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_MODIFY, TRUE);
724 }
725 else
726 {
727 EnableMenuItem(GetMenu(hwnd), ID_REGREMOVE, MF_GRAYED);
728 EnableMenuItem(GetMenu(hwnd), ID_INSTALL, MF_ENABLED);
729 EnableMenuItem(GetMenu(hwnd), ID_UNINSTALL, MF_GRAYED);
730 EnableMenuItem(GetMenu(hwnd), ID_MODIFY, MF_GRAYED);
731
732 EnableMenuItem(GetMenu(hListView), ID_REGREMOVE, MF_GRAYED);
733 EnableMenuItem(GetMenu(hListView), ID_INSTALL, MF_ENABLED);
734 EnableMenuItem(GetMenu(hListView), ID_UNINSTALL, MF_GRAYED);
735 EnableMenuItem(GetMenu(hListView), ID_MODIFY, MF_GRAYED);
736
737 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
738 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_INSTALL, TRUE);
739 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
740 SendMessage(hToolBar, TB_ENABLEBUTTON, ID_MODIFY, FALSE);
741 }
742 }
743 break;
744
745 case LVN_ITEMCHANGED:
746 {
747 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
748
749 if (pnic->hdr.hwndFrom == hListView)
750 {
751 /* Check if this is a valid item
752 * (technically, it can be also an unselect) */
753 INT ItemIndex = pnic->iItem;
754 if (ItemIndex == -1 ||
755 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
756 {
757 break;
758 }
759
760 /* Check if the focus has been moved to another item */
761 if ((pnic->uChanged & LVIF_STATE) &&
762 (pnic->uNewState & LVIS_FOCUSED) &&
763 !(pnic->uOldState & LVIS_FOCUSED))
764 {
765 if (IS_INSTALLED_ENUM(SelectedEnumType))
766 ShowInstalledAppInfo(ItemIndex);
767 if (IS_AVAILABLE_ENUM(SelectedEnumType))
768 ShowAvailableAppInfo(ItemIndex);
769 }
770 }
771 }
772 break;
773
774 case LVN_COLUMNCLICK:
775 {
776 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
777
778 (VOID) ListView_SortItems(hListView, ListViewCompareFunc, pnmv->iSubItem);
779 bAscending = !bAscending;
780 }
781 break;
782
783 case NM_CLICK:
784 {
785 if (data->hwndFrom == hListView && ((LPNMLISTVIEW)lParam)->iItem != -1)
786 {
787 if (IS_INSTALLED_ENUM(SelectedEnumType))
788 ShowInstalledAppInfo(-1);
789 if (IS_AVAILABLE_ENUM(SelectedEnumType))
790 ShowAvailableAppInfo(-1);
791 }
792 }
793 break;
794
795 case NM_DBLCLK:
796 {
797 if (data->hwndFrom == hListView && ((LPNMLISTVIEW)lParam)->iItem != -1)
798 {
799 /* this won't do anything if the program is already installed */
800 SendMessage(hwnd, WM_COMMAND, ID_INSTALL, 0);
801 }
802 }
803 break;
804
805 case NM_RCLICK:
806 {
807 if (data->hwndFrom == hListView && ((LPNMLISTVIEW)lParam)->iItem != -1)
808 {
809 ShowPopupMenu(hListView, 0, ID_INSTALL);
810 }
811 }
812 break;
813
814 case EN_LINK:
815 RichEditOnLink(hwnd, (ENLINK*)lParam);
816 break;
817
818 case TTN_GETDISPINFO:
819 ToolBarOnGetDispInfo((LPTOOLTIPTEXT)lParam);
820 break;
821 }
822 }
823 break;
824
825 case WM_PAINT:
826 break;
827
828 case WM_SIZE:
829 {
830 if ((GetClientWindowHeight(hMainWnd) - GetWindowHeight(hStatusBar) - SPLIT_WIDTH) < GetHSplitterPos())
831 {
832 INT NewSplitPos = GetClientWindowHeight(hwnd) - 100 - GetWindowHeight(hStatusBar) - SPLIT_WIDTH;
833 if (NewSplitPos > GetWindowHeight(hToolBar) + SPLIT_WIDTH)
834 SetHSplitterPos(NewSplitPos);
835 }
836
837 MainWndOnSize(hwnd, wParam, lParam);
838 }
839 break;
840
841 case WM_SIZING:
842 {
843 int RichEditHeight = GetWindowHeight(hRichEdit);
844 LPRECT pRect = (LPRECT)lParam;
845
846 while (RichEditHeight <= 100)
847 {
848 if (GetHSplitterPos() - 1 < GetWindowHeight(hToolBar) + GetWindowHeight(hListView) + SPLIT_WIDTH)
849 break;
850 SetHSplitterPos(GetHSplitterPos() - 1);
851 RichEditHeight++;
852 }
853
854 if (pRect->right-pRect->left < 565)
855 pRect->right = pRect->left + 565;
856
857 if (pRect->bottom-pRect->top < 300)
858 pRect->bottom = pRect->top + 300;
859 return TRUE;
860 }
861
862 case WM_SYSCOLORCHANGE:
863 {
864 /* Forward WM_SYSCOLORCHANGE to common controls */
865 SendMessage(hListView, WM_SYSCOLORCHANGE, 0, 0);
866 SendMessage(hTreeView, WM_SYSCOLORCHANGE, 0, 0);
867 SendMessage(hToolBar, WM_SYSCOLORCHANGE, 0, 0);
868 SendMessageW(hRichEdit, EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
869 }
870 break;
871
872 case WM_DESTROY:
873 {
874 ShowWindow(hwnd, SW_HIDE);
875 SaveSettings(hwnd);
876
877 FreeLogs();
878
879 FreeCachedAvailableEntries();
880
881 if (IS_INSTALLED_ENUM(SelectedEnumType))
882 FreeInstalledAppList();
883
884 if (hImageTreeView)
885 ImageList_Destroy(hImageTreeView);
886
887 PostQuitMessage(0);
888 return 0;
889 }
890 break;
891 }
892
893 return DefWindowProc(hwnd, Msg, wParam, lParam);
894 }
895
896 int WINAPI
897 wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
898 {
899 WNDCLASSEXW WndClass = {0};
900 WCHAR szWindowClass[] = L"ROSAPPMGR";
901 WCHAR szWindowName[MAX_STR_LEN];
902 HANDLE hMutex = NULL;
903 HACCEL KeyBrd;
904 MSG Msg;
905
906 switch (GetUserDefaultUILanguage())
907 {
908 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
909 SetProcessDefaultLayout(LAYOUT_RTL);
910 break;
911
912 default:
913 break;
914 }
915
916 hInst = hInstance;
917
918 hMutex = CreateMutexW(NULL, FALSE, szWindowClass);
919 if ((!hMutex) || (GetLastError() == ERROR_ALREADY_EXISTS))
920 {
921 /* If already started, it is found its window */
922 HWND hWindow = FindWindowW(szWindowClass, NULL);
923
924 /* Activate window */
925 ShowWindow(hWindow, SW_SHOWNORMAL);
926 SetForegroundWindow(hWindow);
927 return 1;
928 }
929
930 if (!LoadSettings())
931 {
932 FillDefaultSettings(&SettingsInfo);
933 }
934
935 InitLogs();
936
937 InitCommonControls();
938
939 /* Create the window */
940 WndClass.cbSize = sizeof(WNDCLASSEXW);
941 WndClass.lpszClassName = szWindowClass;
942 WndClass.lpfnWndProc = MainWindowProc;
943 WndClass.hInstance = hInstance;
944 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
945 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
946 WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
947 WndClass.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
948
949 if (RegisterClassExW(&WndClass) == (ATOM)0) goto Exit;
950
951 LoadStringW(hInst, IDS_APPTITLE, szWindowName, _countof(szWindowName));
952
953 hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE,
954 szWindowClass,
955 szWindowName,
956 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
957 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
958 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
959 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
960 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450),
961 NULL,
962 NULL,
963 hInstance,
964 NULL);
965
966 if (!hMainWnd) goto Exit;
967
968 /* Maximize it if we must */
969 ShowWindow(hMainWnd, (SettingsInfo.bSaveWndPos && SettingsInfo.Maximized ? SW_MAXIMIZE : nShowCmd));
970 UpdateWindow(hMainWnd);
971
972 if (SettingsInfo.bUpdateAtStart)
973 UpdateAppsDB();
974
975 /* Load the menu hotkeys */
976 KeyBrd = LoadAccelerators(NULL, MAKEINTRESOURCE(HOTKEYS));
977
978 /* Message Loop */
979 while (GetMessage(&Msg, NULL, 0, 0))
980 {
981 if (!TranslateAccelerator(hMainWnd, KeyBrd, &Msg))
982 {
983 TranslateMessage(&Msg);
984 DispatchMessage(&Msg);
985 }
986 }
987
988 Exit:
989 if (hMutex)
990 CloseHandle(hMutex);
991
992 return 0;
993 }