2008-01-25 10:02:05 +00:00
|
|
|
|
#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.
|
|
|
|
|
*/
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
using OpenTK.Graphics;
|
2008-01-25 13:13:05 +00:00
|
|
|
|
using System.Diagnostics;
|
2008-01-25 10:02:05 +00:00
|
|
|
|
|
|
|
|
|
namespace OpenTK.Platform.X11
|
|
|
|
|
{
|
|
|
|
|
internal class X11XrandrDisplayDevice : IDisplayDeviceDriver
|
|
|
|
|
{
|
2008-01-25 13:13:05 +00:00
|
|
|
|
static object display_lock = new object();
|
2008-01-26 10:29:13 +00:00
|
|
|
|
int current_size = -1; // current_size == -1 means it hasn't been changed.
|
|
|
|
|
int current_refresh;
|
|
|
|
|
// 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<Dictionary<DisplayResolution, int>> screenResolutionToIndex =
|
|
|
|
|
new List<Dictionary<DisplayResolution, int>>();
|
2008-01-27 14:23:13 +00:00
|
|
|
|
// Store a mapping between DisplayDevices and their default resolutions.
|
|
|
|
|
static Dictionary<DisplayDevice, int> deviceToDefaultResolution = new Dictionary<DisplayDevice, int>();
|
2008-01-26 10:29:13 +00:00
|
|
|
|
// Store a mapping between DisplayDevices and X11 screens.
|
|
|
|
|
static Dictionary<DisplayDevice, int> deviceToScreen = new Dictionary<DisplayDevice, int>();
|
|
|
|
|
// Keep the time when the config of each screen was last updated.
|
|
|
|
|
static List<uint> lastConfigUpdate = new List<uint>();
|
|
|
|
|
|
2008-01-25 10:02:05 +00:00
|
|
|
|
#region --- Constructors ---
|
|
|
|
|
|
|
|
|
|
static X11XrandrDisplayDevice()
|
|
|
|
|
{
|
2008-01-25 14:32:51 +00:00
|
|
|
|
// Get available resolutions. Then, for each resolution get all
|
|
|
|
|
// available rates.
|
|
|
|
|
// TODO: Find a way to get all available depths, too.
|
2008-01-25 15:04:10 +00:00
|
|
|
|
// TODO: Global X11 lock.
|
|
|
|
|
for (int screen = 0; screen < API.ScreenCount; screen++)
|
|
|
|
|
{
|
2008-01-26 10:29:13 +00:00
|
|
|
|
uint 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>();
|
|
|
|
|
|
|
|
|
|
// Add info for a new screen.
|
|
|
|
|
screenResolutionToIndex.Add(new Dictionary<DisplayResolution, int>());
|
|
|
|
|
|
|
|
|
|
int[] depths = FindAvailableDepths(screen);
|
|
|
|
|
|
|
|
|
|
int resolution_count = 0;
|
|
|
|
|
foreach (XRRScreenSize size in FindAvailableResolutions(screen))
|
|
|
|
|
{
|
|
|
|
|
short[] rates = Functions.XRRRates(API.DefaultDisplay, screen, resolution_count);
|
2008-01-25 16:11:46 +00:00
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
// 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
|
|
|
|
|
// "Screens and Graphics" does report these modes, though.
|
|
|
|
|
foreach (short rate in rates)
|
|
|
|
|
{
|
|
|
|
|
if (rate != 0)
|
|
|
|
|
foreach (int depth in depths)
|
|
|
|
|
available_res.Add(new DisplayResolution(size.Width, size.Height, depth, (float)rate));
|
|
|
|
|
}
|
|
|
|
|
// Keep the index of this resolution - we will need it for resolution changes later.
|
2008-01-26 10:33:42 +00:00
|
|
|
|
foreach (int depth in depths)
|
|
|
|
|
screenResolutionToIndex[screen].Add(new DisplayResolution(size.Width, size.Height, depth, 0),
|
|
|
|
|
resolution_count);
|
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
++resolution_count;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-25 16:11:46 +00:00
|
|
|
|
|
2008-01-27 14:23:13 +00:00
|
|
|
|
// The resolution of the current DisplayDevice is discovered through XRRConfigCurrentConfiguration.
|
2008-01-25 15:04:10 +00:00
|
|
|
|
// Its refresh rate is discovered by the FindCurrentRefreshRate call.
|
2008-01-25 16:11:46 +00:00
|
|
|
|
// Its depth is discovered by the FindCurrentDepth call.
|
2008-01-27 14:23:13 +00:00
|
|
|
|
float current_refresh_rate = FindCurrentRefreshRate(screen);
|
|
|
|
|
int current_depth = FindCurrentDepth(screen);
|
|
|
|
|
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, Functions.XRootWindow(API.DefaultDisplay, screen));
|
|
|
|
|
ushort current_rotation; // Not needed.
|
|
|
|
|
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
|
|
|
|
|
|
|
|
|
|
DisplayDevice current_device = new DisplayDevice(
|
|
|
|
|
new DisplayResolution(
|
|
|
|
|
available_res[current_resolution_index].Width,
|
|
|
|
|
available_res[current_resolution_index].Height,
|
|
|
|
|
current_depth, current_refresh_rate),
|
|
|
|
|
screen == API.DefaultScreen, available_res);
|
|
|
|
|
|
|
|
|
|
deviceToScreen.Add(current_device, screen);
|
|
|
|
|
deviceToDefaultResolution.Add(current_device, current_resolution_index);
|
2008-01-25 15:04:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal X11XrandrDisplayDevice() { }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region --- Private Methods ---
|
2008-01-25 14:32:51 +00:00
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
#region static int[] FindAvailableDepths(int screen)
|
2008-01-25 15:04:10 +00:00
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
static int[] FindAvailableDepths(int screen)
|
2008-01-25 15:04:10 +00:00
|
|
|
|
{
|
2008-01-26 10:29:13 +00:00
|
|
|
|
return Functions.XListDepths(API.DefaultDisplay, screen);
|
2008-01-25 10:02:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-25 15:04:10 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
#region static XRRScreenSize[] FindAvailableResolutions(int screen)
|
2008-01-25 16:11:46 +00:00
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
static XRRScreenSize[] FindAvailableResolutions(int screen)
|
2008-01-25 10:02:05 +00:00
|
|
|
|
{
|
2008-01-26 10:29:13 +00:00
|
|
|
|
XRRScreenSize[] resolutions = Functions.XRRSizes(API.DefaultDisplay, screen);
|
|
|
|
|
if (resolutions == null)
|
|
|
|
|
throw new NotSupportedException("XRandR extensions not available.");
|
|
|
|
|
return resolutions;
|
2008-01-25 10:02:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-25 16:11:46 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
#region static float FindCurrentRefreshRate(int screen)
|
2008-01-25 16:11:46 +00:00
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
static float FindCurrentRefreshRate(int screen)
|
2008-01-25 15:31:38 +00:00
|
|
|
|
{
|
2008-01-26 10:29:13 +00:00
|
|
|
|
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, API.RootWindow);
|
|
|
|
|
ushort rotation = 0;
|
|
|
|
|
int size = Functions.XRRConfigCurrentConfiguration(screen_config, out rotation);
|
|
|
|
|
short rate = Functions.XRRConfigCurrentRate(screen_config);
|
|
|
|
|
Functions.XRRFreeScreenConfigInfo(screen_config);
|
|
|
|
|
|
|
|
|
|
return (float)rate;
|
2008-01-25 15:31:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-25 10:02:05 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
#region private static int FindCurrentDepth(int screen)
|
2008-01-25 16:11:46 +00:00
|
|
|
|
|
2008-01-26 10:29:13 +00:00
|
|
|
|
private static int FindCurrentDepth(int screen)
|
2008-01-25 16:11:46 +00:00
|
|
|
|
{
|
2008-01-26 10:29:13 +00:00
|
|
|
|
return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen);
|
2008-01-25 16:11:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-25 10:02:05 +00:00
|
|
|
|
#region --- IDisplayDeviceDriver Members ---
|
|
|
|
|
|
|
|
|
|
public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
|
|
|
|
|
{
|
2008-01-26 10:29:13 +00:00
|
|
|
|
// If resolution == null, restore to default resolution (new_resolution_index = 0).
|
|
|
|
|
|
|
|
|
|
int screen = deviceToScreen[device];
|
|
|
|
|
IntPtr root = Functions.XRootWindow(API.DefaultDisplay, screen);
|
|
|
|
|
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, root);
|
|
|
|
|
|
|
|
|
|
ushort current_rotation;
|
|
|
|
|
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
|
|
|
|
|
int new_resolution_index;
|
|
|
|
|
if (resolution != null)
|
|
|
|
|
new_resolution_index = screenResolutionToIndex[screen]
|
|
|
|
|
[new DisplayResolution(resolution.Width, resolution.Height, resolution.BitsPerPixel, 0)];
|
|
|
|
|
else
|
2008-01-27 14:23:13 +00:00
|
|
|
|
new_resolution_index = deviceToDefaultResolution[device];
|
2008-01-26 10:29:13 +00:00
|
|
|
|
|
|
|
|
|
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,
|
2008-01-26 10:45:13 +00:00
|
|
|
|
current_rotation, (short)(resolution != null ? resolution.RefreshRate : 0), lastConfigUpdate[screen]);
|
2008-01-25 10:02:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-26 11:01:20 +00:00
|
|
|
|
public bool TryRestoreResolution(DisplayDevice device)
|
2008-01-25 10:02:05 +00:00
|
|
|
|
{
|
2008-01-26 11:01:20 +00:00
|
|
|
|
return TryChangeResolution(device, null);
|
2008-01-26 10:45:13 +00:00
|
|
|
|
//System.Diagnostics.Process.Start("xrandr", "-s -0").WaitForExit(); // Hack, but works ;)
|
2008-01-25 10:02:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|