Mergedown.

This commit is contained in:
Lorenz Cuno Klopfenstein 2010-10-16 18:35:29 +02:00
commit 8ad4e78ac5
50 changed files with 5116 additions and 1163 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<UpdateInformation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<latestVersion>3.1.0.0</latestVersion>
<latestVersionRelease>2010-09-09T00:00:00Z</latestVersionRelease>
<latestVersion>3.2.0.0</latestVersion>
<latestVersionRelease>2010-10-15T00:00:00Z</latestVersionRelease>
<downloadPage>http://www.klopfenstein.net/lorenz.aspx/ontopreplica</downloadPage>
</UpdateInformation>

15
OnTopReplica/Actions.cs Normal file
View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OnTopReplica {
public delegate void Action();
public delegate void Action<T1>(T1 arg1);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

View file

@ -7,6 +7,7 @@ namespace OnTopReplica {
public class CloseRequestEventArgs : EventArgs {
public WindowHandle LastWindowHandle { get; set; }
public Rectangle? LastRegion { get; set; }
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OnTopReplica {
/// <summary>
/// Extension methods for IEnumerable.
/// </summary>
static class EnumerableExtensions {
/// <summary>
/// Gets the first element of an enumeration of a default value.
/// </summary>
public static T FirstOrDefault<T>(this IEnumerable<T> collection) {
if (collection == null)
throw new ArgumentNullException();
using (var enumerator = collection.GetEnumerator()) {
if (!enumerator.MoveNext())
return default(T);
else
return enumerator.Current;
}
}
}
}

View file

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Runtime.CompilerServices {
/// <summary>
/// Fake extension attribute that adds extension method support to C# 2 (without System.Core.dll reference).
/// </summary>
class ExtensionAttribute : Attribute {
}
}

View file

@ -52,9 +52,13 @@
this.quarterToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.fullscreenToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.restorePositionAndSizeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.dockToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.disabledToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.topLeftToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.topRightToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.centerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.bottomLeftToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.bottomRightToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.chromeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -115,6 +119,7 @@
this.menuWindows.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.noneToolStripMenuItem});
this.menuWindows.Name = "menuWindows";
this.menuWindows.OwnerItem = this.menuContextWindows;
this.menuWindows.Size = new System.Drawing.Size(118, 26);
this.menuWindows.Opening += new System.ComponentModel.CancelEventHandler(this.Menu_Windows_opening);
//
@ -206,6 +211,7 @@
this.toolStripMenuItem3,
this.toolStripMenuItem4});
this.menuOpacity.Name = "menuOpacity";
this.menuOpacity.OwnerItem = this.fullOpacityToolStripMenuItem;
this.menuOpacity.ShowCheckMargin = true;
this.menuOpacity.ShowImageMargin = false;
this.menuOpacity.Size = new System.Drawing.Size(154, 92);
@ -265,58 +271,75 @@
this.halfToolStripMenuItem1,
this.quarterToolStripMenuItem1,
this.toolStripSeparator3,
this.fullscreenToolStripMenuItem1});
this.fullscreenToolStripMenuItem1,
this.toolStripSeparator2,
this.restorePositionAndSizeToolStripMenuItem});
this.menuResize.Name = "menuResize";
this.menuResize.OwnerItem = this.resizeToolStripMenuItem;
this.menuResize.Size = new System.Drawing.Size(165, 120);
this.menuResize.Size = new System.Drawing.Size(218, 170);
this.menuResize.Opening += new System.ComponentModel.CancelEventHandler(this.Menu_Resize_opening);
//
// doubleToolStripMenuItem1
//
this.doubleToolStripMenuItem1.Name = "doubleToolStripMenuItem1";
this.doubleToolStripMenuItem1.Size = new System.Drawing.Size(164, 22);
this.doubleToolStripMenuItem1.Size = new System.Drawing.Size(217, 22);
this.doubleToolStripMenuItem1.Text = global::OnTopReplica.Strings.MenuFitDouble;
this.doubleToolStripMenuItem1.Click += new System.EventHandler(this.Menu_Resize_Double);
//
// fitToWindowToolStripMenuItem1
//
this.fitToWindowToolStripMenuItem1.Name = "fitToWindowToolStripMenuItem1";
this.fitToWindowToolStripMenuItem1.Size = new System.Drawing.Size(164, 22);
this.fitToWindowToolStripMenuItem1.Size = new System.Drawing.Size(217, 22);
this.fitToWindowToolStripMenuItem1.Text = global::OnTopReplica.Strings.MenuFitOriginal;
this.fitToWindowToolStripMenuItem1.Click += new System.EventHandler(this.Menu_Resize_FitToWindow);
//
// halfToolStripMenuItem1
//
this.halfToolStripMenuItem1.Name = "halfToolStripMenuItem1";
this.halfToolStripMenuItem1.Size = new System.Drawing.Size(164, 22);
this.halfToolStripMenuItem1.Size = new System.Drawing.Size(217, 22);
this.halfToolStripMenuItem1.Text = global::OnTopReplica.Strings.MenuFitHalf;
this.halfToolStripMenuItem1.Click += new System.EventHandler(this.Menu_Resize_Half);
//
// quarterToolStripMenuItem1
//
this.quarterToolStripMenuItem1.Name = "quarterToolStripMenuItem1";
this.quarterToolStripMenuItem1.Size = new System.Drawing.Size(164, 22);
this.quarterToolStripMenuItem1.Size = new System.Drawing.Size(217, 22);
this.quarterToolStripMenuItem1.Text = global::OnTopReplica.Strings.MenuFitQuarter;
this.quarterToolStripMenuItem1.Click += new System.EventHandler(this.Menu_Resize_Quarter);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(161, 6);
this.toolStripSeparator3.Size = new System.Drawing.Size(214, 6);
//
// fullscreenToolStripMenuItem1
//
this.fullscreenToolStripMenuItem1.Image = global::OnTopReplica.Properties.Resources.fullscreen;
this.fullscreenToolStripMenuItem1.Name = "fullscreenToolStripMenuItem1";
this.fullscreenToolStripMenuItem1.Size = new System.Drawing.Size(164, 22);
this.fullscreenToolStripMenuItem1.Size = new System.Drawing.Size(217, 22);
this.fullscreenToolStripMenuItem1.Text = global::OnTopReplica.Strings.MenuFitFullscreen;
this.fullscreenToolStripMenuItem1.Click += new System.EventHandler(this.Menu_Resize_Fullscreen);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(214, 6);
//
// restorePositionAndSizeToolStripMenuItem
//
this.restorePositionAndSizeToolStripMenuItem.Name = "restorePositionAndSizeToolStripMenuItem";
this.restorePositionAndSizeToolStripMenuItem.Size = new System.Drawing.Size(217, 22);
this.restorePositionAndSizeToolStripMenuItem.Text = global::OnTopReplica.Strings.MenuRecall;
this.restorePositionAndSizeToolStripMenuItem.ToolTipText = global::OnTopReplica.Strings.MenuRecallTT;
this.restorePositionAndSizeToolStripMenuItem.Click += new System.EventHandler(this.Menu_Resize_RecallPosition_click);
//
// dockToolStripMenuItem
//
this.dockToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.disabledToolStripMenuItem,
this.topLeftToolStripMenuItem,
this.topRightToolStripMenuItem,
this.centerToolStripMenuItem,
this.bottomLeftToolStripMenuItem,
this.bottomRightToolStripMenuItem});
this.dockToolStripMenuItem.Image = global::OnTopReplica.Properties.Resources.pos_null;
@ -324,6 +347,16 @@
this.dockToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
this.dockToolStripMenuItem.Text = global::OnTopReplica.Strings.MenuPosition;
this.dockToolStripMenuItem.ToolTipText = global::OnTopReplica.Strings.MenuPositionTT;
this.dockToolStripMenuItem.DropDownOpening += new System.EventHandler(this.Menu_Position_Opening);
//
// disabledToolStripMenuItem
//
this.disabledToolStripMenuItem.Checked = true;
this.disabledToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.disabledToolStripMenuItem.Name = "disabledToolStripMenuItem";
this.disabledToolStripMenuItem.Size = new System.Drawing.Size(145, 22);
this.disabledToolStripMenuItem.Text = global::OnTopReplica.Strings.MenuPosDisabled;
this.disabledToolStripMenuItem.Click += new System.EventHandler(this.Menu_Position_Disable);
//
// topLeftToolStripMenuItem
//
@ -341,6 +374,14 @@
this.topRightToolStripMenuItem.Text = global::OnTopReplica.Strings.MenuPosTopRight;
this.topRightToolStripMenuItem.Click += new System.EventHandler(this.Menu_Position_TopRight);
//
// centerToolStripMenuItem
//
this.centerToolStripMenuItem.Image = global::OnTopReplica.Properties.Resources.pos_center;
this.centerToolStripMenuItem.Name = "centerToolStripMenuItem";
this.centerToolStripMenuItem.Size = new System.Drawing.Size(145, 22);
this.centerToolStripMenuItem.Text = global::OnTopReplica.Strings.MenuPosCenter;
this.centerToolStripMenuItem.Click += new System.EventHandler(this.Menu_Position_Center);
//
// bottomLeftToolStripMenuItem
//
this.bottomLeftToolStripMenuItem.Image = global::OnTopReplica.Properties.Resources.pos_bottomleft;
@ -568,6 +609,10 @@
private System.Windows.Forms.ToolStripMenuItem clickThroughToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem groupSwitchModeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem enableClickthroughToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem centerToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem disabledToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
private System.Windows.Forms.ToolStripMenuItem restorePositionAndSizeToolStripMenuItem;
}
}

