Code re-org
4
.gitignore
vendored
|
@ -1,8 +1,8 @@
|
|||
.vs/*
|
||||
**/.vs/*
|
||||
**/bin/*
|
||||
**/obj/*
|
||||
**/publish/*
|
||||
Installer/OnTopReplica-Setup.exe
|
||||
*.user
|
||||
*.suo
|
||||
packages/
|
||||
src/packages/*
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishUrlHistory>publish\</PublishUrlHistory>
|
||||
<InstallUrlHistory>http://www.klopfenstein.net/public/Uploads/ontopreplica/|http://www.klopfenstein.net/download.aspx%3ffile=ontopreplica%252fsetup.exe/|http://www.klopfenstein.net/lorenz/programming/ontopreplica/|http://www.klopfenstein.net/lorenz/programming/|http://lorenz.klopfenstein.net/</InstallUrlHistory>
|
||||
<SupportUrlHistory>http://www.klopfenstein.net/lorenz.aspx/ontopreplica|http://www.klopfenstein.net/loader.php%3fsection=lorenz&page=on_top_replica|http://www.klopfenstein.net/loader.php%3fsection=lorenz&page=programming_on_top_replica</SupportUrlHistory>
|
||||
<UpdateUrlHistory>http://www.klopfenstein.net/public/Uploads/ontopreplica/|http://www.klopfenstein.net/lorenz/programming/ontopreplica/</UpdateUrlHistory>
|
||||
<BootstrapperUrlHistory>
|
||||
</BootstrapperUrlHistory>
|
||||
<FallbackCulture>en-US</FallbackCulture>
|
||||
<VerifyUploadedFiles>false</VerifyUploadedFiles>
|
||||
<ErrorReportUrlHistory>
|
||||
</ErrorReportUrlHistory>
|
||||
<ProjectView>ProjectFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<EnableSecurityDebugging>false</EnableSecurityDebugging>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
</Project>
|
33
src/.editorconfig
Normal file
|
@ -0,0 +1,33 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.cs]
|
||||
indent_style = space
|
||||
indent_size = tab
|
||||
tab_size = 4
|
||||
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_conditional_delegate_call = true
|
||||
csharp_prefer_braces = true
|
||||
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
csharp_new_line_before_open_brace = false
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_preserve_single_line_blocks = true
|
|
@ -1,55 +1,49 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2008
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnTopReplica", "OnTopReplica\OnTopReplica.csproj", "{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x86.Build.0 = Release|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|x64.Build.0 = Debug|x64
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|x86.Build.0 = Debug|x86
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|x64.ActiveCfg = Release|x64
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|x64.Build.0 = Release|x64
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|x64.Deploy.0 = Release|x64
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|x86.ActiveCfg = Release|x86
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|x86.Build.0 = Release|x86
|
||||
{01391A7F-A9A1-4C90-89EB-29E0C98BF9BE}.Release|x86.Deploy.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3F135F78-F70E-4127-BA77-6C262C7CCCEF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2008
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnTopReplica", "OnTopReplica\OnTopReplica.csproj", "{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E626BD6E-BF38-4EB7-A128-5CA6F40EF557}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Debug|Any CPU.ActiveCfg = Debug
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Debug|Any CPU.Build.0 = Debug
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Debug|x64.ActiveCfg = Debug
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Debug|x64.Build.0 = Debug
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Debug|x86.ActiveCfg = Debug
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Debug|x86.Build.0 = Debug
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|Any CPU.ActiveCfg = Release
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|Any CPU.Build.0 = Release
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x64.ActiveCfg = Release
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x64.Build.0 = Release
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x86.ActiveCfg = Release
|
||||
{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x86.Build.0 = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3F135F78-F70E-4127-BA77-6C262C7CCCEF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,34 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica {
|
||||
public static class AppPaths {
|
||||
|
||||
const string AppDataFolder = "OnTopReplica";
|
||||
|
||||
public static void SetupPaths() {
|
||||
var roamingAppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var roamingAppDataApplicationPath = Path.Combine(roamingAppData, AppDataFolder);
|
||||
|
||||
if (!Directory.Exists(roamingAppDataApplicationPath)) {
|
||||
Directory.CreateDirectory(roamingAppDataApplicationPath);
|
||||
}
|
||||
PrivateRoamingFolderPath = roamingAppDataApplicationPath;
|
||||
}
|
||||
|
||||
public static string PrivateRoamingFolderPath { get; private set; }
|
||||
|
||||
public static string GenerateCrashDumpPath() {
|
||||
var now = DateTime.Now;
|
||||
|
||||
string dump = string.Format("OnTopReplica-dump-{0}{1}{2}-{3}{4}.txt",
|
||||
now.Year, now.Month, now.Day,
|
||||
now.Hour, now.Minute);
|
||||
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), dump);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica {
|
||||
public static class AppPaths {
|
||||
|
||||
const string AppDataFolder = "OnTopReplica";
|
||||
|
||||
public static void SetupPaths() {
|
||||
var roamingAppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var roamingAppDataApplicationPath = Path.Combine(roamingAppData, AppDataFolder);
|
||||
|
||||
if (!Directory.Exists(roamingAppDataApplicationPath)) {
|
||||
Directory.CreateDirectory(roamingAppDataApplicationPath);
|
||||
}
|
||||
PrivateRoamingFolderPath = roamingAppDataApplicationPath;
|
||||
}
|
||||
|
||||
public static string PrivateRoamingFolderPath { get; private set; }
|
||||
|
||||
public static string GenerateCrashDumpPath() {
|
||||
var now = DateTime.Now;
|
||||
|
||||
string dump = string.Format("OnTopReplica-dump-{0}{1}{2}-{3}{4}.txt",
|
||||
now.Year, now.Month, now.Day,
|
||||
now.Hour, now.Minute);
|
||||
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), dump);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,135 +1,135 @@
|
|||
<?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>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ApplicationWebsite" xml:space="preserve">
|
||||
<value>http://ontopreplica.codeplex.com</value>
|
||||
</data>
|
||||
<data name="AuthorWebsite" xml:space="preserve">
|
||||
<value>http://lorenz.klopfenstein.net</value>
|
||||
</data>
|
||||
<data name="LatestCommitsLink" xml:space="preserve">
|
||||
<value>http://ontopreplica.codeplex.com/SourceControl/list/changesets</value>
|
||||
</data>
|
||||
<data name="MsRlLicenseLink" xml:space="preserve">
|
||||
<value>http://opensource.org/licenses/ms-rl.html</value>
|
||||
</data>
|
||||
<data name="UpdateFeed" xml:space="preserve">
|
||||
<value>http://ontopreplica.codeplex.com/project/feeds/rss?ProjectRSSFeed=codeplex%3a%2f%2frelease%2fontopreplica</value>
|
||||
</data>
|
||||
<?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>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ApplicationWebsite" xml:space="preserve">
|
||||
<value>http://ontopreplica.codeplex.com</value>
|
||||
</data>
|
||||
<data name="AuthorWebsite" xml:space="preserve">
|
||||
<value>http://lorenz.klopfenstein.net</value>
|
||||
</data>
|
||||
<data name="LatestCommitsLink" xml:space="preserve">
|
||||
<value>http://ontopreplica.codeplex.com/SourceControl/list/changesets</value>
|
||||
</data>
|
||||
<data name="MsRlLicenseLink" xml:space="preserve">
|
||||
<value>http://opensource.org/licenses/ms-rl.html</value>
|
||||
</data>
|
||||
<data name="UpdateFeed" xml:space="preserve">
|
||||
<value>http://ontopreplica.codeplex.com/project/feeds/rss?ProjectRSSFeed=codeplex%3a%2f%2frelease%2fontopreplica</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1,266 +1,266 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
/// <summary>
|
||||
/// Form that automatically keeps a certain aspect ratio and resizes without flickering.
|
||||
/// </summary>
|
||||
public class AspectRatioForm : WindowsFormsAero.AeroForm {
|
||||
|
||||
bool _keepAspectRatio = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the form should keep its aspect ratio.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Refreshes the window's size if set to true.
|
||||
/// </remarks>
|
||||
[Description("Enables fixed aspect ratio for this form."), Category("Appearance"), DefaultValue(true)]
|
||||
public bool KeepAspectRatio {
|
||||
get {
|
||||
return _keepAspectRatio;
|
||||
}
|
||||
set {
|
||||
_keepAspectRatio = value;
|
||||
|
||||
if (value)
|
||||
RefreshAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
double _aspectRatio = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the form's aspect ratio that will be kept automatically when resizing.
|
||||
/// </summary>
|
||||
[Description("Determines this form's fixed aspect ratio."), Category("Appearance"), DefaultValue(1.0)]
|
||||
public double AspectRatio {
|
||||
get {
|
||||
return _aspectRatio;
|
||||
}
|
||||
set {
|
||||
if (value <= 0.0 || Double.IsInfinity(value))
|
||||
return;
|
||||
|
||||
_aspectRatio = value;
|
||||
}
|
||||
}
|
||||
|
||||
Padding _extraPadding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets some additional internal padding of the form that is ignored when keeping the aspect ratio.
|
||||
/// </summary>
|
||||
[Description("Sets some padding inside the form's client area that is ignored when keeping the aspect ratio."),
|
||||
Category("Appearance")]
|
||||
public Padding ExtraPadding {
|
||||
get {
|
||||
return _extraPadding;
|
||||
}
|
||||
set {
|
||||
_extraPadding = value;
|
||||
|
||||
if(KeepAspectRatio)
|
||||
RefreshAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the form to update its height based on the current aspect ratio setting.
|
||||
/// </summary>
|
||||
public void RefreshAspectRatio() {
|
||||
int newWidth = ClientSize.Width;
|
||||
int newHeight = (int)((ClientSize.Width - ExtraPadding.Horizontal) / AspectRatio) + ExtraPadding.Vertical;
|
||||
|
||||
//Adapt height if it doesn't respect the form's minimum size
|
||||
Size clientMinimumSize = FromSizeToClientSize(MinimumSize);
|
||||
if (newHeight < clientMinimumSize.Height) {
|
||||
newHeight = clientMinimumSize.Height;
|
||||
newWidth = (int)((newHeight - ExtraPadding.Vertical) * AspectRatio) + ExtraPadding.Horizontal;
|
||||
}
|
||||
|
||||
//Adapt height if it exceeds the screen's height
|
||||
var workingArea = Screen.GetWorkingArea(this);
|
||||
if (newHeight >= workingArea.Height) {
|
||||
newHeight = workingArea.Height;
|
||||
newWidth = (int)((newHeight - ExtraPadding.Vertical) * AspectRatio) + ExtraPadding.Horizontal;
|
||||
}
|
||||
|
||||
//Update size
|
||||
ClientSize = new Size(newWidth, newHeight);
|
||||
|
||||
//Move form vertically to adapt to new size
|
||||
//REMOVED: allows the window to correctly be restored slightly off screen
|
||||
/*if (Location.Y + Size.Height > workingArea.Y + workingArea.Height) {
|
||||
int offsetY = (workingArea.Y + workingArea.Height) - (Location.Y + Size.Height);
|
||||
Location = new Point(Location.X, Location.Y - offsetY);
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the size of the form by a pixel increment while keeping its aspect ratio.
|
||||
/// </summary>
|
||||
/// <param name="pixelIncrement">Change of size in pixels.</param>
|
||||
public void AdjustSize(int pixelOffset) {
|
||||
Size origSize = Size;
|
||||
|
||||
//Resize to new width (clamped to max allowed size and minimum form size)
|
||||
int newWidth = Math.Max(Math.Min(origSize.Width + pixelOffset,
|
||||
SystemInformation.MaxWindowTrackSize.Width),
|
||||
MinimumSize.Width);
|
||||
|
||||
//Determine new height while keeping aspect ratio
|
||||
var clientConversionDifference = ClientWindowDifference;
|
||||
int newHeight = (int)((newWidth - ExtraPadding.Horizontal - clientConversionDifference.Width) / AspectRatio) + ExtraPadding.Vertical + clientConversionDifference.Height;
|
||||
|
||||
//Apply and move form to recenter
|
||||
Size = new Size(newWidth, newHeight);
|
||||
int deltaX = Size.Width - origSize.Width;
|
||||
int deltaY = Size.Height - origSize.Height;
|
||||
Location = new System.Drawing.Point(Location.X - (deltaX / 2), Location.Y - (deltaY / 2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the aspect ratio of the form and optionally forces a refresh.
|
||||
/// </summary>
|
||||
/// <param name="aspectRatioSource">Size from which aspect ratio should be computed.</param>
|
||||
/// <param name="forceRefresh">True if the size of the form should be refreshed to match the new aspect ratio.</param>
|
||||
public void SetAspectRatio(Size aspectRatioSource, bool forceRefresh) {
|
||||
AspectRatio = ((double)aspectRatioSource.Width / (double)aspectRatioSource.Height);
|
||||
_keepAspectRatio = true;
|
||||
|
||||
//Log.Write("Setting new aspect ratio {0} (for {1})", AspectRatio, aspectRatioSource);
|
||||
|
||||
if (forceRefresh) {
|
||||
RefreshAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
#region Event overriding
|
||||
|
||||
protected override void OnResizeEnd(EventArgs e) {
|
||||
base.OnResizeEnd(e);
|
||||
|
||||
//Ensure that the ClientSize of the form is always respected
|
||||
//(not ensured by the WM_SIZING message alone because of rounding errors and the chrome space)
|
||||
if (KeepAspectRatio) {
|
||||
var newHeight = ComputeHeightFromWidth(ClientSize.Width);
|
||||
ClientSize = new Size(ClientSize.Width, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnResizing(EventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override WM_SIZING message to restrict resizing.
|
||||
/// Taken from: http://www.vcskicks.com/maintain-aspect-ratio.php
|
||||
/// Improved with code from: http://stoyanoff.info/blog/2010/06/27/resizing-forms-while-keeping-aspect-ratio/
|
||||
/// </summary>
|
||||
protected override void WndProc(ref Message m) {
|
||||
if (m.Msg == WM.SIZING) {
|
||||
this.OnResizing(EventArgs.Empty);
|
||||
|
||||
if (KeepAspectRatio) {
|
||||
var clientSizeConversion = ClientWindowDifference;
|
||||
|
||||
var rc = (Native.NRectangle)Marshal.PtrToStructure(m.LParam, typeof(Native.NRectangle));
|
||||
int res = m.WParam.ToInt32();
|
||||
|
||||
int width = (rc.Right - rc.Left) - clientSizeConversion.Width - ExtraPadding.Horizontal;
|
||||
int height = (rc.Bottom - rc.Top) - clientSizeConversion.Height - ExtraPadding.Vertical;
|
||||
|
||||
if (res == WMSZ.LEFT || res == WMSZ.RIGHT) {
|
||||
//Left or right resize, adjust top and bottom
|
||||
int targetHeight = (int)(width / AspectRatio);
|
||||
int diffHeight = height - targetHeight;
|
||||
|
||||
rc.Top += (int)(diffHeight / 2.0);
|
||||
rc.Bottom = rc.Top + targetHeight + ExtraPadding.Vertical + clientSizeConversion.Height;
|
||||
}
|
||||
else if (res == WMSZ.TOP || res == WMSZ.BOTTOM) {
|
||||
//Up or down resize, adjust left and right
|
||||
int targetWidth = (int)(height * AspectRatio);
|
||||
int diffWidth = width - targetWidth;
|
||||
|
||||
rc.Left += (int)(diffWidth / 2.0);
|
||||
rc.Right = rc.Left + targetWidth + ExtraPadding.Horizontal + clientSizeConversion.Width;
|
||||
}
|
||||
else if (res == WMSZ.RIGHT + WMSZ.BOTTOM || res == WMSZ.LEFT + WMSZ.BOTTOM) {
|
||||
//Lower corner resize, adjust bottom
|
||||
rc.Bottom = rc.Top + (int)(width / AspectRatio) + ExtraPadding.Vertical + clientSizeConversion.Height;
|
||||
}
|
||||
else if (res == WMSZ.LEFT + WMSZ.TOP || res == WMSZ.RIGHT + WMSZ.TOP) {
|
||||
//Upper corner resize, adjust top
|
||||
rc.Top = rc.Bottom - (int)(width / AspectRatio) - ExtraPadding.Vertical - clientSizeConversion.Height;
|
||||
}
|
||||
|
||||
Marshal.StructureToPtr(rc, m.LParam, false);
|
||||
}
|
||||
}
|
||||
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conversion helpers
|
||||
|
||||
/// <summary>
|
||||
/// Converts a client size measurement to a window size measurement.
|
||||
/// </summary>
|
||||
/// <param name="clientSize">Size of the window's client area.</param>
|
||||
/// <returns>Size of the whole window.</returns>
|
||||
public Size FromClientSizeToSize(Size clientSize) {
|
||||
var difference = ClientWindowDifference;
|
||||
|
||||
return new Size(clientSize.Width + difference.Width, clientSize.Height + difference.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a window size measurement to a client size measurement.
|
||||
/// </summary>
|
||||
/// <param name="size">Size of the whole window.</param>
|
||||
/// <returns>Size of the window's client area.</returns>
|
||||
public Size FromSizeToClientSize(Size size) {
|
||||
var difference = ClientWindowDifference;
|
||||
|
||||
return new Size(size.Width - difference.Width, size.Height - difference.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes height from width value, according to aspect ratio of window.
|
||||
/// </summary>
|
||||
public int ComputeHeightFromWidth(int width) {
|
||||
return (int)Math.Round(((width - ExtraPadding.Horizontal) / AspectRatio) + ExtraPadding.Vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes width from height value, according to aspect ratio of window.
|
||||
/// </summary>
|
||||
public int ComputeWidthFromHeight(int height) {
|
||||
return (int)Math.Round(((height - ExtraPadding.Vertical) * AspectRatio) + ExtraPadding.Horizontal);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the difference in pixels between a client size value and a window size value (depending on window decoration).
|
||||
/// </summary>
|
||||
protected Size ClientWindowDifference {
|
||||
get {
|
||||
long style = WindowMethods.GetWindowLong(this.Handle, WindowMethods.WindowLong.Style).ToInt64();
|
||||
long exStyle = WindowMethods.GetWindowLong(this.Handle, WindowMethods.WindowLong.ExStyle).ToInt64();
|
||||
return WindowMethods.ConvertClientToWindowRect(new NRectangle(0, 0, 0, 0), style, exStyle).Size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
/// <summary>
|
||||
/// Form that automatically keeps a certain aspect ratio and resizes without flickering.
|
||||
/// </summary>
|
||||
public class AspectRatioForm : WindowsFormsAero.AeroForm {
|
||||
|
||||
bool _keepAspectRatio = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the form should keep its aspect ratio.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Refreshes the window's size if set to true.
|
||||
/// </remarks>
|
||||
[Description("Enables fixed aspect ratio for this form."), Category("Appearance"), DefaultValue(true)]
|
||||
public bool KeepAspectRatio {
|
||||
get {
|
||||
return _keepAspectRatio;
|
||||
}
|
||||
set {
|
||||
_keepAspectRatio = value;
|
||||
|
||||
if (value)
|
||||
RefreshAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
double _aspectRatio = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the form's aspect ratio that will be kept automatically when resizing.
|
||||
/// </summary>
|
||||
[Description("Determines this form's fixed aspect ratio."), Category("Appearance"), DefaultValue(1.0)]
|
||||
public double AspectRatio {
|
||||
get {
|
||||
return _aspectRatio;
|
||||
}
|
||||
set {
|
||||
if (value <= 0.0 || Double.IsInfinity(value))
|
||||
return;
|
||||
|
||||
_aspectRatio = value;
|
||||
}
|
||||
}
|
||||
|
||||
Padding _extraPadding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets some additional internal padding of the form that is ignored when keeping the aspect ratio.
|
||||
/// </summary>
|
||||
[Description("Sets some padding inside the form's client area that is ignored when keeping the aspect ratio."),
|
||||
Category("Appearance")]
|
||||
public Padding ExtraPadding {
|
||||
get {
|
||||
return _extraPadding;
|
||||
}
|
||||
set {
|
||||
_extraPadding = value;
|
||||
|
||||
if(KeepAspectRatio)
|
||||
RefreshAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the form to update its height based on the current aspect ratio setting.
|
||||
/// </summary>
|
||||
public void RefreshAspectRatio() {
|
||||
int newWidth = ClientSize.Width;
|
||||
int newHeight = (int)((ClientSize.Width - ExtraPadding.Horizontal) / AspectRatio) + ExtraPadding.Vertical;
|
||||
|
||||
//Adapt height if it doesn't respect the form's minimum size
|
||||
Size clientMinimumSize = FromSizeToClientSize(MinimumSize);
|
||||
if (newHeight < clientMinimumSize.Height) {
|
||||
newHeight = clientMinimumSize.Height;
|
||||
newWidth = (int)((newHeight - ExtraPadding.Vertical) * AspectRatio) + ExtraPadding.Horizontal;
|
||||
}
|
||||
|
||||
//Adapt height if it exceeds the screen's height
|
||||
var workingArea = Screen.GetWorkingArea(this);
|
||||
if (newHeight >= workingArea.Height) {
|
||||
newHeight = workingArea.Height;
|
||||
newWidth = (int)((newHeight - ExtraPadding.Vertical) * AspectRatio) + ExtraPadding.Horizontal;
|
||||
}
|
||||
|
||||
//Update size
|
||||
ClientSize = new Size(newWidth, newHeight);
|
||||
|
||||
//Move form vertically to adapt to new size
|
||||
//REMOVED: allows the window to correctly be restored slightly off screen
|
||||
/*if (Location.Y + Size.Height > workingArea.Y + workingArea.Height) {
|
||||
int offsetY = (workingArea.Y + workingArea.Height) - (Location.Y + Size.Height);
|
||||
Location = new Point(Location.X, Location.Y - offsetY);
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the size of the form by a pixel increment while keeping its aspect ratio.
|
||||
/// </summary>
|
||||
/// <param name="pixelIncrement">Change of size in pixels.</param>
|
||||
public void AdjustSize(int pixelOffset) {
|
||||
Size origSize = Size;
|
||||
|
||||
//Resize to new width (clamped to max allowed size and minimum form size)
|
||||
int newWidth = Math.Max(Math.Min(origSize.Width + pixelOffset,
|
||||
SystemInformation.MaxWindowTrackSize.Width),
|
||||
MinimumSize.Width);
|
||||
|
||||
//Determine new height while keeping aspect ratio
|
||||
var clientConversionDifference = ClientWindowDifference;
|
||||
int newHeight = (int)((newWidth - ExtraPadding.Horizontal - clientConversionDifference.Width) / AspectRatio) + ExtraPadding.Vertical + clientConversionDifference.Height;
|
||||
|
||||
//Apply and move form to recenter
|
||||
Size = new Size(newWidth, newHeight);
|
||||
int deltaX = Size.Width - origSize.Width;
|
||||
int deltaY = Size.Height - origSize.Height;
|
||||
Location = new System.Drawing.Point(Location.X - (deltaX / 2), Location.Y - (deltaY / 2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the aspect ratio of the form and optionally forces a refresh.
|
||||
/// </summary>
|
||||
/// <param name="aspectRatioSource">Size from which aspect ratio should be computed.</param>
|
||||
/// <param name="forceRefresh">True if the size of the form should be refreshed to match the new aspect ratio.</param>
|
||||
public void SetAspectRatio(Size aspectRatioSource, bool forceRefresh) {
|
||||
AspectRatio = ((double)aspectRatioSource.Width / (double)aspectRatioSource.Height);
|
||||
_keepAspectRatio = true;
|
||||
|
||||
//Log.Write("Setting new aspect ratio {0} (for {1})", AspectRatio, aspectRatioSource);
|
||||
|
||||
if (forceRefresh) {
|
||||
RefreshAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
#region Event overriding
|
||||
|
||||
protected override void OnResizeEnd(EventArgs e) {
|
||||
base.OnResizeEnd(e);
|
||||
|
||||
//Ensure that the ClientSize of the form is always respected
|
||||
//(not ensured by the WM_SIZING message alone because of rounding errors and the chrome space)
|
||||
if (KeepAspectRatio) {
|
||||
var newHeight = ComputeHeightFromWidth(ClientSize.Width);
|
||||
ClientSize = new Size(ClientSize.Width, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnResizing(EventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override WM_SIZING message to restrict resizing.
|
||||
/// Taken from: http://www.vcskicks.com/maintain-aspect-ratio.php
|
||||
/// Improved with code from: http://stoyanoff.info/blog/2010/06/27/resizing-forms-while-keeping-aspect-ratio/
|
||||
/// </summary>
|
||||
protected override void WndProc(ref Message m) {
|
||||
if (m.Msg == WM.SIZING) {
|
||||
this.OnResizing(EventArgs.Empty);
|
||||
|
||||
if (KeepAspectRatio) {
|
||||
var clientSizeConversion = ClientWindowDifference;
|
||||
|
||||
var rc = (Native.NRectangle)Marshal.PtrToStructure(m.LParam, typeof(Native.NRectangle));
|
||||
int res = m.WParam.ToInt32();
|
||||
|
||||
int width = (rc.Right - rc.Left) - clientSizeConversion.Width - ExtraPadding.Horizontal;
|
||||
int height = (rc.Bottom - rc.Top) - clientSizeConversion.Height - ExtraPadding.Vertical;
|
||||
|
||||
if (res == WMSZ.LEFT || res == WMSZ.RIGHT) {
|
||||
//Left or right resize, adjust top and bottom
|
||||
int targetHeight = (int)(width / AspectRatio);
|
||||
int diffHeight = height - targetHeight;
|
||||
|
||||
rc.Top += (int)(diffHeight / 2.0);
|
||||
rc.Bottom = rc.Top + targetHeight + ExtraPadding.Vertical + clientSizeConversion.Height;
|
||||
}
|
||||
else if (res == WMSZ.TOP || res == WMSZ.BOTTOM) {
|
||||
//Up or down resize, adjust left and right
|
||||
int targetWidth = (int)(height * AspectRatio);
|
||||
int diffWidth = width - targetWidth;
|
||||
|
||||
rc.Left += (int)(diffWidth / 2.0);
|
||||
rc.Right = rc.Left + targetWidth + ExtraPadding.Horizontal + clientSizeConversion.Width;
|
||||
}
|
||||
else if (res == WMSZ.RIGHT + WMSZ.BOTTOM || res == WMSZ.LEFT + WMSZ.BOTTOM) {
|
||||
//Lower corner resize, adjust bottom
|
||||
rc.Bottom = rc.Top + (int)(width / AspectRatio) + ExtraPadding.Vertical + clientSizeConversion.Height;
|
||||
}
|
||||
else if (res == WMSZ.LEFT + WMSZ.TOP || res == WMSZ.RIGHT + WMSZ.TOP) {
|
||||
//Upper corner resize, adjust top
|
||||
rc.Top = rc.Bottom - (int)(width / AspectRatio) - ExtraPadding.Vertical - clientSizeConversion.Height;
|
||||
}
|
||||
|
||||
Marshal.StructureToPtr(rc, m.LParam, false);
|
||||
}
|
||||
}
|
||||
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conversion helpers
|
||||
|
||||
/// <summary>
|
||||
/// Converts a client size measurement to a window size measurement.
|
||||
/// </summary>
|
||||
/// <param name="clientSize">Size of the window's client area.</param>
|
||||
/// <returns>Size of the whole window.</returns>
|
||||
public Size FromClientSizeToSize(Size clientSize) {
|
||||
var difference = ClientWindowDifference;
|
||||
|
||||
return new Size(clientSize.Width + difference.Width, clientSize.Height + difference.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a window size measurement to a client size measurement.
|
||||
/// </summary>
|
||||
/// <param name="size">Size of the whole window.</param>
|
||||
/// <returns>Size of the window's client area.</returns>
|
||||
public Size FromSizeToClientSize(Size size) {
|
||||
var difference = ClientWindowDifference;
|
||||
|
||||
return new Size(size.Width - difference.Width, size.Height - difference.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes height from width value, according to aspect ratio of window.
|
||||
/// </summary>
|
||||
public int ComputeHeightFromWidth(int width) {
|
||||
return (int)Math.Round(((width - ExtraPadding.Horizontal) / AspectRatio) + ExtraPadding.Vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes width from height value, according to aspect ratio of window.
|
||||
/// </summary>
|
||||
public int ComputeWidthFromHeight(int height) {
|
||||
return (int)Math.Round(((height - ExtraPadding.Vertical) * AspectRatio) + ExtraPadding.Horizontal);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the difference in pixels between a client size value and a window size value (depending on window decoration).
|
||||
/// </summary>
|
||||
protected Size ClientWindowDifference {
|
||||
get {
|
||||
long style = WindowMethods.GetWindowLong(this.Handle, WindowMethods.WindowLong.Style).ToInt64();
|
||||
long exStyle = WindowMethods.GetWindowLong(this.Handle, WindowMethods.WindowLong.ExStyle).ToInt64();
|
||||
return WindowMethods.ConvertClientToWindowRect(new NRectangle(0, 0, 0, 0), style, exStyle).Size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 639 B |
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 209 B After Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 951 B After Width: | Height: | Size: 951 B |
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 731 B |
Before Width: | Height: | Size: 794 B After Width: | Height: | Size: 794 B |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 241 B After Width: | Height: | Size: 241 B |
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 347 B |
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 209 B After Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 300 B After Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 396 B |
Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 837 B |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 681 B After Width: | Height: | Size: 681 B |
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 770 B |
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 231 B After Width: | Height: | Size: 231 B |
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 280 B |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 259 B After Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 862 B |
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 683 B |
Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 894 B |
Before Width: | Height: | Size: 1,012 B After Width: | Height: | Size: 1,012 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 894 B |
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 810 B |
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 456 B |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 753 B After Width: | Height: | Size: 753 B |
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 437 B |
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 715 B |
Before Width: | Height: | Size: 761 B After Width: | Height: | Size: 761 B |
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 459 B |
|
@ -1,17 +1,17 @@
|
|||
OnTopReplica credits
|
||||
--------------------
|
||||
|
||||
This application was inspired by Switcher (http://insentient.net) and other
|
||||
DWM based application.
|
||||
|
||||
All Aero controls are part of the open-source WindowsFormsAero
|
||||
(http://windowsformsaero.codeplex.com) library for .NET.
|
||||
|
||||
Some DWM example code has ben taken from user Ookii (http://www.ookii.org) on
|
||||
Channel 9 MSDN.
|
||||
|
||||
The NativeToolstripRenderer class has been taken from asztal.net
|
||||
(http://wp.asztal.net/2007/12/vista-style-menus-in-dotnet).
|
||||
|
||||
Some of the icons used by OnTopReplica have been taken from VistaICO.com and
|
||||
the Xiao icon set.
|
||||
OnTopReplica credits
|
||||
--------------------
|
||||
|
||||
This application was inspired by Switcher (http://insentient.net) and other
|
||||
DWM based application.
|
||||
|
||||
All Aero controls are part of the open-source WindowsFormsAero
|
||||
(http://windowsformsaero.codeplex.com) library for .NET.
|
||||
|
||||
Some DWM example code has ben taken from user Ookii (http://www.ookii.org) on
|
||||
Channel 9 MSDN.
|
||||
|
||||
The NativeToolstripRenderer class has been taken from asztal.net
|
||||
(http://wp.asztal.net/2007/12/vista-style-menus-in-dotnet).
|
||||
|
||||
Some of the icons used by OnTopReplica have been taken from VistaICO.com and
|
||||
the Xiao icon set.
|
|
@ -1,32 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
/// <summary>
|
||||
/// EventArgs structure for clicks on a cloned window.
|
||||
/// </summary>
|
||||
public class CloneClickEventArgs : EventArgs {
|
||||
|
||||
public Point ClientClickLocation { get; set; }
|
||||
|
||||
public bool IsDoubleClick { get; set; }
|
||||
|
||||
public MouseButtons Buttons { get; set; }
|
||||
|
||||
public CloneClickEventArgs(Point location, MouseButtons buttons) {
|
||||
ClientClickLocation = location;
|
||||
Buttons = buttons;
|
||||
IsDoubleClick = false;
|
||||
}
|
||||
|
||||
public CloneClickEventArgs(Point location, MouseButtons buttons, bool doubleClick) {
|
||||
ClientClickLocation = location;
|
||||
Buttons = buttons;
|
||||
IsDoubleClick = doubleClick;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
/// <summary>
|
||||
/// EventArgs structure for clicks on a cloned window.
|
||||
/// </summary>
|
||||
public class CloneClickEventArgs : EventArgs {
|
||||
|
||||
public Point ClientClickLocation { get; set; }
|
||||
|
||||
public bool IsDoubleClick { get; set; }
|
||||
|
||||
public MouseButtons Buttons { get; set; }
|
||||
|
||||
public CloneClickEventArgs(Point location, MouseButtons buttons) {
|
||||
ClientClickLocation = location;
|
||||
Buttons = buttons;
|
||||
IsDoubleClick = false;
|
||||
}
|
||||
|
||||
public CloneClickEventArgs(Point location, MouseButtons buttons, bool doubleClick) {
|
||||
ClientClickLocation = location;
|
||||
Buttons = buttons;
|
||||
IsDoubleClick = doubleClick;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OnTopReplica {
|
||||
public class CloseRequestEventArgs : EventArgs {
|
||||
|
||||
public WindowHandle LastWindowHandle { get; set; }
|
||||
|
||||
public Rectangle? LastRegion { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OnTopReplica {
|
||||
public class CloseRequestEventArgs : EventArgs {
|
||||
|
||||
public WindowHandle LastWindowHandle { get; set; }
|
||||
|
||||
public Rectangle? LastRegion { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,68 +1,68 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using WindowsFormsAero;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
class FocusedTextBox : System.Windows.Forms.TextBox {
|
||||
|
||||
protected override bool IsInputChar(char charCode) {
|
||||
if (charCode == '\n' || charCode == '\r')
|
||||
return true;
|
||||
|
||||
return base.IsInputChar(charCode);
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e) {
|
||||
if (e.KeyCode == Keys.Return) {
|
||||
if(!string.IsNullOrEmpty(Text))
|
||||
OnConfirmInput();
|
||||
|
||||
e.Handled = true;
|
||||
e.SuppressKeyPress = true;
|
||||
}
|
||||
else if (e.KeyCode == Keys.Escape) {
|
||||
OnAbortInput();
|
||||
|
||||
e.Handled = true;
|
||||
e.SuppressKeyPress = true;
|
||||
}
|
||||
|
||||
base.OnKeyUp(e);
|
||||
}
|
||||
|
||||
//List of characters to ignore on KeyPress events (because they generate bell rings)
|
||||
readonly char[] IgnoreChars = new char[] {
|
||||
(char)27, (char)13
|
||||
};
|
||||
|
||||
protected override void OnKeyPress(KeyPressEventArgs e) {
|
||||
if (IgnoreChars.Contains(e.KeyChar)) {
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
base.OnKeyPress(e);
|
||||
}
|
||||
|
||||
public event EventHandler ConfirmInput;
|
||||
|
||||
protected virtual void OnConfirmInput() {
|
||||
var evt = ConfirmInput;
|
||||
if (evt != null)
|
||||
evt(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public event EventHandler AbortInput;
|
||||
|
||||
protected virtual void OnAbortInput() {
|
||||
var evt = AbortInput;
|
||||
if (evt != null)
|
||||
evt(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using WindowsFormsAero;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
class FocusedTextBox : System.Windows.Forms.TextBox {
|
||||
|
||||
protected override bool IsInputChar(char charCode) {
|
||||
if (charCode == '\n' || charCode == '\r')
|
||||
return true;
|
||||
|
||||
return base.IsInputChar(charCode);
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e) {
|
||||
if (e.KeyCode == Keys.Return) {
|
||||
if(!string.IsNullOrEmpty(Text))
|
||||
OnConfirmInput();
|
||||
|
||||
e.Handled = true;
|
||||
e.SuppressKeyPress = true;
|
||||
}
|
||||
else if (e.KeyCode == Keys.Escape) {
|
||||
OnAbortInput();
|
||||
|
||||
e.Handled = true;
|
||||
e.SuppressKeyPress = true;
|
||||
}
|
||||
|
||||
base.OnKeyUp(e);
|
||||
}
|
||||
|
||||
//List of characters to ignore on KeyPress events (because they generate bell rings)
|
||||
readonly char[] IgnoreChars = new char[] {
|
||||
(char)27, (char)13
|
||||
};
|
||||
|
||||
protected override void OnKeyPress(KeyPressEventArgs e) {
|
||||
if (IgnoreChars.Contains(e.KeyChar)) {
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
base.OnKeyPress(e);
|
||||
}
|
||||
|
||||
public event EventHandler ConfirmInput;
|
||||
|
||||
protected virtual void OnConfirmInput() {
|
||||
var evt = ConfirmInput;
|
||||
if (evt != null)
|
||||
evt(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public event EventHandler AbortInput;
|
||||
|
||||
protected virtual void OnAbortInput() {
|
||||
var evt = AbortInput;
|
||||
if (evt != null)
|
||||
evt(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +1,116 @@
|
|||
using OnTopReplica.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class FullscreenFormManager {
|
||||
|
||||
private readonly MainForm _mainForm;
|
||||
|
||||
public FullscreenFormManager(MainForm form) {
|
||||
_mainForm = form;
|
||||
IsFullscreen = false;
|
||||
}
|
||||
|
||||
Point _preFullscreenLocation;
|
||||
Size _preFullscreenSize;
|
||||
FormBorderStyle _preFullscreenBorderStyle;
|
||||
|
||||
public bool IsFullscreen {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public void SwitchFullscreen() {
|
||||
SwitchFullscreen(Settings.Default.GetFullscreenMode());
|
||||
}
|
||||
|
||||
public void SwitchFullscreen(FullscreenMode mode) {
|
||||
if (IsFullscreen) {
|
||||
MoveToFullscreenMode(mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_mainForm.ThumbnailPanel.IsShowingThumbnail)
|
||||
return;
|
||||
|
||||
//On switch, always hide side panels
|
||||
_mainForm.CloseSidePanel();
|
||||
|
||||
//Store state
|
||||
_preFullscreenLocation = _mainForm.Location;
|
||||
_preFullscreenSize = _mainForm.ClientSize;
|
||||
_preFullscreenBorderStyle = _mainForm.FormBorderStyle;
|
||||
|
||||
//Change state to fullscreen
|
||||
_mainForm.FormBorderStyle = FormBorderStyle.None;
|
||||
MoveToFullscreenMode(mode);
|
||||
|
||||
CommonCompleteSwitch(true);
|
||||
}
|
||||
|
||||
private void MoveToFullscreenMode(FullscreenMode mode) {
|
||||
var screens = Screen.AllScreens;
|
||||
|
||||
var currentScreen = Screen.FromControl(_mainForm);
|
||||
Size size = _mainForm.Size;
|
||||
Point location = _mainForm.Location;
|
||||
|
||||
switch (mode) {
|
||||
case FullscreenMode.Standard:
|
||||
default:
|
||||
size = currentScreen.WorkingArea.Size;
|
||||
location = currentScreen.WorkingArea.Location;
|
||||
break;
|
||||
|
||||
case FullscreenMode.Fullscreen:
|
||||
size = currentScreen.Bounds.Size;
|
||||
location = currentScreen.Bounds.Location;
|
||||
break;
|
||||
|
||||
case FullscreenMode.AllScreens:
|
||||
size = SystemInformation.VirtualScreen.Size;
|
||||
location = SystemInformation.VirtualScreen.Location;
|
||||
break;
|
||||
}
|
||||
|
||||
_mainForm.Size = size;
|
||||
_mainForm.Location = location;
|
||||
}
|
||||
|
||||
public void SwitchBack() {
|
||||
if (!IsFullscreen)
|
||||
return;
|
||||
|
||||
//Restore state
|
||||
_mainForm.FormBorderStyle = _preFullscreenBorderStyle;
|
||||
_mainForm.Location = _preFullscreenLocation;
|
||||
_mainForm.ClientSize = _preFullscreenSize;
|
||||
_mainForm.RefreshAspectRatio();
|
||||
|
||||
CommonCompleteSwitch(false);
|
||||
}
|
||||
|
||||
private void CommonCompleteSwitch(bool enabled) {
|
||||
//UI stuff switching
|
||||
_mainForm.GlassMargins = (!enabled) ? new Padding(-1) : Padding.Empty;
|
||||
_mainForm.TopMost = !enabled;
|
||||
|
||||
IsFullscreen = enabled;
|
||||
|
||||
Program.Platform.OnFormStateChange(_mainForm);
|
||||
}
|
||||
|
||||
public void Toggle() {
|
||||
if (IsFullscreen)
|
||||
SwitchBack();
|
||||
else
|
||||
SwitchFullscreen(Settings.Default.GetFullscreenMode());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using OnTopReplica.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class FullscreenFormManager {
|
||||
|
||||
private readonly MainForm _mainForm;
|
||||
|
||||
public FullscreenFormManager(MainForm form) {
|
||||
_mainForm = form;
|
||||
IsFullscreen = false;
|
||||
}
|
||||
|
||||
Point _preFullscreenLocation;
|
||||
Size _preFullscreenSize;
|
||||
FormBorderStyle _preFullscreenBorderStyle;
|
||||
|
||||
public bool IsFullscreen {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public void SwitchFullscreen() {
|
||||
SwitchFullscreen(Settings.Default.GetFullscreenMode());
|
||||
}
|
||||
|
||||
public void SwitchFullscreen(FullscreenMode mode) {
|
||||
if (IsFullscreen) {
|
||||
MoveToFullscreenMode(mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_mainForm.ThumbnailPanel.IsShowingThumbnail)
|
||||
return;
|
||||
|
||||
//On switch, always hide side panels
|
||||
_mainForm.CloseSidePanel();
|
||||
|
||||
//Store state
|
||||
_preFullscreenLocation = _mainForm.Location;
|
||||
_preFullscreenSize = _mainForm.ClientSize;
|
||||
_preFullscreenBorderStyle = _mainForm.FormBorderStyle;
|
||||
|
||||
//Change state to fullscreen
|
||||
_mainForm.FormBorderStyle = FormBorderStyle.None;
|
||||
MoveToFullscreenMode(mode);
|
||||
|
||||
CommonCompleteSwitch(true);
|
||||
}
|
||||
|
||||
private void MoveToFullscreenMode(FullscreenMode mode) {
|
||||
var screens = Screen.AllScreens;
|
||||
|
||||
var currentScreen = Screen.FromControl(_mainForm);
|
||||
Size size = _mainForm.Size;
|
||||
Point location = _mainForm.Location;
|
||||
|
||||
switch (mode) {
|
||||
case FullscreenMode.Standard:
|
||||
default:
|
||||
size = currentScreen.WorkingArea.Size;
|
||||
location = currentScreen.WorkingArea.Location;
|
||||
break;
|
||||
|
||||
case FullscreenMode.Fullscreen:
|
||||
size = currentScreen.Bounds.Size;
|
||||
location = currentScreen.Bounds.Location;
|
||||
break;
|
||||
|
||||
case FullscreenMode.AllScreens:
|
||||
size = SystemInformation.VirtualScreen.Size;
|
||||
location = SystemInformation.VirtualScreen.Location;
|
||||
break;
|
||||
}
|
||||
|
||||
_mainForm.Size = size;
|
||||
_mainForm.Location = location;
|
||||
}
|
||||
|
||||
public void SwitchBack() {
|
||||
if (!IsFullscreen)
|
||||
return;
|
||||
|
||||
//Restore state
|
||||
_mainForm.FormBorderStyle = _preFullscreenBorderStyle;
|
||||
_mainForm.Location = _preFullscreenLocation;
|
||||
_mainForm.ClientSize = _preFullscreenSize;
|
||||
_mainForm.RefreshAspectRatio();
|
||||
|
||||
CommonCompleteSwitch(false);
|
||||
}
|
||||
|
||||
private void CommonCompleteSwitch(bool enabled) {
|
||||
//UI stuff switching
|
||||
_mainForm.GlassMargins = (!enabled) ? new Padding(-1) : Padding.Empty;
|
||||
_mainForm.TopMost = !enabled;
|
||||
|
||||
IsFullscreen = enabled;
|
||||
|
||||
Program.Platform.OnFormStateChange(_mainForm);
|
||||
}
|
||||
|
||||
public void Toggle() {
|
||||
if (IsFullscreen)
|
||||
SwitchBack();
|
||||
else
|
||||
SwitchFullscreen(Settings.Default.GetFullscreenMode());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,39 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using OnTopReplica.Properties;
|
||||
|
||||
namespace OnTopReplica {
|
||||
/// <summary>
|
||||
/// Describes a fullscreen mode.
|
||||
/// </summary>
|
||||
enum FullscreenMode {
|
||||
Standard,
|
||||
Fullscreen,
|
||||
AllScreens
|
||||
}
|
||||
|
||||
static class FullscreenModeExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Gets the fullscreen mode as an enumeration value.
|
||||
/// </summary>
|
||||
public static FullscreenMode GetFullscreenMode(this Settings settings) {
|
||||
FullscreenMode retMode = FullscreenMode.Standard;
|
||||
|
||||
Enum.TryParse<FullscreenMode>(settings.FullscreenMode, out retMode);
|
||||
|
||||
return retMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the fullscreen mode.
|
||||
/// </summary>
|
||||
public static void SetFullscreenMode(this Settings settings, FullscreenMode mode) {
|
||||
settings.FullscreenMode = mode.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using OnTopReplica.Properties;
|
||||
|
||||
namespace OnTopReplica {
|
||||
/// <summary>
|
||||
/// Describes a fullscreen mode.
|
||||
/// </summary>
|
||||
enum FullscreenMode {
|
||||
Standard,
|
||||
Fullscreen,
|
||||
AllScreens
|
||||
}
|
||||
|
||||
static class FullscreenModeExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Gets the fullscreen mode as an enumeration value.
|
||||
/// </summary>
|
||||
public static FullscreenMode GetFullscreenMode(this Settings settings) {
|
||||
FullscreenMode retMode = FullscreenMode.Standard;
|
||||
|
||||
Enum.TryParse<FullscreenMode>(settings.FullscreenMode, out retMode);
|
||||
|
||||
return retMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the fullscreen mode.
|
||||
/// </summary>
|
||||
public static void SetFullscreenMode(this Settings settings, FullscreenMode mode) {
|
||||
settings.FullscreenMode = mode.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,74 +1,74 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
/// <summary>
|
||||
/// Common geometry extension methods.
|
||||
/// </summary>
|
||||
static class GeometryExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Returns the difference (offset vector) between two points.
|
||||
/// </summary>
|
||||
public static Point Difference(this Point a, Point b) {
|
||||
return new Point(a.X - b.X, a.Y - b.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands a size value by a padding distance.
|
||||
/// </summary>
|
||||
public static Size Expand(this Size size, Padding padding) {
|
||||
return new Size(size.Width + padding.Horizontal, size.Height + padding.Vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands a size value by a size distance.
|
||||
/// </summary>
|
||||
public static Size Expand(this Size size, Size expandSize) {
|
||||
return new Size(size.Width + expandSize.Width, size.Height + expandSize.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the difference between two size values.
|
||||
/// </summary>
|
||||
public static Size Difference(this Size a, Size b) {
|
||||
return new Size(a.Width - b.Width, a.Height - b.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the minimum size of a control respects a minimum
|
||||
/// client size area.
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Control whose MinimumSize should be altered.</param>
|
||||
/// <param name="minimumClientSize">Minimum client size value to ensure.</param>
|
||||
public static void EnsureMinimumClientSize(this Control ctrl, Size minimumClientSize) {
|
||||
Size offset = ctrl.Size.Difference(ctrl.ClientSize);
|
||||
ctrl.MinimumSize = minimumClientSize.Expand(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to fit a size structure to another fixed destination size, by maintaining
|
||||
/// the original aspect ratio.
|
||||
/// </summary>
|
||||
public static Size Fit(this Size sourceSize, Size destinationSize) {
|
||||
double sourceRatio = (double)sourceSize.Width / (double)sourceSize.Height;
|
||||
double clientRatio = (double)destinationSize.Width / (double)destinationSize.Height;
|
||||
|
||||
Size ret;
|
||||
if (sourceRatio >= clientRatio) {
|
||||
ret = new Size(destinationSize.Width, (int)((double)destinationSize.Width / sourceRatio));
|
||||
}
|
||||
else {
|
||||
ret = new Size((int)((double)destinationSize.Height * sourceRatio), destinationSize.Height);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
/// <summary>
|
||||
/// Common geometry extension methods.
|
||||
/// </summary>
|
||||
static class GeometryExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Returns the difference (offset vector) between two points.
|
||||
/// </summary>
|
||||
public static Point Difference(this Point a, Point b) {
|
||||
return new Point(a.X - b.X, a.Y - b.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands a size value by a padding distance.
|
||||
/// </summary>
|
||||
public static Size Expand(this Size size, Padding padding) {
|
||||
return new Size(size.Width + padding.Horizontal, size.Height + padding.Vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands a size value by a size distance.
|
||||
/// </summary>
|
||||
public static Size Expand(this Size size, Size expandSize) {
|
||||
return new Size(size.Width + expandSize.Width, size.Height + expandSize.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the difference between two size values.
|
||||
/// </summary>
|
||||
public static Size Difference(this Size a, Size b) {
|
||||
return new Size(a.Width - b.Width, a.Height - b.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the minimum size of a control respects a minimum
|
||||
/// client size area.
|
||||
/// </summary>
|
||||
/// <param name="ctrl">Control whose MinimumSize should be altered.</param>
|
||||
/// <param name="minimumClientSize">Minimum client size value to ensure.</param>
|
||||
public static void EnsureMinimumClientSize(this Control ctrl, Size minimumClientSize) {
|
||||
Size offset = ctrl.Size.Difference(ctrl.ClientSize);
|
||||
ctrl.MinimumSize = minimumClientSize.Expand(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to fit a size structure to another fixed destination size, by maintaining
|
||||
/// the original aspect ratio.
|
||||
/// </summary>
|
||||
public static Size Fit(this Size sourceSize, Size destinationSize) {
|
||||
double sourceRatio = (double)sourceSize.Width / (double)sourceSize.Height;
|
||||
double clientRatio = (double)destinationSize.Width / (double)destinationSize.Height;
|
||||
|
||||
Size ret;
|
||||
if (sourceRatio >= clientRatio) {
|
||||
ret = new Size(destinationSize.Width, (int)((double)destinationSize.Width / sourceRatio));
|
||||
}
|
||||
else {
|
||||
ret = new Size((int)((double)destinationSize.Height * sourceRatio), destinationSize.Height);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,56 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
class HotKeyTextBox : TextBox {
|
||||
|
||||
protected override void OnCreateControl() {
|
||||
ReadOnly = true;
|
||||
|
||||
base.OnCreateControl();
|
||||
}
|
||||
|
||||
readonly Keys[] IgnoredKeys = new Keys[] {
|
||||
Keys.ControlKey,
|
||||
Keys.Control,
|
||||
Keys.Alt,
|
||||
Keys.Menu,
|
||||
Keys.ShiftKey,
|
||||
Keys.Shift,
|
||||
Keys.LWin,
|
||||
Keys.RWin
|
||||
};
|
||||
|
||||
readonly Keys[] CancelKeys = new Keys[] {
|
||||
Keys.Back,
|
||||
Keys.Escape
|
||||
};
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e) {
|
||||
if (CancelKeys.Contains(e.KeyCode)) {
|
||||
Text = string.Empty;
|
||||
}
|
||||
else if (!IgnoredKeys.Contains(e.KeyCode)) {
|
||||
var sb = new StringBuilder();
|
||||
if (e.Control)
|
||||
sb.Append("[CTRL]+");
|
||||
if (e.Alt)
|
||||
sb.Append("[ALT]+");
|
||||
if (e.Shift)
|
||||
sb.Append("[SHIFT]+");
|
||||
sb.Append(e.KeyCode.ToString());
|
||||
|
||||
Text = sb.ToString();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
base.OnKeyUp(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
class HotKeyTextBox : TextBox {
|
||||
|
||||
protected override void OnCreateControl() {
|
||||
ReadOnly = true;
|
||||
|
||||
base.OnCreateControl();
|
||||
}
|
||||
|
||||
readonly Keys[] IgnoredKeys = new Keys[] {
|
||||
Keys.ControlKey,
|
||||
Keys.Control,
|
||||
Keys.Alt,
|
||||
Keys.Menu,
|
||||
Keys.ShiftKey,
|
||||
Keys.Shift,
|
||||
Keys.LWin,
|
||||
Keys.RWin
|
||||
};
|
||||
|
||||
readonly Keys[] CancelKeys = new Keys[] {
|
||||
Keys.Back,
|
||||
Keys.Escape
|
||||
};
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e) {
|
||||
if (CancelKeys.Contains(e.KeyCode)) {
|
||||
Text = string.Empty;
|
||||
}
|
||||
else if (!IgnoredKeys.Contains(e.KeyCode)) {
|
||||
var sb = new StringBuilder();
|
||||
if (e.Control)
|
||||
sb.Append("[CTRL]+");
|
||||
if (e.Alt)
|
||||
sb.Append("[ALT]+");
|
||||
if (e.Shift)
|
||||
sb.Append("[SHIFT]+");
|
||||
sb.Append(e.KeyCode.ToString());
|
||||
|
||||
Text = sb.ToString();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
base.OnKeyUp(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
interface IMessagePumpProcessor : IDisposable {
|
||||
|
||||
void Initialize(MainForm form);
|
||||
|
||||
bool Process(ref Message msg);
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
interface IMessagePumpProcessor : IDisposable {
|
||||
|
||||
void Initialize(MainForm form);
|
||||
|
||||
bool Process(ref Message msg);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,77 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class ImageComboBox : ComboBox {
|
||||
|
||||
public ImageComboBox() {
|
||||
DrawMode = DrawMode.OwnerDrawFixed;
|
||||
}
|
||||
|
||||
protected override void OnDrawItem(DrawItemEventArgs ea) {
|
||||
ea.DrawBackground();
|
||||
ea.DrawFocusRectangle();
|
||||
|
||||
if (ea.Index == -1)
|
||||
return;
|
||||
|
||||
Rectangle bounds = ea.Bounds;
|
||||
var foreBrush = new SolidBrush(ea.ForeColor);
|
||||
int textLeftBound = (IconList == null) ? bounds.Left : bounds.Left + IconList.ImageSize.Width;
|
||||
|
||||
var drawObject = Items[ea.Index];
|
||||
if (drawObject is ImageComboBoxItem) {
|
||||
var drawItem = (ImageComboBoxItem)drawObject;
|
||||
|
||||
if (drawItem.ImageListIndex != -1 && IconList != null) {
|
||||
//ea.Graphics.FillRectangle(Brushes.Gray, bounds.Left, bounds.Top, IconList.ImageSize.Width, IconList.ImageSize.Height);
|
||||
ea.Graphics.DrawImage(IconList.Images[drawItem.ImageListIndex], bounds.Left, bounds.Top);
|
||||
}
|
||||
|
||||
ea.Graphics.DrawString(drawItem.Text, ea.Font, foreBrush, textLeftBound, bounds.Top);
|
||||
}
|
||||
else {
|
||||
ea.Graphics.DrawString(drawObject.ToString(), ea.Font, foreBrush, textLeftBound, bounds.Top);
|
||||
}
|
||||
|
||||
base.OnDrawItem(ea);
|
||||
}
|
||||
|
||||
public ImageList IconList { get; set; }
|
||||
|
||||
}
|
||||
|
||||
class ImageComboBoxItem {
|
||||
|
||||
public ImageComboBoxItem() {
|
||||
Text = "";
|
||||
ImageListIndex = -1;
|
||||
}
|
||||
|
||||
public ImageComboBoxItem(string text) {
|
||||
if (text == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
Text = text;
|
||||
ImageListIndex = -1;
|
||||
}
|
||||
|
||||
public ImageComboBoxItem(string text, int imageListIndex) {
|
||||
if (text == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
Text = text;
|
||||
ImageListIndex = imageListIndex;
|
||||
}
|
||||
|
||||
public string Text { get; private set; }
|
||||
|
||||
public int ImageListIndex { get; private set; }
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class ImageComboBox : ComboBox {
|
||||
|
||||
public ImageComboBox() {
|
||||
DrawMode = DrawMode.OwnerDrawFixed;
|
||||
}
|
||||
|
||||
protected override void OnDrawItem(DrawItemEventArgs ea) {
|
||||
ea.DrawBackground();
|
||||
ea.DrawFocusRectangle();
|
||||
|
||||
if (ea.Index == -1)
|
||||
return;
|
||||
|
||||
Rectangle bounds = ea.Bounds;
|
||||
var foreBrush = new SolidBrush(ea.ForeColor);
|
||||
int textLeftBound = (IconList == null) ? bounds.Left : bounds.Left + IconList.ImageSize.Width;
|
||||
|
||||
var drawObject = Items[ea.Index];
|
||||
if (drawObject is ImageComboBoxItem) {
|
||||
var drawItem = (ImageComboBoxItem)drawObject;
|
||||
|
||||
if (drawItem.ImageListIndex != -1 && IconList != null) {
|
||||
//ea.Graphics.FillRectangle(Brushes.Gray, bounds.Left, bounds.Top, IconList.ImageSize.Width, IconList.ImageSize.Height);
|
||||
ea.Graphics.DrawImage(IconList.Images[drawItem.ImageListIndex], bounds.Left, bounds.Top);
|
||||
}
|
||||
|
||||
ea.Graphics.DrawString(drawItem.Text, ea.Font, foreBrush, textLeftBound, bounds.Top);
|
||||
}
|
||||
else {
|
||||
ea.Graphics.DrawString(drawObject.ToString(), ea.Font, foreBrush, textLeftBound, bounds.Top);
|
||||
}
|
||||
|
||||
base.OnDrawItem(ea);
|
||||
}
|
||||
|
||||
public ImageList IconList { get; set; }
|
||||
|
||||
}
|
||||
|
||||
class ImageComboBoxItem {
|
||||
|
||||
public ImageComboBoxItem() {
|
||||
Text = "";
|
||||
ImageListIndex = -1;
|
||||
}
|
||||
|
||||
public ImageComboBoxItem(string text) {
|
||||
if (text == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
Text = text;
|
||||
ImageListIndex = -1;
|
||||
}
|
||||
|
||||
public ImageComboBoxItem(string text, int imageListIndex) {
|
||||
if (text == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
Text = text;
|
||||
ImageListIndex = imageListIndex;
|
||||
}
|
||||
|
||||
public string Text { get; private set; }
|
||||
|
||||
public int ImageListIndex { get; private set; }
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,54 +1,54 @@
|
|||
Microsoft Reciprocal License (Ms-RL)
|
||||
|
||||
This license governs use of the accompanying software. If you use the
|
||||
software, you accept this license. If you do not accept the license, do not
|
||||
use the software.
|
||||
|
||||
1. Definitions
|
||||
The terms "reproduce," "reproduction," "derivative works," and "distribution"
|
||||
have the same meaning here as under U.S. copyright law.
|
||||
A "contribution" is the original software, or any additions or changes to the
|
||||
software.
|
||||
A "contributor" is any person that distributes its contribution under this
|
||||
license.
|
||||
"Licensed patents" are a contributor's patent claims that read directly on its
|
||||
contribution.
|
||||
|
||||
2. Grant of Rights
|
||||
(A) Copyright Grant- Subject to the terms of this license, including the
|
||||
license conditions and limitations in section 3, each contributor grants you a
|
||||
non-exclusive, worldwide, royalty-free copyright license to reproduce its
|
||||
contribution, prepare derivative works of its contribution, and distribute its
|
||||
contribution or any derivative works that you create.
|
||||
(B) Patent Grant- Subject to the terms of this license, including the license
|
||||
conditions and limitations in section 3, each contributor grants you a
|
||||
non-exclusive, worldwide, royalty-free license under its licensed patents to
|
||||
make, have made, use, sell, offer for sale, import, and/or otherwise dispose
|
||||
of its contribution in the software or derivative works of the contribution
|
||||
in the software.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) Reciprocal Grants- For any file you distribute that contains code from the
|
||||
software (in source code or binary format), you must provide recipients the
|
||||
source code to that file along with a copy of this license, which license will
|
||||
govern that file. You may license other files that are entirely your own work
|
||||
and do not contain code from the software under any terms you choose.
|
||||
(B) No Trademark License- This license does not grant you rights to use any
|
||||
contributors' name, logo, or trademarks.
|
||||
(C) If you bring a patent claim against any contributor over patents that you
|
||||
claim are infringed by the software, your patent license from such contributor
|
||||
to the software ends automatically.
|
||||
(D) If you distribute any portion of the software, you must retain all
|
||||
copyright, patent, trademark, and attribution notices that are present in the
|
||||
software.
|
||||
(E) If you distribute any portion of the software in source code form, you may
|
||||
do so only under this license by including a complete copy of this license
|
||||
with your distribution. If you distribute any portion of the software in
|
||||
compiled or object code form, you may only do so under a license that complies
|
||||
with this license.
|
||||
(F) The software is licensed "as-is." You bear the risk of using it. The
|
||||
contributors give no express warranties, guarantees or conditions. You may
|
||||
have additional consumer rights under your local laws which this license
|
||||
cannot change. To the extent permitted under your local laws, the contributors
|
||||
exclude the implied warranties of merchantability, fitness for a particular
|
||||
purpose and non-infringement.
|
||||
Microsoft Reciprocal License (Ms-RL)
|
||||
|
||||
This license governs use of the accompanying software. If you use the
|
||||
software, you accept this license. If you do not accept the license, do not
|
||||
use the software.
|
||||
|
||||
1. Definitions
|
||||
The terms "reproduce," "reproduction," "derivative works," and "distribution"
|
||||
have the same meaning here as under U.S. copyright law.
|
||||
A "contribution" is the original software, or any additions or changes to the
|
||||
software.
|
||||
A "contributor" is any person that distributes its contribution under this
|
||||
license.
|
||||
"Licensed patents" are a contributor's patent claims that read directly on its
|
||||
contribution.
|
||||
|
||||
2. Grant of Rights
|
||||
(A) Copyright Grant- Subject to the terms of this license, including the
|
||||
license conditions and limitations in section 3, each contributor grants you a
|
||||
non-exclusive, worldwide, royalty-free copyright license to reproduce its
|
||||
contribution, prepare derivative works of its contribution, and distribute its
|
||||
contribution or any derivative works that you create.
|
||||
(B) Patent Grant- Subject to the terms of this license, including the license
|
||||
conditions and limitations in section 3, each contributor grants you a
|
||||
non-exclusive, worldwide, royalty-free license under its licensed patents to
|
||||
make, have made, use, sell, offer for sale, import, and/or otherwise dispose
|
||||
of its contribution in the software or derivative works of the contribution
|
||||
in the software.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) Reciprocal Grants- For any file you distribute that contains code from the
|
||||
software (in source code or binary format), you must provide recipients the
|
||||
source code to that file along with a copy of this license, which license will
|
||||
govern that file. You may license other files that are entirely your own work
|
||||
and do not contain code from the software under any terms you choose.
|
||||
(B) No Trademark License- This license does not grant you rights to use any
|
||||
contributors' name, logo, or trademarks.
|
||||
(C) If you bring a patent claim against any contributor over patents that you
|
||||
claim are infringed by the software, your patent license from such contributor
|
||||
to the software ends automatically.
|
||||
(D) If you distribute any portion of the software, you must retain all
|
||||
copyright, patent, trademark, and attribution notices that are present in the
|
||||
software.
|
||||
(E) If you distribute any portion of the software in source code form, you may
|
||||
do so only under this license by including a complete copy of this license
|
||||
with your distribution. If you distribute any portion of the software in
|
||||
compiled or object code form, you may only do so under a license that complies
|
||||
with this license.
|
||||
(F) The software is licensed "as-is." You bear the risk of using it. The
|
||||
contributors give no express warranties, guarantees or conditions. You may
|
||||
have additional consumer rights under your local laws which this license
|
||||
cannot change. To the extent permitted under your local laws, the contributors
|
||||
exclude the implied warranties of merchantability, fitness for a particular
|
||||
purpose and non-infringement.
|
|
@ -1,109 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica {
|
||||
static class Log {
|
||||
|
||||
const string LogFileName = "lastrun.log.txt";
|
||||
const string ConflictLogFileName = "run-{0}.log.txt";
|
||||
|
||||
private readonly static StreamWriter Writer;
|
||||
|
||||
static Log() {
|
||||
try {
|
||||
var filepath = Path.Combine(AppPaths.PrivateRoamingFolderPath, LogFileName);
|
||||
Writer = new StreamWriter(new FileStream(filepath, FileMode.Create));
|
||||
Writer.AutoFlush = true;
|
||||
}
|
||||
catch (Exception) {
|
||||
try {
|
||||
var filepath = Path.Combine(AppPaths.PrivateRoamingFolderPath, string.Format(ConflictLogFileName, System.Diagnostics.Process.GetCurrentProcess().Id));
|
||||
Writer = new StreamWriter(new FileStream(filepath, FileMode.Create));
|
||||
Writer.AutoFlush = true;
|
||||
}
|
||||
catch (Exception) {
|
||||
//No fallback logging possible
|
||||
Writer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(string message) {
|
||||
WriteLine(message);
|
||||
}
|
||||
|
||||
public static void Write(string format, object arg0) {
|
||||
WriteLine(string.Format(format, arg0));
|
||||
}
|
||||
|
||||
public static void Write(string format, object arg0, object arg1) {
|
||||
WriteLine(string.Format(format, arg0, arg1));
|
||||
}
|
||||
|
||||
public static void Write(string format, params object[] args) {
|
||||
WriteLine(string.Format(format, args));
|
||||
}
|
||||
|
||||
public static void WriteDetails(string caption, string format, params object[] args) {
|
||||
WriteLines(caption, string.Format(format, args));
|
||||
}
|
||||
|
||||
public static void WriteException(string message, Exception exception) {
|
||||
if (exception != null) {
|
||||
WriteLines(message, exception.ToString());
|
||||
}
|
||||
else {
|
||||
WriteLines(message, "(No exception data.)");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteLine(string message) {
|
||||
var s = string.Format("{0,-8:HH:mm:ss} {1}", DateTime.Now, message);
|
||||
AddToQueue(s);
|
||||
|
||||
if (Writer != null) {
|
||||
Writer.WriteLine(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteLines(params string[] messages) {
|
||||
if (messages.Length <= 0)
|
||||
return;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendFormat("{0,-8:HH:mm:ss} {1}", DateTime.Now, messages[0]);
|
||||
for (int i = 1; i < messages.Length; ++i) {
|
||||
sb.AppendLine();
|
||||
sb.AppendFormat(" {0}", messages[i]);
|
||||
}
|
||||
|
||||
AddToQueue(sb.ToString());
|
||||
|
||||
if (Writer != null) {
|
||||
Writer.WriteLine(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
const int MaxQueueCapacity = 30;
|
||||
|
||||
private static Queue<string> _entriesQueue = new Queue<string>(MaxQueueCapacity);
|
||||
|
||||
private static void AddToQueue(string entry){
|
||||
_entriesQueue.Enqueue(entry);
|
||||
|
||||
while(_entriesQueue.Count > MaxQueueCapacity){
|
||||
_entriesQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Queue {
|
||||
get {
|
||||
return _entriesQueue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica {
|
||||
static class Log {
|
||||
|
||||
const string LogFileName = "lastrun.log.txt";
|
||||
const string ConflictLogFileName = "run-{0}.log.txt";
|
||||
|
||||
private readonly static StreamWriter Writer;
|
||||
|
||||
static Log() {
|
||||
try {
|
||||
var filepath = Path.Combine(AppPaths.PrivateRoamingFolderPath, LogFileName);
|
||||
Writer = new StreamWriter(new FileStream(filepath, FileMode.Create));
|
||||
Writer.AutoFlush = true;
|
||||
}
|
||||
catch (Exception) {
|
||||
try {
|
||||
var filepath = Path.Combine(AppPaths.PrivateRoamingFolderPath, string.Format(ConflictLogFileName, System.Diagnostics.Process.GetCurrentProcess().Id));
|
||||
Writer = new StreamWriter(new FileStream(filepath, FileMode.Create));
|
||||
Writer.AutoFlush = true;
|
||||
}
|
||||
catch (Exception) {
|
||||
//No fallback logging possible
|
||||
Writer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(string message) {
|
||||
WriteLine(message);
|
||||
}
|
||||
|
||||
public static void Write(string format, object arg0) {
|
||||
WriteLine(string.Format(format, arg0));
|
||||
}
|
||||
|
||||
public static void Write(string format, object arg0, object arg1) {
|
||||
WriteLine(string.Format(format, arg0, arg1));
|
||||
}
|
||||
|
||||
public static void Write(string format, params object[] args) {
|
||||
WriteLine(string.Format(format, args));
|
||||
}
|
||||
|
||||
public static void WriteDetails(string caption, string format, params object[] args) {
|
||||
WriteLines(caption, string.Format(format, args));
|
||||
}
|
||||
|
||||
public static void WriteException(string message, Exception exception) {
|
||||
if (exception != null) {
|
||||
WriteLines(message, exception.ToString());
|
||||
}
|
||||
else {
|
||||
WriteLines(message, "(No exception data.)");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteLine(string message) {
|
||||
var s = string.Format("{0,-8:HH:mm:ss} {1}", DateTime.Now, message);
|
||||
AddToQueue(s);
|
||||
|
||||
if (Writer != null) {
|
||||
Writer.WriteLine(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteLines(params string[] messages) {
|
||||
if (messages.Length <= 0)
|
||||
return;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendFormat("{0,-8:HH:mm:ss} {1}", DateTime.Now, messages[0]);
|
||||
for (int i = 1; i < messages.Length; ++i) {
|
||||
sb.AppendLine();
|
||||
sb.AppendFormat(" {0}", messages[i]);
|
||||
}
|
||||
|
||||
AddToQueue(sb.ToString());
|
||||
|
||||
if (Writer != null) {
|
||||
Writer.WriteLine(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
const int MaxQueueCapacity = 30;
|
||||
|
||||
private static Queue<string> _entriesQueue = new Queue<string>(MaxQueueCapacity);
|
||||
|
||||
private static void AddToQueue(string entry){
|
||||
_entriesQueue.Enqueue(entry);
|
||||
|
||||
while(_entriesQueue.Count > MaxQueueCapacity){
|
||||
_entriesQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Queue {
|
||||
get {
|
||||
return _entriesQueue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,461 +1,461 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
using OnTopReplica.Properties;
|
||||
using OnTopReplica.StartupOptions;
|
||||
using OnTopReplica.Update;
|
||||
using OnTopReplica.WindowSeekers;
|
||||
using WindowsFormsAero.Dwm;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
partial class MainForm : AspectRatioForm {
|
||||
|
||||
//GUI elements
|
||||
ThumbnailPanel _thumbnailPanel;
|
||||
|
||||
//Managers
|
||||
readonly MessagePumpManager _msgPumpManager = new MessagePumpManager();
|
||||
WindowListMenuManager _windowListManager;
|
||||
public FullscreenFormManager FullscreenManager { get; private set; }
|
||||
|
||||
Options _startupOptions;
|
||||
|
||||
public MainForm(Options startupOptions) {
|
||||
_startupOptions = startupOptions;
|
||||
|
||||
FullscreenManager = new FullscreenFormManager(this);
|
||||
_quickRegionDrawingHandler = new ThumbnailPanel.RegionDrawnHandler(HandleQuickRegionDrawn);
|
||||
|
||||
//WinForms init pass
|
||||
InitializeComponent();
|
||||
|
||||
//Store default values
|
||||
DefaultNonClickTransparencyKey = this.TransparencyKey;
|
||||
DefaultBorderStyle = this.FormBorderStyle;
|
||||
|
||||
//Thumbnail panel
|
||||
_thumbnailPanel = new ThumbnailPanel {
|
||||
Location = Point.Empty,
|
||||
Dock = DockStyle.Fill
|
||||
};
|
||||
_thumbnailPanel.CloneClick += new EventHandler<CloneClickEventArgs>(Thumbnail_CloneClick);
|
||||
Controls.Add(_thumbnailPanel);
|
||||
|
||||
//Set native renderer on context menus
|
||||
Asztal.Szótár.NativeToolStripRenderer.SetToolStripRenderer(
|
||||
menuContext, menuWindows, menuOpacity, menuResize, menuFullscreenContext
|
||||
);
|
||||
|
||||
//Set to Key event preview
|
||||
this.KeyPreview = true;
|
||||
|
||||
Log.Write("Main form constructed");
|
||||
}
|
||||
|
||||
#region Event override
|
||||
|
||||
protected override void OnHandleCreated(EventArgs e){
|
||||
base.OnHandleCreated(e);
|
||||
|
||||
//Window init
|
||||
KeepAspectRatio = false;
|
||||
GlassMargins = new Padding(-1);
|
||||
|
||||
//Managers
|
||||
_msgPumpManager.Initialize(this);
|
||||
_windowListManager = new WindowListMenuManager(this, menuWindows);
|
||||
_windowListManager.ParentMenus = new System.Windows.Forms.ContextMenuStrip[] {
|
||||
menuContext, menuFullscreenContext
|
||||
};
|
||||
|
||||
//Platform specific form initialization
|
||||
Program.Platform.PostHandleFormInit(this);
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e) {
|
||||
Log.Write("Main form shown");
|
||||
base.OnShown(e);
|
||||
|
||||
//Apply startup options
|
||||
_startupOptions.Apply(this);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e) {
|
||||
Log.Write("Main form closing");
|
||||
base.OnClosing(e);
|
||||
|
||||
_msgPumpManager.Dispose();
|
||||
Program.Platform.CloseForm(this);
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e) {
|
||||
Log.Write("Main form closed");
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
protected override void OnMove(EventArgs e) {
|
||||
base.OnMove(e);
|
||||
|
||||
AdjustSidePanelLocation();
|
||||
}
|
||||
|
||||
protected override void OnResizeEnd(EventArgs e) {
|
||||
base.OnResizeEnd(e);
|
||||
|
||||
RefreshScreenLock();
|
||||
}
|
||||
|
||||
protected override void OnResizing(EventArgs e) {
|
||||
//Update aspect ratio from thumbnail while resizing (but do not refresh, resizing does that anyway)
|
||||
if (_thumbnailPanel.IsShowingThumbnail) {
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e) {
|
||||
base.OnActivated(e);
|
||||
|
||||
//Deactivate click-through if form is reactivated
|
||||
if (ClickThroughEnabled) {
|
||||
ClickThroughEnabled = false;
|
||||
}
|
||||
|
||||
Program.Platform.RestoreForm(this);
|
||||
}
|
||||
|
||||
protected override void OnDeactivate(EventArgs e) {
|
||||
base.OnDeactivate(e);
|
||||
|
||||
//HACK: sometimes, even if TopMost is true, the window loses its "always on top" status.
|
||||
// This is a fix attempt that probably won't work...
|
||||
if (!FullscreenManager.IsFullscreen) { //fullscreen mode doesn't use TopMost
|
||||
TopMost = false;
|
||||
TopMost = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e) {
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (!FullscreenManager.IsFullscreen) {
|
||||
if (_thumbnailPanel.IsShowingThumbnail) {
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, false);
|
||||
}
|
||||
|
||||
int change = (int)(e.Delta / 6.0); //assumes a mouse wheel "tick" is in the 80-120 range
|
||||
AdjustSize(change);
|
||||
|
||||
RefreshScreenLock();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDoubleClick(MouseEventArgs e) {
|
||||
base.OnMouseDoubleClick(e);
|
||||
|
||||
//This is handled by the WM_NCLBUTTONDBLCLK msg handler usually (because the GlassForm translates
|
||||
//clicks on client to clicks on caption). But if fullscreen mode disables GlassForm dragging, we need
|
||||
//this auxiliary handler to switch mode.
|
||||
FullscreenManager.Toggle();
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e) {
|
||||
base.OnMouseClick(e);
|
||||
|
||||
//Same story as above (OnMouseDoubleClick)
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Right) {
|
||||
OpenContextMenu(null);
|
||||
}
|
||||
}
|
||||
|
||||
private ThumbnailPanel.RegionDrawnHandler _quickRegionDrawingHandler;
|
||||
|
||||
protected override void WndProc(ref Message m) {
|
||||
if (_msgPumpManager != null) {
|
||||
if (_msgPumpManager.PumpMessage(ref m)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m.Msg) {
|
||||
case WM.NCRBUTTONUP:
|
||||
//Open context menu if right button clicked on caption (i.e. all of the window area because of glass)
|
||||
if (m.WParam.ToInt32() == HT.CAPTION) {
|
||||
OpenContextMenu(null);
|
||||
|
||||
m.Result = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM.NCLBUTTONDOWN:
|
||||
if ((ModifierKeys & Keys.Control) == Keys.Control &&
|
||||
ThumbnailPanel.IsShowingThumbnail &&
|
||||
!ThumbnailPanel.DrawMouseRegions) {
|
||||
|
||||
ThumbnailPanel.EnableMouseRegionsDrawingWithMouseDown();
|
||||
ThumbnailPanel.RegionDrawn += _quickRegionDrawingHandler;
|
||||
|
||||
m.Result = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM.NCLBUTTONDBLCLK:
|
||||
//Toggle fullscreen mode if double click on caption (whole glass area)
|
||||
if (m.WParam.ToInt32() == HT.CAPTION) {
|
||||
FullscreenManager.Toggle();
|
||||
|
||||
m.Result = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM.NCHITTEST:
|
||||
//Make transparent to hit-testing if in click through mode
|
||||
if (ClickThroughEnabled) {
|
||||
m.Result = (IntPtr)HT.TRANSPARENT;
|
||||
|
||||
RefreshClickThroughComeBack();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
private void HandleQuickRegionDrawn(object sender, ThumbnailRegion region) {
|
||||
//Reset region drawing state
|
||||
ThumbnailPanel.DrawMouseRegions = false;
|
||||
ThumbnailPanel.RegionDrawn -= _quickRegionDrawingHandler;
|
||||
|
||||
SelectedThumbnailRegion = region;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyboard event handling
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e) {
|
||||
base.OnKeyUp(e);
|
||||
|
||||
//ALT
|
||||
if (e.Modifiers == Keys.Alt) {
|
||||
if (e.KeyCode == Keys.Enter) {
|
||||
e.Handled = true;
|
||||
FullscreenManager.Toggle();
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D1 || e.KeyCode == Keys.NumPad1) {
|
||||
FitToThumbnail(0.25);
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D2 || e.KeyCode == Keys.NumPad2) {
|
||||
FitToThumbnail(0.5);
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D3 || e.KeyCode == Keys.NumPad3 ||
|
||||
e.KeyCode == Keys.D0 || e.KeyCode == Keys.NumPad0) {
|
||||
FitToThumbnail(1.0);
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D4 || e.KeyCode == Keys.NumPad4) {
|
||||
FitToThumbnail(2.0);
|
||||
}
|
||||
}
|
||||
|
||||
//F11 Fullscreen switch
|
||||
else if (e.KeyCode == Keys.F11) {
|
||||
e.Handled = true;
|
||||
FullscreenManager.Toggle();
|
||||
}
|
||||
|
||||
//ESCAPE
|
||||
else if (e.KeyCode == Keys.Escape) {
|
||||
//Disable click-through
|
||||
if (ClickThroughEnabled) {
|
||||
ClickThroughEnabled = false;
|
||||
}
|
||||
//Toggle fullscreen
|
||||
else if (FullscreenManager.IsFullscreen) {
|
||||
FullscreenManager.SwitchBack();
|
||||
}
|
||||
//Disable click forwarding
|
||||
else if (ClickForwardingEnabled) {
|
||||
ClickForwardingEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Thumbnail operation
|
||||
|
||||
/// <summary>
|
||||
/// Sets a new thumbnail.
|
||||
/// </summary>
|
||||
/// <param name="handle">Handle to the window to clone.</param>
|
||||
/// <param name="region">Region of the window to clone or null.</param>
|
||||
public void SetThumbnail(WindowHandle handle, ThumbnailRegion region) {
|
||||
try {
|
||||
Log.Write("Cloning window HWND {0} of class {1}", handle.Handle, handle.Class);
|
||||
|
||||
CurrentThumbnailWindowHandle = handle;
|
||||
_thumbnailPanel.SetThumbnailHandle(handle, region);
|
||||
|
||||
//Set aspect ratio (this will resize the form), do not refresh if in fullscreen
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, !FullscreenManager.IsFullscreen);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.WriteException("Unable to set new thumbnail", ex);
|
||||
|
||||
ThumbnailError(ex, false, Strings.ErrorUnableToCreateThumbnail);
|
||||
_thumbnailPanel.UnsetThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables group mode on a list of window handles.
|
||||
/// </summary>
|
||||
/// <param name="handles">List of window handles.</param>
|
||||
public void SetThumbnailGroup(IList<WindowHandle> handles) {
|
||||
if (handles.Count == 0)
|
||||
return;
|
||||
|
||||
//At last one thumbnail
|
||||
SetThumbnail(handles[0], null);
|
||||
|
||||
//Handle if no real group
|
||||
if (handles.Count == 1)
|
||||
return;
|
||||
|
||||
CurrentThumbnailWindowHandle = null;
|
||||
_msgPumpManager.Get<MessagePumpProcessors.GroupSwitchManager>().EnableGroupMode(handles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the cloned thumbnail.
|
||||
/// </summary>
|
||||
public void UnsetThumbnail() {
|
||||
//Unset handle
|
||||
CurrentThumbnailWindowHandle = null;
|
||||
_thumbnailPanel.UnsetThumbnail();
|
||||
|
||||
//Disable aspect ratio
|
||||
KeepAspectRatio = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the region displayed of the current thumbnail.
|
||||
/// </summary>
|
||||
public ThumbnailRegion SelectedThumbnailRegion {
|
||||
get {
|
||||
if (!_thumbnailPanel.IsShowingThumbnail || !_thumbnailPanel.ConstrainToRegion)
|
||||
return null;
|
||||
|
||||
return _thumbnailPanel.SelectedRegion;
|
||||
}
|
||||
set {
|
||||
if (!_thumbnailPanel.IsShowingThumbnail)
|
||||
return;
|
||||
|
||||
_thumbnailPanel.SelectedRegion = value;
|
||||
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, true);
|
||||
|
||||
FixPositionAndSize();
|
||||
}
|
||||
}
|
||||
|
||||
const int FixMargin = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Fixes the form's position and size, ensuring it is fully displayed in the current screen.
|
||||
/// </summary>
|
||||
private void FixPositionAndSize() {
|
||||
var screen = Screen.FromControl(this);
|
||||
|
||||
if (Width > screen.WorkingArea.Width) {
|
||||
Width = screen.WorkingArea.Width - FixMargin;
|
||||
}
|
||||
if (Height > screen.WorkingArea.Height) {
|
||||
Height = screen.WorkingArea.Height - FixMargin;
|
||||
}
|
||||
if (Location.X + Width > screen.WorkingArea.Right) {
|
||||
Location = new Point(screen.WorkingArea.Right - Width - FixMargin, Location.Y);
|
||||
}
|
||||
if (Location.Y + Height > screen.WorkingArea.Bottom) {
|
||||
Location = new Point(Location.X, screen.WorkingArea.Bottom - Height - FixMargin);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThumbnailError(Exception ex, bool suppress, string title) {
|
||||
if (!suppress) {
|
||||
ShowErrorDialog(title, Strings.ErrorGenericThumbnailHandleError, ex.Message);
|
||||
}
|
||||
|
||||
UnsetThumbnail();
|
||||
}
|
||||
|
||||
/// <summary>Automatically sizes the window in order to accomodate the thumbnail p times.</summary>
|
||||
/// <param name="p">Scale of the thumbnail to consider.</param>
|
||||
private void FitToThumbnail(double p) {
|
||||
try {
|
||||
Size originalSize = _thumbnailPanel.ThumbnailPixelSize;
|
||||
Size fittedSize = new Size((int)(originalSize.Width * p), (int)(originalSize.Height * p));
|
||||
ClientSize = fittedSize;
|
||||
RefreshScreenLock();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ThumbnailError(ex, false, Strings.ErrorUnableToFit);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessors
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form's thumbnail panel.
|
||||
/// </summary>
|
||||
public ThumbnailPanel ThumbnailPanel {
|
||||
get {
|
||||
return _thumbnailPanel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form's message pump manager.
|
||||
/// </summary>
|
||||
public MessagePumpManager MessagePumpManager {
|
||||
get {
|
||||
return _msgPumpManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form's window list drop down menu.
|
||||
/// </summary>
|
||||
public ContextMenuStrip MenuWindows {
|
||||
get {
|
||||
return menuWindows;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the window handle of the currently cloned thumbnail.
|
||||
/// </summary>
|
||||
public WindowHandle CurrentThumbnailWindowHandle {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
using OnTopReplica.Properties;
|
||||
using OnTopReplica.StartupOptions;
|
||||
using OnTopReplica.Update;
|
||||
using OnTopReplica.WindowSeekers;
|
||||
using WindowsFormsAero.Dwm;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
partial class MainForm : AspectRatioForm {
|
||||
|
||||
//GUI elements
|
||||
ThumbnailPanel _thumbnailPanel;
|
||||
|
||||
//Managers
|
||||
readonly MessagePumpManager _msgPumpManager = new MessagePumpManager();
|
||||
WindowListMenuManager _windowListManager;
|
||||
public FullscreenFormManager FullscreenManager { get; private set; }
|
||||
|
||||
Options _startupOptions;
|
||||
|
||||
public MainForm(Options startupOptions) {
|
||||
_startupOptions = startupOptions;
|
||||
|
||||
FullscreenManager = new FullscreenFormManager(this);
|
||||
_quickRegionDrawingHandler = new ThumbnailPanel.RegionDrawnHandler(HandleQuickRegionDrawn);
|
||||
|
||||
//WinForms init pass
|
||||
InitializeComponent();
|
||||
|
||||
//Store default values
|
||||
DefaultNonClickTransparencyKey = this.TransparencyKey;
|
||||
DefaultBorderStyle = this.FormBorderStyle;
|
||||
|
||||
//Thumbnail panel
|
||||
_thumbnailPanel = new ThumbnailPanel {
|
||||
Location = Point.Empty,
|
||||
Dock = DockStyle.Fill
|
||||
};
|
||||
_thumbnailPanel.CloneClick += new EventHandler<CloneClickEventArgs>(Thumbnail_CloneClick);
|
||||
Controls.Add(_thumbnailPanel);
|
||||
|
||||
//Set native renderer on context menus
|
||||
Asztal.Szótár.NativeToolStripRenderer.SetToolStripRenderer(
|
||||
menuContext, menuWindows, menuOpacity, menuResize, menuFullscreenContext
|
||||
);
|
||||
|
||||
//Set to Key event preview
|
||||
this.KeyPreview = true;
|
||||
|
||||
Log.Write("Main form constructed");
|
||||
}
|
||||
|
||||
#region Event override
|
||||
|
||||
protected override void OnHandleCreated(EventArgs e){
|
||||
base.OnHandleCreated(e);
|
||||
|
||||
//Window init
|
||||
KeepAspectRatio = false;
|
||||
GlassMargins = new Padding(-1);
|
||||
|
||||
//Managers
|
||||
_msgPumpManager.Initialize(this);
|
||||
_windowListManager = new WindowListMenuManager(this, menuWindows);
|
||||
_windowListManager.ParentMenus = new System.Windows.Forms.ContextMenuStrip[] {
|
||||
menuContext, menuFullscreenContext
|
||||
};
|
||||
|
||||
//Platform specific form initialization
|
||||
Program.Platform.PostHandleFormInit(this);
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e) {
|
||||
Log.Write("Main form shown");
|
||||
base.OnShown(e);
|
||||
|
||||
//Apply startup options
|
||||
_startupOptions.Apply(this);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e) {
|
||||
Log.Write("Main form closing");
|
||||
base.OnClosing(e);
|
||||
|
||||
_msgPumpManager.Dispose();
|
||||
Program.Platform.CloseForm(this);
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e) {
|
||||
Log.Write("Main form closed");
|
||||
base.OnClosed(e);
|
||||
}
|
||||
|
||||
protected override void OnMove(EventArgs e) {
|
||||
base.OnMove(e);
|
||||
|
||||
AdjustSidePanelLocation();
|
||||
}
|
||||
|
||||
protected override void OnResizeEnd(EventArgs e) {
|
||||
base.OnResizeEnd(e);
|
||||
|
||||
RefreshScreenLock();
|
||||
}
|
||||
|
||||
protected override void OnResizing(EventArgs e) {
|
||||
//Update aspect ratio from thumbnail while resizing (but do not refresh, resizing does that anyway)
|
||||
if (_thumbnailPanel.IsShowingThumbnail) {
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e) {
|
||||
base.OnActivated(e);
|
||||
|
||||
//Deactivate click-through if form is reactivated
|
||||
if (ClickThroughEnabled) {
|
||||
ClickThroughEnabled = false;
|
||||
}
|
||||
|
||||
Program.Platform.RestoreForm(this);
|
||||
}
|
||||
|
||||
protected override void OnDeactivate(EventArgs e) {
|
||||
base.OnDeactivate(e);
|
||||
|
||||
//HACK: sometimes, even if TopMost is true, the window loses its "always on top" status.
|
||||
// This is a fix attempt that probably won't work...
|
||||
if (!FullscreenManager.IsFullscreen) { //fullscreen mode doesn't use TopMost
|
||||
TopMost = false;
|
||||
TopMost = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e) {
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (!FullscreenManager.IsFullscreen) {
|
||||
if (_thumbnailPanel.IsShowingThumbnail) {
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, false);
|
||||
}
|
||||
|
||||
int change = (int)(e.Delta / 6.0); //assumes a mouse wheel "tick" is in the 80-120 range
|
||||
AdjustSize(change);
|
||||
|
||||
RefreshScreenLock();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDoubleClick(MouseEventArgs e) {
|
||||
base.OnMouseDoubleClick(e);
|
||||
|
||||
//This is handled by the WM_NCLBUTTONDBLCLK msg handler usually (because the GlassForm translates
|
||||
//clicks on client to clicks on caption). But if fullscreen mode disables GlassForm dragging, we need
|
||||
//this auxiliary handler to switch mode.
|
||||
FullscreenManager.Toggle();
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e) {
|
||||
base.OnMouseClick(e);
|
||||
|
||||
//Same story as above (OnMouseDoubleClick)
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Right) {
|
||||
OpenContextMenu(null);
|
||||
}
|
||||
}
|
||||
|
||||
private ThumbnailPanel.RegionDrawnHandler _quickRegionDrawingHandler;
|
||||
|
||||
protected override void WndProc(ref Message m) {
|
||||
if (_msgPumpManager != null) {
|
||||
if (_msgPumpManager.PumpMessage(ref m)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m.Msg) {
|
||||
case WM.NCRBUTTONUP:
|
||||
//Open context menu if right button clicked on caption (i.e. all of the window area because of glass)
|
||||
if (m.WParam.ToInt32() == HT.CAPTION) {
|
||||
OpenContextMenu(null);
|
||||
|
||||
m.Result = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM.NCLBUTTONDOWN:
|
||||
if ((ModifierKeys & Keys.Control) == Keys.Control &&
|
||||
ThumbnailPanel.IsShowingThumbnail &&
|
||||
!ThumbnailPanel.DrawMouseRegions) {
|
||||
|
||||
ThumbnailPanel.EnableMouseRegionsDrawingWithMouseDown();
|
||||
ThumbnailPanel.RegionDrawn += _quickRegionDrawingHandler;
|
||||
|
||||
m.Result = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM.NCLBUTTONDBLCLK:
|
||||
//Toggle fullscreen mode if double click on caption (whole glass area)
|
||||
if (m.WParam.ToInt32() == HT.CAPTION) {
|
||||
FullscreenManager.Toggle();
|
||||
|
||||
m.Result = IntPtr.Zero;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM.NCHITTEST:
|
||||
//Make transparent to hit-testing if in click through mode
|
||||
if (ClickThroughEnabled) {
|
||||
m.Result = (IntPtr)HT.TRANSPARENT;
|
||||
|
||||
RefreshClickThroughComeBack();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
private void HandleQuickRegionDrawn(object sender, ThumbnailRegion region) {
|
||||
//Reset region drawing state
|
||||
ThumbnailPanel.DrawMouseRegions = false;
|
||||
ThumbnailPanel.RegionDrawn -= _quickRegionDrawingHandler;
|
||||
|
||||
SelectedThumbnailRegion = region;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyboard event handling
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e) {
|
||||
base.OnKeyUp(e);
|
||||
|
||||
//ALT
|
||||
if (e.Modifiers == Keys.Alt) {
|
||||
if (e.KeyCode == Keys.Enter) {
|
||||
e.Handled = true;
|
||||
FullscreenManager.Toggle();
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D1 || e.KeyCode == Keys.NumPad1) {
|
||||
FitToThumbnail(0.25);
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D2 || e.KeyCode == Keys.NumPad2) {
|
||||
FitToThumbnail(0.5);
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D3 || e.KeyCode == Keys.NumPad3 ||
|
||||
e.KeyCode == Keys.D0 || e.KeyCode == Keys.NumPad0) {
|
||||
FitToThumbnail(1.0);
|
||||
}
|
||||
|
||||
else if (e.KeyCode == Keys.D4 || e.KeyCode == Keys.NumPad4) {
|
||||
FitToThumbnail(2.0);
|
||||
}
|
||||
}
|
||||
|
||||
//F11 Fullscreen switch
|
||||
else if (e.KeyCode == Keys.F11) {
|
||||
e.Handled = true;
|
||||
FullscreenManager.Toggle();
|
||||
}
|
||||
|
||||
//ESCAPE
|
||||
else if (e.KeyCode == Keys.Escape) {
|
||||
//Disable click-through
|
||||
if (ClickThroughEnabled) {
|
||||
ClickThroughEnabled = false;
|
||||
}
|
||||
//Toggle fullscreen
|
||||
else if (FullscreenManager.IsFullscreen) {
|
||||
FullscreenManager.SwitchBack();
|
||||
}
|
||||
//Disable click forwarding
|
||||
else if (ClickForwardingEnabled) {
|
||||
ClickForwardingEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Thumbnail operation
|
||||
|
||||
/// <summary>
|
||||
/// Sets a new thumbnail.
|
||||
/// </summary>
|
||||
/// <param name="handle">Handle to the window to clone.</param>
|
||||
/// <param name="region">Region of the window to clone or null.</param>
|
||||
public void SetThumbnail(WindowHandle handle, ThumbnailRegion region) {
|
||||
try {
|
||||
Log.Write("Cloning window HWND {0} of class {1}", handle.Handle, handle.Class);
|
||||
|
||||
CurrentThumbnailWindowHandle = handle;
|
||||
_thumbnailPanel.SetThumbnailHandle(handle, region);
|
||||
|
||||
//Set aspect ratio (this will resize the form), do not refresh if in fullscreen
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, !FullscreenManager.IsFullscreen);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.WriteException("Unable to set new thumbnail", ex);
|
||||
|
||||
ThumbnailError(ex, false, Strings.ErrorUnableToCreateThumbnail);
|
||||
_thumbnailPanel.UnsetThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables group mode on a list of window handles.
|
||||
/// </summary>
|
||||
/// <param name="handles">List of window handles.</param>
|
||||
public void SetThumbnailGroup(IList<WindowHandle> handles) {
|
||||
if (handles.Count == 0)
|
||||
return;
|
||||
|
||||
//At last one thumbnail
|
||||
SetThumbnail(handles[0], null);
|
||||
|
||||
//Handle if no real group
|
||||
if (handles.Count == 1)
|
||||
return;
|
||||
|
||||
CurrentThumbnailWindowHandle = null;
|
||||
_msgPumpManager.Get<MessagePumpProcessors.GroupSwitchManager>().EnableGroupMode(handles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the cloned thumbnail.
|
||||
/// </summary>
|
||||
public void UnsetThumbnail() {
|
||||
//Unset handle
|
||||
CurrentThumbnailWindowHandle = null;
|
||||
_thumbnailPanel.UnsetThumbnail();
|
||||
|
||||
//Disable aspect ratio
|
||||
KeepAspectRatio = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the region displayed of the current thumbnail.
|
||||
/// </summary>
|
||||
public ThumbnailRegion SelectedThumbnailRegion {
|
||||
get {
|
||||
if (!_thumbnailPanel.IsShowingThumbnail || !_thumbnailPanel.ConstrainToRegion)
|
||||
return null;
|
||||
|
||||
return _thumbnailPanel.SelectedRegion;
|
||||
}
|
||||
set {
|
||||
if (!_thumbnailPanel.IsShowingThumbnail)
|
||||
return;
|
||||
|
||||
_thumbnailPanel.SelectedRegion = value;
|
||||
|
||||
SetAspectRatio(_thumbnailPanel.ThumbnailPixelSize, true);
|
||||
|
||||
FixPositionAndSize();
|
||||
}
|
||||
}
|
||||
|
||||
const int FixMargin = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Fixes the form's position and size, ensuring it is fully displayed in the current screen.
|
||||
/// </summary>
|
||||
private void FixPositionAndSize() {
|
||||
var screen = Screen.FromControl(this);
|
||||
|
||||
if (Width > screen.WorkingArea.Width) {
|
||||
Width = screen.WorkingArea.Width - FixMargin;
|
||||
}
|
||||
if (Height > screen.WorkingArea.Height) {
|
||||
Height = screen.WorkingArea.Height - FixMargin;
|
||||
}
|
||||
if (Location.X + Width > screen.WorkingArea.Right) {
|
||||
Location = new Point(screen.WorkingArea.Right - Width - FixMargin, Location.Y);
|
||||
}
|
||||
if (Location.Y + Height > screen.WorkingArea.Bottom) {
|
||||
Location = new Point(Location.X, screen.WorkingArea.Bottom - Height - FixMargin);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThumbnailError(Exception ex, bool suppress, string title) {
|
||||
if (!suppress) {
|
||||
ShowErrorDialog(title, Strings.ErrorGenericThumbnailHandleError, ex.Message);
|
||||
}
|
||||
|
||||
UnsetThumbnail();
|
||||
}
|
||||
|
||||
/// <summary>Automatically sizes the window in order to accomodate the thumbnail p times.</summary>
|
||||
/// <param name="p">Scale of the thumbnail to consider.</param>
|
||||
private void FitToThumbnail(double p) {
|
||||
try {
|
||||
Size originalSize = _thumbnailPanel.ThumbnailPixelSize;
|
||||
Size fittedSize = new Size((int)(originalSize.Width * p), (int)(originalSize.Height * p));
|
||||
ClientSize = fittedSize;
|
||||
RefreshScreenLock();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ThumbnailError(ex, false, Strings.ErrorUnableToFit);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessors
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form's thumbnail panel.
|
||||
/// </summary>
|
||||
public ThumbnailPanel ThumbnailPanel {
|
||||
get {
|
||||
return _thumbnailPanel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form's message pump manager.
|
||||
/// </summary>
|
||||
public MessagePumpManager MessagePumpManager {
|
||||
get {
|
||||
return _msgPumpManager;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the form's window list drop down menu.
|
||||
/// </summary>
|
||||
public ContextMenuStrip MenuWindows {
|
||||
get {
|
||||
return menuWindows;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the window handle of the currently cloned thumbnail.
|
||||
/// </summary>
|
||||
public WindowHandle CurrentThumbnailWindowHandle {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -1,93 +1,93 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
partial class MainForm {
|
||||
|
||||
//SidePanel _currentSidePanel = null;
|
||||
SidePanelContainer _sidePanelContainer = null;
|
||||
|
||||
/// <summary>
|
||||
/// Opens a new side panel.
|
||||
/// </summary>
|
||||
/// <param name="panel">The side panel to embed.</param>
|
||||
public void SetSidePanel(SidePanel panel) {
|
||||
if (IsSidePanelOpen) {
|
||||
CloseSidePanel();
|
||||
}
|
||||
|
||||
_sidePanelContainer = new SidePanelContainer(this);
|
||||
_sidePanelContainer.SetSidePanel(panel);
|
||||
_sidePanelContainer.Location = ComputeSidePanelLocation(_sidePanelContainer);
|
||||
_sidePanelContainer.Show(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the current side panel.
|
||||
/// </summary>
|
||||
public void CloseSidePanel() {
|
||||
if (_sidePanelContainer == null || _sidePanelContainer.IsDisposed) {
|
||||
_sidePanelContainer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_sidePanelContainer.Hide();
|
||||
_sidePanelContainer.FreeSidePanel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether a side panel is currently shown.
|
||||
/// </summary>
|
||||
public bool IsSidePanelOpen {
|
||||
get {
|
||||
if (_sidePanelContainer == null)
|
||||
return false;
|
||||
if (_sidePanelContainer.IsDisposed) {
|
||||
_sidePanelContainer = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return _sidePanelContainer.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the side panel based on the main form's current location.
|
||||
/// </summary>
|
||||
protected void AdjustSidePanelLocation() {
|
||||
if (!IsSidePanelOpen)
|
||||
return;
|
||||
|
||||
_sidePanelContainer.Location = ComputeSidePanelLocation(_sidePanelContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the target location of a side panel form that ensures it is visible on the current
|
||||
/// screen that contains the main form.
|
||||
/// </summary>
|
||||
private Point ComputeSidePanelLocation(Form sidePanel) {
|
||||
//Check if moving the panel on the form's right would put it off-screen
|
||||
var screen = Screen.FromControl(this);
|
||||
if (Location.X + Width + sidePanel.Width > screen.WorkingArea.Right) {
|
||||
return new Point(Location.X - sidePanel.Width, Location.Y);
|
||||
}
|
||||
else {
|
||||
return new Point(Location.X + Width, Location.Y);
|
||||
}
|
||||
}
|
||||
|
||||
void SidePanel_RequestClosing(object sender, EventArgs e) {
|
||||
CloseSidePanel();
|
||||
}
|
||||
|
||||
void Thumbnail_CloneClick(object sender, CloneClickEventArgs e) {
|
||||
Win32Helper.InjectFakeMouseClick(CurrentThumbnailWindowHandle.Handle, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OnTopReplica {
|
||||
|
||||
partial class MainForm {
|
||||
|
||||
//SidePanel _currentSidePanel = null;
|
||||
SidePanelContainer _sidePanelContainer = null;
|
||||
|
||||
/// <summary>
|
||||
/// Opens a new side panel.
|
||||
/// </summary>
|
||||
/// <param name="panel">The side panel to embed.</param>
|
||||
public void SetSidePanel(SidePanel panel) {
|
||||
if (IsSidePanelOpen) {
|
||||
CloseSidePanel();
|
||||
}
|
||||
|
||||
_sidePanelContainer = new SidePanelContainer(this);
|
||||
_sidePanelContainer.SetSidePanel(panel);
|
||||
_sidePanelContainer.Location = ComputeSidePanelLocation(_sidePanelContainer);
|
||||
_sidePanelContainer.Show(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the current side panel.
|
||||
/// </summary>
|
||||
public void CloseSidePanel() {
|
||||
if (_sidePanelContainer == null || _sidePanelContainer.IsDisposed) {
|
||||
_sidePanelContainer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_sidePanelContainer.Hide();
|
||||
_sidePanelContainer.FreeSidePanel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether a side panel is currently shown.
|
||||
/// </summary>
|
||||
public bool IsSidePanelOpen {
|
||||
get {
|
||||
if (_sidePanelContainer == null)
|
||||
return false;
|
||||
if (_sidePanelContainer.IsDisposed) {
|
||||
_sidePanelContainer = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return _sidePanelContainer.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the side panel based on the main form's current location.
|
||||
/// </summary>
|
||||
protected void AdjustSidePanelLocation() {
|
||||
if (!IsSidePanelOpen)
|
||||
return;
|
||||
|
||||
_sidePanelContainer.Location = ComputeSidePanelLocation(_sidePanelContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the target location of a side panel form that ensures it is visible on the current
|
||||
/// screen that contains the main form.
|
||||
/// </summary>
|
||||
private Point ComputeSidePanelLocation(Form sidePanel) {
|
||||
//Check if moving the panel on the form's right would put it off-screen
|
||||
var screen = Screen.FromControl(this);
|
||||
if (Location.X + Width + sidePanel.Width > screen.WorkingArea.Right) {
|
||||
return new Point(Location.X - sidePanel.Width, Location.Y);
|
||||
}
|
||||
else {
|
||||
return new Point(Location.X + Width, Location.Y);
|
||||
}
|
||||
}
|
||||
|
||||
void SidePanel_RequestClosing(object sender, EventArgs e) {
|
||||
CloseSidePanel();
|
||||
}
|
||||
|
||||
void Thumbnail_CloneClick(object sender, CloneClickEventArgs e) {
|
||||
Win32Helper.InjectFakeMouseClick(CurrentThumbnailWindowHandle.Handle, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,167 +1,167 @@
|
|||
using OnTopReplica.Native;
|
||||
using OnTopReplica.Properties;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
|
||||
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 = CommonButton.Yes | CommonButton.No
|
||||
};
|
||||
if (dlg.Show(this).CommonButton == CommonButtonResult.No)
|
||||
return;
|
||||
|
||||
Settings.Default.FirstTimeClickForwarding = false;
|
||||
}
|
||||
|
||||
_thumbnailPanel.ReportThumbnailClicks = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Click-through
|
||||
|
||||
bool _clickThrough = false;
|
||||
|
||||
readonly Color DefaultNonClickTransparencyKey;
|
||||
|
||||
public bool ClickThroughEnabled {
|
||||
get {
|
||||
return _clickThrough;
|
||||
}
|
||||
set {
|
||||
TransparencyKey = (value) ? Color.Black : DefaultNonClickTransparencyKey;
|
||||
if (value) {
|
||||
//Re-force as top most (always helps in some cases)
|
||||
TopMost = false;
|
||||
this.Activate();
|
||||
TopMost = true;
|
||||
}
|
||||
|
||||
_clickThrough = value;
|
||||
}
|
||||
}
|
||||
|
||||
//Must NOT be equal to any other valid opacity value
|
||||
const double ClickThroughHoverOpacity = 0.6;
|
||||
|
||||
Timer _clickThroughComeBackTimer = null;
|
||||
long _clickThroughComeBackTicks;
|
||||
const int ClickThroughComeBackTimerInterval = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// When the mouse hovers over a fully opaque click-through form,
|
||||
/// this fades the form to semi-transparency
|
||||
/// and starts a timeout to get back to full opacity.
|
||||
/// </summary>
|
||||
private void RefreshClickThroughComeBack() {
|
||||
if (this.Opacity == 1.0) {
|
||||
this.Opacity = ClickThroughHoverOpacity;
|
||||
}
|
||||
|
||||
if (_clickThroughComeBackTimer == null) {
|
||||
_clickThroughComeBackTimer = new Timer();
|
||||
_clickThroughComeBackTimer.Tick += _clickThroughComeBackTimer_Tick;
|
||||
_clickThroughComeBackTimer.Interval = ClickThroughComeBackTimerInterval;
|
||||
}
|
||||
_clickThroughComeBackTicks = DateTime.UtcNow.Ticks;
|
||||
_clickThroughComeBackTimer.Start();
|
||||
}
|
||||
|
||||
void _clickThroughComeBackTimer_Tick(object sender, EventArgs e) {
|
||||
var diff = DateTime.UtcNow.Subtract(new DateTime(_clickThroughComeBackTicks));
|
||||
if (diff.TotalSeconds > 2) {
|
||||
var mousePointer = WindowMethods.GetCursorPos();
|
||||
|
||||
if (!this.ContainsMousePointer(mousePointer)) {
|
||||
if (this.Opacity == ClickThroughHoverOpacity) {
|
||||
this.Opacity = 1.0;
|
||||
}
|
||||
_clickThroughComeBackTimer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Chrome
|
||||
|
||||
readonly FormBorderStyle DefaultBorderStyle; // = FormBorderStyle.Sizable; // FormBorderStyle.SizableToolWindow;
|
||||
|
||||
public bool IsChromeVisible {
|
||||
get {
|
||||
return (FormBorderStyle == DefaultBorderStyle);
|
||||
}
|
||||
set {
|
||||
//Cancel hiding chrome if no thumbnail is shown
|
||||
if (!value && !_thumbnailPanel.IsShowingThumbnail)
|
||||
return;
|
||||
|
||||
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 = DefaultBorderStyle;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes window position if in lock mode.
|
||||
/// </summary>
|
||||
private void RefreshScreenLock() {
|
||||
//If locked in position, move accordingly
|
||||
if (PositionLock.HasValue) {
|
||||
this.SetScreenPosition(PositionLock.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
using OnTopReplica.Native;
|
||||
using OnTopReplica.Properties;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
|
||||
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 = CommonButton.Yes | CommonButton.No
|
||||
};
|
||||
if (dlg.Show(this).CommonButton == CommonButtonResult.No)
|
||||
return;
|
||||
|
||||
Settings.Default.FirstTimeClickForwarding = false;
|
||||
}
|
||||
|
||||
_thumbnailPanel.ReportThumbnailClicks = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Click-through
|
||||
|
||||
bool _clickThrough = false;
|
||||
|
||||
readonly Color DefaultNonClickTransparencyKey;
|
||||
|
||||
public bool ClickThroughEnabled {
|
||||
get {
|
||||
return _clickThrough;
|
||||
}
|
||||
set {
|
||||
TransparencyKey = (value) ? Color.Black : DefaultNonClickTransparencyKey;
|
||||
if (value) {
|
||||
//Re-force as top most (always helps in some cases)
|
||||
TopMost = false;
|
||||
this.Activate();
|
||||
TopMost = true;
|
||||
}
|
||||
|
||||
_clickThrough = value;
|
||||
}
|
||||
}
|
||||
|
||||
//Must NOT be equal to any other valid opacity value
|
||||
const double ClickThroughHoverOpacity = 0.6;
|
||||
|
||||
Timer _clickThroughComeBackTimer = null;
|
||||
long _clickThroughComeBackTicks;
|
||||
const int ClickThroughComeBackTimerInterval = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// When the mouse hovers over a fully opaque click-through form,
|
||||
/// this fades the form to semi-transparency
|
||||
/// and starts a timeout to get back to full opacity.
|
||||
/// </summary>
|
||||
private void RefreshClickThroughComeBack() {
|
||||
if (this.Opacity == 1.0) {
|
||||
this.Opacity = ClickThroughHoverOpacity;
|
||||
}
|
||||
|
||||
if (_clickThroughComeBackTimer == null) {
|
||||
_clickThroughComeBackTimer = new Timer();
|
||||
_clickThroughComeBackTimer.Tick += _clickThroughComeBackTimer_Tick;
|
||||
_clickThroughComeBackTimer.Interval = ClickThroughComeBackTimerInterval;
|
||||
}
|
||||
_clickThroughComeBackTicks = DateTime.UtcNow.Ticks;
|
||||
_clickThroughComeBackTimer.Start();
|
||||
}
|
||||
|
||||
void _clickThroughComeBackTimer_Tick(object sender, EventArgs e) {
|
||||
var diff = DateTime.UtcNow.Subtract(new DateTime(_clickThroughComeBackTicks));
|
||||
if (diff.TotalSeconds > 2) {
|
||||
var mousePointer = WindowMethods.GetCursorPos();
|
||||
|
||||
if (!this.ContainsMousePointer(mousePointer)) {
|
||||
if (this.Opacity == ClickThroughHoverOpacity) {
|
||||
this.Opacity = 1.0;
|
||||
}
|
||||
_clickThroughComeBackTimer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Chrome
|
||||
|
||||
readonly FormBorderStyle DefaultBorderStyle; // = FormBorderStyle.Sizable; // FormBorderStyle.SizableToolWindow;
|
||||
|
||||
public bool IsChromeVisible {
|
||||
get {
|
||||
return (FormBorderStyle == DefaultBorderStyle);
|
||||
}
|
||||
set {
|
||||
//Cancel hiding chrome if no thumbnail is shown
|
||||
if (!value && !_thumbnailPanel.IsShowingThumbnail)
|
||||
return;
|
||||
|
||||
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 = DefaultBorderStyle;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes window position if in lock mode.
|
||||
/// </summary>
|
||||
private void RefreshScreenLock() {
|
||||
//If locked in position, move accordingly
|
||||
if (PositionLock.HasValue) {
|
||||
this.SetScreenPosition(PositionLock.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -1,117 +1,117 @@
|
|||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
|
||||
namespace OnTopReplica {
|
||||
partial class MainForm {
|
||||
|
||||
/// <summary>
|
||||
/// Opens the context menu.
|
||||
/// </summary>
|
||||
/// <param name="position">Optional position of the mouse, relative to which the menu is shown.</param>
|
||||
public void OpenContextMenu(Point? position) {
|
||||
Point menuPosition = MousePosition;
|
||||
if (position.HasValue)
|
||||
menuPosition = position.Value;
|
||||
|
||||
if (FullscreenManager.IsFullscreen) {
|
||||
menuFullscreenContext.Show(menuPosition);
|
||||
}
|
||||
else {
|
||||
menuContext.Show(menuPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window's vertical chrome size.
|
||||
/// </summary>
|
||||
public int ChromeBorderVertical {
|
||||
get {
|
||||
if (IsChromeVisible)
|
||||
return SystemInformation.FrameBorderSize.Height;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window's horizontal chrome size.
|
||||
/// </summary>
|
||||
public int ChromeBorderHorizontal {
|
||||
get {
|
||||
if (IsChromeVisible)
|
||||
return SystemInformation.FrameBorderSize.Width;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays an error task dialog.
|
||||
/// </summary>
|
||||
/// <param name="mainInstruction">Main instruction of the error dialog.</param>
|
||||
/// <param name="explanation">Detailed informations about the error.</param>
|
||||
/// <param name="errorMessage">Expanded error codes/messages.</param>
|
||||
private void ShowErrorDialog(string mainInstruction, string explanation, string errorMessage) {
|
||||
TaskDialog dlg = new TaskDialog(mainInstruction, Strings.ErrorGenericTitle, explanation) {
|
||||
CommonIcon = CommonIcon.Stop,
|
||||
IsExpanded = false
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMessage)) {
|
||||
dlg.ExpandedInformation = Strings.ErrorGenericInfoText + errorMessage;
|
||||
dlg.ExpandedControlText = Strings.ErrorGenericInfoButton;
|
||||
}
|
||||
|
||||
dlg.Show(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the main form is visible (either closing the fullscreen mode or reactivating from task icon).
|
||||
/// </summary>
|
||||
public void EnsureMainFormVisible() {
|
||||
//Reset special modes
|
||||
FullscreenManager.SwitchBack();
|
||||
ClickThroughEnabled = false;
|
||||
|
||||
//Restore main form in a platform-dependent method
|
||||
Program.Platform.RestoreForm(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a confirmation dialog to confirm whether to reset the main form or not.
|
||||
/// </summary>
|
||||
public void ResetMainFormWithConfirmation() {
|
||||
var dlg = new TaskDialog(Strings.AskReset, Strings.AskResetTitle, Strings.AskResetContent);
|
||||
dlg.UseCommandLinks = true;
|
||||
dlg.CustomButtons = new CustomButton[] {
|
||||
new CustomButton(CommonButtonResult.OK, Strings.AskResetButtonOk),
|
||||
new CustomButton(CommonButtonResult.Cancel, Strings.ButtonCancel)
|
||||
};
|
||||
dlg.CommonIcon = CommonIcon.Information;
|
||||
|
||||
if (dlg.Show(this).CommonButton == CommonButtonResult.OK) {
|
||||
ResetMainForm();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the main form to its initial state.
|
||||
/// </summary>
|
||||
public void ResetMainForm() {
|
||||
//Reset form settings
|
||||
UnsetThumbnail();
|
||||
CloseSidePanel();
|
||||
|
||||
//Reset location and size (edge of the screen, min size)
|
||||
Point nuLoc = Screen.PrimaryScreen.WorkingArea.Location;
|
||||
nuLoc.Offset(40, 40);
|
||||
Location = nuLoc;
|
||||
Size = new Size(240, 220);
|
||||
|
||||
this.Show();
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
|
||||
namespace OnTopReplica {
|
||||
partial class MainForm {
|
||||
|
||||
/// <summary>
|
||||
/// Opens the context menu.
|
||||
/// </summary>
|
||||
/// <param name="position">Optional position of the mouse, relative to which the menu is shown.</param>
|
||||
public void OpenContextMenu(Point? position) {
|
||||
Point menuPosition = MousePosition;
|
||||
if (position.HasValue)
|
||||
menuPosition = position.Value;
|
||||
|
||||
if (FullscreenManager.IsFullscreen) {
|
||||
menuFullscreenContext.Show(menuPosition);
|
||||
}
|
||||
else {
|
||||
menuContext.Show(menuPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window's vertical chrome size.
|
||||
/// </summary>
|
||||
public int ChromeBorderVertical {
|
||||
get {
|
||||
if (IsChromeVisible)
|
||||
return SystemInformation.FrameBorderSize.Height;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window's horizontal chrome size.
|
||||
/// </summary>
|
||||
public int ChromeBorderHorizontal {
|
||||
get {
|
||||
if (IsChromeVisible)
|
||||
return SystemInformation.FrameBorderSize.Width;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays an error task dialog.
|
||||
/// </summary>
|
||||
/// <param name="mainInstruction">Main instruction of the error dialog.</param>
|
||||
/// <param name="explanation">Detailed informations about the error.</param>
|
||||
/// <param name="errorMessage">Expanded error codes/messages.</param>
|
||||
private void ShowErrorDialog(string mainInstruction, string explanation, string errorMessage) {
|
||||
TaskDialog dlg = new TaskDialog(mainInstruction, Strings.ErrorGenericTitle, explanation) {
|
||||
CommonIcon = CommonIcon.Stop,
|
||||
IsExpanded = false
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMessage)) {
|
||||
dlg.ExpandedInformation = Strings.ErrorGenericInfoText + errorMessage;
|
||||
dlg.ExpandedControlText = Strings.ErrorGenericInfoButton;
|
||||
}
|
||||
|
||||
dlg.Show(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the main form is visible (either closing the fullscreen mode or reactivating from task icon).
|
||||
/// </summary>
|
||||
public void EnsureMainFormVisible() {
|
||||
//Reset special modes
|
||||
FullscreenManager.SwitchBack();
|
||||
ClickThroughEnabled = false;
|
||||
|
||||
//Restore main form in a platform-dependent method
|
||||
Program.Platform.RestoreForm(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a confirmation dialog to confirm whether to reset the main form or not.
|
||||
/// </summary>
|
||||
public void ResetMainFormWithConfirmation() {
|
||||
var dlg = new TaskDialog(Strings.AskReset, Strings.AskResetTitle, Strings.AskResetContent);
|
||||
dlg.UseCommandLinks = true;
|
||||
dlg.CustomButtons = new CustomButton[] {
|
||||
new CustomButton(CommonButtonResult.OK, Strings.AskResetButtonOk),
|
||||
new CustomButton(CommonButtonResult.Cancel, Strings.ButtonCancel)
|
||||
};
|
||||
dlg.CommonIcon = CommonIcon.Information;
|
||||
|
||||
if (dlg.Show(this).CommonButton == CommonButtonResult.OK) {
|
||||
ResetMainForm();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the main form to its initial state.
|
||||
/// </summary>
|
||||
public void ResetMainForm() {
|
||||
//Reset form settings
|
||||
UnsetThumbnail();
|
||||
CloseSidePanel();
|
||||
|
||||
//Reset location and size (edge of the screen, min size)
|
||||
Point nuLoc = Screen.PrimaryScreen.WorkingArea.Location;
|
||||
nuLoc.Offset(40, 40);
|
||||
Location = nuLoc;
|
||||
Size = new Size(240, 220);
|
||||
|
||||
this.Show();
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,202 +1,202 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Properties;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
using OnTopReplica.SidePanels;
|
||||
|
||||
namespace OnTopReplica {
|
||||
partial class MainForm {
|
||||
|
||||
private void Menu_opening(object sender, CancelEventArgs e) {
|
||||
//Cancel if currently in "fullscreen" mode or a side panel is open
|
||||
if (FullscreenManager.IsFullscreen || IsSidePanelOpen) {
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
bool showing = _thumbnailPanel.IsShowingThumbnail;
|
||||
|
||||
selectRegionToolStripMenuItem.Enabled = showing;
|
||||
switchToWindowToolStripMenuItem.Enabled = showing;
|
||||
resizeToolStripMenuItem.Enabled = showing;
|
||||
chromeToolStripMenuItem.Checked = IsChromeVisible;
|
||||
clickForwardingToolStripMenuItem.Checked = ClickForwardingEnabled;
|
||||
chromeToolStripMenuItem.Enabled = showing;
|
||||
clickThroughToolStripMenuItem.Enabled = showing;
|
||||
clickForwardingToolStripMenuItem.Enabled = showing;
|
||||
}
|
||||
|
||||
private void Menu_Switch_click(object sender, EventArgs e) {
|
||||
if (CurrentThumbnailWindowHandle == null)
|
||||
return;
|
||||
|
||||
Program.Platform.HideForm(this);
|
||||
Native.WindowManagerMethods.SetForegroundWindow(CurrentThumbnailWindowHandle.Handle);
|
||||
}
|
||||
|
||||
private void Menu_Advanced_opening(object sender, EventArgs e) {
|
||||
restoreLastClonedWindowToolStripMenuItem.Checked = Settings.Default.RestoreLastWindow;
|
||||
}
|
||||
|
||||
private void Menu_GroupSwitchMode_click(object sender, EventArgs e) {
|
||||
SetSidePanel(new SidePanels.GroupSwitchPanel());
|
||||
}
|
||||
|
||||
private void Menu_RestoreLastWindow_click(object sender, EventArgs e) {
|
||||
Settings.Default.RestoreLastWindow = !Settings.Default.RestoreLastWindow;
|
||||
}
|
||||
|
||||
private void Menu_ClickForwarding_click(object sender, EventArgs e) {
|
||||
ClickForwardingEnabled = !ClickForwardingEnabled;
|
||||
}
|
||||
|
||||
private void Menu_ClickThrough_click(object sender, EventArgs e) {
|
||||
ClickThroughEnabled = true;
|
||||
}
|
||||
|
||||
private void Menu_Opacity_opening(object sender, CancelEventArgs e) {
|
||||
ToolStripMenuItem[] items = {
|
||||
toolStripMenuItem1,
|
||||
toolStripMenuItem2,
|
||||
toolStripMenuItem3,
|
||||
toolStripMenuItem4
|
||||
};
|
||||
|
||||
foreach (ToolStripMenuItem i in items) {
|
||||
if (((double)i.Tag) == this.Opacity)
|
||||
i.Checked = true;
|
||||
else
|
||||
i.Checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Opacity_click(object sender, EventArgs e) {
|
||||
ToolStripMenuItem tsi = (ToolStripMenuItem)sender;
|
||||
|
||||
if (this.Visible) {
|
||||
//Target opacity is stored in the item's tag
|
||||
this.Opacity = (double)tsi.Tag;
|
||||
Program.Platform.OnFormStateChange(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Region_click(object sender, EventArgs e) {
|
||||
SetSidePanel(new OnTopReplica.SidePanels.RegionPanel());
|
||||
}
|
||||
|
||||
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) {
|
||||
FitToThumbnail(2.0);
|
||||
}
|
||||
|
||||
private void Menu_Resize_FitToWindow(object sender, EventArgs e) {
|
||||
FitToThumbnail(1.0);
|
||||
}
|
||||
|
||||
private void Menu_Resize_Half(object sender, EventArgs e) {
|
||||
FitToThumbnail(0.5);
|
||||
}
|
||||
|
||||
private void Menu_Resize_Quarter(object sender, EventArgs e) {
|
||||
FitToThumbnail(0.25);
|
||||
}
|
||||
|
||||
private void Menu_Resize_Fullscreen(object sender, EventArgs e) {
|
||||
FullscreenManager.SwitchFullscreen();
|
||||
}
|
||||
|
||||
private void Menu_Resize_RecallPosition_click(object sender, EventArgs e) {
|
||||
Settings.Default.RestoreSizeAndPosition = !Settings.Default.RestoreSizeAndPosition;
|
||||
}
|
||||
|
||||
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) {
|
||||
PositionLock = ScreenPosition.TopRight;
|
||||
}
|
||||
|
||||
private void Menu_Position_Center(object sender, EventArgs e) {
|
||||
PositionLock = ScreenPosition.Center;
|
||||
}
|
||||
|
||||
private void Menu_Position_BottomLeft(object sender, EventArgs e) {
|
||||
PositionLock = ScreenPosition.BottomLeft;
|
||||
}
|
||||
|
||||
private void Menu_Position_BottomRight(object sender, EventArgs e) {
|
||||
PositionLock = ScreenPosition.BottomRight;
|
||||
}
|
||||
|
||||
private void Menu_Reduce_click(object sender, EventArgs e) {
|
||||
//Hide form in a platform specific way
|
||||
Program.Platform.HideForm(this);
|
||||
}
|
||||
|
||||
private void Menu_Chrome_click(object sender, EventArgs e) {
|
||||
IsChromeVisible = !IsChromeVisible;
|
||||
}
|
||||
|
||||
private void Menu_Settings_click(object sender, EventArgs e) {
|
||||
this.SetSidePanel(new OptionsPanel());
|
||||
}
|
||||
|
||||
private void Menu_About_click(object sender, EventArgs e) {
|
||||
this.SetSidePanel(new AboutPanel());
|
||||
}
|
||||
|
||||
private void Menu_Close_click(object sender, EventArgs e) {
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_ExitFullscreen_click(object sender, EventArgs e) {
|
||||
FullscreenManager.SwitchBack();
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_opening(object sender, EventArgs e) {
|
||||
var mode = Settings.Default.GetFullscreenMode();
|
||||
|
||||
menuModeStandardToolStripMenuItem.Checked = (mode == FullscreenMode.Standard);
|
||||
menuModeFullscreenToolStripMenuItem.Checked = (mode == FullscreenMode.Fullscreen);
|
||||
menuModeAllScreensToolStripMenuItem.Checked = (mode == FullscreenMode.AllScreens);
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_Standard_click(object sender, EventArgs e) {
|
||||
Settings.Default.SetFullscreenMode(FullscreenMode.Standard);
|
||||
FullscreenManager.SwitchFullscreen(FullscreenMode.Standard);
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_Fullscreen_click(object sender, EventArgs e) {
|
||||
Settings.Default.SetFullscreenMode(FullscreenMode.Fullscreen);
|
||||
FullscreenManager.SwitchFullscreen(FullscreenMode.Fullscreen);
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_AllScreens_click(object sender, EventArgs e) {
|
||||
Settings.Default.SetFullscreenMode(FullscreenMode.AllScreens);
|
||||
FullscreenManager.SwitchFullscreen(FullscreenMode.AllScreens);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Properties;
|
||||
using WindowsFormsAero.TaskDialog;
|
||||
using OnTopReplica.SidePanels;
|
||||
|
||||
namespace OnTopReplica {
|
||||
partial class MainForm {
|
||||
|
||||
private void Menu_opening(object sender, CancelEventArgs e) {
|
||||
//Cancel if currently in "fullscreen" mode or a side panel is open
|
||||
if (FullscreenManager.IsFullscreen || IsSidePanelOpen) {
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
bool showing = _thumbnailPanel.IsShowingThumbnail;
|
||||
|
||||
selectRegionToolStripMenuItem.Enabled = showing;
|
||||
switchToWindowToolStripMenuItem.Enabled = showing;
|
||||
resizeToolStripMenuItem.Enabled = showing;
|
||||
chromeToolStripMenuItem.Checked = IsChromeVisible;
|
||||
clickForwardingToolStripMenuItem.Checked = ClickForwardingEnabled;
|
||||
chromeToolStripMenuItem.Enabled = showing;
|
||||
clickThroughToolStripMenuItem.Enabled = showing;
|
||||
clickForwardingToolStripMenuItem.Enabled = showing;
|
||||
}
|
||||
|
||||
private void Menu_Switch_click(object sender, EventArgs e) {
|
||||
if (CurrentThumbnailWindowHandle == null)
|
||||
return;
|
||||
|
||||
Program.Platform.HideForm(this);
|
||||
Native.WindowManagerMethods.SetForegroundWindow(CurrentThumbnailWindowHandle.Handle);
|
||||
}
|
||||
|
||||
private void Menu_Advanced_opening(object sender, EventArgs e) {
|
||||
restoreLastClonedWindowToolStripMenuItem.Checked = Settings.Default.RestoreLastWindow;
|
||||
}
|
||||
|
||||
private void Menu_GroupSwitchMode_click(object sender, EventArgs e) {
|
||||
SetSidePanel(new SidePanels.GroupSwitchPanel());
|
||||
}
|
||||
|
||||
private void Menu_RestoreLastWindow_click(object sender, EventArgs e) {
|
||||
Settings.Default.RestoreLastWindow = !Settings.Default.RestoreLastWindow;
|
||||
}
|
||||
|
||||
private void Menu_ClickForwarding_click(object sender, EventArgs e) {
|
||||
ClickForwardingEnabled = !ClickForwardingEnabled;
|
||||
}
|
||||
|
||||
private void Menu_ClickThrough_click(object sender, EventArgs e) {
|
||||
ClickThroughEnabled = true;
|
||||
}
|
||||
|
||||
private void Menu_Opacity_opening(object sender, CancelEventArgs e) {
|
||||
ToolStripMenuItem[] items = {
|
||||
toolStripMenuItem1,
|
||||
toolStripMenuItem2,
|
||||
toolStripMenuItem3,
|
||||
toolStripMenuItem4
|
||||
};
|
||||
|
||||
foreach (ToolStripMenuItem i in items) {
|
||||
if (((double)i.Tag) == this.Opacity)
|
||||
i.Checked = true;
|
||||
else
|
||||
i.Checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Opacity_click(object sender, EventArgs e) {
|
||||
ToolStripMenuItem tsi = (ToolStripMenuItem)sender;
|
||||
|
||||
if (this.Visible) {
|
||||
//Target opacity is stored in the item's tag
|
||||
this.Opacity = (double)tsi.Tag;
|
||||
Program.Platform.OnFormStateChange(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Region_click(object sender, EventArgs e) {
|
||||
SetSidePanel(new OnTopReplica.SidePanels.RegionPanel());
|
||||
}
|
||||
|
||||
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) {
|
||||
FitToThumbnail(2.0);
|
||||
}
|
||||
|
||||
private void Menu_Resize_FitToWindow(object sender, EventArgs e) {
|
||||
FitToThumbnail(1.0);
|
||||
}
|
||||
|
||||
private void Menu_Resize_Half(object sender, EventArgs e) {
|
||||
FitToThumbnail(0.5);
|
||||
}
|
||||
|
||||
private void Menu_Resize_Quarter(object sender, EventArgs e) {
|
||||
FitToThumbnail(0.25);
|
||||
}
|
||||
|
||||
private void Menu_Resize_Fullscreen(object sender, EventArgs e) {
|
||||
FullscreenManager.SwitchFullscreen();
|
||||
}
|
||||
|
||||
private void Menu_Resize_RecallPosition_click(object sender, EventArgs e) {
|
||||
Settings.Default.RestoreSizeAndPosition = !Settings.Default.RestoreSizeAndPosition;
|
||||
}
|
||||
|
||||
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) {
|
||||
PositionLock = ScreenPosition.TopRight;
|
||||
}
|
||||
|
||||
private void Menu_Position_Center(object sender, EventArgs e) {
|
||||
PositionLock = ScreenPosition.Center;
|
||||
}
|
||||
|
||||
private void Menu_Position_BottomLeft(object sender, EventArgs e) {
|
||||
PositionLock = ScreenPosition.BottomLeft;
|
||||
}
|
||||
|
||||
private void Menu_Position_BottomRight(object sender, EventArgs e) {
|
||||
PositionLock = ScreenPosition.BottomRight;
|
||||
}
|
||||
|
||||
private void Menu_Reduce_click(object sender, EventArgs e) {
|
||||
//Hide form in a platform specific way
|
||||
Program.Platform.HideForm(this);
|
||||
}
|
||||
|
||||
private void Menu_Chrome_click(object sender, EventArgs e) {
|
||||
IsChromeVisible = !IsChromeVisible;
|
||||
}
|
||||
|
||||
private void Menu_Settings_click(object sender, EventArgs e) {
|
||||
this.SetSidePanel(new OptionsPanel());
|
||||
}
|
||||
|
||||
private void Menu_About_click(object sender, EventArgs e) {
|
||||
this.SetSidePanel(new AboutPanel());
|
||||
}
|
||||
|
||||
private void Menu_Close_click(object sender, EventArgs e) {
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_ExitFullscreen_click(object sender, EventArgs e) {
|
||||
FullscreenManager.SwitchBack();
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_opening(object sender, EventArgs e) {
|
||||
var mode = Settings.Default.GetFullscreenMode();
|
||||
|
||||
menuModeStandardToolStripMenuItem.Checked = (mode == FullscreenMode.Standard);
|
||||
menuModeFullscreenToolStripMenuItem.Checked = (mode == FullscreenMode.Fullscreen);
|
||||
menuModeAllScreensToolStripMenuItem.Checked = (mode == FullscreenMode.AllScreens);
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_Standard_click(object sender, EventArgs e) {
|
||||
Settings.Default.SetFullscreenMode(FullscreenMode.Standard);
|
||||
FullscreenManager.SwitchFullscreen(FullscreenMode.Standard);
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_Fullscreen_click(object sender, EventArgs e) {
|
||||
Settings.Default.SetFullscreenMode(FullscreenMode.Fullscreen);
|
||||
FullscreenManager.SwitchFullscreen(FullscreenMode.Fullscreen);
|
||||
}
|
||||
|
||||
private void Menu_Fullscreen_Mode_AllScreens_click(object sender, EventArgs e) {
|
||||
Settings.Default.SetFullscreenMode(FullscreenMode.AllScreens);
|
||||
FullscreenManager.SwitchFullscreen(FullscreenMode.AllScreens);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,85 +1,85 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.MessagePumpProcessors;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class MessagePumpManager : IDisposable {
|
||||
|
||||
Dictionary<Type, IMessagePumpProcessor> _processors = new Dictionary<Type, IMessagePumpProcessor>();
|
||||
|
||||
public MainForm Form { get; private set; }
|
||||
|
||||
private void Register(IMessagePumpProcessor processor, MainForm form) {
|
||||
_processors[processor.GetType()] = processor;
|
||||
processor.Initialize(form);
|
||||
|
||||
Log.Write("Registered message pump processor {0}", processor.GetType());
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
//Register window shell hook
|
||||
if (!HookMethods.RegisterShellHookWindow(form.Handle)) {
|
||||
Log.Write("Failed to register shell hook window");
|
||||
}
|
||||
else {
|
||||
Log.Write("Shell hook window registered successfully");
|
||||
}
|
||||
|
||||
//Register message pump processors
|
||||
Register(new WindowKeeper(), form);
|
||||
Register(new HotKeyManager(), form);
|
||||
Register(new GroupSwitchManager(), form);
|
||||
Register(new FlashCloner(), form);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the registered message pump processors.
|
||||
/// </summary>
|
||||
/// <param name="msg">Message to process.</param>
|
||||
/// <returns>True if the message has been handled internally.</returns>
|
||||
public bool PumpMessage(ref Message msg) {
|
||||
foreach (var processor in _processors.Values) {
|
||||
if (processor.Process(ref msg))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the instance of a registered message pump processor.
|
||||
/// Throws if instance not found.
|
||||
/// </summary>
|
||||
public T Get<T>() {
|
||||
return (T)_processors[typeof(T)];
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose() {
|
||||
if (!HookMethods.DeregisterShellHookWindow(Form.Handle)) {
|
||||
Log.Write("Failed to deregister shell hook window");
|
||||
}
|
||||
else {
|
||||
Log.Write("Deregistered shell hook window successfully");
|
||||
}
|
||||
|
||||
foreach (var processor in _processors.Values) {
|
||||
processor.Dispose();
|
||||
}
|
||||
_processors.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.MessagePumpProcessors;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica {
|
||||
class MessagePumpManager : IDisposable {
|
||||
|
||||
Dictionary<Type, IMessagePumpProcessor> _processors = new Dictionary<Type, IMessagePumpProcessor>();
|
||||
|
||||
public MainForm Form { get; private set; }
|
||||
|
||||
private void Register(IMessagePumpProcessor processor, MainForm form) {
|
||||
_processors[processor.GetType()] = processor;
|
||||
processor.Initialize(form);
|
||||
|
||||
Log.Write("Registered message pump processor {0}", processor.GetType());
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
//Register window shell hook
|
||||
if (!HookMethods.RegisterShellHookWindow(form.Handle)) {
|
||||
Log.Write("Failed to register shell hook window");
|
||||
}
|
||||
else {
|
||||
Log.Write("Shell hook window registered successfully");
|
||||
}
|
||||
|
||||
//Register message pump processors
|
||||
Register(new WindowKeeper(), form);
|
||||
Register(new HotKeyManager(), form);
|
||||
Register(new GroupSwitchManager(), form);
|
||||
Register(new FlashCloner(), form);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the registered message pump processors.
|
||||
/// </summary>
|
||||
/// <param name="msg">Message to process.</param>
|
||||
/// <returns>True if the message has been handled internally.</returns>
|
||||
public bool PumpMessage(ref Message msg) {
|
||||
foreach (var processor in _processors.Values) {
|
||||
if (processor.Process(ref msg))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the instance of a registered message pump processor.
|
||||
/// Throws if instance not found.
|
||||
/// </summary>
|
||||
public T Get<T>() {
|
||||
return (T)_processors[typeof(T)];
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose() {
|
||||
if (!HookMethods.DeregisterShellHookWindow(Form.Handle)) {
|
||||
Log.Write("Failed to deregister shell hook window");
|
||||
}
|
||||
else {
|
||||
Log.Write("Deregistered shell hook window successfully");
|
||||
}
|
||||
|
||||
foreach (var processor in _processors.Values) {
|
||||
processor.Dispose();
|
||||
}
|
||||
_processors.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
abstract class BaseMessagePumpProcessor : IMessagePumpProcessor {
|
||||
|
||||
protected MainForm Form { get; private set; }
|
||||
|
||||
#region IMessagePumpProcessor Members
|
||||
|
||||
public virtual void Initialize(MainForm form) {
|
||||
Form = form;
|
||||
}
|
||||
|
||||
public abstract bool Process(ref Message msg);
|
||||
|
||||
#endregion
|
||||
|
||||
protected abstract void Shutdown();
|
||||
|
||||
bool _isDisposed = false;
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose() {
|
||||
if (_isDisposed)
|
||||
return;
|
||||
|
||||
Shutdown();
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
abstract class BaseMessagePumpProcessor : IMessagePumpProcessor {
|
||||
|
||||
protected MainForm Form { get; private set; }
|
||||
|
||||
#region IMessagePumpProcessor Members
|
||||
|
||||
public virtual void Initialize(MainForm form) {
|
||||
Form = form;
|
||||
}
|
||||
|
||||
public abstract bool Process(ref Message msg);
|
||||
|
||||
#endregion
|
||||
|
||||
protected abstract void Shutdown();
|
||||
|
||||
bool _isDisposed = false;
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose() {
|
||||
if (_isDisposed)
|
||||
return;
|
||||
|
||||
Shutdown();
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -1,35 +1,35 @@
|
|||
using OnTopReplica.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
/// <summary>
|
||||
/// Automatically clones windows that are flashing.
|
||||
/// </summary>
|
||||
class FlashCloner : BaseMessagePumpProcessor {
|
||||
|
||||
public override bool Process(ref System.Windows.Forms.Message msg) {
|
||||
if (false &&
|
||||
msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
|
||||
if (hookCode == HookMethods.HSHELL_FLASH) {
|
||||
IntPtr flashHandle = msg.LParam;
|
||||
|
||||
Form.SetThumbnail(new WindowHandle(flashHandle), null);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using OnTopReplica.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
/// <summary>
|
||||
/// Automatically clones windows that are flashing.
|
||||
/// </summary>
|
||||
class FlashCloner : BaseMessagePumpProcessor {
|
||||
|
||||
public override bool Process(ref System.Windows.Forms.Message msg) {
|
||||
if (false &&
|
||||
msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
|
||||
if (hookCode == HookMethods.HSHELL_FLASH) {
|
||||
IntPtr flashHandle = msg.LParam;
|
||||
|
||||
Form.SetThumbnail(new WindowHandle(flashHandle), null);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,133 +1,133 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
class GroupSwitchManager : BaseMessagePumpProcessor {
|
||||
|
||||
bool _active = false;
|
||||
List<WindowHandleWrapper> _lruHandles;
|
||||
|
||||
/// <summary>
|
||||
/// Enables group switch mode.
|
||||
/// </summary>
|
||||
/// <param name="handles">List of window handles to track.</param>
|
||||
public void EnableGroupMode(IList<WindowHandle> handles) {
|
||||
if (handles == null || handles.Count == 0)
|
||||
return;
|
||||
|
||||
//Okey dokey, will now track handles
|
||||
TrackHandles(handles);
|
||||
_active = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the LRU sorted list of window handles.
|
||||
/// </summary>
|
||||
private void TrackHandles(IList<WindowHandle> handles) {
|
||||
_lruHandles = new List<WindowHandleWrapper>(handles.Count);
|
||||
var now = DateTime.Now;
|
||||
|
||||
foreach(var h in handles){
|
||||
_lruHandles.Add(new WindowHandleWrapper {
|
||||
WindowHandle = h,
|
||||
LastTimeUsed = now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables group switch mode.
|
||||
/// </summary>
|
||||
public void Disable() {
|
||||
if (!_active)
|
||||
return;
|
||||
|
||||
_lruHandles = null;
|
||||
_active = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the message pump.
|
||||
/// </summary>
|
||||
public override bool Process(ref Message msg) {
|
||||
if (_active && msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
if (hookCode == HookMethods.HSHELL_WINDOWACTIVATED ||
|
||||
hookCode == HookMethods.HSHELL_RUDEAPPACTIVATED) {
|
||||
|
||||
IntPtr activeHandle = msg.LParam;
|
||||
HandleForegroundWindowChange(activeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void HandleForegroundWindowChange(IntPtr activeWindow) {
|
||||
//Seek window in tracked handles
|
||||
WindowHandleWrapper activated = null;
|
||||
foreach (var i in _lruHandles) {
|
||||
if (i.WindowHandle.Handle == activeWindow)
|
||||
activated = i;
|
||||
}
|
||||
|
||||
if (activated == null) {
|
||||
//New foreground window is not tracked
|
||||
return;
|
||||
}
|
||||
|
||||
//Update tracked handle
|
||||
activated.LastTimeUsed = DateTime.Now;
|
||||
_lruHandles.Sort(new LruDateTimeComparer());
|
||||
|
||||
//Get least recently used
|
||||
var next = _lruHandles[0];
|
||||
|
||||
Log.Write("Switched to tracked window: switching to {0} (last use: {1})", next.WindowHandle.Title, next.LastTimeUsed);
|
||||
|
||||
Form.SetThumbnail(next.WindowHandle, null);
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
Disable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the group switch manager ia active.
|
||||
/// </summary>
|
||||
public bool IsActive {
|
||||
get {
|
||||
return _active;
|
||||
}
|
||||
}
|
||||
|
||||
#region List sorting stuff
|
||||
|
||||
class WindowHandleWrapper {
|
||||
public WindowHandle WindowHandle { get; set; }
|
||||
public DateTime LastTimeUsed { get; set; }
|
||||
}
|
||||
|
||||
class LruDateTimeComparer : IComparer<WindowHandleWrapper> {
|
||||
|
||||
#region IComparer<WindowHandleWrapper> Members
|
||||
|
||||
public int Compare(WindowHandleWrapper x, WindowHandleWrapper y) {
|
||||
return x.LastTimeUsed.CompareTo(y.LastTimeUsed);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
class GroupSwitchManager : BaseMessagePumpProcessor {
|
||||
|
||||
bool _active = false;
|
||||
List<WindowHandleWrapper> _lruHandles;
|
||||
|
||||
/// <summary>
|
||||
/// Enables group switch mode.
|
||||
/// </summary>
|
||||
/// <param name="handles">List of window handles to track.</param>
|
||||
public void EnableGroupMode(IList<WindowHandle> handles) {
|
||||
if (handles == null || handles.Count == 0)
|
||||
return;
|
||||
|
||||
//Okey dokey, will now track handles
|
||||
TrackHandles(handles);
|
||||
_active = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the LRU sorted list of window handles.
|
||||
/// </summary>
|
||||
private void TrackHandles(IList<WindowHandle> handles) {
|
||||
_lruHandles = new List<WindowHandleWrapper>(handles.Count);
|
||||
var now = DateTime.Now;
|
||||
|
||||
foreach(var h in handles){
|
||||
_lruHandles.Add(new WindowHandleWrapper {
|
||||
WindowHandle = h,
|
||||
LastTimeUsed = now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables group switch mode.
|
||||
/// </summary>
|
||||
public void Disable() {
|
||||
if (!_active)
|
||||
return;
|
||||
|
||||
_lruHandles = null;
|
||||
_active = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the message pump.
|
||||
/// </summary>
|
||||
public override bool Process(ref Message msg) {
|
||||
if (_active && msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
if (hookCode == HookMethods.HSHELL_WINDOWACTIVATED ||
|
||||
hookCode == HookMethods.HSHELL_RUDEAPPACTIVATED) {
|
||||
|
||||
IntPtr activeHandle = msg.LParam;
|
||||
HandleForegroundWindowChange(activeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void HandleForegroundWindowChange(IntPtr activeWindow) {
|
||||
//Seek window in tracked handles
|
||||
WindowHandleWrapper activated = null;
|
||||
foreach (var i in _lruHandles) {
|
||||
if (i.WindowHandle.Handle == activeWindow)
|
||||
activated = i;
|
||||
}
|
||||
|
||||
if (activated == null) {
|
||||
//New foreground window is not tracked
|
||||
return;
|
||||
}
|
||||
|
||||
//Update tracked handle
|
||||
activated.LastTimeUsed = DateTime.Now;
|
||||
_lruHandles.Sort(new LruDateTimeComparer());
|
||||
|
||||
//Get least recently used
|
||||
var next = _lruHandles[0];
|
||||
|
||||
Log.Write("Switched to tracked window: switching to {0} (last use: {1})", next.WindowHandle.Title, next.LastTimeUsed);
|
||||
|
||||
Form.SetThumbnail(next.WindowHandle, null);
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
Disable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the group switch manager ia active.
|
||||
/// </summary>
|
||||
public bool IsActive {
|
||||
get {
|
||||
return _active;
|
||||
}
|
||||
}
|
||||
|
||||
#region List sorting stuff
|
||||
|
||||
class WindowHandleWrapper {
|
||||
public WindowHandle WindowHandle { get; set; }
|
||||
public DateTime LastTimeUsed { get; set; }
|
||||
}
|
||||
|
||||
class LruDateTimeComparer : IComparer<WindowHandleWrapper> {
|
||||
|
||||
#region IComparer<WindowHandleWrapper> Members
|
||||
|
||||
public int Compare(WindowHandleWrapper x, WindowHandleWrapper y) {
|
||||
return x.LastTimeUsed.CompareTo(y.LastTimeUsed);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,167 +1,167 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
using OnTopReplica.Properties;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
/// <summary>
|
||||
/// HotKey registration helper.
|
||||
/// </summary>
|
||||
class HotKeyManager : BaseMessagePumpProcessor {
|
||||
|
||||
public HotKeyManager() {
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
delegate void HotKeyHandler();
|
||||
|
||||
/// <summary>
|
||||
/// Wraps hot key handler registration data.
|
||||
/// </summary>
|
||||
private class HotKeyHandlerRegistration : IDisposable {
|
||||
private HotKeyHandlerRegistration() {
|
||||
}
|
||||
|
||||
private HotKeyHandlerRegistration(IntPtr hwnd, int key, HotKeyHandler handler) {
|
||||
if (hwnd == IntPtr.Zero)
|
||||
throw new ArgumentException();
|
||||
if (handler == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
_hwnd = hwnd;
|
||||
RegistrationKey = key;
|
||||
Handler = handler;
|
||||
}
|
||||
|
||||
static int _lastUsedKey = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new hotkey and returns a handle to the registration.
|
||||
/// </summary>
|
||||
/// <returns>Returns null on failure.</returns>
|
||||
public static HotKeyHandlerRegistration Register(Form owner, int keyCode, int modifiers, HotKeyHandler handler) {
|
||||
var key = ++_lastUsedKey;
|
||||
|
||||
if (!HotKeyMethods.RegisterHotKey(owner.Handle, key, modifiers, keyCode)) {
|
||||
Log.Write("Failed to create hotkey on key {0} with modifiers {1}", keyCode, modifiers);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new HotKeyHandlerRegistration(owner.Handle, key, handler);
|
||||
}
|
||||
|
||||
IntPtr _hwnd;
|
||||
public int RegistrationKey { get; private set; }
|
||||
public HotKeyHandler Handler { get; private set; }
|
||||
|
||||
public void Dispose() {
|
||||
if (!HotKeyMethods.UnregisterHotKey(_hwnd, RegistrationKey)) {
|
||||
Log.Write("Failed to unregister hotkey #{0}", RegistrationKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<int, HotKeyHandlerRegistration> _handlers = new Dictionary<int, HotKeyHandlerRegistration>();
|
||||
|
||||
public override void Initialize(MainForm form) {
|
||||
base.Initialize(form);
|
||||
|
||||
RefreshHotkeys();
|
||||
}
|
||||
|
||||
public override bool Process(ref Message msg) {
|
||||
if (Enabled && msg.Msg == HotKeyMethods.WM_HOTKEY) {
|
||||
int keyId = msg.WParam.ToInt32();
|
||||
if (!_handlers.ContainsKey(keyId))
|
||||
return false;
|
||||
|
||||
_handlers[keyId].Handler.Invoke();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes registered hotkeys from Settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Application settings contain hotkey registration strings that are used
|
||||
/// automatically by this registration process.
|
||||
/// </remarks>
|
||||
public void RefreshHotkeys() {
|
||||
ClearHandlers();
|
||||
|
||||
RegisterHandler(Settings.Default.HotKeyCloneCurrent, HotKeyCloneHandler);
|
||||
RegisterHandler(Settings.Default.HotKeyShowHide, HotKeyShowHideHandler);
|
||||
}
|
||||
|
||||
private void RegisterHandler(string spec, HotKeyHandler handler) {
|
||||
if (string.IsNullOrEmpty(spec))
|
||||
return; //this can happen and is allowed => simply don't register
|
||||
if (handler == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
int modifiers = 0, keyCode = 0;
|
||||
|
||||
try {
|
||||
HotKeyMethods.TranslateStringToKeyValues(spec, out modifiers, out keyCode);
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
//TODO: swallowed exception
|
||||
return;
|
||||
}
|
||||
|
||||
var reg = HotKeyHandlerRegistration.Register(Form, keyCode, modifiers, handler);
|
||||
if(reg != null)
|
||||
_handlers.Add(reg.RegistrationKey, reg);
|
||||
}
|
||||
|
||||
private void ClearHandlers() {
|
||||
foreach (var hotkey in _handlers) {
|
||||
hotkey.Value.Dispose();
|
||||
}
|
||||
_handlers.Clear();
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
ClearHandlers();
|
||||
}
|
||||
|
||||
#region Hotkey callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Handles "show/hide" hotkey. Ensures the form is in restored state and switches
|
||||
/// between shown and hidden states.
|
||||
/// </summary>
|
||||
void HotKeyShowHideHandler() {
|
||||
Form.FullscreenManager.SwitchBack();
|
||||
|
||||
if (!Program.Platform.IsHidden(Form)) {
|
||||
Program.Platform.HideForm(Form);
|
||||
}
|
||||
else {
|
||||
Form.EnsureMainFormVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the "clone current" hotkey.
|
||||
/// </summary>
|
||||
void HotKeyCloneHandler() {
|
||||
var handle = Win32Helper.GetCurrentForegroundWindow();
|
||||
if (handle.Handle == Form.Handle)
|
||||
return;
|
||||
|
||||
Form.SetThumbnail(handle, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
using OnTopReplica.Properties;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
/// <summary>
|
||||
/// HotKey registration helper.
|
||||
/// </summary>
|
||||
class HotKeyManager : BaseMessagePumpProcessor {
|
||||
|
||||
public HotKeyManager() {
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
delegate void HotKeyHandler();
|
||||
|
||||
/// <summary>
|
||||
/// Wraps hot key handler registration data.
|
||||
/// </summary>
|
||||
private class HotKeyHandlerRegistration : IDisposable {
|
||||
private HotKeyHandlerRegistration() {
|
||||
}
|
||||
|
||||
private HotKeyHandlerRegistration(IntPtr hwnd, int key, HotKeyHandler handler) {
|
||||
if (hwnd == IntPtr.Zero)
|
||||
throw new ArgumentException();
|
||||
if (handler == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
_hwnd = hwnd;
|
||||
RegistrationKey = key;
|
||||
Handler = handler;
|
||||
}
|
||||
|
||||
static int _lastUsedKey = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new hotkey and returns a handle to the registration.
|
||||
/// </summary>
|
||||
/// <returns>Returns null on failure.</returns>
|
||||
public static HotKeyHandlerRegistration Register(Form owner, int keyCode, int modifiers, HotKeyHandler handler) {
|
||||
var key = ++_lastUsedKey;
|
||||
|
||||
if (!HotKeyMethods.RegisterHotKey(owner.Handle, key, modifiers, keyCode)) {
|
||||
Log.Write("Failed to create hotkey on key {0} with modifiers {1}", keyCode, modifiers);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new HotKeyHandlerRegistration(owner.Handle, key, handler);
|
||||
}
|
||||
|
||||
IntPtr _hwnd;
|
||||
public int RegistrationKey { get; private set; }
|
||||
public HotKeyHandler Handler { get; private set; }
|
||||
|
||||
public void Dispose() {
|
||||
if (!HotKeyMethods.UnregisterHotKey(_hwnd, RegistrationKey)) {
|
||||
Log.Write("Failed to unregister hotkey #{0}", RegistrationKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<int, HotKeyHandlerRegistration> _handlers = new Dictionary<int, HotKeyHandlerRegistration>();
|
||||
|
||||
public override void Initialize(MainForm form) {
|
||||
base.Initialize(form);
|
||||
|
||||
RefreshHotkeys();
|
||||
}
|
||||
|
||||
public override bool Process(ref Message msg) {
|
||||
if (Enabled && msg.Msg == HotKeyMethods.WM_HOTKEY) {
|
||||
int keyId = msg.WParam.ToInt32();
|
||||
if (!_handlers.ContainsKey(keyId))
|
||||
return false;
|
||||
|
||||
_handlers[keyId].Handler.Invoke();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes registered hotkeys from Settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Application settings contain hotkey registration strings that are used
|
||||
/// automatically by this registration process.
|
||||
/// </remarks>
|
||||
public void RefreshHotkeys() {
|
||||
ClearHandlers();
|
||||
|
||||
RegisterHandler(Settings.Default.HotKeyCloneCurrent, HotKeyCloneHandler);
|
||||
RegisterHandler(Settings.Default.HotKeyShowHide, HotKeyShowHideHandler);
|
||||
}
|
||||
|
||||
private void RegisterHandler(string spec, HotKeyHandler handler) {
|
||||
if (string.IsNullOrEmpty(spec))
|
||||
return; //this can happen and is allowed => simply don't register
|
||||
if (handler == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
int modifiers = 0, keyCode = 0;
|
||||
|
||||
try {
|
||||
HotKeyMethods.TranslateStringToKeyValues(spec, out modifiers, out keyCode);
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
//TODO: swallowed exception
|
||||
return;
|
||||
}
|
||||
|
||||
var reg = HotKeyHandlerRegistration.Register(Form, keyCode, modifiers, handler);
|
||||
if(reg != null)
|
||||
_handlers.Add(reg.RegistrationKey, reg);
|
||||
}
|
||||
|
||||
private void ClearHandlers() {
|
||||
foreach (var hotkey in _handlers) {
|
||||
hotkey.Value.Dispose();
|
||||
}
|
||||
_handlers.Clear();
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
ClearHandlers();
|
||||
}
|
||||
|
||||
#region Hotkey callbacks
|
||||
|
||||
/// <summary>
|
||||
/// Handles "show/hide" hotkey. Ensures the form is in restored state and switches
|
||||
/// between shown and hidden states.
|
||||
/// </summary>
|
||||
void HotKeyShowHideHandler() {
|
||||
Form.FullscreenManager.SwitchBack();
|
||||
|
||||
if (!Program.Platform.IsHidden(Form)) {
|
||||
Program.Platform.HideForm(Form);
|
||||
}
|
||||
else {
|
||||
Form.EnsureMainFormVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the "clone current" hotkey.
|
||||
/// </summary>
|
||||
void HotKeyCloneHandler() {
|
||||
var handle = Win32Helper.GetCurrentForegroundWindow();
|
||||
if (handle.Handle == Form.Handle)
|
||||
return;
|
||||
|
||||
Form.SetThumbnail(handle, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,34 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
#if DEBUG
|
||||
|
||||
/// <summary>
|
||||
/// Basic shell message interceptor to use for debugging.
|
||||
/// </summary>
|
||||
class ShellInterceptProcessor : BaseMessagePumpProcessor {
|
||||
|
||||
public override bool Process(ref Message msg) {
|
||||
if (msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
|
||||
Log.Write("Hook msg #{0}: {1}", hookCode, msg.LParam);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using OnTopReplica.Native;
|
||||
|
||||
namespace OnTopReplica.MessagePumpProcessors {
|
||||
|
||||
#if DEBUG
|
||||
|
||||
/// <summary>
|
||||
/// Basic shell message interceptor to use for debugging.
|
||||
/// </summary>
|
||||
class ShellInterceptProcessor : BaseMessagePumpProcessor {
|
||||
|
||||
public override bool Process(ref Message msg) {
|
||||
if (msg.Msg == HookMethods.WM_SHELLHOOKMESSAGE) {
|
||||
int hookCode = msg.WParam.ToInt32();
|
||||
|
||||
Log.Write("Hook msg #{0}: {1}", hookCode, msg.LParam);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
|
@ -1,40 +1,40 @@
|
|||
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 bool Process(ref 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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 bool Process(ref 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Shutdown() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,30 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
public static class CommonControls {
|
||||
|
||||
[DllImport("comctl32.dll", EntryPoint = "InitCommonControlsEx", CallingConvention = CallingConvention.StdCall)]
|
||||
static extern bool InitCommonControlsEx(ref INITCOMMONCONTROLSEX iccex);
|
||||
|
||||
const int ICC_STANDARD_CLASSES = 0x00004000;
|
||||
const int ICC_WIN95_CLASSES = 0x000000FF;
|
||||
|
||||
public static bool InitStandard() {
|
||||
INITCOMMONCONTROLSEX ex = new INITCOMMONCONTROLSEX();
|
||||
ex.dwSize = 8;
|
||||
ex.dwICC = ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
|
||||
|
||||
return InitCommonControlsEx(ref ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct INITCOMMONCONTROLSEX {
|
||||
public int dwSize;
|
||||
public int dwICC;
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
public static class CommonControls {
|
||||
|
||||
[DllImport("comctl32.dll", EntryPoint = "InitCommonControlsEx", CallingConvention = CallingConvention.StdCall)]
|
||||
static extern bool InitCommonControlsEx(ref INITCOMMONCONTROLSEX iccex);
|
||||
|
||||
const int ICC_STANDARD_CLASSES = 0x00004000;
|
||||
const int ICC_WIN95_CLASSES = 0x000000FF;
|
||||
|
||||
public static bool InitStandard() {
|
||||
INITCOMMONCONTROLSEX ex = new INITCOMMONCONTROLSEX();
|
||||
ex.dwSize = 8;
|
||||
ex.dwICC = ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
|
||||
|
||||
return InitCommonControlsEx(ref ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct INITCOMMONCONTROLSEX {
|
||||
public int dwSize;
|
||||
public int dwICC;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
/// <summary>
|
||||
/// Common Win32 error handling methods.
|
||||
/// </summary>
|
||||
static class ErrorMethods {
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
|
||||
int dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer,
|
||||
uint nSize, IntPtr Arguments);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of a Win32 error code.
|
||||
/// </summary>
|
||||
/// <param name="msgCode">ID of the Win32 error code.</param>
|
||||
/// <returns>String representation of the error.</returns>
|
||||
public static string GetErrorMessage(int msgCode) {
|
||||
var sb = new StringBuilder(300);
|
||||
FormatMessage((uint)(0x00001000), IntPtr.Zero, msgCode, 0, sb, 299, IntPtr.Zero);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the last Win32 error on this thread.
|
||||
/// </summary>
|
||||
public static string GetLastErrorMessage() {
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
return GetErrorMessage(errorCode);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
/// <summary>
|
||||
/// Common Win32 error handling methods.
|
||||
/// </summary>
|
||||
static class ErrorMethods {
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
|
||||
int dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer,
|
||||
uint nSize, IntPtr Arguments);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of a Win32 error code.
|
||||
/// </summary>
|
||||
/// <param name="msgCode">ID of the Win32 error code.</param>
|
||||
/// <returns>String representation of the error.</returns>
|
||||
public static string GetErrorMessage(int msgCode) {
|
||||
var sb = new StringBuilder(300);
|
||||
FormatMessage((uint)(0x00001000), IntPtr.Zero, msgCode, 0, sb, 299, IntPtr.Zero);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the last Win32 error on this thread.
|
||||
/// </summary>
|
||||
public static string GetLastErrorMessage() {
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
return GetErrorMessage(errorCode);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,51 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
|
||||
/// <summary>
|
||||
/// Native methods for filesystem interop.
|
||||
/// </summary>
|
||||
static class FilesystemMethods {
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the current user's download path.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Code taken from http://stackoverflow.com/questions/3795023/downloads-folder-not-special-enough
|
||||
/// </remarks>
|
||||
public static string DownloadsPath {
|
||||
get {
|
||||
string path = null;
|
||||
|
||||
//Requires Vista or superior
|
||||
if (Environment.OSVersion.Version.Major >= 6) {
|
||||
IntPtr pathPtr;
|
||||
Guid folderId = FolderDownloads;
|
||||
int hr = SHGetKnownFolderPath(ref folderId, 0, IntPtr.Zero, out pathPtr);
|
||||
if (hr == 0) {
|
||||
path = Marshal.PtrToStringUni(pathPtr);
|
||||
Marshal.FreeCoTaskMem(pathPtr);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
//Fallback code
|
||||
path = Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
|
||||
path = Path.Combine(path, "Downloads");
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static readonly Guid FolderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
|
||||
/// <summary>
|
||||
/// Native methods for filesystem interop.
|
||||
/// </summary>
|
||||
static class FilesystemMethods {
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the current user's download path.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Code taken from http://stackoverflow.com/questions/3795023/downloads-folder-not-special-enough
|
||||
/// </remarks>
|
||||
public static string DownloadsPath {
|
||||
get {
|
||||
string path = null;
|
||||
|
||||
//Requires Vista or superior
|
||||
if (Environment.OSVersion.Version.Major >= 6) {
|
||||
IntPtr pathPtr;
|
||||
Guid folderId = FolderDownloads;
|
||||
int hr = SHGetKnownFolderPath(ref folderId, 0, IntPtr.Zero, out pathPtr);
|
||||
if (hr == 0) {
|
||||
path = Marshal.PtrToStringUni(pathPtr);
|
||||
Marshal.FreeCoTaskMem(pathPtr);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
//Fallback code
|
||||
path = Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
|
||||
path = Path.Combine(path, "Downloads");
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static readonly Guid FolderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
/// <summary>
|
||||
/// Native Win32 Hit Testing codes.
|
||||
/// </summary>
|
||||
static class HT {
|
||||
public const int TRANSPARENT = -1;
|
||||
public const int CLIENT = 1;
|
||||
public const int CAPTION = 2;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
/// <summary>
|
||||
/// Native Win32 Hit Testing codes.
|
||||
/// </summary>
|
||||
static class HT {
|
||||
public const int TRANSPARENT = -1;
|
||||
public const int CLIENT = 1;
|
||||
public const int CAPTION = 2;
|
||||
}
|
||||
}
|
|
@ -1,54 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
|
||||
/// <summary>
|
||||
/// Helpers for interop with native Windows hooks.
|
||||
/// </summary>
|
||||
static class HookMethods {
|
||||
|
||||
static HookMethods() {
|
||||
WM_SHELLHOOKMESSAGE = RegisterWindowMessage("SHELLHOOK");
|
||||
if (WM_SHELLHOOKMESSAGE == 0) {
|
||||
Log.Write("Failed to register SHELLHOOK window message");
|
||||
}
|
||||
}
|
||||
|
||||
public static int WM_SHELLHOOKMESSAGE {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
const int HSHELL_HIGHBIT = 0x8000;
|
||||
|
||||
public const int HSHELL_WINDOWCREATED = 1;
|
||||
public const int HSHELL_WINDOWDESTROYED = 2;
|
||||
public const int HSHELL_WINDOWACTIVATED = 4;
|
||||
public const int HSHELL_REDRAW = 6;
|
||||
public const int HSHELL_RUDEAPPACTIVATED = (HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT);
|
||||
public const int HSHELL_FLASH = (HSHELL_REDRAW | HSHELL_HIGHBIT);
|
||||
|
||||
/// <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 int RegisterWindowMessage(string wndMessageName);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a window as a shell hook window.
|
||||
/// </summary>
|
||||
[DllImport("User32.dll")]
|
||||
public static extern bool RegisterShellHookWindow(IntPtr hwnd);
|
||||
|
||||
/// <summary>
|
||||
/// Deregisters a window as a shell hook window.
|
||||
/// </summary>
|
||||
[DllImport("User32.dll")]
|
||||
public static extern bool DeregisterShellHookWindow(IntPtr hwnd);
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace OnTopReplica.Native {
|
||||
|
||||
/// <summary>
|
||||
/// Helpers for interop with native Windows hooks.
|
||||
/// </summary>
|
||||
static class HookMethods {
|
||||
|
||||
static HookMethods() {
|
||||
WM_SHELLHOOKMESSAGE = RegisterWindowMessage("SHELLHOOK");
|
||||
if (WM_SHELLHOOKMESSAGE == 0) {
|
||||
Log.Write("Failed to register SHELLHOOK window message");
|
||||
}
|
||||
}
|
||||
|
||||
public static int WM_SHELLHOOKMESSAGE {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
const int HSHELL_HIGHBIT = 0x8000;
|
||||
|
||||
public const int HSHELL_WINDOWCREATED = 1;
|
||||
public const int HSHELL_WINDOWDESTROYED = 2;
|
||||
public const int HSHELL_WINDOWACTIVATED = 4;
|
||||
public const int HSHELL_REDRAW = 6;
|
||||
public const int HSHELL_RUDEAPPACTIVATED = (HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT);
|
||||
public const int HSHELL_FLASH = (HSHELL_REDRAW | HSHELL_HIGHBIT);
|
||||
|
||||
/// <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 int RegisterWindowMessage(string wndMessageName);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a window as a shell hook window.
|
||||
/// </summary>
|
||||
[DllImport("User32.dll")]
|
||||
public static extern bool RegisterShellHookWindow(IntPtr hwnd);
|
||||
|
||||
/// <summary>
|
||||
/// Deregisters a window as a shell hook window.
|
||||
/// </summary>
|
||||
[DllImport("User32.dll")]
|
||||
public static extern bool DeregisterShellHookWindow(IntPtr hwnd);
|
||||
|
||||
}
|
||||
}
|