mirror of
https://github.com/LorenzCK/OnTopReplica.git
synced 2024-05-20 20:33:06 +12:00
Refactored HookMethods: OnTopReplica always hooks to shell events.
Added WindowKeeper that keeps track of cloned windows and checks whether they are destroyed.
This commit is contained in:
parent
8973532765
commit
1ae9effa6f
|
@ -19,7 +19,6 @@ namespace OnTopReplica {
|
|||
|
||||
//Window manager
|
||||
WindowManager _windowManager = new WindowManager();
|
||||
WindowHandle _lastWindowHandle = null;
|
||||
|
||||
//Message pump extension
|
||||
MessagePumpManager _msgPumpManager = new MessagePumpManager();
|
||||
|
@ -297,20 +296,20 @@ namespace OnTopReplica {
|
|||
/// <param name="region">Region of the window to clone.</param>
|
||||
public void SetThumbnail(WindowHandle handle, StoredRegion region) {
|
||||
try {
|
||||
_lastWindowHandle = handle;
|
||||
CurrentThumbnailWindowHandle = handle;
|
||||
_thumbnailPanel.SetThumbnailHandle(handle);
|
||||
|
||||
if (region != null)
|
||||
_thumbnailPanel.SelectedRegion = region.Rect;
|
||||
else
|
||||
_thumbnailPanel.ConstrainToRegion = false;
|
||||
|
||||
//Set aspect ratio (this will resize the form), do not refresh if in fullscreen
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailOriginalSize, !IsFullscreen);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ThumbnailError(ex, false, Strings.ErrorUnableToCreateThumbnail);
|
||||
}
|
||||
|
||||
//Set aspect ratio (this will resize the form), do not refresh if in fullscreen
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailOriginalSize, !IsFullscreen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -328,7 +327,7 @@ namespace OnTopReplica {
|
|||
if (handles.Count == 1)
|
||||
return;
|
||||
|
||||
_lastWindowHandle = null;
|
||||
CurrentThumbnailWindowHandle = null;
|
||||
_msgPumpManager.Get<MessagePumpProcessors.GroupSwitchManager>().EnableGroupMode(handles);
|
||||
}
|
||||
|
||||
|
@ -337,7 +336,7 @@ namespace OnTopReplica {
|
|||
/// </summary>
|
||||
public void UnsetThumbnail() {
|
||||
//Unset handle
|
||||
_lastWindowHandle = null;
|
||||
CurrentThumbnailWindowHandle = null;
|
||||
_thumbnailPanel.UnsetThumbnail();
|
||||
|
||||
//Disable aspect ratio
|
||||
|
@ -446,6 +445,14 @@ namespace OnTopReplica {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the window handle of the currently cloned thumbnail.
|
||||
/// </summary>
|
||||
public WindowHandle CurrentThumbnailWindowHandle {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace OnTopReplica {
|
|||
}
|
||||
|
||||
void Thumbnail_CloneClick(object sender, CloneClickEventArgs e) {
|
||||
Win32Helper.InjectFakeMouseClick(_lastWindowHandle.Handle, e);
|
||||
Win32Helper.InjectFakeMouseClick(CurrentThumbnailWindowHandle.Handle, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace OnTopReplica {
|
|||
private void Menu_Windows_opening(object sender, CancelEventArgs e) {
|
||||
_windowManager.Refresh(WindowManager.EnumerationMode.TaskWindows);
|
||||
WindowListHelper.PopulateMenu(this, _windowManager, (ToolStrip)sender,
|
||||
_lastWindowHandle, new EventHandler(Menu_Windows_itemclick));
|
||||
CurrentThumbnailWindowHandle, new EventHandler(Menu_Windows_itemclick));
|
||||
}
|
||||
|
||||
void Menu_Windows_itemclick(object sender, EventArgs e) {
|
||||
|
@ -54,11 +54,11 @@ namespace OnTopReplica {
|
|||
}
|
||||
|
||||
private void Menu_Switch_click(object sender, EventArgs e) {
|
||||
if (_lastWindowHandle == null)
|
||||
if (CurrentThumbnailWindowHandle == null)
|
||||
return;
|
||||
|
||||
Program.Platform.HideForm(this);
|
||||
Native.WindowManagerMethods.SetForegroundWindow(_lastWindowHandle.Handle);
|
||||
Native.WindowManagerMethods.SetForegroundWindow(CurrentThumbnailWindowHandle.Handle);
|
||||
}
|
||||
|
||||
private void Menu_GroupSwitchMode_click(object sender, EventArgs e) {
|
||||
|
|
|
@ -3,17 +3,22 @@ using System.Collections.Generic;
|
|||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class MessagePumpManager : IDisposable {
|
||||
|
||||
Dictionary<Type, IMessagePumpProcessor> _processors = new Dictionary<Type, IMessagePumpProcessor>();
|
||||
|
||||
public MainForm Form { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates all message pump processors and registers them on the main form.
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public void Initialize(MainForm form) {
|
||||
Form = form;
|
||||
|
||||
foreach (var t in Assembly.GetExecutingAssembly().GetTypes()) {
|
||||
if (typeof(IMessagePumpProcessor).IsAssignableFrom(t) && !t.IsAbstract) {
|
||||
var instance = (IMessagePumpProcessor)Activator.CreateInstance(t);
|
||||
|
@ -26,6 +31,11 @@ namespace OnTopReplica {
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//Register window shell hook
|
||||
if (!HookMethods.RegisterShellHookWindow(form.Handle)) {
|
||||
Console.Error.WriteLine("Failed to register shell hook window.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -49,6 +59,10 @@ namespace OnTopReplica {
|
|||
#region IDisposable Members
|
||||
|
||||
public void Dispose() {
|
||||
if (!HookMethods.DeregisterShellHookWindow(Form.Handle)) {
|
||||
Console.Error.WriteLine("Failed to deregister sheel hook window.");
|
||||
}
|
||||
|
||||
foreach (var processor in _processors.Values) {
|
||||
processor.Dispose();
|
||||
}
|
||||
|
|
|
@ -12,13 +12,6 @@ namespace OnTopReplica.MessagePumpProcessors {
|
|||
|
||||
class GroupSwitchManager : BaseMessagePumpProcessor {
|
||||
|
||||
public GroupSwitchManager() {
|
||||
_hookMsgId = HookMethods.RegisterWindowMessage("SHELLHOOK");
|
||||
if (_hookMsgId == 0)
|
||||
Console.Error.WriteLine("Failed to register SHELLHOOK Windows message.");
|
||||
}
|
||||
|
||||
uint _hookMsgId;
|
||||
bool _active = false;
|
||||
List<WindowHandleWrapper> _lruHandles;
|
||||
|
||||
|
@ -30,14 +23,6 @@ namespace OnTopReplica.MessagePumpProcessors {
|
|||
if (handles == null || handles.Count == 0)
|
||||
return;
|
||||
|
||||
//Enable new hook
|
||||
if (!_active) {
|
||||
if (!HookMethods.RegisterShellHookWindow(Form.Handle)) {
|
||||
Console.Error.WriteLine("Failed to register shell hook window.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Okey dokey, will now track handles
|
||||
TrackHandles(handles);
|
||||
_active = true;
|
||||
|
@ -65,9 +50,6 @@ namespace OnTopReplica.MessagePumpProcessors {
|
|||
if (!_active)
|
||||
return;
|
||||
|
||||
if (!HookMethods.DeregisterShellHookWindow(Form.Handle))
|
||||
Console.Error.WriteLine("Failed to deregister shell hook window.");
|
||||
|
||||
_lruHandles = null;
|
||||
_active = false;
|
||||
}
|
||||
|
@ -76,7 +58,7 @@ namespace OnTopReplica.MessagePumpProcessors {
|
|||
/// Processes the message pump.
|
||||
/// </summary>
|
||||
public override void Process(Message msg) {
|
||||
if (_active && msg.Msg == _hookMsgId) {
|
||||
if (_active && msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
if (hookCode == HookMethods.HSHELL_WINDOWACTIVATED ||
|
||||
hookCode == HookMethods.HSHELL_RUDEAPPACTIVATED) {
|
||||
|
|
37
OnTopReplica/MessagePumpProcessors/WindowKeeper.cs
Normal file
37
OnTopReplica/MessagePumpProcessors/WindowKeeper.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
/// <summary>
|
||||
/// Listens for shell events and closes the thumbnail if a cloned window is destroyed.
|
||||
/// </summary>
|
||||
class WindowKeeper : BaseMessagePumpProcessor {
|
||||
|
||||
public override void Process(Message msg) {
|
||||
if (Form.CurrentThumbnailWindowHandle != null &&
|
||||
msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
if (hookCode == HookMethods.HSHELL_WINDOWDESTROYED) {
|
||||
//Check whether the destroyed window is the one we were cloning
|
||||
IntPtr destroyedHandle = msg.LParam;
|
||||
if (destroyedHandle == Form.CurrentThumbnailWindowHandle.Handle) {
|
||||
//Disable group switch mode, since a window of the group has been destroyed
|
||||
Form.MessagePumpManager.Get<GroupSwitchManager>().Disable();
|
||||
|
||||
//Disable cloning
|
||||
Form.UnsetThumbnail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -10,16 +10,29 @@ namespace OnTopReplica.Native {
|
|||
/// </summary>
|
||||
static class HookMethods {
|
||||
|
||||
static HookMethods() {
|
||||
WM_SHELLHOOKMESSAGE = RegisterWindowMessage("SHELLHOOK");
|
||||
if (WM_SHELLHOOKMESSAGE == 0)
|
||||
Console.Error.WriteLine("Failed to register SHELLHOOK Windows message.");
|
||||
}
|
||||
|
||||
public static int WM_SHELLHOOKMESSAGE {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public const int HSHELL_WINDOWACTIVATED = 4;
|
||||
public const int HSHELL_RUDEAPPACTIVATED = HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT;
|
||||
const int HSHELL_HIGHBIT = 0x8000;
|
||||
public const int HSHELL_WINDOWDESTROYED = 2;
|
||||
public const int HSHELL_WINDOWCREATED = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Registers the WM_ID for a window message.
|
||||
/// </summary>
|
||||
/// <param name="wndMessageName">Name of the window message.</param>
|
||||
[DllImport("User32.dll")]
|
||||
public static extern uint RegisterWindowMessage(string wndMessageName);
|
||||
public static extern int RegisterWindowMessage(string wndMessageName);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a window as a shell hook window.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ApplicationIcon>Assets\icon-new.ico</ApplicationIcon>
|
||||
<IsWebBootstrapper>true</IsWebBootstrapper>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<GenerateManifests>true</GenerateManifests>
|
||||
<TargetZone>Internet</TargetZone>
|
||||
<StartupObject>OnTopReplica.Program</StartupObject>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<UpgradeBackupLocation />
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Web</InstallFrom>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>true</UpdateEnabled>
|
||||
<UpdateMode>Background</UpdateMode>
|
||||
<UpdateInterval>1</UpdateInterval>
|
||||
|
@ -39,16 +39,15 @@
|
|||
<UpdatePeriodically>true</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<InstallUrl>http://www.klopfenstein.net/public/Uploads/ontopreplica/</InstallUrl>
|
||||
<UpdateUrl>http://www.klopfenstein.net/public/Uploads/ontopreplica/</UpdateUrl>
|
||||
<SupportUrl>http://www.klopfenstein.net/lorenz.aspx/ontopreplica</SupportUrl>
|
||||
<TargetCulture>en</TargetCulture>
|
||||
<ProductName>OnTopReplica</ProductName>
|
||||
<PublisherName>Lorenz Cuno Klopfenstein</PublisherName>
|
||||
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
|
||||
<WebPage>publish.htm</WebPage>
|
||||
<OpenBrowserOnPublish>false</OpenBrowserOnPublish>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<AutorunEnabled>true</AutorunEnabled>
|
||||
<ApplicationRevision>1</ApplicationRevision>
|
||||
<ApplicationVersion>3.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||
|
@ -145,6 +144,7 @@
|
|||
<Compile Include="MessagePumpProcessors\GroupSwitchManager.cs" />
|
||||
<Compile Include="IMessagePumpProcessor.cs" />
|
||||
<Compile Include="MessagePumpProcessors\BaseMessagePumpProcessor.cs" />
|
||||
<Compile Include="MessagePumpProcessors\WindowKeeper.cs" />
|
||||
<Compile Include="Native\ErrorMethods.cs" />
|
||||
<Compile Include="Native\HookMethods.cs" />
|
||||
<Compile Include="Native\HotKeyMethods.cs" />
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</application>
|
||||
</compatibility>
|
||||
|
||||
<assemblyIdentity processorArchitecture="*" type="win32" name="OnTopReplica"/>
|
||||
<!--<assemblyIdentity processorArchitecture="*" type="win32" name="OnTopReplica"/>-->
|
||||
|
||||
<description>Lightweight clone of a window.</description>
|
||||
<!--
|
||||
|
|
Loading…
Reference in a new issue