From 569c4c86c79f351ec9116047041af80e48e8d4b6 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Sun, 21 Nov 2010 20:16:18 +0000 Subject: [PATCH] Refactored and simplified DisplayDevice detection (devices are now stored in the platform-specific drivers instead of the frontend). Made XRR resolution changes more robust. Resolution changes now refresh the DisplayDevices on Windows. --- Source/OpenTK/DisplayDevice.cs | 96 +++++++---- Source/OpenTK/DisplayIndex.cs | 72 ++++++++ Source/OpenTK/Graphics/GraphicsMode.cs | 4 +- Source/OpenTK/OpenTK.csproj | 2 + Source/OpenTK/Platform/DisplayDeviceBase.cs | 53 ++++++ .../OpenTK/Platform/IDisplayDeviceDriver.cs | 32 +++- Source/OpenTK/Platform/MacOS/AglContext.cs | 2 +- .../MacOS/QuartzDisplayDeviceDriver.cs | 74 ++++---- .../Platform/Windows/WinDisplayDevice.cs | 159 +++++++++++------- .../Platform/Windows/WinGraphicsMode.cs | 2 +- Source/OpenTK/Platform/X11/API.cs | 2 +- .../OpenTK/Platform/X11/X11DisplayDevice.cs | 113 +++++++++---- 12 files changed, 453 insertions(+), 158 deletions(-) create mode 100644 Source/OpenTK/DisplayIndex.cs create mode 100644 Source/OpenTK/Platform/DisplayDeviceBase.cs diff --git a/Source/OpenTK/DisplayDevice.cs b/Source/OpenTK/DisplayDevice.cs index 5a20ba35..a95cb19a 100644 --- a/Source/OpenTK/DisplayDevice.cs +++ b/Source/OpenTK/DisplayDevice.cs @@ -1,16 +1,33 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK team. - * This notice may not be removed. - * See license.txt for licensing detailed licensing details. - */ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// #endregion using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; -using System.Threading; using System.Drawing; namespace OpenTK @@ -21,23 +38,19 @@ namespace OpenTK /// public class DisplayDevice { - // TODO: Add support for refresh rate queries and switches. - // TODO: Check whether bits_per_pixel works correctly under Mono/X11. // TODO: Add properties that describe the 'usable' size of the Display, i.e. the maximized size without the taskbar etc. // TODO: Does not detect changes to primary device. - // TODO: Mono does not support System.Windows.Forms.Screen.BitsPerPixel -- find workaround! - #region --- Fields --- + #region Fields + bool primary; + Rectangle bounds; DisplayResolution current_resolution = new DisplayResolution(), original_resolution; List available_resolutions = new List(); IList available_resolutions_readonly; - bool primary; + + internal object Id; // A platform-specific id for this monitor - Rectangle bounds; - - static readonly List available_displays = new List(); - static readonly IList available_displays_readonly; static readonly object display_lock = new object(); static DisplayDevice primary_display; @@ -45,26 +58,21 @@ namespace OpenTK #endregion - #region --- Constructors --- + #region Constructors static DisplayDevice() { implementation = Platform.Factory.Default.CreateDisplayDeviceDriver(); - available_displays_readonly = available_displays.AsReadOnly(); } internal DisplayDevice() { - lock (display_lock) - { - available_displays.Add(this); - } - available_resolutions_readonly = available_resolutions.AsReadOnly(); } internal DisplayDevice(DisplayResolution currentResolution, bool primary, - IEnumerable availableResolutions, Rectangle bounds) + IEnumerable availableResolutions, Rectangle bounds, + object id) : this() { #warning "Consolidate current resolution with bounds? Can they fall out of sync right now?" @@ -72,9 +80,7 @@ namespace OpenTK IsPrimary = primary; this.available_resolutions.AddRange(availableResolutions); this.bounds = bounds == Rectangle.Empty ? currentResolution.Bounds : bounds; - - Debug.Print("DisplayDevice {0} ({1}) supports {2} resolutions.", - available_displays.Count, primary ? "primary" : "secondary", available_resolutions.Count); + this.Id = id; } #endregion @@ -280,10 +286,23 @@ namespace OpenTK /// /// Gets the list of available objects. + /// This function allocates memory. /// + [Obsolete("Use GetDisplay(DisplayIndex) instead.")] public static IList AvailableDisplays { - get { return available_displays_readonly; } + get + { + List displays = new List(); + for (int i = 0; i < 6; i++) + { + DisplayDevice dev = GetDisplay(DisplayIndex.First + i); + if (dev != null) + displays.Add(dev); + } + + return displays.AsReadOnly(); + } } #endregion @@ -291,7 +310,24 @@ namespace OpenTK #region public static DisplayDevice Default /// Gets the default (primary) display of this system. - public static DisplayDevice Default { get { return primary_display; } } + public static DisplayDevice Default + { + get { return implementation.GetDisplay(DisplayIndex.Primary); } + } + + #endregion + + #region GetDisplay + + /// + /// Gets the for the specified . + /// + /// The that defines the desired display. + /// A or null, if no device corresponds to the specified index. + public static DisplayDevice GetDisplay(DisplayIndex index) + { + return implementation.GetDisplay(index); + } #endregion diff --git a/Source/OpenTK/DisplayIndex.cs b/Source/OpenTK/DisplayIndex.cs new file mode 100644 index 00000000..14ff6cff --- /dev/null +++ b/Source/OpenTK/DisplayIndex.cs @@ -0,0 +1,72 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Defines indices. + /// + public enum DisplayIndex + { + /// + /// The first DisplayDevice. + /// + First = 0, + /// + /// The second DisplayDevice. + /// + Second, + /// + /// The third DisplayDevice. + /// + Third, + /// + /// The fourth DisplayDevice. + /// + Fourth, + /// + /// The fifth DisplayDevice. + /// + Fifth, + /// + /// The sixth DisplayDevice. + /// + Sixth, + /// + /// The default (primary) DisplayDevice. + /// + Primary = -1, + /// + /// The default (primary) DisplayDevice. + /// + Default = Primary, + } +} diff --git a/Source/OpenTK/Graphics/GraphicsMode.cs b/Source/OpenTK/Graphics/GraphicsMode.cs index 6854beb0..89379131 100644 --- a/Source/OpenTK/Graphics/GraphicsMode.cs +++ b/Source/OpenTK/Graphics/GraphicsMode.cs @@ -321,8 +321,8 @@ namespace OpenTK.Graphics { if (defaultMode == null) { - Debug.Print("Creating default GraphicsMode ({0}, {1}, {2}, {3}, {4}, {5}, {6}).", DisplayDevice.Default.BitsPerPixel, - 16, 0, 0, 0, 2, false); + Debug.Print("Creating default GraphicsMode ({0}, {1}, {2}, {3}, {4}, {5}, {6}).", + DisplayDevice.Default.BitsPerPixel, 16, 0, 0, 0, 2, false); defaultMode = new GraphicsMode(DisplayDevice.Default.BitsPerPixel, 16, 0, 0, 0, 2, false); } return defaultMode; diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 803dd745..4dbe1bf0 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -128,11 +128,13 @@ Code + + Code diff --git a/Source/OpenTK/Platform/DisplayDeviceBase.cs b/Source/OpenTK/Platform/DisplayDeviceBase.cs new file mode 100644 index 00000000..723d8221 --- /dev/null +++ b/Source/OpenTK/Platform/DisplayDeviceBase.cs @@ -0,0 +1,53 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Platform +{ + abstract class DisplayDeviceBase : IDisplayDeviceDriver + { + protected readonly List AvailableDevices = new List(); + protected DisplayDevice Primary; + + public abstract bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution); + public abstract bool TryRestoreResolution(DisplayDevice device); + + // Gets the DisplayDevice that corresponds to the specified index. + public virtual DisplayDevice GetDisplay(DisplayIndex index) + { + if (index == DisplayIndex.Primary) + return Primary; + else if ((int)index >= 0 && (int)index < AvailableDevices.Count) + return AvailableDevices[(int)index]; + else + return null; + } + } +} diff --git a/Source/OpenTK/Platform/IDisplayDeviceDriver.cs b/Source/OpenTK/Platform/IDisplayDeviceDriver.cs index f66bca4e..cc3e67da 100644 --- a/Source/OpenTK/Platform/IDisplayDeviceDriver.cs +++ b/Source/OpenTK/Platform/IDisplayDeviceDriver.cs @@ -1,9 +1,28 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK team. - * This notice may not be removed. - * See license.txt for licensing detailed licensing details. - */ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// #endregion using System; @@ -16,5 +35,6 @@ namespace OpenTK.Platform { bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution); bool TryRestoreResolution(DisplayDevice device); + DisplayDevice GetDisplay(DisplayIndex displayIndex); } } diff --git a/Source/OpenTK/Platform/MacOS/AglContext.cs b/Source/OpenTK/Platform/MacOS/AglContext.cs index 4d52d337..960d4abf 100644 --- a/Source/OpenTK/Platform/MacOS/AglContext.cs +++ b/Source/OpenTK/Platform/MacOS/AglContext.cs @@ -140,7 +140,7 @@ namespace OpenTK.Platform.MacOS IntPtr cgdevice = GetQuartzDevice(carbonWindow); if (cgdevice == IntPtr.Zero) - cgdevice = QuartzDisplayDeviceDriver.MainDisplay; + cgdevice = (IntPtr)DisplayDevice.Default.Id; OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(cgdevice, out gdevice, false); diff --git a/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs b/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs index 999b1d45..b7da1bc1 100644 --- a/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs +++ b/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs @@ -1,25 +1,43 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + using System; using System.Collections.Generic; using System.Diagnostics; +using System.Drawing; +using OpenTK.Platform.MacOS.Carbon; namespace OpenTK.Platform.MacOS { - using System.Drawing; - using Carbon; - - class QuartzDisplayDeviceDriver : IDisplayDeviceDriver + sealed class QuartzDisplayDeviceDriver : DisplayDeviceBase { static object display_lock = new object(); - static Dictionary displayMap = new Dictionary(); - - static IntPtr mainDisplay; - static internal IntPtr MainDisplay - { - get { return mainDisplay; } - } - - static QuartzDisplayDeviceDriver() + public QuartzDisplayDeviceDriver() { lock (display_lock) { @@ -52,9 +70,6 @@ namespace OpenTK.Platform.MacOS // main display. bool primary = (i == 0); - if (primary) - mainDisplay = currentDisplay; - // gets current settings int currentWidth = CG.DisplayPixelsWide(currentDisplay); int currentHeight = CG.DisplayPixelsHigh(currentDisplay); @@ -97,22 +112,22 @@ namespace OpenTK.Platform.MacOS Debug.Print("Display {0} bounds: {1}", i, newRect); - DisplayDevice opentk_dev = new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res, newRect); - - displayMap.Add(opentk_dev, currentDisplay); + DisplayDevice opentk_dev = new DisplayDevice(opentk_dev_current_res, + primary, opentk_dev_available_res, newRect, currentDisplay); + + AvailableDevices.Add(opentk_dev); + + if (primary) + Primary = opentk_dev; } Debug.Unindent(); } } - static internal IntPtr HandleTo(DisplayDevice displayDevice) { - if (displayMap.ContainsKey(displayDevice)) - return displayMap[displayDevice]; - else - return IntPtr.Zero; + return (IntPtr)displayDevice.Id; } #region IDisplayDeviceDriver Members @@ -120,9 +135,9 @@ namespace OpenTK.Platform.MacOS Dictionary storedModes = new Dictionary(); List displaysCaptured = new List(); - public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) { - IntPtr display = displayMap[device]; + IntPtr display = HandleTo(device); IntPtr currentModePtr = CG.DisplayCurrentMode(display); if (storedModes.ContainsKey(display) == false) @@ -160,9 +175,9 @@ namespace OpenTK.Platform.MacOS return false; } - public bool TryRestoreResolution(DisplayDevice device) + public sealed override bool TryRestoreResolution(DisplayDevice device) { - IntPtr display = displayMap[device]; + IntPtr display = HandleTo(device); if (storedModes.ContainsKey(display)) { @@ -177,8 +192,7 @@ namespace OpenTK.Platform.MacOS return false; } - + #endregion - } } diff --git a/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs b/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs index ec0025a8..195c119b 100644 --- a/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs +++ b/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs @@ -1,37 +1,101 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK team. - * This notice may not be removed. - * See license.txt for licensing detailed licensing details. - */ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// #endregion using System; using System.Collections.Generic; -using System.Text; - -using OpenTK.Graphics; -using System.Runtime.InteropServices; using System.Diagnostics; namespace OpenTK.Platform.Windows { - internal class WinDisplayDeviceDriver : IDisplayDeviceDriver + sealed class WinDisplayDeviceDriver : DisplayDeviceBase { - static object display_lock = new object(); - static Dictionary available_device_names = - new Dictionary(); // Needed for ChangeDisplaySettingsEx + readonly object display_lock = new object(); - #region --- Constructors --- + #region Constructors - /// Queries available display devices and display resolutions. - static WinDisplayDeviceDriver() + public WinDisplayDeviceDriver() + { + RefreshDisplayDevices(); + Microsoft.Win32.SystemEvents.DisplaySettingsChanged += + HandleDisplaySettingsChanged; + } + + #endregion + + #region IDisplayDeviceDriver Members + + #region TryChangeResolution + + public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + { + DeviceMode mode = null; + + if (resolution != null) + { + mode = new DeviceMode(); + mode.PelsWidth = resolution.Width; + mode.PelsHeight = resolution.Height; + mode.BitsPerPel = resolution.BitsPerPixel; + mode.DisplayFrequency = (int)resolution.RefreshRate; + mode.Fields = Constants.DM_BITSPERPEL + | Constants.DM_PELSWIDTH + | Constants.DM_PELSHEIGHT + | Constants.DM_DISPLAYFREQUENCY; + } + + return Constants.DISP_CHANGE_SUCCESSFUL == + Functions.ChangeDisplaySettingsEx((string)device.Id, mode, IntPtr.Zero, + ChangeDisplaySettingsEnum.Fullscreen, IntPtr.Zero); + } + + #endregion + + #region TryRestoreResolution + + public sealed override bool TryRestoreResolution(DisplayDevice device) + { + return TryChangeResolution(device, null); + } + + #endregion + + #endregion + + #region Private Members + + #region RefreshDisplayDevices + + public void RefreshDisplayDevices() { lock (display_lock) { - // To minimize the need to add static methods to OpenTK.Graphics.DisplayDevice - // we only allow settings to be set through its constructor. - // Thus, we save all necessary parameters in temporary variables + AvailableDevices.Clear(); + + // We save all necessary parameters in temporary variables // and construct the device when every needed detail is available. // The main DisplayDevice constructor adds the newly constructed device // to the list of available devices. @@ -82,56 +146,37 @@ namespace OpenTK.Platform.Windows opentk_dev_current_res, opentk_dev_primary, opentk_dev_available_res, - opentk_dev_current_res.Bounds); + opentk_dev_current_res.Bounds, + dev1.DeviceName); - available_device_names.Add(opentk_dev, dev1.DeviceName); + AvailableDevices.Add(opentk_dev); + + if (opentk_dev_primary) + Primary = opentk_dev; + + Debug.Print("DisplayDevice {0} ({1}) supports {2} resolutions.", + device_count, opentk_dev.IsPrimary ? "primary" : "secondary", opentk_dev.AvailableResolutions.Count); } } } - public WinDisplayDeviceDriver() + #endregion + + #region HandleDisplaySettingsChanged + + void HandleDisplaySettingsChanged(object sender, EventArgs e) { + RefreshDisplayDevices(); } #endregion - #region --- IDisplayDeviceDriver Members --- - - #region public bool TryChangeResolution(OpenTK.Graphics.DisplayDevice device, DisplayResolution resolution) - - public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + ~WinDisplayDeviceDriver() { - DeviceMode mode = null; - - if (resolution != null) - { - mode = new DeviceMode(); - mode.PelsWidth = resolution.Width; - mode.PelsHeight = resolution.Height; - mode.BitsPerPel = resolution.BitsPerPixel; - mode.DisplayFrequency = (int)resolution.RefreshRate; - mode.Fields = Constants.DM_BITSPERPEL - | Constants.DM_PELSWIDTH - | Constants.DM_PELSHEIGHT - | Constants.DM_DISPLAYFREQUENCY; - } - - return Constants.DISP_CHANGE_SUCCESSFUL == - Functions.ChangeDisplaySettingsEx(available_device_names[device], mode, IntPtr.Zero, - ChangeDisplaySettingsEnum.Fullscreen, IntPtr.Zero); + Microsoft.Win32.SystemEvents.DisplaySettingsChanged -= + HandleDisplaySettingsChanged; } #endregion - - #region public TryRestoreResolution TryRestoreResolution(OpenTK.Graphics.DisplayDevice device) - - public bool TryRestoreResolution(DisplayDevice device) - { - return TryChangeResolution(device, null); - } - - #endregion - - #endregion } } diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index c93ae4e1..69d0be95 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -44,7 +44,7 @@ namespace OpenTK.Platform.Windows #endregion - #region --- Constructors --- + #region Constructors public WinGraphicsMode() { diff --git a/Source/OpenTK/Platform/X11/API.cs b/Source/OpenTK/Platform/X11/API.cs index 43581b2b..dd7a5d25 100644 --- a/Source/OpenTK/Platform/X11/API.cs +++ b/Source/OpenTK/Platform/X11/API.cs @@ -1501,7 +1501,7 @@ XF86VidModeGetGammaRampSize( [DllImport(XrandrLibrary)] public static extern Status XRRSetScreenConfig(Display dpy, XRRScreenConfiguration config, - Drawable draw, int size_index, ref Rotation rotation, Time timestamp); + Drawable draw, int size_index, Rotation rotation, Time timestamp); [DllImport(XrandrLibrary)] public static extern Status XRRSetScreenConfigAndRate(Display dpy, XRRScreenConfiguration config, diff --git a/Source/OpenTK/Platform/X11/X11DisplayDevice.cs b/Source/OpenTK/Platform/X11/X11DisplayDevice.cs index 76788beb..3262ce1b 100644 --- a/Source/OpenTK/Platform/X11/X11DisplayDevice.cs +++ b/Source/OpenTK/Platform/X11/X11DisplayDevice.cs @@ -1,9 +1,28 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK Team. - * This notice may not be removed from any source distribution. - * See license.txt for licensing detailed licensing details. - */ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// #endregion using System; @@ -14,27 +33,35 @@ using System.Runtime.InteropServices; namespace OpenTK.Platform.X11 { - internal class X11DisplayDevice : IDisplayDeviceDriver + sealed class X11DisplayDevice : DisplayDeviceBase { - static object display_lock = new object(); // Store a mapping between resolutions and their respective // size_index (needed for XRRSetScreenConfig). The size_index // is simply the sequence number of the resolution as returned by // XRRSizes. This is done per available screen. - static List> screenResolutionToIndex = + readonly List> screenResolutionToIndex = new List>(); // Store a mapping between DisplayDevices and their default resolutions. - static Dictionary deviceToDefaultResolution = new Dictionary(); + readonly Dictionary deviceToDefaultResolution = new Dictionary(); // Store a mapping between DisplayDevices and X11 screens. - static Dictionary deviceToScreen = new Dictionary(); + readonly Dictionary deviceToScreen = new Dictionary(); // Keep the time when the config of each screen was last updated. - static List lastConfigUpdate = new List(); + readonly List lastConfigUpdate = new List(); - static bool xinerama_supported, xrandr_supported, xf86_supported; + bool xinerama_supported, xrandr_supported, xf86_supported; - #region --- Constructors --- + #region Constructors - static X11DisplayDevice() + public X11DisplayDevice() + { + RefreshDisplayDevices(); + } + + #endregion + + #region Private Methods + + void RefreshDisplayDevices() { using (new XLock(API.DefaultDisplay)) { @@ -82,16 +109,23 @@ namespace OpenTK.Platform.X11 Debug.Print("XF86 query failed, no DisplayDevice support available."); } } + + AvailableDevices.Clear(); + AvailableDevices.AddRange(devices); + Primary = FindDefaultDevice(devices); } } - internal X11DisplayDevice() { } + static DisplayDevice FindDefaultDevice(IEnumerable devices) + { + foreach (DisplayDevice dev in devices) + if (dev.IsPrimary) + return dev; - #endregion + throw new InvalidOperationException("No primary display found. Please file a bug at http://www.opentk.com"); + } - #region --- Private Methods --- - - static bool QueryXinerama(List devices) + bool QueryXinerama(List devices) { // Try to use Xinerama to obtain the geometry of all output devices. int event_base, error_base; @@ -119,7 +153,7 @@ namespace OpenTK.Platform.X11 return (devices.Count>0); } - static bool QueryXRandR(List devices) + bool QueryXRandR(List devices) { // Get available resolutions. Then, for each resolution get all available rates. foreach (DisplayDevice dev in devices) @@ -196,7 +230,7 @@ namespace OpenTK.Platform.X11 return true; } - static bool QueryXF86(List devices) + bool QueryXF86(List devices) { int major; int minor; @@ -286,14 +320,14 @@ namespace OpenTK.Platform.X11 #region private static int FindCurrentDepth(int screen) - private static int FindCurrentDepth(int screen) + static int FindCurrentDepth(int screen) { return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen); } #endregion - static bool ChangeResolutionXRandR(DisplayDevice device, DisplayResolution resolution) + bool ChangeResolutionXRandR(DisplayDevice device, DisplayResolution resolution) { using (new XLock(API.DefaultDisplay)) { @@ -313,8 +347,28 @@ namespace OpenTK.Platform.X11 Debug.Print("Changing size of screen {0} from {1} to {2}", screen, current_resolution_index, new_resolution_index); - return 0 == Functions.XRRSetScreenConfigAndRate(API.DefaultDisplay, screen_config, root, new_resolution_index, - current_rotation, (short)(resolution != null ? resolution.RefreshRate : 0), lastConfigUpdate[screen]); + int ret = 0; + short refresh_rate =(short)(resolution != null ? resolution.RefreshRate : 0); + if (refresh_rate > 0) + { + ret = Functions.XRRSetScreenConfigAndRate(API.DefaultDisplay, + screen_config, root, new_resolution_index, current_rotation, + refresh_rate, IntPtr.Zero); + } + else + { + ret = Functions.XRRSetScreenConfig(API.DefaultDisplay, + screen_config, root, new_resolution_index, current_rotation, + IntPtr.Zero); + } + + if (ret != 0) + { + Debug.Print("[Error] Change to resolution {0} failed with error {1}.", + resolution, (ErrorCode)ret); + } + + return ret == 0; } } @@ -325,9 +379,9 @@ namespace OpenTK.Platform.X11 #endregion - #region --- IDisplayDeviceDriver Members --- + #region IDisplayDeviceDriver Members - public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) + public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) { // If resolution is null, restore the default resolution (new_resolution_index = 0). @@ -345,8 +399,7 @@ namespace OpenTK.Platform.X11 } } - - public bool TryRestoreResolution(DisplayDevice device) + public sealed override bool TryRestoreResolution(DisplayDevice device) { return TryChangeResolution(device, null); }