Merge from feature branch

This commit is contained in:
Terry MacDonald 2022-03-30 10:49:10 +13:00
commit 168fab9fc2
18 changed files with 348 additions and 620 deletions

View File

@ -155,12 +155,6 @@
<DependentUpon>HotkeyForm.cs</DependentUpon>
</Compile>
<Compile Include="UIForms\ImageListViewRenderers.cs" />
<Compile Include="UIForms\ProfileToolsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UIForms\ProfileToolsForm.Designer.cs">
<DependentUpon>ProfileToolsForm.cs</DependentUpon>
</Compile>
<Compile Include="UIForms\ShortcutLoadingForm.cs">
<SubType>Form</SubType>
</Compile>
@ -247,9 +241,6 @@
<EmbeddedResource Include="UIForms\HotkeyForm.resx">
<DependentUpon>HotkeyForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UIForms\ProfileToolsForm.resx">
<DependentUpon>ProfileToolsForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UIForms\ShortcutLoadingForm.resx">
<DependentUpon>ShortcutLoadingForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -297,21 +297,39 @@ namespace DisplayMagician {
// Check if it's an upgrade from DisplayMagician v2.x to v2.2
// and if it is then copy the old configs to the new filenames and
// explain to the user what they need to do.
string dp23 = Path.Combine(AppProfilePath, "DisplayProfiles_2.3.json");
string dp22 = Path.Combine(AppProfilePath, "DisplayProfiles_2.2.json");
string dp21 = Path.Combine(AppProfilePath, "DisplayProfiles_2.1.json");
string dp20 = Path.Combine(AppProfilePath, "DisplayProfiles_2.0.json");
string dp10 = Path.Combine(AppProfilePath, "DisplayProfiles_1.0.json");
string targetdp = dp22;
// This is the latest displayprofile config file
string targetdp = dp23;
if (File.Exists(dp21) && !File.Exists(Path.Combine(AppProfilePath, targetdp)))
if (File.Exists(dp22) && !File.Exists(Path.Combine(AppProfilePath, targetdp)))
{
logger.Info($"Program/Main: This is an upgrade from DisplayMagician v2.1 to DisplayMagician v2.2, so performing some upgrade steps.");
logger.Info($"Program/Main: This is an upgrade from DisplayMagician v2.1 to DisplayMagician v2.3, so performing some upgrade steps.");
// Copy the older files across to the new names, then the migrate JSON function
// within the ProfileRepository will take care of the rest
File.Copy(dp21, dp22);
File.Copy(dp22, targetdp);
// Warn the user about the fact we need them to recreate their Display Profiles again!
StartMessageForm myMessageWindow = new StartMessageForm();
myMessageWindow.MessageMode = "rtf";
myMessageWindow.URL = "https://displaymagician.littlebitbig.com/messages/DisplayMagicianRecreateProfiles.rtf";
myMessageWindow.HeadingText = "You need to recreate your Display Profiles";
myMessageWindow.ButtonText = "&Close";
myMessageWindow.ShowDialog();
}
else if (File.Exists(dp21) && !File.Exists(Path.Combine(AppProfilePath, targetdp)))
{
logger.Info($"Program/Main: This is an upgrade from DisplayMagician v2.1 to DisplayMagician v2.3, so performing some upgrade steps.");
// Copy the older files across to the new names, then the migrate JSON function
// within the ProfileRepository will take care of the rest
File.Copy(dp21, targetdp);
// Warn the user about the fact we need them to recreate their Display Profiles again!
StartMessageForm myMessageWindow = new StartMessageForm();
@ -323,11 +341,11 @@ namespace DisplayMagician {
}
else if (File.Exists(dp20) && !File.Exists(Path.Combine(AppProfilePath, targetdp)))
{
logger.Info($"Program/Main: This is an upgrade from DisplayMagician v2.0 to DisplayMagician v2.2, so performing some upgrade steps.");
logger.Info($"Program/Main: This is an upgrade from DisplayMagician v2.0 to DisplayMagician v2.3, so performing some upgrade steps.");
// Copy the older files across to the new names, then the migrate JSON function
// within the ProfileRepository will take care of the rest
File.Copy(dp20, dp22);
File.Copy(dp20, targetdp);
// Warn the user about the fact we need them to recreate their Display Profiles again!
StartMessageForm myMessageWindow = new StartMessageForm();
@ -614,6 +632,71 @@ namespace DisplayMagician {
});
});
// This is the CurrentProfile command
// This will output the current display profile if one matches, or 'Unknown'
app.Command(DisplayMagicianStartupAction.CurrentProfile.ToString(), (currentProfileCmd) =>
{
// Set the --trace or --debug options if supplied
if (trace.HasValue())
{
Console.WriteLine($"Changing logging level to TRACE level as --trace was provided on the commandline.");
logger.Info($"Changing logging level to TRACE level as --trace was provided on the commandline.");
loggingRule.SetLoggingLevels(NLog.LogLevel.Trace, NLog.LogLevel.Fatal);
NLog.LogManager.ReconfigExistingLoggers();
}
else if (debug.HasValue())
{
Console.WriteLine($"Changing logging level to DEBUG level as --debug was provided on the commandline.");
logger.Info($"Changing logging level to DEBUG level as --debug was provided on the commandline.");
loggingRule.SetLoggingLevels(NLog.LogLevel.Debug, NLog.LogLevel.Fatal);
NLog.LogManager.ReconfigExistingLoggers();
}
// Set the --force-video-library option if supplied
if (forcedVideoLibrary.HasValue())
{
if (forcedVideoLibrary.Value().Equals("NVIDIA"))
{
ProfileRepository.InitialiseRepository(FORCED_VIDEO_MODE.NVIDIA);
Console.WriteLine($"Forcing NVIDIA Video Library as '--force-video-library NVIDIA' was provided on the commandline.");
logger.Info($"Forcing NVIDIA Video Library as '--force-video-library NVIDIA' was provided on the commandline.");
}
else if (forcedVideoLibrary.Value().Equals("AMD"))
{
ProfileRepository.InitialiseRepository(FORCED_VIDEO_MODE.AMD);
Console.WriteLine($"Forcing AMD Video Library as '--force-video-library AMD' was provided on the commandline.");
logger.Info($"Forcing AMD Video Library as '--force-video-library AMD' was provided on the commandline.");
}
else if (forcedVideoLibrary.Value().Equals("Windows"))
{
ProfileRepository.InitialiseRepository(FORCED_VIDEO_MODE.WINDOWS);
Console.WriteLine($"Forcing Windows CCD Video Library as '--force-video-library Windows' was provided on the commandline.");
logger.Info($"Forcing Windows CCD Video Library as '--force-video-library Windows' was provided on the commandline.");
}
else
{
ProfileRepository.InitialiseRepository(FORCED_VIDEO_MODE.DETECT);
logger.Info($"Leaving DisplayMagician to detect the best Video Library to use.");
}
}
else
{
ProfileRepository.InitialiseRepository(FORCED_VIDEO_MODE.DETECT);
logger.Info($"Leaving DisplayMagician to detect the best Video Library to use.");
}
//description and help text of the command.
currentProfileCmd.Description = "Use this command to output the name of the display profile currently in use. It will return 'UNKNOWN' if the display profile doesn't match any saved display profiles";
currentProfileCmd.OnExecute(() =>
{
logger.Debug($"CurrentProfile commandline command was invoked!");
CurrentProfile();
DeRegisterDisplayMagicianWithWindows();
return 0;
});
});
app.OnExecute(() =>
{
// Set the --trace or --debug options if supplied
@ -871,6 +954,35 @@ namespace DisplayMagician {
}
public static void CurrentProfile()
{
logger.Trace($"Program/CurrentProfile: Finding the current profile in use");
// Close the splash screen
if (ProgramSettings.LoadSettings().ShowSplashScreen && AppSplashScreen != null && !AppSplashScreen.Disposing && !AppSplashScreen.IsDisposed)
AppSplashScreen.Invoke(new Action(() => AppSplashScreen.Close()));
// Lookup the profile
ProfileItem currentProfile;
string profileName = "UNKNOWN";
try
{
currentProfile = ProfileRepository.GetActiveProfile();
if (currentProfile is ProfileItem)
{
profileName = currentProfile.Name;
}
}
catch (Exception ex)
{
}
Console.WriteLine($"CurrentProfile Display Profile: {profileName}");
logger.Trace($"Program/RunProfile: Current display profile in use is called {profileName}. Informing the user of this fact.");
}
public static void RunProfile(string profileName)
{
logger.Trace($"Program/RunProfile: Running profile {profileName}");

View File

@ -4,6 +4,7 @@ using DisplayMagician.GameLibraries;
using DisplayMagician.Processes;
using DisplayMagician.UIForms;
using DisplayMagicianShared;
using DisplayMagicianShared.Windows;
using Microsoft.Toolkit.Uwp.Notifications;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

View File

@ -59,7 +59,6 @@ namespace DisplayMagician.UIForms
this.dv_profile = new DisplayMagicianShared.UserControls.DisplayView();
this.p_upper = new System.Windows.Forms.Panel();
this.btn_donate = new System.Windows.Forms.Button();
this.btn_tools = new System.Windows.Forms.Button();
this.btn_help = new System.Windows.Forms.Button();
this.btn_profile_settings = new System.Windows.Forms.Button();
this.pbLogo = new System.Windows.Forms.PictureBox();
@ -376,7 +375,6 @@ namespace DisplayMagician.UIForms
this.p_upper.BackColor = System.Drawing.Color.DimGray;
this.p_upper.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("p_upper.BackgroundImage")));
this.p_upper.Controls.Add(this.btn_donate);
this.p_upper.Controls.Add(this.btn_tools);
this.p_upper.Controls.Add(this.btn_help);
this.p_upper.Controls.Add(this.txt_profile_save_name);
this.p_upper.Controls.Add(this.lbl_save_profile);
@ -412,23 +410,6 @@ namespace DisplayMagician.UIForms
this.btn_donate.UseVisualStyleBackColor = false;
this.btn_donate.Click += new System.EventHandler(this.btn_donate_Click);
//
// btn_tools
//
this.btn_tools.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btn_tools.BackColor = System.Drawing.Color.Black;
this.btn_tools.FlatAppearance.MouseDownBackColor = System.Drawing.Color.IndianRed;
this.btn_tools.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Brown;
this.btn_tools.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btn_tools.ForeColor = System.Drawing.Color.White;
this.btn_tools.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.btn_tools.Location = new System.Drawing.Point(655, 63);
this.btn_tools.Name = "btn_tools";
this.btn_tools.Size = new System.Drawing.Size(111, 23);
this.btn_tools.TabIndex = 41;
this.btn_tools.Text = "Profile Too&ls";
this.btn_tools.UseVisualStyleBackColor = false;
this.btn_tools.Click += new System.EventHandler(this.btn_tools_Click);
//
// btn_help
//
this.btn_help.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@ -562,7 +543,6 @@ namespace DisplayMagician.UIForms
private System.Windows.Forms.Button btn_help;
private System.Windows.Forms.ToolStripMenuItem deleteProfileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem saveProfileToDesktopToolStripMenuItem;
private System.Windows.Forms.Button btn_tools;
private System.Windows.Forms.Button btn_donate;
}
}

