[RAPPS] Refresh item info after installer completes (#7697)

- Refresh the details view of the item that was just installed.
- Hint update of uninstallers list is needed.
- Restore focus correctly after installer process finishes.

CORE-17677
This commit is contained in:
Whindmar Saksit 2025-02-07 21:33:19 +01:00 committed by GitHub
parent a610016952
commit 5bc6d59142
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 109 additions and 29 deletions

View file

@ -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);
}

View file

@ -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<CAppInfo *>(CallbackParam);
m_AppsInfo->ShowAppInfo(Info);
RefreshDetailsPane(*Info);
if (ApplicationViewType == AppViewTypeInstalledApps)
{

View file

@ -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

View file

@ -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
{

View file

@ -175,7 +175,7 @@ class CAppInfoDisplay : public CUiWindow<CWindowImpl<CAppInfoDisplay>>
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<CWindowImpl<CApplicationView>>
void
SetRedraw(BOOL bRedraw);
void
RefreshAvailableItem(PCWSTR PackageName);
void
SetFocusOnSearchBar();
BOOL
SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
@ -415,6 +417,9 @@ class CApplicationView : public CUiWindow<CWindowImpl<CApplicationView>>
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

View file

@ -65,6 +65,9 @@ class CMainWindow : public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
AppsCategories SelectedEnumType;
public:
static HWND m_hLastFocus;
static bool m_PendingInstalledViewRefresh;
explicit CMainWindow(CAppDB *db, BOOL bAppwiz = FALSE);
~CMainWindow();

View file

@ -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

View file

@ -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<const CAvailableApplicationInfo&>(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
{

View file

@ -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);
}

View file

@ -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);