Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Workspaces] Implement PWA recognition, launch. #35913

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ CRH
critsec
Crossdevice
CRSEL
crx
crw
CSearch
CSettings
Expand Down Expand Up @@ -639,6 +640,7 @@ HWNDLAST
HWNDNEXT
HWNDPREV
hyjiacan
IApp
IBeam
ICapture
IClass
Expand Down Expand Up @@ -1140,7 +1142,7 @@ pdo
pdto
pdtobj
pdw
Peb
peb
pef
PElems
Pels
Expand Down Expand Up @@ -1627,6 +1629,7 @@ tkconverters
TLayout
tlb
tlbimp
tlhelp
TMPVAR
TNP
Toolhelp
Expand Down
2 changes: 2 additions & 0 deletions src/modules/Workspaces/WorkspacesEditor/Data/ProjectData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public struct WindowPositionWrapper

public string AppUserModelId { get; set; }

public string PwaAppId { get; set; }

public string CommandLineArguments { get; set; }

public bool IsElevated { get; set; }
Expand Down
40 changes: 39 additions & 1 deletion src/modules/Workspaces/WorkspacesEditor/Models/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
Expand All @@ -16,6 +17,8 @@

using ManagedCommon;
using Windows.Management.Deployment;
using Windows.UI.Xaml;
using WorkspacesEditor.ViewModels;

namespace WorkspacesEditor.Models
{
Expand All @@ -37,6 +40,7 @@ public Application(Application other)
AppTitle = other.AppTitle;
PackageFullName = other.PackageFullName;
AppUserModelId = other.AppUserModelId;
PwaAppId = other.PwaAppId;
CommandLineArguments = other.CommandLineArguments;
IsElevated = other.IsElevated;
CanLaunchElevated = other.CanLaunchElevated;
Expand Down Expand Up @@ -110,6 +114,8 @@ public override int GetHashCode()

public string CommandLineArguments { get; set; }

public string PwaAppId { get; set; }

private bool _isElevated;

public bool IsElevated
Expand Down Expand Up @@ -241,10 +247,32 @@ public Icon Icon
var iconHandle = bitmap.GetHicon();
_icon = Icon.FromHandle(iconHandle);
}
else
else if (MainViewModel.IsPwaApp(this))
{
string iconFilename = MainViewModel.GetPwaIconFilename(this);
if (iconFilename != null)
{
Bitmap bitmap;
if (iconFilename.EndsWith("ico", StringComparison.InvariantCultureIgnoreCase))
{
bitmap = new Bitmap(iconFilename);
}
else
{
bitmap = (Bitmap)Image.FromFile(iconFilename);
}

var iconHandle = bitmap.GetHicon();
_icon = Icon.FromHandle(iconHandle);
}
}

if (_icon == null)
{
_icon = Icon.ExtractAssociatedIcon(AppPath);
}

IsNotFound = false;
}
catch (Exception)
{
Expand Down Expand Up @@ -474,5 +502,15 @@ internal void MinimizedChecked()
{
Maximized = false;
}

internal bool IsEdge()
{
return AppPath.EndsWith("edge.exe", StringComparison.InvariantCultureIgnoreCase);
}

internal bool IsChrome()
{
return AppPath.EndsWith("chrome.exe", StringComparison.InvariantCultureIgnoreCase);
}
}
}
1 change: 1 addition & 0 deletions src/modules/Workspaces/WorkspacesEditor/Models/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ public Project(ProjectData.ProjectWrapper project)
AppName = app.Application,
AppPath = app.ApplicationPath,
AppTitle = app.Title,
PwaAppId = app.PwaAppId,
PackageFullName = app.PackageFullName,
AppUserModelId = app.AppUserModelId,
Parent = this,
Expand Down
8 changes: 4 additions & 4 deletions src/modules/Workspaces/WorkspacesEditor/Utils/DrawHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@ Rectangle GetAppRect(Application app)

foreach (Application app in appsIncluded)
{
if (repeatCounter.TryGetValue(app.AppPath, out int value))
if (repeatCounter.TryGetValue(app.AppPath + app.AppTitle, out int value))
{
repeatCounter[app.AppPath] = ++value;
repeatCounter[app.AppPath + app.AppTitle] = ++value;
}
else
{
repeatCounter.Add(app.AppPath, 1);
repeatCounter.Add(app.AppPath + app.AppTitle, 1);
}

app.RepeatIndex = repeatCounter[app.AppPath];
app.RepeatIndex = repeatCounter[app.AppPath + app.AppTitle];
}

foreach (Application app in project.Applications.Where(x => !x.IsIncluded))
Expand Down
23 changes: 23 additions & 0 deletions src/modules/Workspaces/WorkspacesEditor/Utils/PwaApp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WorkspacesEditor.Utils
{
public class PwaApp
{
public string Name { get; set; }

public string ShortcutFilename { get; set; }

public string IconFilename { get; set; }

public string AppId { get; set; }
}
}
110 changes: 110 additions & 0 deletions src/modules/Workspaces/WorkspacesEditor/Utils/PwaHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Win32;