View File

@ -762,17 +762,6 @@ namespace DisplayMagician.UIForms
string targetURL = @"https://github.com/sponsors/terrymacdonald";
System.Diagnostics.Process.Start(targetURL);
}
private void btn_tools_Click(object sender, EventArgs e)
{
ProfileToolsForm profileToolsForm = new ProfileToolsForm();
profileToolsForm.CurrentProfile = _selectedProfile;
profileToolsForm.ShowDialog(this);
if (profileToolsForm.DialogResult == DialogResult.OK)
{
// If we change something, then we refresh the current profile
btn_view_current.PerformClick();
}
}
}
}

View File

@ -1,149 +0,0 @@

namespace DisplayMagician.UIForms
{
partial class ProfileToolsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btn_cancel = new System.Windows.Forms.Button();
this.gb_taskbars = new System.Windows.Forms.GroupBox();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.cmb_taskbar_edge = new System.Windows.Forms.ComboBox();
this.btn_apply = new System.Windows.Forms.Button();
this.gb_taskbars.SuspendLayout();
this.SuspendLayout();
//
// btn_cancel
//
this.btn_cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btn_cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btn_cancel.FlatAppearance.MouseDownBackColor = System.Drawing.Color.IndianRed;
this.btn_cancel.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Brown;
this.btn_cancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btn_cancel.ForeColor = System.Drawing.Color.White;
this.btn_cancel.Location = new System.Drawing.Point(480, 145);
this.btn_cancel.Name = "btn_cancel";
this.btn_cancel.Size = new System.Drawing.Size(94, 25);
this.btn_cancel.TabIndex = 6;
this.btn_cancel.Text = "&Back";
this.btn_cancel.UseVisualStyleBackColor = true;
this.btn_cancel.Click += new System.EventHandler(this.btn_back_Click);
//
// gb_taskbars
//
this.gb_taskbars.Controls.Add(this.btn_apply);
this.gb_taskbars.Controls.Add(this.label2);
this.gb_taskbars.Controls.Add(this.label1);
this.gb_taskbars.Controls.Add(this.cmb_taskbar_edge);
this.gb_taskbars.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.gb_taskbars.ForeColor = System.Drawing.SystemColors.Control;
this.gb_taskbars.Location = new System.Drawing.Point(22, 22);
this.gb_taskbars.Name = "gb_taskbars";
this.gb_taskbars.Size = new System.Drawing.Size(552, 100);
this.gb_taskbars.TabIndex = 7;
this.gb_taskbars.TabStop = false;
this.gb_taskbars.Text = "Taskbar Tools";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(316, 46);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(84, 16);
this.label2.TabIndex = 2;
this.label2.Text = "of the screen";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(34, 46);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(158, 16);
this.label1.TabIndex = 1;
this.label1.Text = "Move all Taskbars to the ";
//
// cmb_taskbar_edge
//
this.cmb_taskbar_edge.FormattingEnabled = true;
this.cmb_taskbar_edge.Location = new System.Drawing.Point(189, 43);
this.cmb_taskbar_edge.Name = "cmb_taskbar_edge";
this.cmb_taskbar_edge.Size = new System.Drawing.Size(121, 24);
this.cmb_taskbar_edge.TabIndex = 0;
//
// btn_apply
//
this.btn_apply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btn_apply.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btn_apply.FlatAppearance.MouseDownBackColor = System.Drawing.Color.IndianRed;
this.btn_apply.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Brown;
this.btn_apply.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btn_apply.ForeColor = System.Drawing.Color.White;
this.btn_apply.Location = new System.Drawing.Point(417, 42);
this.btn_apply.Name = "btn_apply";
this.btn_apply.Size = new System.Drawing.Size(94, 25);
this.btn_apply.TabIndex = 7;
this.btn_apply.Text = "&Apply";
this.btn_apply.UseVisualStyleBackColor = true;
this.btn_apply.Click += new System.EventHandler(this.btn_apply_Click);
//
// ProfileToolsForm
//
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(598, 193);
this.Controls.Add(this.gb_taskbars);
this.Controls.Add(this.btn_cancel);
this.ForeColor = System.Drawing.Color.White;
this.Name = "ProfileToolsForm";
this.ShowIcon = false;
this.Text = "Profile Tools";
this.gb_taskbars.ResumeLayout(false);
this.gb_taskbars.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button btn_back;
private System.Windows.Forms.GroupBox gb_general;
private System.Windows.Forms.Label lbl_style;
private System.Windows.Forms.ComboBox cmb_wallpaper_display_mode;
private System.Windows.Forms.Button btn_select;
private System.Windows.Forms.Button btn_clear;
private System.Windows.Forms.PictureBox pb_wallpaper;
private System.Windows.Forms.Button btn_current;
private System.Windows.Forms.RadioButton rb_leave_wallpaper;
private System.Windows.Forms.RadioButton rb_clear_wallpaper;
private System.Windows.Forms.RadioButton rb_apply_wallpaper;
private System.Windows.Forms.Button btn_cancel;
private System.Windows.Forms.GroupBox gb_taskbars;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox cmb_taskbar_edge;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button btn_apply;
}
}

