* Platform/Windows/WinDisplayDevice.cs:

* Platform/MacOS/QuartzDisplayDeviceDriver.cs: Updated to use the new
  DisplayDevice constructors.

* Platform/X11/X11XrandrDisplayDevice.cs: Query Xinerama for the exact
  bounds of each display device, if available.
Use global X lock to protect from multithreaded access.
This commit is contained in:
the_fiddler 2009-11-06 09:50:50 +00:00
parent 2f3481231b
commit 139b6af9fa
3 changed files with 174 additions and 90 deletions

View file

@ -92,7 +92,7 @@ namespace OpenTK.Platform.MacOS
}
DisplayDevice opentk_dev =
new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res);
new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res, Rectangle.Empty);
displayMap.Add(opentk_dev, currentDisplay);
}

View file

@ -1,4 +1,4 @@
#region --- License ---
#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK team.
* This notice may not be removed.
@ -81,7 +81,8 @@ namespace OpenTK.Platform.Windows
opentk_dev = new DisplayDevice(
opentk_dev_current_res,
opentk_dev_primary,
opentk_dev_available_res);
opentk_dev_available_res,
opentk_dev_current_res.Bounds);
available_device_names.Add(opentk_dev, dev1.DeviceName);
}

View file

@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using OpenTK.Graphics;
@ -35,17 +36,59 @@ namespace OpenTK.Platform.X11
static X11XrandrDisplayDevice()
{
// Get available resolutions. Then, for each resolution get all
// available rates.
// TODO: Global X11 lock.
// TODO: Use xinerama to get the bounds of each monitor.
for (int screen = 0; screen < API.ScreenCount; screen++)
{
IntPtr timestamp_of_last_update;
using (new XLock(API.DefaultDisplay))
{
Functions.XRRTimes(API.DefaultDisplay, screen, out timestamp_of_last_update);
List<DisplayDevice> devices = new List<DisplayDevice>();
bool xinerama_supported = false;
try
{
// Try to use Xinerama to obtain the geometry of all output devices.
int event_base, error_base;
if (NativeMethods.XineramaQueryExtension(API.DefaultDisplay, out event_base, out error_base) &&
NativeMethods.XineramaIsActive(API.DefaultDisplay))
{
IList<XineramaScreenInfo> screens = NativeMethods.XineramaQueryScreens(API.DefaultDisplay);
bool first = true;
foreach (XineramaScreenInfo screen in screens)
{
DisplayDevice dev = new DisplayDevice();
dev.Bounds = new Rectangle(screen.X, screen.Y, screen.Width, screen.Height);
if (first)
{
// We consider the first device returned by Xinerama as the primary one.
// Makes sense conceptually, but is there a way to verify this?
dev.IsPrimary = true;
first = false;
}
devices.Add(dev);
// It seems that all X screens are equal to 0 is Xinerama is enabled, at least on Nvidia (verify?)
deviceToScreen.Add(dev, 0 /*screen.ScreenNumber*/);
xinerama_supported = true;
}
}
}
catch { Debug.Print("Xinerama query failed."); }
if (!xinerama_supported)
{
// We assume that devices are equivalent to the number of available screens.
// Note: this won't work correctly in the case of distinct X servers.
for (int i = 0; i < API.ScreenCount; i++)
{
DisplayDevice dev = new DisplayDevice();
dev.IsPrimary = i == Functions.XDefaultScreen(API.DefaultDisplay);
devices.Add(dev);
deviceToScreen.Add(dev, i);
}
}
// Get available resolutions. Then, for each resolution get all available rates.
foreach (DisplayDevice dev in devices)
{
int screen = deviceToScreen[dev];
IntPtr timestamp_of_last_update;
Functions.XRRTimes(API.DefaultDisplay, screen, out timestamp_of_last_update);
lastConfigUpdate.Add(timestamp_of_last_update);
List<DisplayResolution> available_res = new List<DisplayResolution>();
@ -64,10 +107,7 @@ namespace OpenTK.Platform.X11
continue;
}
short[] rates = null;
using (new XLock(API.DefaultDisplay))
{
rates = Functions.XRRRates(API.DefaultDisplay, screen, resolution_count);
}
// It seems that XRRRates returns 0 for modes that are larger than the screen
// can support, as well as for all supported modes. On Ubuntu 7.10 the tool
@ -82,8 +122,15 @@ namespace OpenTK.Platform.X11
}
// Keep the index of this resolution - we will need it for resolution changes later.
foreach (int depth in depths)
screenResolutionToIndex[screen].Add(new DisplayResolution(0, 0, size.Width, size.Height, depth, 0),
resolution_count);
{
// Note that Xinerama may return multiple devices for a single screen. XRandR will
// not distinguish between the two as far as resolutions are supported (since XRandR
// operates on X screens, not display devices) - we need to be careful not to add the
// same resolution twice!
DisplayResolution res = new DisplayResolution(0, 0, size.Width, size.Height, depth, 0);
if (!screenResolutionToIndex[screen].ContainsKey(res))
screenResolutionToIndex[screen].Add(res, resolution_count);
}
++resolution_count;
}
@ -98,16 +145,14 @@ namespace OpenTK.Platform.X11
ushort current_rotation; // Not needed.
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
DisplayDevice current_device = new DisplayDevice(
new DisplayResolution(
0, 0,
available_res[current_resolution_index].Width, available_res[current_resolution_index].Height,
current_depth, current_refresh_rate),
screen == Functions.XDefaultScreen(API.DefaultDisplay),
available_res);
if (dev.Bounds == Rectangle.Empty)
dev.Bounds = new Rectangle(0, 0, available_res[current_resolution_index].Width, available_res[current_resolution_index].Height);
dev.BitsPerPixel = current_depth;
dev.RefreshRate = current_refresh_rate;
dev.AvailableResolutions = available_res;
deviceToScreen.Add(current_device, screen);
deviceToDefaultResolution.Add(current_device, current_resolution_index);
deviceToDefaultResolution.Add(dev, current_resolution_index);
}
}
}
@ -120,12 +165,9 @@ namespace OpenTK.Platform.X11
#region static int[] FindAvailableDepths(int screen)
static int[] FindAvailableDepths(int screen)
{
using (new XLock(API.DefaultDisplay))
{
return Functions.XListDepths(API.DefaultDisplay, screen);
}
}
#endregion
@ -134,10 +176,7 @@ namespace OpenTK.Platform.X11
static XRRScreenSize[] FindAvailableResolutions(int screen)
{
XRRScreenSize[] resolutions = null;
using (new XLock(API.DefaultDisplay))
{
resolutions = Functions.XRRSizes(API.DefaultDisplay, screen);
}
if (resolutions == null)
throw new NotSupportedException("XRandR extensions not available.");
return resolutions;
@ -150,14 +189,11 @@ namespace OpenTK.Platform.X11
static float FindCurrentRefreshRate(int screen)
{
short rate = 0;
using (new XLock(API.DefaultDisplay))
{
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, Functions.XRootWindow(API.DefaultDisplay, screen));
ushort rotation = 0;
int size = Functions.XRRConfigCurrentConfiguration(screen_config, out rotation);
rate = Functions.XRRConfigCurrentRate(screen_config);
Functions.XRRFreeScreenConfigInfo(screen_config);
}
return (float)rate;
}
@ -166,12 +202,9 @@ namespace OpenTK.Platform.X11
#region private static int FindCurrentDepth(int screen)
private static int FindCurrentDepth(int screen)
{
using (new XLock(API.DefaultDisplay))
{
return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen);
}
}
#endregion
@ -181,7 +214,7 @@ namespace OpenTK.Platform.X11
public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
{
// If resolution == null, restore to default resolution (new_resolution_index = 0).
// If resolution is null, restore the default resolution (new_resolution_index = 0).
using (new XLock(API.DefaultDisplay))
{
@ -213,5 +246,55 @@ namespace OpenTK.Platform.X11
}
#endregion
#region NativeMethods
static class NativeMethods
{
const string Xinerama = "libXinerama";
[DllImport(Xinerama)]
public static extern bool XineramaQueryExtension(IntPtr dpy, out int event_basep, out int error_basep);
[DllImport(Xinerama)]
public static extern int XineramaQueryVersion (IntPtr dpy, out int major_versionp, out int minor_versionp);
[DllImport(Xinerama)]
public static extern bool XineramaIsActive(IntPtr dpy);
[DllImport(Xinerama)]
static extern IntPtr XineramaQueryScreens(IntPtr dpy, out int number);
public static IList<XineramaScreenInfo> XineramaQueryScreens(IntPtr dpy)
{
int number;
IntPtr screen_ptr = XineramaQueryScreens(dpy, out number);
List<XineramaScreenInfo> screens = new List<XineramaScreenInfo>(number);
unsafe
{
XineramaScreenInfo* ptr = (XineramaScreenInfo*)screen_ptr;
while (--number >= 0)
{
screens.Add(*ptr);
ptr++;
}
}
return screens;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct XineramaScreenInfo
{
public int ScreenNumber;
public short X;
public short Y;
public short Width;
public short Height;
}
#endregion
}
}