namespace WorkspacesEditor.Utils
{
public class PwaHelper
{
private const string ChromeBase = "Google\\Chrome\\User Data\\Default\\Web Applications";
private const string EdgeBase = "Microsoft\\Edge\\User Data\\Default\\Web Applications";
private const string ResourcesDir = "Manifest Resources";
private const string IconsDir = "Icons";
private const string PwaDirIdentifier = "_CRX_";

private static List<PwaApp> edgePwaApps = new List<PwaApp>();
private static List<PwaApp> chromePwaApps = new List<PwaApp>();

public static int EdgeAppsCount { get => edgePwaApps.Count; }

public static int ChromeAppsCount { get => chromePwaApps.Count; }

public PwaHelper()
{
edgePwaApps = InitPwaData(EdgeBase);
chromePwaApps = InitPwaData(ChromeBase);
}

private List<PwaApp> InitPwaData(string p_baseDir)
{
List<PwaApp> result = new List<PwaApp>();
var baseFolderName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), p_baseDir);
if (Directory.Exists(baseFolderName))
{
foreach (string subDir in Directory.GetDirectories(baseFolderName))
{
string dirName = Path.GetFileName(subDir);
if (!dirName.StartsWith(PwaDirIdentifier, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}

string appId = dirName.Substring(PwaDirIdentifier.Length, dirName.Length - PwaDirIdentifier.Length).Trim('_');

foreach (string iconFile in Directory.GetFiles(subDir, "*.ico"))
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(iconFile);

result.Add(new PwaApp() { Name = filenameWithoutExtension, IconFilename = iconFile, AppId = appId });
break;
}
}

string resourcesDir = Path.Combine(baseFolderName, ResourcesDir);
if (Directory.Exists(resourcesDir))
{
foreach (string subDir in Directory.GetDirectories(resourcesDir))
{
string dirName = Path.GetFileName(subDir);
if (result.Any(app => app.AppId == dirName))
{
continue;
}

string iconsDir = Path.Combine(subDir, IconsDir);
if (Directory.Exists(iconsDir))
{
foreach (string iconFile in Directory.GetFiles(iconsDir, "*.png"))
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(iconFile);

result.Add(new PwaApp() { Name = filenameWithoutExtension, IconFilename = iconFile, AppId = dirName });
break;
}
}
}
}
}

return result;
}

internal static string GetChromeAppIconFile(string pwaAppId)
{
var candidates = chromePwaApps.Where(x => x.AppId == pwaAppId).ToList();
if (candidates.Count > 0)
{
return candidates.First().IconFilename;
}

return null;
}

internal static string GetEdgeAppIconFile(string pwaAppId)
{
var candidates = edgePwaApps.Where(x => x.AppId == pwaAppId).ToList();
if (candidates.Count > 0)
{
return candidates.First().IconFilename;
}

return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public void SerializeWorkspaces(List<Project> workspaces, bool useTempFile = fal
Title = app.AppTitle,
PackageFullName = app.PackageFullName,
AppUserModelId = app.AppUserModelId,
PwaAppId = app.PwaAppId,
CommandLineArguments = app.CommandLineArguments,
IsElevated = app.IsElevated,
CanLaunchElevated = app.CanLaunchElevated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using System.Threading.Tasks;
using System.Timers;
using System.Windows;

using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
Expand All @@ -39,6 +38,7 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
private MainWindow _mainWindow;
private Timer lastUpdatedTimer;
private WorkspacesSettings settings;
private PwaHelper _pwaHelper;

public ObservableCollection<Project> Workspaces { get; set; } = new ObservableCollection<Project>();

Expand Down Expand Up @@ -147,6 +147,7 @@ public MainViewModel(WorkspacesEditorIO workspacesEditorIO)
settings = Utils.Settings.ReadSettings();
_orderByIndex = (int)settings.Properties.SortBy;
_workspacesEditorIO = workspacesEditorIO;
_pwaHelper = new PwaHelper();
lastUpdatedTimer = new System.Timers.Timer();
lastUpdatedTimer.Interval = 1000;
lastUpdatedTimer.Elapsed += LastUpdatedTimerElapsed;
Expand Down Expand Up @@ -601,5 +602,37 @@ private void SendDeleteTelemetryEvent()
telemetryEvent.Successful = true;
PowerToysTelemetry.Log.WriteEvent(telemetryEvent);
}

internal static bool IsPwaApp(Models.Application application)
{
if (application.IsEdge())
{
return true;
}
else if (application.IsChrome())
{
return true;
}
else
{
return false;
}
}

internal static string GetPwaIconFilename(Models.Application application)
{
if (application.IsEdge())
{
return PwaHelper.GetEdgeAppIconFile(application.PwaAppId);
}
else if (application.IsChrome())
{
return PwaHelper.GetChromeAppIconFile(application.PwaAppId);
}
else
{
return string.Empty;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="{Binding IconBitmapImage}" />
Source="{Binding IconBitmapImage, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock
Grid.Column="2"
Width="20"
Expand Down
Loading
Loading