View File

@ -1,141 +0,0 @@
using DisplayMagicianShared;
using DisplayMagicianShared.Windows;
//using Microsoft.Win32;
using NHotkey;
using NHotkey.WindowsForms;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace DisplayMagician.UIForms
{
public partial class ProfileToolsForm : Form
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private Dictionary<TaskBarStuckRectangle.TaskBarEdge, string> forcedTaskBarEdgeText = new Dictionary<TaskBarStuckRectangle.TaskBarEdge, string>();
public ProfileToolsForm()
{
logger.Info($"ProfileToolsForm/ProfileToolsForm: Creating a ProfileToolsForm UI Form");
InitializeComponent();
// Set up the default return value of Cancel
DialogResult = DialogResult.Cancel;
// Populate the Forced Taskbar Location dictionary
if (Utils.IsWindows11())
{
// Is Windows 11
// In Windows 11, the taskbars will only work properly up top or bottom. Left or right will show the taskbar, but there will be nothing on the taskbar.
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarEdge.Top, "Top");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarEdge.Bottom, "Bottom");
}
else
{
// Is Windows 10
// We can put the taskbar anywhere!
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarEdge.Left, "Left");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarEdge.Top, "Top");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarEdge.Right, "Right");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarEdge.Bottom, "Bottom");
}
cmb_taskbar_edge.DisplayMember = "Value";
cmb_taskbar_edge.ValueMember = "Text";
cmb_taskbar_edge.DataSource = new BindingSource(forcedTaskBarEdgeText, null);
}
public ProfileItem CurrentProfile
{
get;
set;
}
private void ProfileToolsForm_Load(object sender, EventArgs e)
{
cmb_taskbar_edge.SelectedIndex = 0;
}
private void btn_back_Click(object sender, EventArgs e)
{
this.Close();
}
private void btn_apply_Click(object sender, EventArgs e)
{
ProfileRepository.UpdateActiveProfile();
if (CurrentProfile.NVIDIADisplayConfig.MosaicConfig.IsMosaicEnabled)
{
MessageBox.Show(this, "You cannot change the taskbar position while in a NVIDIA Surround/Mosaic display profile",
"Taskbar move failed",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (CurrentProfile.AMDDisplayConfig.SlsConfig.IsSlsEnabled)
{
MessageBox.Show(this, "You cannot change the taskbar position while in an AMD Eyefinity display profile",
"Taskbar move failed",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// Now set the taskbar position for each screen
if (CurrentProfile.WindowsDisplayConfig.TaskBarLayout.Count > 0)
{
TaskBarStuckRectangle.TaskBarEdge taskbarForcedEdge = ((KeyValuePair<TaskBarStuckRectangle.TaskBarEdge, string>)cmb_taskbar_edge.SelectedItem).Key;
SharedLogger.logger.Trace($"ProfileToolsForm/btn_apply_Click: Setting the taskbar layout.");
// Tell Windows to refresh the Other Windows Taskbars if needed
if (CurrentProfile.WindowsDisplayConfig.TaskBarLayout.Count > 1)
{
SharedLogger.logger.Trace($"ProfileToolsForm/btn_apply_Click: Setting the taskbar layout.");
foreach (TaskBarStuckRectangle tbsr in CurrentProfile.WindowsDisplayConfig.TaskBarLayout)
{
if (tbsr.Version >= 2 && tbsr.Version <= 3)
{
tbsr.Edge = taskbarForcedEdge;
if (tbsr.MainScreen)
{
tbsr.Location = new Rectangle(0, 1392, 2560, 48);
tbsr.Options = (TaskBarStuckRectangle.TaskBarOptions)62586;
}
// Write the settings to registry
tbsr.WriteToRegistry();
if (tbsr.MainScreen)
{
WinLibrary.RepositionMainTaskBar(taskbarForcedEdge);
}
}
else
{
SharedLogger.logger.Error($"ProfileToolsForm/btn_apply_Click: Unable to set the {tbsr.DevicePath} TaskBarStuckRectangle registry settings as the version isn't v2 or v3!");
}
}
}
else
{
SharedLogger.logger.Trace($"ProfileToolsForm/btn_apply_Click: No taskbar layout in display profile so skipping setting it!");
}
WinLibrary.RepositionSecondaryTaskBars();
// Now set the option to completed.
DialogResult = DialogResult.OK;
}
}
}
}

View File

@ -1,120 +0,0 @@
<?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>
</root>

View File

@ -83,7 +83,7 @@
</Compile>
<Compile Include="Utils.cs" />
<Compile Include="Windows\TaskBarLayout.cs" />
<Compile Include="Windows\TaskBarStuckRectangle.cs" />
<Compile Include="Windows\TaskBarSettings.cs" />
<Compile Include="UserControls\DisplayView.cs">
<SubType>UserControl</SubType>
</Compile>

View File

@ -5,6 +5,7 @@
RunShortcut,
ChangeProfile,
CreateProfile,
CurrentProfile,
StartUpNormally
}
}

