2013-10-17 53 views
3

我在Ubuntu上遇到了一些有關全屏行爲的奇怪問題。窗口模式工作正常,但「假」(SDL_WINDOW_FULLSCREEN)和「真實」(SDL_WINDOW_FULLSCREEN_DESKTOP)全屏模式都沒有。Ubuntu中的全屏模式(SDL + OpenGL)

在Windows上,「假」全屏模式會更改視頻模式,並且我們將窗口的內容看到整個顯示屏。 「真實」全屏模式需要桌面的大小。在這種模式下,我在左上角繪製窗口的內容,並將其餘區域留空。

在Ubuntu上,「假」全屏模式會改變視頻模式,並且窗口的內容會被拉伸到整個顯示屏,但只會繪製其中的一部分內容。它可以是頂部(顯示器的90%以上)或底部(顯示器的10%以下)。未繪製的部分爲黑色或包含應用程序定義之前在屏幕上繪製的內容。有時候應用程序在退出時不會改變視頻模式。即使只繪製底部部分,光標也會鎖定在頂部內部。

「真實」全屏模式可能是全黑或在顯示屏中央顯示窗口內容。內容轉移到頂部,並且該區域周圍的所有內容都是黑色的(儘管背景顏色不是)。在這種模式下,光標被鎖定在該區域內。

如果我在運行時更改全屏模式,繪製區域(也是光標被鎖定的區域)的行爲會有所不同,它不僅可以位於任何位置,不僅可以位於「假」模式的頂部/底部,也可以位於「真實」 。

  • 在Windows上 「打假」 全屏模式: (800×600:視頻模式)
  • 「真實」 在Windows全屏模式:real windows (800×600窗口的內容繪製在角落裏,其他面積空)
  • 「假」全屏Ubuntu的模式:fake ubuntu (800×600:視頻模式,但不是整個區域可見你可以看到,雖然gedit中的一部分。 )
  • 「真正的」全屏Ubuntu的模式:real ubuntu (800x600的區域中心,但圖像轉移到頂部(紅方意味着要在角落))

我很手動使用OpenGL在屏幕上繪製而不是SDL。我寫了一個小例子來說明問題。它創建一個800x600的窗口,並在它的中心繪製一個藍色三角形。綠色正方形畫在屏幕的角落,紅色正方形畫在窗口的角落(這些可以在同一個地方,所以綠色方塊比較大,紅色正方形畫在上面)。可以分別使用'1','2'或'3'鍵輸入窗口化的「假」或「真實」全屏模式。退出鍵關閉應用程序。

#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); 
} 
+0

SDL_WINDOW_FULLSCREEN意思是「按照用戶請求的最接近的匹配視頻模式進行全屏顯示」,而SDL_WINDOW_FULLSCREEN_DESKTOP表示「以當前桌面分辨率全屏顯示」,我不明白你的意思。根據窗口管理器,顯卡驅動程序,顯示器數量,xrandr支持等(在我的系統上運行KDE + nVidia blob + Twinview),Linux上更改模式可能會也可能不會正常工作。如果您的系統沒有按預期運行,請儘可能詳細地填寫錯誤。 – gabomdq

回答

3

模式轉換是eeeeevil,特別是在多顯示器環境中。

嘗試無國界,桌面大小的窗口,而不是:

#include <GL/glew.h> 
#include <SDL2/SDL.h> 

// use border state as proxy for fullscreenedness 
SDL_Rect ToggleFakeFullscreen(SDL_Window* window, const SDL_Rect& oldBounds) 
{ 
    if(SDL_GetWindowFlags(window) & SDL_WINDOW_BORDERLESS) 
    { 
     SDL_SetWindowBordered(window, SDL_TRUE); 
     SDL_SetWindowSize(window, oldBounds.w, oldBounds.h); 
     SDL_SetWindowPosition(window, oldBounds.x, oldBounds.y); 
     return oldBounds; 
    } 
    else 
    { 
     SDL_Rect curBounds; 
     SDL_GetWindowPosition(window, &curBounds.x, &curBounds.y); 
     SDL_GetWindowSize(window, &curBounds.w, &curBounds.h); 

     int idx = SDL_GetWindowDisplayIndex(window); 
     SDL_Rect bounds; 
     SDL_GetDisplayBounds(idx, &bounds); 
     SDL_SetWindowBordered(window, SDL_FALSE); 
     SDL_SetWindowPosition(window, bounds.x, bounds.y); 
     SDL_SetWindowSize(window, bounds.w, bounds.h); 

     return curBounds; 
    } 
} 

int main(int argc, char **argv) 
{ 
    if(SDL_Init(SDL_INIT_EVERYTHING) < 0) 
     return -1; 

    SDL_Window* window = SDL_CreateWindow 
     (
     "Test", 
     SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 
     640, 480, 
     SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL 
     ); 
    if(NULL == window) 
     return -1; 

    SDL_GLContext ctx = SDL_GL_CreateContext(window); 
    if(GLEW_OK != glewInit()) 
     return -1; 

    SDL_Rect curBounds; 

    bool running = true; 
    while(running) 
    { 
     SDL_Event ev; 
     while(SDL_WaitEventTimeout(&ev, 16)) 
     { 
      if(ev.type == SDL_QUIT) 
       running = false; 
      if(ev.type == SDL_KEYUP && 
       ev.key.keysym.sym == SDLK_ESCAPE) 
       running = false; 

      if(ev.type == SDL_KEYUP && 
       ev.key.keysym.sym == SDLK_f) 
       curBounds = ToggleFakeFullscreen(window, curBounds); 
     } 

     int w, h; 
     SDL_GetWindowSize(window, &w, &h); 
     glViewport(0, 0, w, h); 

     glClearColor(0, 0, 0, 1); 
     glClear(GL_COLOR_BUFFER_BIT); 

     glMatrixMode(GL_PROJECTION); 
     glLoadIdentity(); 

     glMatrixMode(GL_MODELVIEW); 
     glLoadIdentity(); 

     glColor3ub(255, 0, 0); 
     glBegin(GL_TRIANGLES); 
     glVertex2i(-1, -1); 
     glVertex2i( 1, -1); 
     glVertex2i( 0, 1); 
     glEnd(); 

     SDL_GL_SwapWindow(window); 
    } 

    SDL_GL_DeleteContext(ctx); 
    SDL_DestroyWindow(window); 
    SDL_Quit(); 

    return 0; 
} 

命中f切換 「全屏」。

+0

嗯,有趣的想法。看起來像正確的解決方案,因爲假全屏,但至少它的工作=)謝謝。如果我找不到更好的東西,我想我會用這個。 在Ubuntu上,頂部面板總是在窗口之上。對我來說沒問題,但這不是真正的全屏顯示。 –

+0

在窗口上,如果窗口可調整大小,則在虛假全屏模式下,底部和左邊緣仍將有一個小邊框。 – manylegged