Blender  V3.3
GHOST_DisplayManagerX11.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved.
3  * 1997-2001 Id Software, Inc. Video mode switching.
4  * Ported from Quake 2 by Alex Fraser <alex@phatcore.com>. */
5 
10 #include <stdio.h>
11 
12 #ifdef WITH_X11_XF86VMODE
13 # include <X11/Xlib.h>
14 # include <X11/extensions/xf86vmode.h>
15 #endif
16 
18 #include "GHOST_SystemX11.h"
19 
21  : GHOST_DisplayManager(), m_system(system)
22 {
23  /* nothing to do. */
24 }
25 
27 {
28  numDisplays = m_system->getNumDisplays();
29  return GHOST_kSuccess;
30 }
31 
33  int32_t &numSettings) const
34 {
35 #ifdef WITH_X11_XF86VMODE
36  int majorVersion, minorVersion;
37  XF86VidModeModeInfo **vidmodes;
38  Display *dpy = m_system->getXDisplay();
39 
40  GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
41 
42  if (dpy == nullptr) {
43  return GHOST_kFailure;
44  }
45 
46  majorVersion = minorVersion = 0;
47  if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
48  fprintf(stderr, "Error: XF86VidMode extension missing!\n");
49  return GHOST_kFailure;
50  }
51 
52  if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes)) {
53  XFree(vidmodes);
54  }
55 
56 #else
57  /* We only have one X11 setting at the moment. */
58  GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
59  numSettings = 1;
60 #endif
61 
62  (void)display;
63  return GHOST_kSuccess;
64 }
65 
66 /* from SDL2 */
67 #ifdef WITH_X11_XF86VMODE
68 static int calculate_rate(XF86VidModeModeInfo *info)
69 {
70  return (info->htotal && info->vtotal) ? (1000 * info->dotclock / (info->htotal * info->vtotal)) :
71  0;
72 }
73 #endif
74 
76  int32_t index,
77  GHOST_DisplaySetting &setting) const
78 {
79  Display *dpy = m_system->getXDisplay();
80 
81  if (dpy == nullptr) {
82  return GHOST_kFailure;
83  }
84 
85  (void)display;
86 
87 #ifdef WITH_X11_XF86VMODE
88  int majorVersion, minorVersion;
89 
90  GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
91 
92  majorVersion = minorVersion = 0;
93  if (XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
94  XF86VidModeModeInfo **vidmodes;
95  int numSettings;
96 
97  if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &numSettings, &vidmodes)) {
98  GHOST_ASSERT(index < numSettings, "Requested setting outside of valid range.\n");
99 
100  setting.xPixels = vidmodes[index]->hdisplay;
101  setting.yPixels = vidmodes[index]->vdisplay;
102  setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
103  setting.frequency = calculate_rate(vidmodes[index]);
104  XFree(vidmodes);
105 
106  return GHOST_kSuccess;
107  }
108  }
109  else {
110  fprintf(stderr, "Warning: XF86VidMode extension missing!\n");
111  /* fallback to non xf86vmode below */
112  }
113 #endif /* WITH_X11_XF86VMODE */
114 
115  GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
116  GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n");
117  (void)index;
118 
119  setting.xPixels = DisplayWidth(dpy, DefaultScreen(dpy));
120  setting.yPixels = DisplayHeight(dpy, DefaultScreen(dpy));
121  setting.bpp = DefaultDepth(dpy, DefaultScreen(dpy));
122  setting.frequency = 60.0f;
123 
124  return GHOST_kSuccess;
125 }
126 
128  uint8_t display, GHOST_DisplaySetting &setting) const
129 {
130  /* According to the xf86vidmodegetallmodelines man page,
131  * "The first element of the array corresponds to the current video mode."
132  */
133  return getDisplaySetting(display, 0, setting);
134 }
135 
137  uint8_t /*display*/, const GHOST_DisplaySetting &setting)
138 {
139 #ifdef WITH_X11_XF86VMODE
140  /* Mode switching code ported from SDL:
141  * See: src/video/x11/SDL_x11modes.c:set_best_resolution
142  */
143  int majorVersion, minorVersion;
144  XF86VidModeModeInfo **vidmodes;
145  Display *dpy = m_system->getXDisplay();
146  int scrnum, num_vidmodes;
147 
148  if (dpy == nullptr) {
149  return GHOST_kFailure;
150  }
151 
152  scrnum = DefaultScreen(dpy);
153 
154  /* Get video mode list */
155  majorVersion = minorVersion = 0;
156  if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
157  fprintf(stderr, "Error: XF86VidMode extension missing!\n");
158  return GHOST_kFailure;
159  }
160 # ifdef DEBUG
161  printf("Using XFree86-VidModeExtension Version %d.%d\n", majorVersion, minorVersion);
162 # endif
163 
164  if (XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes)) {
165  int best_fit = -1;
166 
167  for (int i = 0; i < num_vidmodes; i++) {
168  if (vidmodes[i]->hdisplay < setting.xPixels || vidmodes[i]->vdisplay < setting.yPixels) {
169  continue;
170  }
171 
172  if (best_fit == -1 || (vidmodes[i]->hdisplay < vidmodes[best_fit]->hdisplay) ||
173  (vidmodes[i]->hdisplay == vidmodes[best_fit]->hdisplay &&
174  vidmodes[i]->vdisplay < vidmodes[best_fit]->vdisplay)) {
175  best_fit = i;
176  continue;
177  }
178 
179  if ((vidmodes[i]->hdisplay == vidmodes[best_fit]->hdisplay) &&
180  (vidmodes[i]->vdisplay == vidmodes[best_fit]->vdisplay)) {
181  if (!setting.frequency) {
182  /* Higher is better, right? */
183  if (calculate_rate(vidmodes[i]) > calculate_rate(vidmodes[best_fit])) {
184  best_fit = i;
185  }
186  }
187  else {
188  if (abs(calculate_rate(vidmodes[i]) - (int)setting.frequency) <
189  abs(calculate_rate(vidmodes[best_fit]) - (int)setting.frequency)) {
190  best_fit = i;
191  }
192  }
193  }
194  }
195 
196  if (best_fit != -1) {
197 # ifdef DEBUG
198  printf("Switching to video mode %dx%d %dx%d %d\n",
199  vidmodes[best_fit]->hdisplay,
200  vidmodes[best_fit]->vdisplay,
201  vidmodes[best_fit]->htotal,
202  vidmodes[best_fit]->vtotal,
203  calculate_rate(vidmodes[best_fit]));
204 # endif
205 
206  /* change to the mode */
207  XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
208 
209  /* Move the viewport to top left */
210  XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
211  }
212 
213  XFree(vidmodes);
214  }
215  else {
216  return GHOST_kFailure;
217  }
218 
219  XFlush(dpy);
220  return GHOST_kSuccess;
221 
222 #else
223  (void)setting;
224 
225  /* Just pretend the request was successful. */
226  return GHOST_kSuccess;
227 #endif
228 }
#define GHOST_ASSERT(x, info)
Definition: GHOST_Debug.h:54
GHOST_TSuccess
Definition: GHOST_Types.h:74
@ GHOST_kFailure
Definition: GHOST_Types.h:74
@ GHOST_kSuccess
Definition: GHOST_Types.h:74
GHOST_TSuccess getNumDisplaySettings(uint8_t display, int32_t &numSettings) const
GHOST_DisplayManagerX11(GHOST_SystemX11 *system)
GHOST_TSuccess getDisplaySetting(uint8_t display, int32_t index, GHOST_DisplaySetting &setting) const
GHOST_TSuccess getNumDisplays(uint8_t &numDisplays) const
GHOST_TSuccess setCurrentDisplaySetting(uint8_t display, const GHOST_DisplaySetting &setting)
GHOST_TSuccess getCurrentDisplaySetting(uint8_t display, GHOST_DisplaySetting &setting) const
Display * getXDisplay()
uint8_t getNumDisplays() const
SyclQueue void void size_t num_bytes void
T abs(const T &a)
signed int int32_t
Definition: stdint.h:77
unsigned char uint8_t
Definition: stdint.h:78