View File

@ -1093,7 +1093,7 @@ namespace DisplayMagicianShared.NVIDIA
public UInt32 Pclk; //!< pixel clock in 10 kHz
//other timing related extras - points to a NV_TIMING_EXTRA_INTERNAL
public IntPtr Extra;
public NV_TIMING_EXTRA_INTERNAL Extra;
}
@ -1372,10 +1372,10 @@ namespace DisplayMagicianShared.NVIDIA
// Backend (raster) timing standard
public NV_TIMING_OVERRIDE TimingOverride; //!< Ignored if timingOverride == NV_TIMING_OVERRIDE_CURRENT
public IntPtr Timing; // Points to a NV_TIMING_INTERNAL object
//!< Scan out timing, valid only if timingOverride == NV_TIMING_OVERRIDE_CUST
//!< The value NV_TIMING::NV_TIMINGEXT::rrx1k is obtained from the EDID. The driver may
//!< tweak this value for HDTV, stereo, etc., before reporting it to the OS.
public NV_TIMING_INTERNAL Timing; // Points to a NV_TIMING_INTERNAL object
//!< Scan out timing, valid only if timingOverride == NV_TIMING_OVERRIDE_CUST
//!< The value NV_TIMING::NV_TIMINGEXT::rrx1k is obtained from the EDID. The driver may
//!< tweak this value for HDTV, stereo, etc., before reporting it to the OS.
}
@ -3948,23 +3948,48 @@ namespace DisplayMagicianShared.NVIDIA
totalTargetInfoCount += (int)PathInfos[x].TargetInfoCount;
}
// Get the size of the each object
int onePathInfoMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
int oneSourceModeMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
int onePathTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2));
int oneAdvTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1));
IntPtr pathInfoPointer = Marshal.AllocHGlobal(onePathInfoMemSize * (int)PathInfoCount);
IntPtr sourceModeInfoPointer = Marshal.AllocHGlobal(oneSourceModeMemSize * (int)PathInfoCount);
IntPtr targetInfoPointer = Marshal.AllocHGlobal(onePathTargetMemSize * totalTargetInfoCount);
IntPtr advTargetPointer = Marshal.AllocHGlobal(oneAdvTargetMemSize * totalTargetInfoCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentPathInfoPointer = pathInfoPointer;
IntPtr currentSourceModeInfoPointer = sourceModeInfoPointer;
IntPtr currentTargetInfoPointer = targetInfoPointer;
IntPtr currentAdvTargetPointer = advTargetPointer;
int onePathTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL));
int oneAdvTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL));
int oneTimingMemSize = Marshal.SizeOf(typeof(NV_TIMING_INTERNAL));
int oneTimingExtraMemSize = Marshal.SizeOf(typeof(NV_TIMING_EXTRA_INTERNAL));
// Figure out the size of the memory we need to allocate
int allPathInfoMemSize = onePathInfoMemSize * (int)PathInfoCount;
int allSourceModeMemSize = oneSourceModeMemSize * (int)PathInfoCount;
int allPathTargetMemSize = onePathTargetMemSize * totalTargetInfoCount;
int allAdvTargetMemSize = (oneAdvTargetMemSize + oneTimingMemSize + oneTimingExtraMemSize) * totalTargetInfoCount;
//int allTimingMemSize = oneTimingMemSize * totalTargetInfoCount;
//int allTimingExtraMemSize = oneTimingExtraMemSize * totalTargetInfoCount;
//int allObjectsMemSize = allPathInfoMemSize + allSourceModeMemSize + allPathTargetMemSize + allAdvTargetMemSize + allTimingMemSize + allTimingExtraMemSize;
int allObjectsMemSize = allPathInfoMemSize + allSourceModeMemSize + allPathTargetMemSize + allAdvTargetMemSize;
IntPtr memPointer = IntPtr.Zero;
try
{
// Allocate the memory we need
memPointer = Marshal.AllocHGlobal(allObjectsMemSize * 2);
// Figure out the address of the arrays we will use
IntPtr pathInfoPointer = memPointer;
IntPtr sourceModeInfoPointer = new IntPtr(memPointer.ToInt64() + allPathInfoMemSize);
IntPtr targetInfoPointer = new IntPtr(memPointer.ToInt64() + allPathInfoMemSize + allSourceModeMemSize);
IntPtr advTargetPointer = new IntPtr(memPointer.ToInt64() + allPathInfoMemSize + allSourceModeMemSize + allPathTargetMemSize);
//IntPtr timingPointer = new IntPtr(memPointer.ToInt64() + allPathInfoMemSize + allSourceModeMemSize + allPathTargetMemSize + allAdvTargetMemSize);
//IntPtr timingExtraPointer = new IntPtr(memPointer.ToInt64() + allPathInfoMemSize + allSourceModeMemSize + allPathTargetMemSize + allAdvTargetMemSize + allTimingMemSize);
// Figure out each memory pointer so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentPathInfoPointer = new IntPtr(pathInfoPointer.ToInt64());
IntPtr currentSourceModeInfoPointer = new IntPtr(sourceModeInfoPointer.ToInt64());
IntPtr currentTargetInfoPointer = new IntPtr(targetInfoPointer.ToInt64());
IntPtr currentAdvTargetPointer = new IntPtr(advTargetPointer.ToInt64());
//IntPtr currentTimingPointer = new IntPtr(timingPointer.ToInt64());
//IntPtr currentTimingExtraPointer = new IntPtr(timingExtraPointer.ToInt64());
// Go through the array and copy things from managed code to unmanaged code
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
@ -3980,19 +4005,34 @@ namespace DisplayMagicianShared.NVIDIA
//for (Int32 y = 0; y < (Int32)PathInfos[x].TargetInfoCount; y++)
for (Int32 y = 0; y < (Int32)PathInfos[x].TargetInfoCount; y++)
{
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 advInfo = new NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1();
// Create the timingExtra object ready to use shortly
//NV_TIMING_EXTRA_INTERNAL timingExtra = new NV_TIMING_EXTRA_INTERNAL();
//Marshal.StructureToPtr(timingExtra, currentTimingExtraPointer, true);
// Create the timing object, and connect it to the timingExtra object we created earlier
//NV_TIMING_INTERNAL timing = new NV_TIMING_INTERNAL();
//timing.Extra = new IntPtr(currentTimingExtraPointer.ToInt64());
//Marshal.StructureToPtr(timing, currentTimingPointer, true);
// Create the Advanced Details object, and connect it to the timing object we ust created
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL advInfo = new NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL();
advInfo.Version = NVImport.NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_VER;
//advInfo.Timing = new IntPtr(currentTimingPointer.ToInt64());
Marshal.StructureToPtr(advInfo, currentAdvTargetPointer, true);
targetInforArray[y].Details = currentAdvTargetPointer;
// Now connect the Advanced details we created to the details in the TargetInfo array item
targetInforArray[y].Details = new IntPtr(currentAdvTargetPointer.ToInt64());
Marshal.StructureToPtr(targetInforArray[y], currentTargetInfoPointer, true);
currentTargetInfoPointer = new IntPtr(currentTargetInfoPointer.ToInt64() + onePathTargetMemSize);
currentAdvTargetPointer = new IntPtr(currentAdvTargetPointer.ToInt64() + oneAdvTargetMemSize);
currentAdvTargetPointer = new IntPtr(currentAdvTargetPointer.ToInt64() + oneAdvTargetMemSize + oneTimingMemSize + oneTimingExtraMemSize);
//currentTimingPointer = new IntPtr(currentTimingPointer.ToInt64() + oneTimingMemSize);
//currentTimingExtraPointer = new IntPtr(currentTimingExtraPointer.ToInt64() + oneTimingExtraMemSize);
}
// Create a source mode info object and copy it over
NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 sourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)PathInfos[x].SourceModeInfo.Clone();
Marshal.StructureToPtr(sourceModeInfo, currentSourceModeInfoPointer, true);
pass2PathInfos[x].SourceModeInfo = currentSourceModeInfoPointer;
pass2PathInfos[x].SourceModeInfo = new IntPtr(currentSourceModeInfoPointer.ToInt64());
// Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
Marshal.StructureToPtr(pass2PathInfos[x], currentPathInfoPointer, true);
@ -4012,7 +4052,8 @@ namespace DisplayMagicianShared.NVIDIA
// If everything worked, then copy the data back from the unmanaged array into the managed array
// So that we can use it in C# land
// Reset the memory pointer we're using for tracking where we are back to the start of the unmanaged memory buffer
currentPathInfoPointer = pathInfoPointer;
currentPathInfoPointer = new IntPtr(pathInfoPointer.ToInt64());
// Create a managed array to store the received information within
PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[] returnedPass2PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[PathInfoCount];
@ -4037,19 +4078,83 @@ namespace DisplayMagicianShared.NVIDIA
currentTargetInfoPointer = returnedPass2PathInfos[i].TargetInfo;
for (Int32 y = 0; y < (Int32)PathInfos[i].TargetInfoCount; y++)
{
NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL targetInfo;
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 targetInfoDetails;
// And turn the memory pointer to NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 into an actual object and populate the object.
targetInfo = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL)Marshal.PtrToStructure(currentTargetInfoPointer, typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL));
PathInfos[i].TargetInfo[y].DisplayId = targetInfo.DisplayId;
PathInfos[i].TargetInfo[y].WindowsCCDTargetId = targetInfo.WindowsCCDTargetId;
// And turn the memory pointer to NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL into an actual object and populate the our wanted object
NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL returnedTargetInfo = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL)Marshal.PtrToStructure(currentTargetInfoPointer, typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL));
// Next we need to get access to the details object.
targetInfoDetails = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)Marshal.PtrToStructure(targetInfo.Details, typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1));
PathInfos[i].TargetInfo[y].Details = targetInfoDetails;
currentTargetInfoPointer = new IntPtr(currentTargetInfoPointer.ToInt64() + onePathTargetMemSize);
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL returnedAdvTarget = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL)Marshal.PtrToStructure(returnedTargetInfo.Details, typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL));
// Next we need to get access to the timing object.
//NV_TIMING_INTERNAL returnedTiming = (NV_TIMING_INTERNAL)Marshal.PtrToStructure(returnedAdvTarget.Timing, typeof(NV_TIMING_INTERNAL));
// Next we need to get access to the timing extra object.
//NV_TIMING_EXTRA_INTERNAL returnedTimingExtra = (NV_TIMING_EXTRA_INTERNAL)Marshal.PtrToStructure(returnedTiming.Extra, typeof(NV_TIMING_EXTRA_INTERNAL));
// Now we start copying the info into the object we want to return
// We'll start with filling in the Timing Extra info we want to return
/*PathInfos[i].TargetInfo[y].Details.Timing.Extra.Flags = returnedTimingExtra.Flags;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.FrequencyInMillihertz = returnedTimingExtra.FrequencyInMillihertz;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.HorizontalAspect = returnedTimingExtra.HorizontalAspect;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.HorizontalPixelRepetition = returnedTimingExtra.HorizontalPixelRepetition;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.Name = returnedTimingExtra.Name;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.RefreshRate = returnedTimingExtra.RefreshRate;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.TimingStandard = returnedTimingExtra.TimingStandard;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.VerticalAspect = returnedTimingExtra.VerticalAspect;*/
PathInfos[i].TargetInfo[y].Details.Timing.Extra.Flags = returnedAdvTarget.Timing.Extra.Flags;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.FrequencyInMillihertz = returnedAdvTarget.Timing.Extra.FrequencyInMillihertz;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.HorizontalAspect = returnedAdvTarget.Timing.Extra.HorizontalAspect;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.HorizontalPixelRepetition = returnedAdvTarget.Timing.Extra.HorizontalPixelRepetition;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.Name = returnedAdvTarget.Timing.Extra.Name;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.RefreshRate = returnedAdvTarget.Timing.Extra.RefreshRate;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.TimingStandard = returnedAdvTarget.Timing.Extra.TimingStandard;
PathInfos[i].TargetInfo[y].Details.Timing.Extra.VerticalAspect = returnedAdvTarget.Timing.Extra.VerticalAspect;
// Next, we'll fill in the Timing info we want to return
/*PathInfos[i].TargetInfo[y].Details.Timing.HBorder = returnedTiming.HBorder;
PathInfos[i].TargetInfo[y].Details.Timing.HFrontPorch = returnedTiming.HFrontPorch;
PathInfos[i].TargetInfo[y].Details.Timing.HSyncPol = returnedTiming.HSyncPol;
PathInfos[i].TargetInfo[y].Details.Timing.HSyncWidth = returnedTiming.HSyncWidth;
PathInfos[i].TargetInfo[y].Details.Timing.HTotal = returnedTiming.HTotal;
PathInfos[i].TargetInfo[y].Details.Timing.HVisible = returnedTiming.HVisible;
PathInfos[i].TargetInfo[y].Details.Timing.Pclk = returnedTiming.Pclk;
PathInfos[i].TargetInfo[y].Details.Timing.ScanMode = returnedTiming.ScanMode;
PathInfos[i].TargetInfo[y].Details.Timing.VBorder = returnedTiming.VBorder;
PathInfos[i].TargetInfo[y].Details.Timing.VFrontPorch = returnedTiming.VFrontPorch;
PathInfos[i].TargetInfo[y].Details.Timing.VSyncPol = returnedTiming.VSyncPol;
PathInfos[i].TargetInfo[y].Details.Timing.VSyncWidth = returnedTiming.VSyncWidth;
PathInfos[i].TargetInfo[y].Details.Timing.VTotal = returnedTiming.VTotal;
PathInfos[i].TargetInfo[y].Details.Timing.VVisible = returnedTiming.VVisible;*/
PathInfos[i].TargetInfo[y].Details.Timing.HBorder = returnedAdvTarget.Timing.HBorder;
PathInfos[i].TargetInfo[y].Details.Timing.HFrontPorch = returnedAdvTarget.Timing.HFrontPorch;
PathInfos[i].TargetInfo[y].Details.Timing.HSyncPol = returnedAdvTarget.Timing.HSyncPol;
PathInfos[i].TargetInfo[y].Details.Timing.HSyncWidth = returnedAdvTarget.Timing.HSyncWidth;
PathInfos[i].TargetInfo[y].Details.Timing.HTotal = returnedAdvTarget.Timing.HTotal;
PathInfos[i].TargetInfo[y].Details.Timing.HVisible = returnedAdvTarget.Timing.HVisible;
PathInfos[i].TargetInfo[y].Details.Timing.Pclk = returnedAdvTarget.Timing.Pclk;
PathInfos[i].TargetInfo[y].Details.Timing.ScanMode = returnedAdvTarget.Timing.ScanMode;
PathInfos[i].TargetInfo[y].Details.Timing.VBorder = returnedAdvTarget.Timing.VBorder;
PathInfos[i].TargetInfo[y].Details.Timing.VFrontPorch = returnedAdvTarget.Timing.VFrontPorch;
PathInfos[i].TargetInfo[y].Details.Timing.VSyncPol = returnedAdvTarget.Timing.VSyncPol;
PathInfos[i].TargetInfo[y].Details.Timing.VSyncWidth = returnedAdvTarget.Timing.VSyncWidth;
PathInfos[i].TargetInfo[y].Details.Timing.VTotal = returnedAdvTarget.Timing.VTotal;
PathInfos[i].TargetInfo[y].Details.Timing.VVisible = returnedAdvTarget.Timing.VVisible;
// Next, we'll deal with the advanced details
PathInfos[i].TargetInfo[y].Details.ConnectorType = returnedAdvTarget.ConnectorType;
PathInfos[i].TargetInfo[y].Details.Flags = returnedAdvTarget.Flags;
PathInfos[i].TargetInfo[y].Details.RefreshRateInMillihertz = returnedAdvTarget.RefreshRateInMillihertz;
PathInfos[i].TargetInfo[y].Details.Rotation = returnedAdvTarget.Rotation;
PathInfos[i].TargetInfo[y].Details.Scaling = returnedAdvTarget.Scaling;
PathInfos[i].TargetInfo[y].Details.TimingOverride = returnedAdvTarget.TimingOverride;
PathInfos[i].TargetInfo[y].Details.TvFormat = returnedAdvTarget.TvFormat;
PathInfos[i].TargetInfo[y].Details.Version = returnedAdvTarget.Version;
// We'll finish with the TargetInfo
PathInfos[i].TargetInfo[y].DisplayId = returnedTargetInfo.DisplayId;
PathInfos[i].TargetInfo[y].WindowsCCDTargetId = returnedTargetInfo.WindowsCCDTargetId;
currentTargetInfoPointer = new IntPtr(currentTargetInfoPointer.ToInt64() + onePathTargetMemSize);
}
// advance the buffer forwards to the next object
@ -4061,13 +4166,16 @@ namespace DisplayMagicianShared.NVIDIA
{
status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
}
// Try and remove the memory used
pass2PathInfos = null;
}
finally
{
Marshal.FreeCoTaskMem(pathInfoPointer);
Marshal.FreeCoTaskMem(sourceModeInfoPointer);
Marshal.FreeCoTaskMem(targetInfoPointer);
Marshal.FreeCoTaskMem(advTargetPointer);
if (memPointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(memPointer);
}
}
}
@ -4082,15 +4190,19 @@ namespace DisplayMagicianShared.NVIDIA
int onePathInfoMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
int oneSourceModeMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
IntPtr pathInfoPointer = Marshal.AllocHGlobal(onePathInfoMemSize * (int)PathInfoCount);
IntPtr sourceModeInfoPointer = Marshal.AllocHGlobal(oneSourceModeMemSize * (int)PathInfoCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentPathInfoPointer = pathInfoPointer;
IntPtr currentSourceModeInfoPointer = sourceModeInfoPointer;
IntPtr pathInfoPointer = IntPtr.Zero;
IntPtr sourceModeInfoPointer = IntPtr.Zero;
try
{
pathInfoPointer = Marshal.AllocHGlobal(onePathInfoMemSize * (int)PathInfoCount);
sourceModeInfoPointer = Marshal.AllocHGlobal(oneSourceModeMemSize * (int)PathInfoCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentPathInfoPointer = pathInfoPointer;
IntPtr currentSourceModeInfoPointer = sourceModeInfoPointer;
// Go through the array and copy things from managed code to unmanaged code
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
@ -4156,11 +4268,22 @@ namespace DisplayMagicianShared.NVIDIA
{
status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
}
// Try and remove the memory used
pass2PathInfos = null;
}
finally
{
Marshal.FreeCoTaskMem(pathInfoPointer);
Marshal.FreeCoTaskMem(sourceModeInfoPointer);
if (pathInfoPointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pathInfoPointer);
}
if (sourceModeInfoPointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(sourceModeInfoPointer);
}
}
}

