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