我在Ubuntu上遇到了全屏模式的奇怪问题。窗口模式运行正常,但"伪全屏"(`SDL_WINDOW_FULLSCREEN`)和"真全屏"(`SDL_WINDOW_FULLSCREEN_DESKTOP`)模式都有问题。
在Windows上,"伪全屏"模式会进行视频模式更改,我们可以看到窗口内容被拉伸到整个显示器。"真全屏"模式则占据整个桌面。在该模式下,我将窗口内容绘制在左上角并留出额外的空间。
在Ubuntu上,"伪全屏"模式会进行视频模式更改,窗口内容被拉伸到整个显示器,但只有部分被绘制。它要么是顶部部分(超过90%的显示器)或底部部分(少于10%的显示器)。没有被绘制的部分是黑色的或包含应用程序启动前屏幕上绘制的东西。有时应用程序退出后不会更改视频模式。即使只绘制了底部部分,光标也会锁定在顶部部分内。
"真全屏"模式要么完全是黑的,要么将窗口内容显示在显示器中央。内容被向上移动,并且周围的所有区域都是黑色的(尽管背景颜色不是)。在这种模式下,光标被锁定在该区域内。
如果我在运行时更改全屏模式,则行为会略有不同 - 绘制区域(也是光标锁定的区域)可以位于任何位置,而不仅仅是"伪"模式中的顶部/底部或"真"模式中的中心。
在Windows上,"伪全屏"模式会进行视频模式更改,我们可以看到窗口内容被拉伸到整个显示器。"真全屏"模式则占据整个桌面。在该模式下,我将窗口内容绘制在左上角并留出额外的空间。
在Ubuntu上,"伪全屏"模式会进行视频模式更改,窗口内容被拉伸到整个显示器,但只有部分被绘制。它要么是顶部部分(超过90%的显示器)或底部部分(少于10%的显示器)。没有被绘制的部分是黑色的或包含应用程序启动前屏幕上绘制的东西。有时应用程序退出后不会更改视频模式。即使只绘制了底部部分,光标也会锁定在顶部部分内。
"真全屏"模式要么完全是黑的,要么将窗口内容显示在显示器中央。内容被向上移动,并且周围的所有区域都是黑色的(尽管背景颜色不是)。在这种模式下,光标被锁定在该区域内。
如果我在运行时更改全屏模式,则行为会略有不同 - 绘制区域(也是光标锁定的区域)可以位于任何位置,而不仅仅是"伪"模式中的顶部/底部或"真"模式中的中心。
- Windows上的"伪全屏"模式:
(800x600视频模式)
- Windows上的"真全屏"模式:
(800x600窗口内容绘制在角落,其他区域为空)
- Ubuntu上的"伪全屏"模式:
(800x600视频模式,但不是整个区域都可见。您可以看到gedit的一部分)
- Ubuntu上的"真全屏"模式:
(800x600区域位于中心,但是图像被向上移动(红色正方形应该在角落)
我手动使用OpenGL在屏幕上绘制而不是使用SDL。我写了一个小例子来展示问题。它创建一个800x600的窗口并在其中心绘制了一个蓝色三角形。绿色正方形绘制在屏幕角落,红色正方形绘制在窗口角落(它们可以在同一位置,因此绿色正方形更大,红色正方形位于其上方)。可以使用'1'、'2'或'3'键进入窗口化、"假"或"真"全屏模式。按下Escape键关闭应用程序。
#include <SDL.h>
#include <GL/gl.h>
#define FULLSCREEN 0
#define WIDTH 800
#define HEIGHT 600
//fullscreen:
// 0 - windowed mode,
// 1 - "fake" fullscreen mode,
// 2 - "real" fullscreen mode
int real_width;
int real_height;
//screen width & height - to draw green square that shows us actual screen size
void set_viewport(SDL_Window* window);
void draw(SDL_Window* window);
int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO);
int position;
#if FULLSCREEN == 0
position = SDL_WINDOWPOS_CENTERED;
#else
position = 0;
#endif
//the only thing I've found - some guy said it works
//if window is in (0,0) while entering fullscreen
//well, it's not, but I've kept it
int flags = SDL_WINDOW_OPENGL;
#if FULLSCREEN == 1
flags |= SDL_WINDOW_FULLSCREEN;
#elif FULLSCREEN == 2
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
#endif
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_Window* window = SDL_CreateWindow(
"",
position, position, /* centered/(0,0) */
WIDTH, HEIGHT, /* request 800x600 window */
flags /* needed mode */
);
//setup GL
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
glShadeModel(GL_SMOOTH);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
//viewport and projection
set_viewport(window);
draw(window);
bool done = false;
while(!done) {
draw(window);
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT: done = true; break;
case SDL_KEYDOWN:
if(event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
done = true;
else if(event.key.keysym.scancode == SDL_SCANCODE_1) {
SDL_SetWindowFullscreen(window, 0);
set_viewport(window);
} else if(event.key.keysym.scancode == SDL_SCANCODE_2) {
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
set_viewport(window);
} else if(event.key.keysym.scancode == SDL_SCANCODE_3) {
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
set_viewport(window);
}
break;
}
}
}
SDL_GL_DeleteContext(glcontext);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
void set_viewport(SDL_Window* window) {
SDL_GetWindowSize(window, &real_width, &real_height);
glClearColor(1, 1, 1, 1);
glViewport(0, 0, real_width, real_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, real_width, real_height, 0, -1, 0);
}
void draw_triangle();
void draw_square(int x, int y, float side);
void draw(SDL_Window* window) {
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//triangle on while background
glClearColor(1, 1, 1, 1);
draw_triangle();
//green square at screen corner
glColor3f(0, 1, 0);
draw_square(real_width, real_height, 20);
//red square at window corner
glColor3f(1, 0, 0);
draw_square(WIDTH, HEIGHT, 10);
SDL_GL_SwapWindow(window);
}
void draw_triangle() {
const float w = 460;
const float h = 400;
float colorBuffer[9] = {
0, 0.43f, 0.85f /*#006dd9*/,
0, 0.22f, 0.43f /*#00376e*/,
0, 0.43f, 0.85f /*#006dd9*/
};
float vertexBuffer[9] = {
0, 0, 0,
w/2, h, 0,
w, 0, 0
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glTranslatef((WIDTH-w)/2,(HEIGHT-h)/2,0);
glColorPointer(3, GL_FLOAT, 0, colorBuffer);
glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
glTranslatef(-(WIDTH-w)/2,-(HEIGHT-h)/2,0);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
void draw_square(int x, int y, float side) {
float vertexBuffer[12] = {
0, 0, 0, /*top left*/
0, side, 0, /*bottom left*/
side, side, 0, /*bottom right*/
side, 0, 0 /*top right*/
};
glEnableClientState(GL_VERTEX_ARRAY);
glTranslatef(x-side/2, y-side/2, 0);
glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glTranslatef(-x+side/2, -y+side/2, 0);
glDisableClientState(GL_VERTEX_ARRAY);
}