View File

@ -1367,57 +1367,6 @@ namespace DisplayMagicianShared.NVIDIA
// Get the display identifiers
myDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers();
// Go through and find the list of displayIDs
// ignore the ones that were found
// if one was not found, then
// go through the modes
// patch the target
if (myDisplayConfig.IsCloned)
{
List<UInt32> clonedIdsWeKnow = new List<uint>();
List<UInt32> missingIdsWeWant = new List<uint>();
// Find all displays in the displayconfig
foreach (var displayConfig in myDisplayConfig.DisplayConfigs)
{
foreach (var targetInfo in displayConfig.TargetInfo)
{
if (foundDisplayIds.Contains(targetInfo.DisplayId))
{
// We have this foundId
clonedIdsWeKnow.Add(targetInfo.DisplayId);
}
}
}
// Now go through and figure out which foundDisplayId we're missing
foreach (var foundDisplayId in foundDisplayIds)
{
if (!clonedIdsWeKnow.Contains(foundDisplayId))
{
// We found a cloned display id \o/
missingIdsWeWant.Add(foundDisplayId);
}
}
int clonedIdOffset = 0;
// Now we go through the list of missing cloned id's and we fill them in
for (int x = 0; x < myDisplayConfig.DisplayConfigs.Count; x++)
{
// We go through all the displayconfigs, but we want to only change the cloned displays (those with > 1 targetInfo)
if (myDisplayConfig.DisplayConfigs[x].TargetInfoCount > 1)
{
// We only want to change the cloned displays, so we start at index 1 (the clones themselves)
for (int y = 1; y < myDisplayConfig.DisplayConfigs[x].TargetInfoCount; y++)
{
// We want to assign the cloned display the display ID from the missing display
myDisplayConfig.DisplayConfigs[x].TargetInfo[y].DisplayId = missingIdsWeWant[clonedIdOffset++];
// We also want to clone the Details struct from the base display (the first display) and replicate them on the clone
// This copies the process used within the DisplayCOnfiguration C++ Sample released by NVIDIA
myDisplayConfig.DisplayConfigs[x].TargetInfo[y].Details = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)myDisplayConfig.DisplayConfigs[0].TargetInfo[0].Details.Clone();
}
}
}
}
}
else