View file

@ -8,6 +8,8 @@ using VistaControls.TaskDialog;
using System.Collections.Generic;
using OnTopReplica.Native;
using OnTopReplica.Update;
using OnTopReplica.StartupOptions;
using OnTopReplica.WindowSeekers;
namespace OnTopReplica {
@ -19,18 +21,23 @@ namespace OnTopReplica {
Panel _sidePanelContainer;
//Managers
WindowManager _windowManager = new WindowManager();
BaseWindowSeeker _windowSeeker = new TaskWindowSeeker {
SkipNotVisibleWindows = true
};
MessagePumpManager _msgPumpManager = new MessagePumpManager();
UpdateManager _updateManager = new UpdateManager();
FormBorderStyle _defaultBorderStyle;
Options _startupOptions;
public MainForm() {
public MainForm(Options startupOptions) {
_startupOptions = startupOptions;
//WinForms init pass
InitializeComponent();
KeepAspectRatio = false;
GlassEnabled = true;
//Store default values
_defaultBorderStyle = FormBorderStyle;
_nonClickThroughKey = TransparencyKey;
//Thumbnail panel
@ -97,18 +104,20 @@ namespace OnTopReplica {
}
}
protected override void OnShown(EventArgs e) {
base.OnShown(e);
protected override void OnHandleCreated(EventArgs e){
base.OnHandleCreated(e);
_windowSeeker.OwnerHandle = this.Handle;
//Platform specific form initialization
Program.Platform.InitForm(this);
//Glassify window
GlassEnabled = true;
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
protected override void OnShown(EventArgs e) {
base.OnShown(e);
//Apply startup options
_startupOptions.Apply(this);
//Check for updates
_updateManager.UpdateCheckCompleted += new EventHandler<UpdateCheckCompletedEventArgs>(UpdateManager_CheckCompleted);
@ -131,10 +140,19 @@ namespace OnTopReplica {
fullMargins;
}
protected override void OnResizeEnd(EventArgs e) {
base.OnResizeEnd(e);
//If locked in position, move accordingly
if (PositionLock.HasValue) {
this.SetScreenPosition(PositionLock.Value);
}
}
protected override void OnActivated(EventArgs e) {
base.OnActivated(e);
//Deactivate click-through if reactivated
//Deactivate click-through if form is reactivated
if (ClickThroughEnabled) {
ClickThroughEnabled = false;
}
@ -146,7 +164,7 @@ namespace OnTopReplica {
base.OnDeactivate(e);
//HACK: sometimes, even if TopMost is true, the window loses its "always on top" status.
// This is an attempt of a fix that probably won't work...
// This is a fix attempt that probably won't work...
if (!IsFullscreen) { //fullscreen mode doesn't use TopMost
TopMost = false;
TopMost = true;
@ -269,8 +287,8 @@ namespace OnTopReplica {
IsFullscreen = false;
}
//Disable click forwarding
else if (_thumbnailPanel.ReportThumbnailClicks) {
_thumbnailPanel.ReportThumbnailClicks = false;
else if (ClickForwardingEnabled) {
ClickForwardingEnabled = false;
}
}
}
@ -302,6 +320,7 @@ namespace OnTopReplica {
bool _isFullscreen = false;
Point _preFullscreenLocation;
Size _preFullscreenSize;
FormBorderStyle _preFullscreenBorderStyle;
public bool IsFullscreen {
get {
@ -314,26 +333,30 @@ namespace OnTopReplica {
return;
CloseSidePanel(); //on switch, always hide side panels
GlassEnabled = !value;
FormBorderStyle = (value) ? FormBorderStyle.None : _defaultBorderStyle;
TopMost = !value;
HandleMouseMove = !value;
//Location and size
if (value) {
_preFullscreenLocation = Location;
_preFullscreenSize = Size;
_preFullscreenSize = ClientSize;
_preFullscreenBorderStyle = FormBorderStyle;
var currentScreen = Screen.FromControl(this);
FormBorderStyle = FormBorderStyle.None;
Size = currentScreen.WorkingArea.Size;
Location = currentScreen.WorkingArea.Location;
}
else {
FormBorderStyle = _preFullscreenBorderStyle;
Location = _preFullscreenLocation;
Size = _preFullscreenSize;
ClientSize = _preFullscreenSize;
RefreshAspectRatio();
}
//Common
GlassEnabled = !value;
TopMost = !value;
HandleMouseMove = !value;
_isFullscreen = value;
Program.Platform.OnFormStateChange(this);
@ -349,13 +372,18 @@ namespace OnTopReplica {
/// </summary>
/// <param name="handle">Handle to the window to clone.</param>
/// <param name="region">Region of the window to clone.</param>
public void SetThumbnail(WindowHandle handle, StoredRegion region) {
public void SetThumbnail(WindowHandle handle, Rectangle? region) {
try {
CurrentThumbnailWindowHandle = handle;
_thumbnailPanel.SetThumbnailHandle(handle);
if (region != null)
_thumbnailPanel.SelectedRegion = region.Rect;
#if DEBUG
string windowClass = WindowMethods.GetWindowClass(handle.Handle);
Console.WriteLine("Cloning window HWND {0} of class {1}.", handle.Handle, windowClass);
#endif
if (region.HasValue)
_thumbnailPanel.SelectedRegion = region.Value;
else
_thumbnailPanel.ConstrainToRegion = false;
@ -470,33 +498,6 @@ namespace OnTopReplica {
#endregion
#region Click-through
bool _clickThrough = false;
Color _nonClickThroughKey;
public bool ClickThroughEnabled {
get {
return _clickThrough;
}
set {
//Adjust opacity if fully opaque
if (value && Opacity == 1.0)
Opacity = 0.75;
if (!value)
Opacity = 1.0;
//Enable transparency and force as top-most
TransparencyKey = (value) ? Color.Black : _nonClickThroughKey;
if (value)
TopMost = true;
_clickThrough = value;
}
}
#endregion
#region Accessors
/// <summary>

View file

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Properties;
using VistaControls.TaskDialog;
using System.Drawing;
using System.Windows.Forms;
namespace OnTopReplica {
//Contains some feature implementations of MainForm
partial class MainForm {
#region Click forwarding
public bool ClickForwardingEnabled {
get {
return _thumbnailPanel.ReportThumbnailClicks;
}
set {
if (value && Settings.Default.FirstTimeClickForwarding) {
TaskDialog dlg = new TaskDialog(Strings.InfoClickForwarding, Strings.InfoClickForwardingTitle, Strings.InfoClickForwardingContent) {
CommonButtons = TaskDialogButton.Yes | TaskDialogButton.No
};
if (dlg.Show(this).CommonButton == Result.No)
return;
Settings.Default.FirstTimeClickForwarding = false;
}
_thumbnailPanel.ReportThumbnailClicks = value;
}
}
#endregion
#region Click-through
bool _clickThrough = false;
Color _nonClickThroughKey;
public bool ClickThroughEnabled {
get {
return _clickThrough;
}
set {
//Adjust opacity if fully opaque
/*if (value && Opacity == 1.0)
Opacity = 0.75;
if (!value)
Opacity = 1.0;*/
//Enable transparency and force as top-most
TransparencyKey = (value) ? Color.Black : _nonClickThroughKey;
if (value)
TopMost = true;
_clickThrough = value;
}
}
#endregion
#region Chrome
public bool IsChromeVisible {
get {
return (FormBorderStyle == FormBorderStyle.SizableToolWindow);
}
set {
if (!value) {
Location = new Point {
X = Location.X + SystemInformation.FrameBorderSize.Width,
Y = Location.Y + SystemInformation.FrameBorderSize.Height
};
FormBorderStyle = FormBorderStyle.None;
}
else if(value) {
Location = new Point {
X = Location.X - SystemInformation.FrameBorderSize.Width,
Y = Location.Y - SystemInformation.FrameBorderSize.Height
};
FormBorderStyle = FormBorderStyle.SizableToolWindow;
}
Program.Platform.OnFormStateChange(this);
Invalidate();
}
}
#endregion
#region Position lock
ScreenPosition? _positionLock = null;
/// <summary>
/// Gets or sets the screen position where the window is currently locked in.
/// </summary>
public ScreenPosition? PositionLock {
get {
return _positionLock;
}
set {
if (value != null)
this.SetScreenPosition(value.Value);
_positionLock = value;
}
}
#endregion
}
}

View file

@ -38,18 +38,24 @@ namespace OnTopReplica {
return new Point(finX, finY);
}
private int ChromeBorderVertical {
/// <summary>
/// Gets the window's vertical chrome size.
/// </summary>
public int ChromeBorderVertical {
get {
if (FormBorderStyle == _defaultBorderStyle)
if (IsChromeVisible)
return SystemInformation.FrameBorderSize.Height;
else
return 0;
}
}
private int ChromeBorderHorizontal {
/// <summary>
/// Gets the window's horizontal chrome size.
/// </summary>
public int ChromeBorderHorizontal {
get {
if (FormBorderStyle == _defaultBorderStyle)
if (IsChromeVisible)
return SystemInformation.FrameBorderSize.Width;
else
return 0;

View file

@ -20,8 +20,8 @@ namespace OnTopReplica {
selectRegionToolStripMenuItem.Enabled = showing;
switchToWindowToolStripMenuItem.Enabled = showing;
resizeToolStripMenuItem.Enabled = showing;
chromeToolStripMenuItem.Checked = (FormBorderStyle == _defaultBorderStyle);
clickForwardingToolStripMenuItem.Checked = _thumbnailPanel.ReportThumbnailClicks;
chromeToolStripMenuItem.Checked = IsChromeVisible;
clickForwardingToolStripMenuItem.Checked = ClickForwardingEnabled;
chromeToolStripMenuItem.Enabled = showing;
clickThroughToolStripMenuItem.Enabled = showing;
clickForwardingToolStripMenuItem.Enabled = showing;
@ -29,8 +29,9 @@ namespace OnTopReplica {
}
private void Menu_Windows_opening(object sender, CancelEventArgs e) {
_windowManager.Refresh(WindowManager.EnumerationMode.TaskWindows);
WindowListHelper.PopulateMenu(this, _windowManager, (ToolStrip)sender,
_windowSeeker.Refresh();
var menu = (ToolStrip)sender;
menu.PopulateMenu(this, _windowSeeker,
CurrentThumbnailWindowHandle, new EventHandler(Menu_Windows_itemclick));
}
@ -50,7 +51,9 @@ namespace OnTopReplica {
}
var selectionData = (WindowListHelper.WindowSelectionData)tsi.Tag;
SetThumbnail(selectionData.Handle, selectionData.Region);
Rectangle? bounds = (selectionData.Region != null)
? (Rectangle?)selectionData.Region.Bounds : null;
SetThumbnail(selectionData.Handle, bounds);
}
private void Menu_Switch_click(object sender, EventArgs e) {
@ -66,17 +69,7 @@ namespace OnTopReplica {
}
private void Menu_ClickForwarding_click(object sender, EventArgs e) {
if (Settings.Default.FirstTimeClickForwarding && !_thumbnailPanel.ReportThumbnailClicks) {
TaskDialog dlg = new TaskDialog(Strings.InfoClickForwarding, Strings.InfoClickForwardingTitle, Strings.InfoClickForwardingContent) {
CommonButtons = TaskDialogButton.Yes | TaskDialogButton.No
};
if (dlg.Show(this).CommonButton == Result.No)
return;
Settings.Default.FirstTimeClickForwarding = false;
}
_thumbnailPanel.ReportThumbnailClicks = !_thumbnailPanel.ReportThumbnailClicks;
ClickForwardingEnabled = !ClickForwardingEnabled;
}
private void Menu_ClickThrough_click(object sender, EventArgs e) {
@ -116,6 +109,8 @@ namespace OnTopReplica {
private void Menu_Resize_opening(object sender, CancelEventArgs e) {
if (!_thumbnailPanel.IsShowingThumbnail)
e.Cancel = true;
restorePositionAndSizeToolStripMenuItem.Checked = Settings.Default.RestoreSizeAndPosition;
}
private void Menu_Resize_Double(object sender, EventArgs e) {
@ -138,40 +133,41 @@ namespace OnTopReplica {
IsFullscreen = true;
}
private void Menu_Position_TopLeft(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
private void Menu_Resize_RecallPosition_click(object sender, EventArgs e) {
Settings.Default.RestoreSizeAndPosition = !Settings.Default.RestoreSizeAndPosition;
}
Location = new Point(
screen.WorkingArea.Left - ChromeBorderHorizontal,
screen.WorkingArea.Top - ChromeBorderVertical
);
private void Menu_Position_Opening(object sender, EventArgs e) {
disabledToolStripMenuItem.Checked = (PositionLock == null);
topLeftToolStripMenuItem.Checked = (PositionLock == ScreenPosition.TopLeft);
topRightToolStripMenuItem.Checked = (PositionLock == ScreenPosition.TopRight);
centerToolStripMenuItem.Checked = (PositionLock == ScreenPosition.Center);
bottomLeftToolStripMenuItem.Checked = (PositionLock == ScreenPosition.BottomLeft);
bottomRightToolStripMenuItem.Checked = (PositionLock == ScreenPosition.BottomRight);
}
private void Menu_Position_Disable(object sender, EventArgs e) {
PositionLock = null;
}
private void Menu_Position_TopLeft(object sender, EventArgs e) {
PositionLock = ScreenPosition.TopLeft;
}
private void Menu_Position_TopRight(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
PositionLock = ScreenPosition.TopRight;
}
Location = new Point(
screen.WorkingArea.Width - Size.Width + ChromeBorderHorizontal,
screen.WorkingArea.Top - ChromeBorderVertical
);
private void Menu_Position_Center(object sender, EventArgs e) {
PositionLock = ScreenPosition.Center;
}
private void Menu_Position_BottomLeft(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
Location = new Point(
screen.WorkingArea.Left - ChromeBorderHorizontal,
screen.WorkingArea.Height - Size.Height + ChromeBorderVertical
);
PositionLock = ScreenPosition.BottomLeft;
}
private void Menu_Position_BottomRight(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
Location = new Point(
screen.WorkingArea.Width - Size.Width + ChromeBorderHorizontal,
screen.WorkingArea.Height - Size.Height + ChromeBorderVertical
);
PositionLock = ScreenPosition.BottomRight;
}
private void Menu_Reduce_click(object sender, EventArgs e) {
@ -180,23 +176,7 @@ namespace OnTopReplica {
}
private void Menu_Chrome_click(object sender, EventArgs e) {
if (FormBorderStyle == _defaultBorderStyle) {
FormBorderStyle = FormBorderStyle.None;
Location = new Point {
X = Location.X + SystemInformation.FrameBorderSize.Width,
Y = Location.Y + SystemInformation.FrameBorderSize.Height
};
}
else {
FormBorderStyle = _defaultBorderStyle;
Location = new Point {
X = Location.X - SystemInformation.FrameBorderSize.Width,
Y = Location.Y - SystemInformation.FrameBorderSize.Height
};
}
Program.Platform.OnFormStateChange(this);
Invalidate();
IsChromeVisible = !IsChromeVisible;
}
private void Menu_Language_click(object sender, EventArgs e) {

View file

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using OnTopReplica.MessagePumpProcessors;
using OnTopReplica.Native;
namespace OnTopReplica {
@ -12,6 +11,15 @@ namespace OnTopReplica {
public MainForm Form { get; private set; }
private void Register(IMessagePumpProcessor processor, MainForm form) {
_processors[processor.GetType()] = processor;
processor.Initialize(form);
#if DEBUG
Console.WriteLine("Registered message pump processor: {0}", processor.GetType());
#endif
}
/// <summary>
/// Instantiates all message pump processors and registers them on the main form.
/// </summary>
@ -29,18 +37,10 @@ namespace OnTopReplica {
#endif
}
foreach (var t in Assembly.GetExecutingAssembly().GetTypes()) {
if (typeof(IMessagePumpProcessor).IsAssignableFrom(t) && !t.IsAbstract) {
var instance = (IMessagePumpProcessor)Activator.CreateInstance(t);
instance.Initialize(form);
_processors[t] = instance;
#if DEBUG
Console.WriteLine("Registered message pump processor: {0}", t);
#endif
}
}
//Register message pump processors
Register(new WindowKeeper(), form);
Register(new HotKeyManager(), form);
Register(new GroupSwitchManager(), form);
}
/// <summary>

View file

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using OnTopReplica.Native;
using System.Runtime.InteropServices;
namespace OnTopReplica.MessagePumpProcessors {
class TitleSetter : BaseMessagePumpProcessor {
const string Title = "OnTopReplica";
public override bool Process(ref Message msg) {
switch (msg.Msg) {
case WM.GETTEXT: {
Console.WriteLine("GetText");
int maxLen = msg.WParam.ToInt32();
byte[] strBytes = Encoding.UTF8.GetBytes(Title);
byte[] termBytes = new byte[strBytes.Length + 1];
strBytes.CopyTo(termBytes, 0);
termBytes[strBytes.Length] = 0;
Marshal.Copy(termBytes, 0, msg.LParam, Math.Min(maxLen, Title.Length + 1));
}
goto case WM.GETTEXTLENGTH;
case WM.GETTEXTLENGTH:
Console.WriteLine("GetTextLength");
msg.Result = (IntPtr)Title.Length;
return true;
}
return false;
}
protected override void Shutdown() {
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,17 @@ namespace OnTopReplica.Native {
return String.Empty;
}
const int MaxClassLength = 255;
public static string GetWindowClass(IntPtr hwnd) {
var sb = new StringBuilder(MaxClassLength + 1);
RealGetWindowClass(hwnd, sb, MaxClassLength);
return sb.ToString();
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RealGetWindowClass(IntPtr hwnd, [Out] StringBuilder lpString, uint maxCount);
public enum WindowLong {
WndProc = (-4),
HInstance = (-6),

View file

@ -48,7 +48,7 @@
<WebPage>publish.htm</WebPage>
<OpenBrowserOnPublish>false</OpenBrowserOnPublish>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>3.0.2.%2a</ApplicationVersion>
<ApplicationVersion>3.2.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>true</BootstrapperEnabled>
@ -106,11 +106,17 @@
<Compile Include="AboutForm.Designer.cs">
<DependentUpon>AboutForm.cs</DependentUpon>
</Compile>
<Compile Include="Actions.cs" />
<Compile Include="AspectRatioForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="CloneClickEventArgs.cs" />
<Compile Include="CloseRequestEventArgs.cs" />
<Compile Include="EnumerableExtensions.cs" />
<Compile Include="ExtensionAttribute.cs" />
<Compile Include="MainForm_Features.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm_Gui.cs">
<SubType>Form</SubType>
</Compile>
@ -124,12 +130,16 @@
<Compile Include="MessagePumpProcessors\GroupSwitchManager.cs" />
<Compile Include="IMessagePumpProcessor.cs" />
<Compile Include="MessagePumpProcessors\BaseMessagePumpProcessor.cs" />
<None Include="MessagePumpProcessors\TitleSetter.cs" />
<Compile Include="MessagePumpProcessors\WindowKeeper.cs" />
<Compile Include="Native\ErrorMethods.cs" />
<Compile Include="Native\HookMethods.cs" />
<Compile Include="Native\HotKeyMethods.cs" />
<Compile Include="Native\HT.cs" />
<Compile Include="Pair.cs" />
<Compile Include="WindowSeekers\BaseWindowSeeker.cs" />
<Compile Include="WindowSeekers\ByClassWindowSeeker.cs" />
<Compile Include="WindowSeekers\ByTitleWindowSeeker.cs" />
<Compile Include="WindowSeekers\TaskWindowSeeker.cs" />
<None Include="Native\ITaskBarList.cs" />
<Compile Include="Native\InputMethods.cs" />
<Compile Include="Native\MessagingMethods.cs" />
@ -141,7 +151,9 @@
<Compile Include="Native\WindowMethods.cs" />
<Compile Include="Native\WM.cs" />
<Compile Include="Native\WMSZ.cs" />
<Compile Include="NDesk\Options\Options.cs" />
<Compile Include="NotificationIcon.cs" />
<Compile Include="ScreenPosition.cs" />
<Compile Include="SidePanel.cs">
<SubType>UserControl</SubType>
</Compile>
@ -151,6 +163,18 @@
<Compile Include="SidePanels\GroupSwitchPanel.Designer.cs">
<DependentUpon>GroupSwitchPanel.cs</DependentUpon>
</Compile>
<Compile Include="StartupOptions\CliStatus.cs" />
<Compile Include="StartupOptions\CommandLineReportForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="StartupOptions\CommandLineReportForm.Designer.cs">
<DependentUpon>CommandLineReportForm.cs</DependentUpon>
</Compile>
<Compile Include="StartupOptions\RectangleConverter.cs" />
<Compile Include="StartupOptions\Factory.cs" />
<Compile Include="StartupOptions\Options.cs" />
<Compile Include="StartupOptions\ScreenPositionConverter.cs" />
<Compile Include="StartupOptions\SizeConverter.cs" />
<Compile Include="StoredRegionComparer.cs" />
<Compile Include="Native\WindowsSevenMethods.cs" />
<None Include="Native\CommonControls.cs" />
@ -186,6 +210,9 @@
<DependentUpon>GroupSwitchPanel.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="StartupOptions\CommandLineReportForm.resx">
<DependentUpon>CommandLineReportForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Strings.cs.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.cs.Designer.cs</LastGenOutput>
@ -240,6 +267,11 @@
</Compile>
<Compile Include="StoredRegion.cs" />
<Compile Include="StoredRegionArray.cs" />
<Compile Include="Strings.it.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Strings.it.resx</DependentUpon>
</Compile>
<Compile Include="ThumbnailPanel.cs">
<SubType>Component</SubType>
</Compile>
@ -249,7 +281,6 @@
<Compile Include="Win32Helper.cs" />
<Compile Include="WindowHandle.cs" />
<Compile Include="WindowListHelper.cs" />
<Compile Include="WindowManager.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Assets\windows.png" />
@ -273,6 +304,7 @@
<None Include="Assets\fullscreen.png" />
<None Include="Assets\clickforwarding.png" />
<None Include="Assets\groupmode.png" />
<None Include="Assets\pos_center.png" />
<Content Include="Assets\xiao_arrow.png" />
<None Include="Assets\xiao_help.png" />
<None Include="Assets\window_opacity_new.png" />

View file

@ -15,4 +15,8 @@
<PropertyGroup>
<EnableSecurityDebugging>false</EnableSecurityDebugging>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>
</StartArguments>
</PropertyGroup>
</Project>

15
OnTopReplica/Pair.cs Normal file
View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OnTopReplica {
/// <summary>
/// Simple tuple with two values.
/// </summary>
struct Pair<T1, T2> {
public T1 Item1;
public T2 Item2;
}
}

View file

@ -9,6 +9,7 @@ using System.IO;
using VistaControls.TaskDialog;
using OnTopReplica.Update;
using System.Reflection;
using OnTopReplica.StartupOptions;
namespace OnTopReplica {
@ -26,7 +27,7 @@ namespace OnTopReplica {
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
static void Main(string[] args) {
//Hook abort handler
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
@ -45,6 +46,16 @@ namespace OnTopReplica {
Settings.Default.MustUpdate = false;
}
//Load startup options
var options = StartupOptions.Factory.CreateOptions(args);
string optionsMessage = options.DebugMessage;
if (!string.IsNullOrEmpty(optionsMessage)) { //show dialog if debug message present or if parsing failed
var dlg = new CommandLineReportForm(options.Status, optionsMessage);
dlg.ShowDialog();
}
if (options.Status == CliStatus.Information || options.Status == CliStatus.Error)
return;
bool mustReloadForm = false;
Point reloadLocation = new Point();
Size reloadSize = new Size();
@ -55,7 +66,7 @@ namespace OnTopReplica {
Settings.Default.Language = _languageChangeCode;
_languageChangeCode = null;
_mainForm = new MainForm();
_mainForm = new MainForm(options);
if (mustReloadForm) {
_mainForm.Location = reloadLocation;
_mainForm.Size = reloadSize;
@ -71,6 +82,8 @@ namespace OnTopReplica {
while (_languageChangeCode != null);
//Persist settings
Settings.Default.RestoreLastPosition = reloadLocation;
Settings.Default.RestoreLastSize = reloadSize;
Settings.Default.Save();
}

View file

@ -33,5 +33,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.1.1.0")]
[assembly: AssemblyFileVersion("3.1.1.0")]
[assembly: AssemblyVersion("3.2.0.0")]
[assembly: AssemblyFileVersion("3.2.0.0")]

View file

@ -165,6 +165,13 @@ namespace OnTopReplica.Properties {
}
}
internal static System.Drawing.Bitmap pos_center {
get {
object obj = ResourceManager.GetObject("pos_center", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
internal static System.Drawing.Bitmap pos_null {
get {
object obj = ResourceManager.GetObject("pos_null", resourceCulture);

View file

@ -223,8 +223,11 @@
<data name="flag_usa" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\flag_usa.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="groupmode" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\groupmode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="pos_center" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Assets\pos_center.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View file

@ -132,25 +132,37 @@ namespace OnTopReplica.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string Setting {
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool RestoreSizeAndPosition {
get {
return ((string)(this["Setting"]));
return ((bool)(this["RestoreSizeAndPosition"]));
}
set {
this["Setting"] = value;
this["RestoreSizeAndPosition"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string Setting1 {
[global::System.Configuration.DefaultSettingValueAttribute("0, 0")]
public global::System.Drawing.Size RestoreLastSize {
get {
return ((string)(this["Setting1"]));
return ((global::System.Drawing.Size)(this["RestoreLastSize"]));
}
set {
this["Setting1"] = value;
this["RestoreLastSize"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0, 0")]
public global::System.Drawing.Point RestoreLastPosition {
get {
return ((global::System.Drawing.Point)(this["RestoreLastPosition"]));
}
set {
this["RestoreLastPosition"] = value;
}
}
}

View file

@ -29,11 +29,14 @@
<Setting Name="FullscreenAlwaysOnTop" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="Setting" Type="System.String" Scope="User">
<Value Profile="(Default)" />
<Setting Name="RestoreSizeAndPosition" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="Setting1" Type="System.String" Scope="User">
<Value Profile="(Default)" />
<Setting Name="RestoreLastSize" Type="System.Drawing.Size" Scope="User">
<Value Profile="(Default)">0, 0</Value>
</Setting>
<Setting Name="RestoreLastPosition" Type="System.Drawing.Point" Scope="User">
<Value Profile="(Default)">0, 0</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace OnTopReplica {
/// <summary>
/// Describes a resolution independent position.
/// </summary>
enum ScreenPosition {
TopLeft,
TopRight,
BottomLeft,
BottomRight,
Center
}
/// <summary>
/// Extension methods for ScreenPositions.
/// </summary>
static class ScreenPositionExtensions {
/// <summary>
/// Sets the form's screen position in independent coordinates.
/// </summary>
/// <remarks>
/// Position is set relative to the form's current screen.
/// </remarks>
public static void SetScreenPosition(this MainForm form, ScreenPosition position) {
var screen = Screen.FromControl(form);
var wa = screen.WorkingArea;
Point p = new Point();
switch (position) {
case ScreenPosition.TopLeft:
p = new Point(
wa.Left - form.ChromeBorderHorizontal,
wa.Top - form.ChromeBorderVertical
);
break;
case ScreenPosition.TopRight:
p = new Point(
wa.Right - form.Width + form.ChromeBorderHorizontal,
wa.Top - form.ChromeBorderVertical
);
break;
case ScreenPosition.BottomLeft:
p = new Point(
wa.Left - form.ChromeBorderHorizontal,
wa.Bottom - form.Height + form.ChromeBorderVertical
);
break;
case ScreenPosition.BottomRight:
p = new Point(
wa.Right - form.Width + form.ChromeBorderHorizontal,
wa.Bottom - form.Height + form.ChromeBorderVertical
);
break;
case ScreenPosition.Center:
p = new Point(
wa.X + (wa.Width / 2) - (form.Width / 2) - (form.ChromeBorderHorizontal / 2),
wa.Y + (wa.Height / 2) - (form.Height / 2) - (form.ChromeBorderVertical / 2)
);
break;
}
form.Location = p;
}
}
}

View file

@ -4,6 +4,7 @@ using System.Windows.Forms;
using OnTopReplica.Properties;
using System.Collections.Generic;
using OnTopReplica.MessagePumpProcessors;
using OnTopReplica.WindowSeekers;
namespace OnTopReplica.SidePanels {
partial class GroupSwitchPanel : SidePanel {
@ -23,8 +24,8 @@ namespace OnTopReplica.SidePanels {
}
private void LoadWindowList() {
var manager = new WindowManager();
manager.Refresh(WindowManager.EnumerationMode.TaskWindows);
var manager = new TaskWindowSeeker();
manager.Refresh();
var imageList = new ImageList();
imageList.ColorDepth = ColorDepth.Depth32Bit;
@ -46,7 +47,7 @@ namespace OnTopReplica.SidePanels {
public override void OnClosing(MainForm form) {
base.OnClosing(form);
if (_enableOnClose) {
if (_enableOnClose && listWindows.SelectedItems.Count > 0) {
List<WindowHandle> ret = new List<WindowHandle>();
foreach (ListViewItem i in listWindows.SelectedItems) {
ret.Add((WindowHandle)i.Tag);

View file

@ -55,7 +55,7 @@ namespace OnTopReplica.SidePanels {
return;
}
SetRegion(region.Rect);
SetRegion(region.Bounds);
//Select right combobox
if (comboRegions.Items.Contains(region)) {
@ -207,7 +207,7 @@ namespace OnTopReplica.SidePanels {
if (region == null)
return;
SetRegion(region.Rect);
SetRegion(region.Bounds);
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OnTopReplica.StartupOptions {
public enum CliStatus {
/// <summary>
/// No errors while parsing.
/// </summary>
Ok,
/// <summary>
/// User asked for help.
/// </summary>
Information,
/// <summary>
/// Error while parsing.
/// </summary>
Error
}
}

View file

@ -0,0 +1,116 @@
namespace OnTopReplica.StartupOptions {
partial class CommandLineReportForm {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CommandLineReportForm));
this.buttonOk = new System.Windows.Forms.Button();
this.labelInstruction = new System.Windows.Forms.Label();
this.txtDescription = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.txtCliArgs = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// buttonOk
//
this.buttonOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK;
this.buttonOk.Location = new System.Drawing.Point(440, 200);
this.buttonOk.Name = "buttonOk";
this.buttonOk.Size = new System.Drawing.Size(75, 23);
this.buttonOk.TabIndex = 0;
this.buttonOk.Text = "OK";
this.buttonOk.UseVisualStyleBackColor = true;
//
// labelInstruction
//
this.labelInstruction.AutoSize = true;
this.labelInstruction.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelInstruction.ForeColor = System.Drawing.SystemColors.HotTrack;
this.labelInstruction.Location = new System.Drawing.Point(12, 10);
this.labelInstruction.Name = "labelInstruction";
this.labelInstruction.Size = new System.Drawing.Size(112, 21);
this.labelInstruction.TabIndex = 1;
this.labelInstruction.Text = "Command line";
//
// txtDescription
//
this.txtDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtDescription.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtDescription.Location = new System.Drawing.Point(12, 42);
this.txtDescription.Multiline = true;
this.txtDescription.Name = "txtDescription";
this.txtDescription.ReadOnly = true;
this.txtDescription.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.txtDescription.Size = new System.Drawing.Size(503, 152);
this.txtDescription.TabIndex = 2;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 205);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(60, 13);
this.label1.TabIndex = 3;
this.label1.Text = "Arguments:";
//
// txtCliArgs
//
this.txtCliArgs.Location = new System.Drawing.Point(79, 202);
this.txtCliArgs.Name = "txtCliArgs";
this.txtCliArgs.ReadOnly = true;
this.txtCliArgs.Size = new System.Drawing.Size(355, 20);
this.txtCliArgs.TabIndex = 4;
//
// CommandLineReportForm
//
this.AcceptButton = this.buttonOk;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.ClientSize = new System.Drawing.Size(527, 235);
this.Controls.Add(this.txtCliArgs);
this.Controls.Add(this.label1);
this.Controls.Add(this.txtDescription);
this.Controls.Add(this.labelInstruction);
this.Controls.Add(this.buttonOk);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "CommandLineReportForm";
this.Text = "Command line parameters";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button buttonOk;
private System.Windows.Forms.Label labelInstruction;
private System.Windows.Forms.TextBox txtDescription;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox txtCliArgs;
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace OnTopReplica.StartupOptions {
public partial class CommandLineReportForm : Form {
public CommandLineReportForm(CliStatus status, string message) {
InitializeComponent();
switch (status) {
case CliStatus.Information:
labelInstruction.Text = "Command line help";
break;
case CliStatus.Error:
labelInstruction.Text = "Command line parsing error";
break;
}
txtDescription.Text = message;
txtCliArgs.Text = Environment.CommandLine;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using OnTopReplica.Properties;
namespace OnTopReplica.StartupOptions {
class Factory {
static Factory() {
//Custom type conversion attributes
TypeDescriptor.AddAttributes(typeof(Size), new TypeConverterAttribute(typeof(SizeConverter)));
TypeDescriptor.AddAttributes(typeof(ScreenPosition), new TypeConverterAttribute(typeof(ScreenPositionConverter)));
TypeDescriptor.AddAttributes(typeof(Rectangle), new TypeConverterAttribute(typeof(RectangleConverter)));
}
public static Options CreateOptions(string[] args) {
var options = new Options();
LoadSettings(options);
ParseCommandLine(args, options);
return options;
}
private static void LoadSettings(Options options) {
if (Settings.Default.RestoreSizeAndPosition) {
options.StartLocation = Settings.Default.RestoreLastPosition;
options.StartSize = Settings.Default.RestoreLastSize;
}
}
private static void ParseCommandLine(string[] args, Options options) {
var cmdOptions = new NDesk.Options.OptionSet()
.Add<long>("windowId=", "Window handle ({HWND}) to be cloned.", id => {
options.WindowId = new IntPtr(id);
})
.Add<string>("windowTitle=", "{TITLE} of the window to be cloned.", s => {
options.WindowTitle = s;
})
.Add<string>("windowClass=", "{CLASS} of the window to be cloned.", s => {
options.WindowClass = s;
})
.Add("v|visible", "If set, only clones windows that are visible.", s => {
options.MustBeVisible = true;
})
.Add<Size>("size=", "Target {SIZE} of the cloned thumbnail.", s => {
options.StartSize = s;
})
.Add<Size>("position=", "Target {COORDINATES} of the OnTopReplica window.", s => {
options.StartLocation = new Point(s.Width, s.Height);
options.StartScreenPosition = null;
})
.Add<ScreenPosition>("screenPosition=", "Resolution independent window position on current screen, with locking (TR|TL|C|BR|BL).", pos => {
options.StartLocation = null;
options.StartScreenPosition = pos;
})
.Add<Rectangle>("r|region=", "Region {BOUNDS} of the original window.", region => {
options.Region = region;
})
.Add<byte>("o|opacity=", "Opacity of the window (0-255).", opacity => {
options.Opacity = opacity;
})
.Add("clickForwarding", "Enables click forwarding.", s => {
options.EnableClickForwarding = true;
})
.Add("chromeOff", "Disables the window's chrome (border).", s => {
options.DisableChrome = true;
})
.Add("h|help|?", "Show command line help.", s => {
options.Status = CliStatus.Information;
});
List<string> values;
try {
values = cmdOptions.Parse(args);
}
catch (NDesk.Options.OptionException ex) {
options.DebugMessageWriter.WriteLine(ex.Message);
options.DebugMessageWriter.WriteLine("Try 'OnTopReplica /help' for more information.");
options.Status = CliStatus.Error;
}
if (options.Status == CliStatus.Information) {
cmdOptions.WriteOptionDescriptions(options.DebugMessageWriter);
}
}
}
}

View file

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using OnTopReplica.WindowSeekers;
namespace OnTopReplica.StartupOptions {
/// <summary>
/// Represents startup options that can be set via CLI scripting (or other stuff).
/// </summary>
class Options {
public Options() {
Status = CliStatus.Ok;
Opacity = 255;
DisableChrome = false;
MustBeVisible = false;
}
#region Position and size
public Point? StartLocation { get; set; }
public ScreenPosition? StartScreenPosition { get; set; }
public Size? StartSize { get; set; }
#endregion
#region Window cloning
public IntPtr? WindowId { get; set; }
public string WindowTitle { get; set; }
public string WindowClass { get; set; }
public Rectangle? Region { get; set; }
public bool MustBeVisible { get; set; }
#endregion
#region Options
public bool EnableClickForwarding { get; set; }
public byte Opacity { get; set; }
public bool DisableChrome { get; set; }
#endregion
#region Debug info
StringBuilder _sb = new StringBuilder();
TextWriter _sbWriter;
public CliStatus Status { get; set; }
/// <summary>
/// Gets a debug message writer.
/// </summary>
public TextWriter DebugMessageWriter {
get {
if (_sbWriter == null) {
_sbWriter = new StringWriter(_sb);
}
return _sbWriter;
}
}
/// <summary>
/// Gets the debug message.
/// </summary>
public string DebugMessage {
get {
if(_sbWriter != null)
_sbWriter.Flush();
return _sb.ToString();
}
}
#endregion
#region Application
public void Apply(MainForm form) {
//GUI
form.IsChromeVisible = !DisableChrome;
form.Opacity = (double)Opacity / 255.0;
//Thumbnail cloning
WindowHandle handle = null;
if (WindowId.HasValue) {
handle = WindowHandle.FromHandle(WindowId.Value);
}
else if (WindowTitle != null) {
var seeker = new ByTitleWindowSeeker(WindowTitle) {
OwnerHandle = form.Handle,
SkipNotVisibleWindows = MustBeVisible
};
seeker.Refresh();
handle = seeker.Windows.FirstOrDefault();
}
else if (WindowClass != null) {
var seeker = new ByClassWindowSeeker(WindowClass) {
OwnerHandle = form.Handle,
SkipNotVisibleWindows = MustBeVisible
};
seeker.Refresh();
handle = seeker.Windows.FirstOrDefault();
}
if (handle != null) {
form.SetThumbnail(handle, Region);
}
//Size
if (StartSize.HasValue) {
form.ClientSize = StartSize.Value;
}
//Position
if (StartLocation.HasValue) {
form.Location = StartLocation.Value;
}
else if (StartScreenPosition.HasValue) {
form.PositionLock = StartScreenPosition.Value;
}
//Other features
if (EnableClickForwarding) {
form.ClickForwardingEnabled = true;
}
}
#endregion
}
}

View file

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Text.RegularExpressions;
namespace OnTopReplica.StartupOptions {
class RectangleConverter : TypeConverter {
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
if (value != null) {
var sVal = value.ToString();
return Convert(sVal);
}
else
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
return sourceType == typeof(string);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
return destinationType == typeof(Rectangle);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
if (value != null && destinationType == typeof(Rectangle)) {
var sVal = value.ToString();
return Convert(sVal);
}
else
return base.ConvertTo(context, culture, value, destinationType);
}
static Regex _sizeRegex = new Regex("^\\D*(?<x>\\d*)\\s*,\\s*(?<y>\\d*)\\s*,\\s*(?<width>\\d*)\\s*,\\s*(?<height>\\d*)\\D*$",
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.Singleline);
private Rectangle Convert(string s) {
var match = _sizeRegex.Match(s);
var x = match.Groups["x"];
var y = match.Groups["y"];
var width = match.Groups["width"];
var height = match.Groups["height"];
if (match.Success && x.Success && y.Success && width.Success && height.Success) {
var xVal = int.Parse(x.Value);
var yVal = int.Parse(y.Value);
var widthVal = int.Parse(width.Value);
var heightVal = int.Parse(height.Value);
return new Rectangle(xVal, yVal, widthVal, heightVal);
}
else
throw new ArgumentException("Cannot convert '" + s + "' to rectangle.");
}
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace OnTopReplica.StartupOptions {
class ScreenPositionConverter : TypeConverter {
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
if (destinationType == typeof(ScreenPosition))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
var sValue = value.ToString();
switch (sValue) {
case "TL":
return ScreenPosition.TopLeft;
case "TR":
return ScreenPosition.TopRight;
case "BL":
return ScreenPosition.BottomLeft;
case "BR":
return ScreenPosition.BottomRight;
case "C":
return ScreenPosition.Center;
default:
throw new ArgumentException("Invalid screen position value '" + sValue + "'.");
}
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
if (destinationType == typeof(ScreenPosition))
return ConvertFrom(context, culture, value);
return base.ConvertTo(context, culture, value, destinationType);
}
}
}

View file

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Text.RegularExpressions;
namespace OnTopReplica.StartupOptions {
class SizeConverter : TypeConverter {
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
if (value != null) {
var sVal = value.ToString();
return StringToSize(sVal);
}
else
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
return (sourceType == typeof(string) || sourceType == typeof(Size));
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
return (destinationType == typeof(Size) || destinationType == typeof(string));
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
if (value == null)
return base.ConvertTo(context, culture, value, destinationType);
if (destinationType == typeof(Size)) {
var sVal = value.ToString();
return StringToSize(sVal);
}
else if (destinationType == typeof(string)) {
if (value is Size) {
Size sValue = (Size)value;
return string.Format("{0}, {1}", sValue.Width, sValue.Height);
}
return value.ToString();
}
else
return base.ConvertTo(context, culture, value, destinationType);
}
static Regex _sizeRegex = new Regex("^\\D*(?<x>\\d*)\\s*,\\s*(?<y>\\d*)\\D*$",
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.Singleline);
private Size StringToSize(string s) {
var match = _sizeRegex.Match(s);
var x = match.Groups["x"];
var y = match.Groups["y"];
if (!match.Success || !x.Success || !y.Success)
throw new ArgumentException("Cannot convert '" + s + "' to coordinates pair.");
var xVal = Int32.Parse(x.Value);
var yVal = Int32.Parse(y.Value);
return new Size(xVal, yVal);
}
}
}

View file

@ -13,11 +13,11 @@ namespace OnTopReplica {
}
public StoredRegion(Rectangle r, string n) {
Rect = r;
Bounds = r;
Name = n;
}
public Rectangle Rect {
public Rectangle Bounds {
get;
set;
}
@ -47,14 +47,14 @@ namespace OnTopReplica {
reader.Read();
XmlSerializer x = new XmlSerializer(typeof(Rectangle));
Rect = (Rectangle)x.Deserialize(reader);
Bounds = (Rectangle)x.Deserialize(reader);
}
public void WriteXml(System.Xml.XmlWriter writer) {
writer.WriteAttributeString("name", Name);
XmlSerializer x = new XmlSerializer(typeof(Rectangle));
x.Serialize(writer, Rect);
x.Serialize(writer, Bounds);
}
#endregion

View file

@ -1025,7 +1025,25 @@ namespace OnTopReplica {
}
/// <summary>
/// Looks up a localized string similar to Position.
/// Looks up a localized string similar to Center.
/// </summary>
internal static string MenuPosCenter {
get {
return ResourceManager.GetString("MenuPosCenter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Disabled.
/// </summary>
internal static string MenuPosDisabled {
get {
return ResourceManager.GetString("MenuPosDisabled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Position lock.
/// </summary>
internal static string MenuPosition {
get {

View file

@ -171,7 +171,7 @@ Dette program kræver Windows Vista Home Premium eller bedre.</value>
<value>Ingen miniature indlæst.</value>
</data>
<data name="ErrorUnableToCreateThumbnail" xml:space="preserve">
<value>Kan ikke lave miniature.</value>
<value>Kan ikke lave miniature</value>
</data>
<data name="ErrorUnableToFit" xml:space="preserve">
<value>Kunne ikke passes til vinduet.</value>

0
OnTopReplica/Strings.it.Designer.cs generated Normal file
View file

View file

@ -1,5 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
@ -176,7 +281,7 @@ Per farlo, clicca col tasto destro del mouse sul desktop e poi su Personalizza.<
<value>Nessuna finestra clonata al momento.</value>
</data>
<data name="ErrorUnableToCreateThumbnail" xml:space="preserve">
<value>Impossibile clonare la finestra.</value>
<value>Impossibile clonare la finestra</value>
</data>
<data name="ErrorUnableToFit" xml:space="preserve">
<value>Impossibile adattare la finestra.</value>
@ -386,7 +491,7 @@ Puoi abilitare il Click-Through in futuro</value>
<value>In basso a destra</value>
</data>
<data name="MenuPosition" xml:space="preserve">
<value>Posizione</value>
<value>Blocco posizione</value>
</data>
<data name="MenuPositionTT" xml:space="preserve">
<value>Posiziona automaticamente OnTopReplica sul monitor corrente.</value>
@ -484,4 +589,7 @@ Puoi abilitare il Click-Through in futuro</value>
<data name="UpdateNow" xml:space="preserve">
<value>Aggiorna!</value>
</data>
<data name="MenuPosDisabled" xml:space="preserve">
<value>Disabilitato</value>
</data>
</root>

View file

@ -1,5 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
@ -176,7 +281,7 @@ You must run this application on Windows Vista Home Premium or better.</value>
<value>No thumbnail loaded.</value>
</data>
<data name="ErrorUnableToCreateThumbnail" xml:space="preserve">
<value>Unable to create thumbnail.</value>
<value>Unable to create thumbnail</value>
</data>
<data name="ErrorUnableToFit" xml:space="preserve">
<value>Unable to fit window.</value>
@ -386,7 +491,7 @@ You can enable click-through later</value>
<value>Bottom Right</value>
</data>
<data name="MenuPosition" xml:space="preserve">
<value>Position</value>
<value>Position lock</value>
</data>
<data name="MenuPositionTT" xml:space="preserve">
<value>Automatically position OnTopReplica on the current screen.</value>
@ -484,4 +589,10 @@ You can enable click-through later</value>
<data name="UpdateNow" xml:space="preserve">
<value>Update now!</value>
</data>
<data name="MenuPosCenter" xml:space="preserve">
<value>Center</value>
</data>
<data name="MenuPosDisabled" xml:space="preserve">
<value>Disabled</value>
</data>
</root>

View file

@ -8,6 +8,7 @@ namespace OnTopReplica {
/// <summary>Helper class that keeps a window handle (HWND), the title of the window and can load its icon.</summary>
public class WindowHandle : System.Windows.Forms.IWin32Window {
IntPtr _handle;
string _title;
@ -81,5 +82,13 @@ namespace OnTopReplica {
#endregion
/// <summary>
/// Creates a new windowHandle instance from a given IntPtr handle.
/// </summary>
/// <param name="handle">Handle value.</param>
public static WindowHandle FromHandle(IntPtr handle) {
return new WindowHandle(handle, string.Empty);
}
}
}

View file

@ -3,8 +3,12 @@ using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using OnTopReplica.Properties;
using OnTopReplica.WindowSeekers;
namespace OnTopReplica {
/// <summary>
/// Extension methods used to apply a window list to a menu.
/// </summary>
static class WindowListHelper {
public class WindowSelectionData {
@ -14,7 +18,15 @@ namespace OnTopReplica {
const int MaxWindowTitleLength = 55;
public static void PopulateMenu(Form ownerForm, WindowManager windowManager, ToolStrip menu,
/// <summary>
/// Populates the menu with a list of windows.
/// </summary>
/// <param name="menu">The menu to populate.</param>
/// <param name="ownerForm">The owning form.</param>
/// <param name="windowManager">The window manager that provides the windows list.</param>
/// <param name="currentHandle">The currently used window (will be checked in the list).</param>
/// <param name="clickHandler">Event handler for clicks on window items.</param>
public static void PopulateMenu(this ToolStrip menu, Form ownerForm, BaseWindowSeeker windowManager,
WindowHandle currentHandle, EventHandler clickHandler) {
var regions = GetRegions();

View file

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Native;
namespace OnTopReplica {
/// <summary>A helper class that allows you to easily build and keep a list of Windows (in the form of WindowHandle objects).</summary>
public class WindowManager {
List<WindowHandle> _windows = new List<WindowHandle>();
public enum EnumerationMode {
/// <summary>All windows with 'Visible' flag.</summary>
AllVisible,
/// <summary>All top level windows.</summary>
AllTopLevel,
/// <summary>Windows of a task (like Alt+Tab).</summary>
TaskWindows
}
/// <summary>Refreshes the window list.</summary>
public void Refresh(EnumerationMode mode) {
_windows = new List<WindowHandle>();
WindowManagerMethods.EnumWindowsProc proc = null;
switch (mode) {
case EnumerationMode.AllVisible:
proc = new WindowManagerMethods.EnumWindowsProc(EnumWindowProcAll);
break;
case EnumerationMode.AllTopLevel:
proc = new WindowManagerMethods.EnumWindowsProc(EnumWindowProcTopLevel);
break;
case EnumerationMode.TaskWindows:
proc = new WindowManagerMethods.EnumWindowsProc(EnumWindowProcTask);
break;
}
WindowManagerMethods.EnumWindows(proc, IntPtr.Zero);
}
public IEnumerable<WindowHandle> Windows {
get {
return _windows;
}
}
private bool EnumWindowProcAll(IntPtr hwnd, IntPtr lParam) {
if (WindowManagerMethods.IsWindowVisible(hwnd)) {
string title = WindowMethods.GetWindowText(hwnd);
_windows.Add( new WindowHandle(hwnd, title));
}
return true;
}
private bool EnumWindowProcTopLevel(IntPtr hwnd, IntPtr lParam) {
if (WindowManagerMethods.IsWindowVisible(hwnd)) {
//Check if window has no parent
if ((long)WindowManagerMethods.GetParent(hwnd) == 0 && WindowManagerMethods.GetDesktopWindow() != hwnd) {
string title = WindowMethods.GetWindowText(hwnd);
_windows.Add( new WindowHandle(hwnd, title));
}
}
return true;
}
private bool EnumWindowProcTask(IntPtr hwnd, IntPtr lParam) {
//Code taken from: http://www.thescarms.com/VBasic/alttab.aspx
//Accept windows that
// - are visible
// - do not have a parent
// - have no owner and are not Tool windows OR
// - have an owner and are App windows
//Reject empty titles
string title = WindowMethods.GetWindowText(hwnd);
if (string.IsNullOrEmpty(title))
return true;
if (WindowManagerMethods.IsWindowVisible(hwnd)) {
if ((long)WindowManagerMethods.GetParent(hwnd) == 0) {
bool hasOwner = (long)WindowManagerMethods.GetWindow(hwnd, WindowManagerMethods.GetWindowMode.GW_OWNER) != 0;
WindowMethods.WindowExStyles exStyle = (WindowMethods.WindowExStyles)WindowMethods.GetWindowLong(hwnd, WindowMethods.WindowLong.ExStyle);
if (((exStyle & WindowMethods.WindowExStyles.ToolWindow) == 0 && !hasOwner) || //unowned non-tool window
((exStyle & WindowMethods.WindowExStyles.AppWindow) == WindowMethods.WindowExStyles.AppWindow && hasOwner)) { //owned application window
_windows.Add(new WindowHandle(hwnd, title));
}
}
}
return true;
}
}
}

View file

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Native;
namespace OnTopReplica.WindowSeekers {
/// <summary>
/// Base class for window seekers that can populate a list of window handles based on some criteria.
/// </summary>
abstract class BaseWindowSeeker {
List<WindowHandle> _list = new List<WindowHandle>();
/// <summary>
/// Get the matching windows from the last refresh.
/// </summary>
public IEnumerable<WindowHandle> Windows {
get {
return _list;
}
}
/// <summary>
/// Forces a window list refresh.
/// </summary>
public virtual void Refresh() {
_list.Clear();
WindowManagerMethods.EnumWindows(
new WindowManagerMethods.EnumWindowsProc(RefreshCallback),
IntPtr.Zero);
}
private bool RefreshCallback(IntPtr hwnd, IntPtr lParam) {
bool cont = true;
//Skip owner
if (hwnd == OwnerHandle)
return true;
if (SkipNotVisibleWindows && !WindowManagerMethods.IsWindowVisible(hwnd))
return true;
//Extract basic properties
string title = WindowMethods.GetWindowText(hwnd);
if (InspectWindow(hwnd, title, ref cont)) {
//Window has been picked
_list.Add(new WindowHandle(hwnd, title));
}
return cont;
}
/// <summary>
/// Inspects a window and returns whether the window should be listed or not.
/// </summary>
/// <param name="hwnd">Handle of the window.</param>
/// <param name="title">Title of the window (if any).</param>
/// <param name="terminate">Indicates whether the inspection loop should terminate after this window.</param>
/// <returns>True if the window should be listed.</returns>
protected abstract bool InspectWindow(IntPtr hwnd, string title, ref bool terminate);
/// <summary>
/// Gets or sets the window handle of the owner.
/// </summary>
/// <remarks>
/// Windows with this handle will be automatically skipped.
/// </remarks>
public IntPtr OwnerHandle { get; set; }
/// <summary>
/// Gets or sets whether not visible windows should be skipped.
/// </summary>
public bool SkipNotVisibleWindows { get; set; }
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Native;
namespace OnTopReplica.WindowSeekers {
/// <summary>
/// Seeks a single window by matching its window class.
/// </summary>
/// <remarks>
/// Class matching is exact and case-sensititve.
/// </remarks>
class ByClassWindowSeeker : BaseWindowSeeker {
public ByClassWindowSeeker(string className) {
if (className == null)
throw new ArgumentNullException();
ClassName = className;
}
public string ClassName { get; private set; }
protected override bool InspectWindow(IntPtr hwnd, string title, ref bool terminate) {
var wndClass = WindowMethods.GetWindowClass(hwnd);
if (ClassName.Equals(wndClass, StringComparison.CurrentCulture)) {
return true;
}
return false;
}
}
}

View file

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Native;
namespace OnTopReplica.WindowSeekers {
/// <summary>
/// Seeks a single window by approximately matching its title.
/// </summary>
/// <remarks>
/// Title search is case-insensitive and matches only the beginning of the windows' titles.
/// </remarks>
class ByTitleWindowSeeker : BaseWindowSeeker {
public ByTitleWindowSeeker(string titleSeekString) {
if (titleSeekString == null)
throw new ArgumentNullException();
TitleMatch = titleSeekString.Trim().ToLower();
}
public string TitleMatch { get; private set; }
protected override bool InspectWindow(IntPtr hwnd, string title, ref bool terminate) {
//Skip empty titles
if (string.IsNullOrEmpty(title))
return false;
//Skip non-top-level windows (skips most internal controls)
bool hasParent = (long)WindowManagerMethods.GetParent(hwnd) != 0;
bool hasOwner = (long)WindowManagerMethods.GetWindow(hwnd, WindowManagerMethods.GetWindowMode.GW_OWNER) != 0;
if (hasParent || hasOwner)
return false;
var modTitle = title.Trim().ToLower();
if (modTitle.StartsWith(TitleMatch)) {
terminate = true; //only one needed
return true;
}
return false;
}
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Native;
namespace OnTopReplica.WindowSeekers {
class TaskWindowSeeker : BaseWindowSeeker {
protected override bool InspectWindow(IntPtr hwnd, string title, ref bool terminate) {
//Code taken from: http://www.thescarms.com/VBasic/alttab.aspx
//Accept windows that
// - are visible
// - do not have a parent
// - have no owner and are not Tool windows OR
// - have an owner and are App windows
//Reject empty titles
if (string.IsNullOrEmpty(title))
return false;
if ((long)WindowManagerMethods.GetParent(hwnd) == 0) {
bool hasOwner = (long)WindowManagerMethods.GetWindow(hwnd, WindowManagerMethods.GetWindowMode.GW_OWNER) != 0;
WindowMethods.WindowExStyles exStyle = (WindowMethods.WindowExStyles)WindowMethods.GetWindowLong(hwnd, WindowMethods.WindowLong.ExStyle);
if (((exStyle & WindowMethods.WindowExStyles.ToolWindow) == 0 && !hasOwner) || //unowned non-tool window
((exStyle & WindowMethods.WindowExStyles.AppWindow) == WindowMethods.WindowExStyles.AppWindow && hasOwner)) { //owned application window
return true;
}
}
return false;
}
}
}

View file

@ -31,11 +31,14 @@
<setting name="FullscreenAlwaysOnTop" serializeAs="String">
<value>False</value>
</setting>
<setting name="Setting" serializeAs="String">
<value />
<setting name="RestoreSizeAndPosition" serializeAs="String">
<value>False</value>
</setting>
<setting name="Setting1" serializeAs="String">
<value />
<setting name="RestoreLastSize" serializeAs="String">
<value>0, 0</value>
</setting>
<setting name="RestoreLastPosition" serializeAs="String">
<value>0, 0</value>
</setting>
</OnTopReplica.Properties.Settings>
</userSettings>