diff --git a/base/applications/rapps/appinfo.cpp b/base/applications/rapps/appinfo.cpp index 1970b9459d9..5442380fbad 100644 --- a/base/applications/rapps/appinfo.cpp +++ b/base/applications/rapps/appinfo.cpp @@ -10,6 +10,14 @@ #include "rapps.h" #include "appview.h" +static inline AppsCategories +ClampAvailableCategory(AppsCategories Category) +{ + if (Category <= ENUM_LASTCATEGORY) + return Category; + return ENUM_CAT_OTHER; // Treat future categories we don't know as Other +} + CAppInfo::CAppInfo(const CStringW &Identifier, AppsCategories Category) : szIdentifier(Identifier), iCategory(Category) { @@ -24,7 +32,7 @@ CAvailableApplicationInfo::CAvailableApplicationInfo( const CStringW &PkgName, AppsCategories Category, const CPathW &BasePath) - : CAppInfo(PkgName, Category), m_Parser(Parser), m_ScrnshotRetrieved(false), m_LanguagesLoaded(false) + : CAppInfo(PkgName, ClampAvailableCategory(Category)), m_Parser(Parser), m_ScrnshotRetrieved(false), m_LanguagesLoaded(false) { m_Parser->GetString(L"Name", szDisplayName); m_Parser->GetString(L"Version", szDisplayVersion); @@ -588,7 +596,7 @@ CInstalledApplicationInfo::GetInstallerType() const BOOL CInstalledApplicationInfo::UninstallApplication(UninstallCommandFlags Flags) { - if (GetInstallerType() == INSTALLER_GENERATE) + if (GetInstallerType() == INSTALLER_GENERATE && (Flags & UCF_SAMEPROCESS)) { return UninstallGenerated(*this, Flags); } diff --git a/base/applications/rapps/appview.cpp b/base/applications/rapps/appview.cpp index c0f18107c1e..248050ebb92 100644 --- a/base/applications/rapps/appview.cpp +++ b/base/applications/rapps/appview.cpp @@ -955,19 +955,22 @@ CAppInfoDisplay::Create(HWND hwndParent) } VOID -CAppInfoDisplay::ShowAppInfo(CAppInfo *Info) +CAppInfoDisplay::ShowAppInfo(CAppInfo &Info, bool OnlyUpdateText) { - CStringW ScrnshotLocation; - if (Info->RetrieveScreenshot(ScrnshotLocation)) + if (!OnlyUpdateText) { - ScrnshotPrev->DisplayImage(ScrnshotLocation); - } - else - { - ScrnshotPrev->DisplayEmpty(); + CStringW ScrnshotLocation; + if (Info.RetrieveScreenshot(ScrnshotLocation)) + { + ScrnshotPrev->DisplayImage(ScrnshotLocation); + } + else + { + ScrnshotPrev->DisplayEmpty(); + } } ResizeChildren(); - Info->ShowAppInfo(RichEdit); + Info.ShowAppInfo(RichEdit); } void @@ -1805,6 +1808,22 @@ CApplicationView::SetRedraw(BOOL bRedraw) m_ListView->SetRedraw(bRedraw); } +void +CApplicationView::RefreshAvailableItem(PCWSTR PackageName) +{ + if (ApplicationViewType != AppViewTypeAvailableApps || !PackageName) + return; + CAppInfo *pApp; + for (UINT i = 0; (pApp = (CAppInfo*)m_ListView->GetItemData(i)) != NULL; ++i) + { + if (pApp->szIdentifier.CompareNoCase(PackageName) == 0) + { + RefreshDetailsPane(*pApp, true); + break; + } + } +} + void CApplicationView::SetFocusOnSearchBar() { @@ -2134,6 +2153,12 @@ CApplicationView::RestoreListSelection(const RESTORELISTSELECTION &Restore) } } +VOID +CApplicationView::RefreshDetailsPane(CAppInfo &Info, bool OnlyUpdateText) +{ + m_AppsInfo->ShowAppInfo(Info, OnlyUpdateText); +} + // this function is called when a item of listview get focus. // CallbackParam is the param passed to listview when adding the item (the one getting focus now). VOID @@ -2142,7 +2167,7 @@ CApplicationView::ItemGetFocus(LPVOID CallbackParam) if (CallbackParam) { CAppInfo *Info = static_cast(CallbackParam); - m_AppsInfo->ShowAppInfo(Info); + RefreshDetailsPane(*Info); if (ApplicationViewType == AppViewTypeInstalledApps) { diff --git a/base/applications/rapps/gui.cpp b/base/applications/rapps/gui.cpp index 6f2e1a1d3d8..8470ba092d1 100644 --- a/base/applications/rapps/gui.cpp +++ b/base/applications/rapps/gui.cpp @@ -81,6 +81,8 @@ CSideTreeView::~CSideTreeView() // **** CSideTreeView **** // **** CMainWindow **** +HWND CMainWindow::m_hLastFocus = NULL; +bool CMainWindow::m_PendingInstalledViewRefresh = false; CMainWindow::CMainWindow(CAppDB *db, BOOL bAppwiz) : m_ClientPanel(NULL), m_Db(db), m_bAppwizMode(bAppwiz), SelectedEnumType(ENUM_ALL_INSTALLED) { @@ -343,10 +345,32 @@ CMainWindow::ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lPa SendMessage(WM_CLOSE, 0, 0); break; + case WM_NOTIFY_INSTALLERFINISHED: + m_PendingInstalledViewRefresh = true; // Something just installed, our uninstall list is probably outdated + m_ApplicationView->RefreshAvailableItem((PCWSTR)lParam); + break; + case DM_REPOSITION: EmulateDialogReposition(hwnd); // We are not a real dialog, we need help from a real one break; + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) + m_hLastFocus = ::GetFocus(); + break; + + case WM_SETFOCUS: + if (m_hLastFocus) + ::SetFocus(m_hLastFocus); + break; + + case WM_NEXTDLGCTL: + if (!LOWORD(lParam)) + HandleTabOrder(wParam ? -1 : 1); + else if (wParam) + ::SetFocus((HWND)wParam); + break; + case WM_COMMAND: OnCommand(wParam, lParam); break; @@ -678,6 +702,12 @@ CMainWindow::UpdateApplicationsList(AppsCategories EnumType, BOOL bReload, BOOL if (bCheckAvailable) CheckAvailable(); + if (m_PendingInstalledViewRefresh && IsInstalledEnum(EnumType) && !IsInstalledEnum(SelectedEnumType)) + { + m_PendingInstalledViewRefresh = FALSE; + bReload = TRUE; // Reload because we are switching from Available to Installed after something installed + } + BOOL TryRestoreSelection = SelectedEnumType == EnumType; if (SelectedEnumType != EnumType) SelectedEnumType = EnumType; @@ -812,16 +842,7 @@ CMainWindow::ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam) BOOL CMainWindow::InstallApplication(CAppInfo *Info) { - if (Info) - { - if (DownloadApplication(Info)) - { - //FIXME: Delay UpdateApplicationsList(SelectedEnumType); until install completes - return TRUE; - } - } - - return FALSE; + return Info && DownloadApplication(Info); } BOOL diff --git a/base/applications/rapps/include/appinfo.h b/base/applications/rapps/include/appinfo.h index 32cfc20b3dd..961ad0711bd 100644 --- a/base/applications/rapps/include/appinfo.h +++ b/base/applications/rapps/include/appinfo.h @@ -41,6 +41,7 @@ enum AppsCategories ENUM_CAT_THEMES, ENUM_CAT_OTHER, ENUM_CAT_SELECTED, + ENUM_LASTCATEGORY = ENUM_CAT_SELECTED - 1, ENUM_ALL_INSTALLED = 30, ENUM_INSTALLED_APPLICATIONS, ENUM_UPDATES, @@ -54,6 +55,12 @@ enum AppsCategories inline BOOL IsAvailableEnum(INT x) { + C_ASSERT(ENUM_CAT_AUDIO == 1 && ENUM_CAT_THEMES == 15 && ENUM_CAT_OTHER == 16); + C_ASSERT(ENUM_LASTCATEGORY >= ENUM_CAT_OTHER); + C_ASSERT(ENUM_LASTCATEGORY < ENUM_CAT_SELECTED); + C_ASSERT(ENUM_LASTCATEGORY < ENUM_INSTALLED_MIN); + C_ASSERT(ENUM_CAT_SELECTED < ENUM_INSTALLED_MIN); + return (x >= ENUM_AVAILABLE_MIN && x <= ENUM_AVAILABLE_MAX); } @@ -68,7 +75,9 @@ enum UninstallCommandFlags UCF_NONE = 0x00, UCF_MODIFY = 0x01, UCF_SILENT = 0x02, + UCF_SAMEPROCESS = 0x04, }; +DEFINE_ENUM_FLAG_OPERATORS(UninstallCommandFlags); enum InstallerType { diff --git a/base/applications/rapps/include/appview.h b/base/applications/rapps/include/appview.h index d457d45c799..169d0b23151 100644 --- a/base/applications/rapps/include/appview.h +++ b/base/applications/rapps/include/appview.h @@ -175,7 +175,7 @@ class CAppInfoDisplay : public CUiWindow> Create(HWND hwndParent); VOID - ShowAppInfo(CAppInfo *Info); + ShowAppInfo(CAppInfo &Info, bool OnlyUpdateText = false); void SetWelcomeText(bool bAppwiz); VOID @@ -388,6 +388,8 @@ class CApplicationView : public CUiWindow> void SetRedraw(BOOL bRedraw); void + RefreshAvailableItem(PCWSTR PackageName); + void SetFocusOnSearchBar(); BOOL SetDisplayAppType(APPLICATION_VIEW_TYPE AppType); @@ -415,6 +417,9 @@ class CApplicationView : public CUiWindow> VOID RestoreListSelection(const RESTORELISTSELECTION &Restore); + VOID + RefreshDetailsPane(CAppInfo &Info, bool OnlyUpdateText = false); + // this function is called when a item of listview get focus. // CallbackParam is the param passed to listview when adding the item (the one getting focus now). VOID diff --git a/base/applications/rapps/include/gui.h b/base/applications/rapps/include/gui.h index 36ff852dde3..fbe36a7fea1 100644 --- a/base/applications/rapps/include/gui.h +++ b/base/applications/rapps/include/gui.h @@ -65,6 +65,9 @@ class CMainWindow : public CWindowImpl AppsCategories SelectedEnumType; public: + static HWND m_hLastFocus; + static bool m_PendingInstalledViewRefresh; + explicit CMainWindow(CAppDB *db, BOOL bAppwiz = FALSE); ~CMainWindow(); diff --git a/base/applications/rapps/include/rapps.h b/base/applications/rapps/include/rapps.h index c03a06d092d..f42c5919c2e 100644 --- a/base/applications/rapps/include/rapps.h +++ b/base/applications/rapps/include/rapps.h @@ -14,8 +14,10 @@ #include "configparser.h" extern LONG g_Busy; +extern bool g_PendingInstalledViewRefresh; #define WM_NOTIFY_OPERATIONCOMPLETED (WM_APP + 0) +#define WM_NOTIFY_INSTALLERFINISHED (WM_APP + 1) #define MAINWINDOWCLASSNAME L"ROSAPPMGR2" #define MAINWINDOWMUTEX szWindowClass diff --git a/base/applications/rapps/loaddlg.cpp b/base/applications/rapps/loaddlg.cpp index c863a5e2165..21b7b88d1fc 100644 --- a/base/applications/rapps/loaddlg.cpp +++ b/base/applications/rapps/loaddlg.cpp @@ -142,8 +142,7 @@ struct DownloadInfo AppInfo.GetDownloadInfo(szUrl, szSHA1, SizeInBytes); szName = AppInfo.szDisplayName; IType = AppInfo.GetInstallerType(); - if (IType == INSTALLER_GENERATE) - szPackageName = AppInfo.szIdentifier; + szPackageName = AppInfo.szIdentifier; CConfigParser *cfg = static_cast(AppInfo).GetConfigParser(); if (cfg) @@ -452,6 +451,8 @@ ShowLastError(HWND hWndOwner, BOOL bInetError, DWORD dwLastError) return FALSE; } + if (hWndOwner && !IsWindowVisible(hWndOwner)) + hWndOwner = NULL; MessageBoxW(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR); return TRUE; } @@ -1090,8 +1091,12 @@ run: SendMessageW(hDlg, WM_SETSTATUS, DLSTATUS_INSTALLING, 0); // TODO: issue an install operation separately so that the apps could be downloaded in the background - WaitForSingleObject(shExInfo.hProcess, INFINITE); - CloseHandle(shExInfo.hProcess); + if (shExInfo.hProcess) + { + WaitForSingleObject(shExInfo.hProcess, INFINITE); + CloseHandle(shExInfo.hProcess); + SendMessageW(hMainWnd, WM_NOTIFY_INSTALLERFINISHED, 0, (LPARAM)(PCWSTR)Info.szPackageName); + } } else { diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp index c5fe6f0c4bc..baafe5309fd 100644 --- a/base/applications/rapps/misc.cpp +++ b/base/applications/rapps/misc.cpp @@ -160,6 +160,8 @@ StartProcess(const CStringW &Path, BOOL Wait) { EnableWindow(hMainWnd, TRUE); SetForegroundWindow(hMainWnd); + // We got the real activation message during MsgWaitForMultipleObjects while + // we were disabled, we need to set the focus again now. SetFocus(hMainWnd); } diff --git a/base/applications/rapps/unattended.cpp b/base/applications/rapps/unattended.cpp index 4967f259de3..06db5f0aba6 100644 --- a/base/applications/rapps/unattended.cpp +++ b/base/applications/rapps/unattended.cpp @@ -191,7 +191,7 @@ HandleUninstallCommand(CAppDB &db, UINT argcLeft, LPWSTR *argvLeft) if (pInfo) { - retval = pInfo->UninstallApplication(silent ? UCF_SILENT : UCF_NONE); + retval = pInfo->UninstallApplication((silent ? UCF_SILENT : UCF_NONE) | UCF_SAMEPROCESS); } delete pDelete; return retval; @@ -368,7 +368,7 @@ ParseCmdAndExecute(LPWSTR lpCmdLine, BOOL bIsFirstLaunch, int nCmdShow) if (hWindow) { /* Activate the window in the other instance */ - ShowWindow(hWindow, SW_SHOW); + ShowWindow(hWindow, SW_SHOWNA); SwitchToThisWindow(hWindow, TRUE); if (bAppwizMode) PostMessage(hWindow, WM_COMMAND, ID_ACTIVATE_APPWIZ, 0);