View File

@ -5,6 +5,7 @@ using System.Drawing.Drawing2D;
using System.Drawing.IconLib;
using System.Drawing.Imaging;
using System.Linq;
using DisplayMagicianShared.Windows;
namespace DisplayMagicianShared
{
@ -323,16 +324,16 @@ namespace DisplayMagicianShared
//int startButtonSize = 2 * startButtonSpacer;
switch (screen.TaskBarEdge)
{
case Windows.TaskBarStuckRectangle.TaskBarEdge.Left:
case TaskBarLayout.TaskBarEdge.Left:
taskBarRect = new Rectangle(screenRect.X, screenRect.Y + 2, taskBarWidth, screenRect.Height - 4);
break;
case Windows.TaskBarStuckRectangle.TaskBarEdge.Top:
case TaskBarLayout.TaskBarEdge.Top:
taskBarRect = new Rectangle(screenRect.X + 2, screenRect.Y, screenRect.Width - 4, taskBarWidth);
break;
case Windows.TaskBarStuckRectangle.TaskBarEdge.Right:
case TaskBarLayout.TaskBarEdge.Right:
taskBarRect = new Rectangle(screenRect.X + screenRect.Width - taskBarWidth, screenRect.Y + 2, taskBarWidth, screenRect.Height - 4);
break;
case Windows.TaskBarStuckRectangle.TaskBarEdge.Bottom:
case TaskBarLayout.TaskBarEdge.Bottom:
taskBarRect = new Rectangle(screenRect.X + 2, screenRect.Y + screenRect.Height - taskBarWidth, screenRect.Width - 4, taskBarWidth);
break;
default:

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using DisplayMagicianShared.Resources;
using Newtonsoft.Json;
@ -40,7 +41,7 @@ namespace DisplayMagicianShared
public List<SpannedScreenPosition> SpannedScreens;
public int SpannedColumns;
public int SpannedRows;
public TaskBarStuckRectangle.TaskBarEdge TaskBarEdge;
public TaskBarLayout.TaskBarEdge TaskBarEdge;
}
public struct SpannedScreenPosition
@ -937,28 +938,19 @@ namespace DisplayMagicianShared
// Set some basics about the screen
try
{
string displayId = _nvidiaDisplayConfig.MosaicConfig.MosaicGridTopos[i].Displays[0].DisplayId.ToString();
string windowsDisplayName = _nvidiaDisplayConfig.DisplayNames[displayId];
List<uint> sourceIndexes = _windowsDisplayConfig.DisplaySources[windowsDisplayName];
for (int x = 0; x < _windowsDisplayConfig.DisplayConfigModes.Length; x++)
UInt32 displayId = _nvidiaDisplayConfig.MosaicConfig.MosaicGridTopos[i].Displays[0].DisplayId;
List<NV_DISPLAYCONFIG_PATH_INFO_V2> displaySources = _nvidiaDisplayConfig.DisplayConfigs;
foreach (var displaySource in displaySources)
{
// Skip this if its not a source info config type
if (_windowsDisplayConfig.DisplayConfigModes[x].InfoType != DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE)
{
continue;
}
screen.Name = displayId.ToString();
// If the source index matches the index of the source info object we're looking at, then process it!
if (sourceIndexes.Contains(_windowsDisplayConfig.DisplayConfigModes[x].Id))
{
screen.Name = displayId.ToString();
screen.ScreenX = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Position.X;
screen.ScreenY = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Position.Y;
screen.ScreenWidth = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Width;
screen.ScreenHeight = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Height;
break;
}
screen.ScreenX = displaySource.SourceModeInfo.Position.X;
screen.ScreenY = displaySource.SourceModeInfo.Position.Y;
screen.ScreenWidth = (int)displaySource.SourceModeInfo.Resolution.Width;
screen.ScreenHeight = (int)displaySource.SourceModeInfo.Resolution.Height;
break;
}
}
catch (KeyNotFoundException ex)
@ -996,27 +988,18 @@ namespace DisplayMagicianShared
try
{
string displayId = _nvidiaDisplayConfig.MosaicConfig.MosaicGridTopos[i].Displays[0].DisplayId.ToString();
string windowsDisplayName = _nvidiaDisplayConfig.DisplayNames[displayId];
List<uint> sourceIndexes = _windowsDisplayConfig.DisplaySources[windowsDisplayName];
for (int x = 0; x < _windowsDisplayConfig.DisplayConfigModes.Length; x++)
List<NV_DISPLAYCONFIG_PATH_INFO_V2> displaySources = _nvidiaDisplayConfig.DisplayConfigs;
foreach (var displaySource in displaySources)
{
// Skip this if its not a source info config type
if (_windowsDisplayConfig.DisplayConfigModes[x].InfoType != DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE)
{
continue;
}
// If the source index matches the index of the source info object we're looking at, then process it!
if (sourceIndexes.Contains(_windowsDisplayConfig.DisplayConfigModes[x].Id))
{
screen.Name = displayId.ToString();
screen.Name = displayId.ToString();
screen.ScreenX = displaySource.SourceModeInfo.Position.X;
screen.ScreenY = displaySource.SourceModeInfo.Position.Y;
screen.ScreenWidth = (int)displaySource.SourceModeInfo.Resolution.Width;
screen.ScreenHeight = (int)displaySource.SourceModeInfo.Resolution.Height;
break;
screen.ScreenX = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Position.X;
screen.ScreenY = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Position.Y;
screen.ScreenWidth = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Width;
screen.ScreenHeight = (int)_windowsDisplayConfig.DisplayConfigModes[x].SourceMode.Height;
break;
}
}
}
catch (KeyNotFoundException ex)
@ -1049,7 +1032,7 @@ namespace DisplayMagicianShared
}
// Force the taskbar edge to the bottom as it is an NVIDIA surround screen
screen.TaskBarEdge = TaskBarStuckRectangle.TaskBarEdge.Bottom;
screen.TaskBarEdge = TaskBarLayout.TaskBarEdge.Bottom;
SharedLogger.logger.Trace($"ProfileItem/GetNVIDIAScreenPositions: Added a new NVIDIA Spanned Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}.");
@ -1162,20 +1145,23 @@ namespace DisplayMagicianShared
screen.ClonedCopies = 0;
try
{
screen.TaskBarEdge = _windowsDisplayConfig.TaskBarLayout.First(tbr => tbr.DevicePath.Contains($"UID{targetId}")).Edge;
screen.TaskBarEdge = _windowsDisplayConfig.TaskBarLayout.First(tbr => tbr.Value.RegKeyValue.Contains($"UID{targetId}")).Value.Edge;
SharedLogger.logger.Trace($"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen.");
}
catch (Exception ex)
{
// Guess that it is at the bottom (90% correct)
SharedLogger.logger.Error(ex, $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}");
screen.TaskBarEdge = TaskBarStuckRectangle.TaskBarEdge.Bottom;
screen.TaskBarEdge = TaskBarLayout.TaskBarEdge.Bottom;
}
// Find out if this source is cloned
foreach (var displaySource in _windowsDisplayConfig.DisplaySources)
{
if (displaySource.Value.Contains(sourceId))
// All of the items in the Value array are the same source, so we can just check the first one in the array!
if (displaySource.Value[0].SourceId == sourceId)
{
// If there is more than one item in the array, then it's a cloned source!
if (displaySource.Value.Count > 1)
{
// We have a cloned display
@ -1287,11 +1273,26 @@ namespace DisplayMagicianShared
screen.IsSpanned = false;
screen.Colour = normalScreenColor; // this is the default unless overridden by the primary screen
screen.IsClone = false;
screen.ClonedCopies = 0;
screen.ClonedCopies = 0;
try
{
screen.TaskBarEdge = _windowsDisplayConfig.TaskBarLayout.First(tbr => tbr.Value.RegKeyValue.Contains($"UID{targetId}")).Value.Edge;
SharedLogger.logger.Trace($"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen.");
}
catch (Exception ex)
{
// Guess that it is at the bottom (90% correct)
SharedLogger.logger.Error(ex, $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}");
screen.TaskBarEdge = TaskBarLayout.TaskBarEdge.Bottom;
}
// Find out if this source is cloned
foreach (var displaySource in _windowsDisplayConfig.DisplaySources)
{
if (displaySource.Value.Contains(sourceId))
// All of the items in the Value array are the same source, so we can just check the first one in the array!
if (displaySource.Value[0].SourceId == sourceId)
{
// If there is more than one item in the array, then it's a cloned source!
if (displaySource.Value.Count > 1)
{
// We have a cloned display

View File

@ -67,7 +67,7 @@ namespace DisplayMagicianShared
public static string AppIconPath = System.IO.Path.Combine(AppDataPath, $"Icons");
public static string AppDisplayMagicianIconFilename = System.IO.Path.Combine(AppIconPath, @"DisplayMagician.ico");
private static readonly string AppProfileStoragePath = System.IO.Path.Combine(AppDataPath, $"Profiles");
private static readonly string _profileStorageJsonFileName = System.IO.Path.Combine(AppProfileStoragePath, $"DisplayProfiles_2.2.json");
private static readonly string _profileStorageJsonFileName = System.IO.Path.Combine(AppProfileStoragePath, $"DisplayProfiles_2.3.json");

View File

@ -1,6 +1,7 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using DisplayMagicianShared.Windows;
namespace DisplayMagicianShared.UserControls
{
@ -211,19 +212,19 @@ namespace DisplayMagicianShared.UserControls
int startButtonSize = 2 * startButtonSpacer;
switch (screen.TaskBarEdge)
{
case Windows.TaskBarStuckRectangle.TaskBarEdge.Left:
case TaskBarLayout.TaskBarEdge.Left:
taskBarRect = new Rectangle(screenRect.X, screenRect.Y + 2, taskBarWidth, screenRect.Height - 4);
startButtonRect = new Rectangle(taskBarRect.X + startButtonSpacer, taskBarRect.Y + startButtonSpacer, startButtonSize, startButtonSize);
break;
case Windows.TaskBarStuckRectangle.TaskBarEdge.Top:
case TaskBarLayout.TaskBarEdge.Top:
taskBarRect = new Rectangle(screenRect.X + 2, screenRect.Y, screenRect.Width - 4, taskBarWidth);
startButtonRect = new Rectangle(taskBarRect.X + startButtonSpacer, taskBarRect.Y + startButtonSpacer, startButtonSize, startButtonSize);
break;
case Windows.TaskBarStuckRectangle.TaskBarEdge.Right:
case TaskBarLayout.TaskBarEdge.Right:
taskBarRect = new Rectangle(screenRect.X + screenRect.Width - taskBarWidth, screenRect.Y + 2, taskBarWidth, screenRect.Height - 4);
startButtonRect = new Rectangle(taskBarRect.X + startButtonSpacer, taskBarRect.Y + startButtonSpacer, startButtonSize, startButtonSize);
break;
case Windows.TaskBarStuckRectangle.TaskBarEdge.Bottom:
case TaskBarLayout.TaskBarEdge.Bottom:
taskBarRect = new Rectangle(screenRect.X + 2, screenRect.Y + screenRect.Height - taskBarWidth, screenRect.Width - 4, taskBarWidth);
startButtonRect = new Rectangle(taskBarRect.X + startButtonSpacer, taskBarRect.Y + startButtonSpacer, startButtonSize, startButtonSize);
break;

View File

@ -762,17 +762,6 @@ namespace DisplayMagician.UIForms
string targetURL = @"https://github.com/sponsors/terrymacdonald";
System.Diagnostics.Process.Start(targetURL);
}
private void btn_tools_Click(object sender, EventArgs e)
{
ProfileToolsForm profileToolsForm = new ProfileToolsForm();
profileToolsForm.CurrentProfile = _selectedProfile;
profileToolsForm.ShowDialog(this);
if (profileToolsForm.DialogResult == DialogResult.OK)
{
// If we change something, then we refresh the current profile
btn_view_current.PerformClick();
}
}
}
}