2015-02-18 4 views
3

Я пытаюсь создать окно SDL, которое сохраняет соотношение сторон при изменении размера события. Если пользователь расширяет окно, высота увеличивается и наоборот. Я улавливаю событие SDL_WINDOWEVENT_RESIZED, вычисляет новую ширину или высоту, которая поддерживает соотношение сторон, а затем вызывает SDL_SetWindowSize() с вычисленными значениями.SDL2: Как сохранить соотношение сторон при изменении размера окна

Проблема заключается в том, что вызов функции SDL_SetWindowSize() внутри цикла опроса событий ничего не делает на экране. SDL обновляет переменные размера окна (вызов SDL_GetWindowSize() в моем основном цикле возвращает обновленные размеры окна). Однако фактическое окно не обновляется.

Единственный способ, которым я могу заставить это работать, - постоянно вызывать SDL_SetWindowSize() в основном цикле, но я думаю, что это неправильный способ делать что-то. Следующий код иллюстрирует мою проблему. Есть ли лучший и более чистый способ заставить это работать?

Я использую SDL 2.0.3 и 64-разрядный Ubuntu Linux с рабочим столом GNOME.

#include <SDL2/SDL.h> 

static const float ASPECT_RATIO = 16.f/9.f; 

SDL_Window* window; 
SDL_Renderer* renderer; 

uint32_t windowID; 
SDL_Rect screen; 
bool done = false; 
bool resizeDone = false; 

void handle_events() 
{ 
    SDL_Event e; 
    while (SDL_PollEvent(&e)) { 
     switch (e.type) { 

     case SDL_WINDOWEVENT: 
      if(e.window.windowID == windowID) { 
       switch(e.window.event) { 
        case SDL_WINDOWEVENT_RESIZED: { 
         int width = e.window.data1; 
         int height = e.window.data2; 
         float aspectRatio = (float)width/(float)height; 

         if(aspectRatio != ASPECT_RATIO) { 
          if(aspectRatio > ASPECT_RATIO) { 
           height = (1.f/ASPECT_RATIO) * width; 
          } 
          else { 
           width = ASPECT_RATIO * height; 
          } 

          printf("Setting window size to %d, %d, aspect ratio: %f\n", 
           width, height, (float)width/(float)height); 
        } 
        screen.w = width; 
        screen.h = height; 

        SDL_SetWindowSize(window, width, height); // <-- does not work 
        resizeDone = true; 
        break; 
        } 
       } 
      } 
      break; 

     case SDL_QUIT: 
      done = true; 
      break; 

     default: 
      break; 
     } 
    } 
} 

void run() { 
    while(!done) { 
     //SDL_SetWindowSize(window, screen.w, screen.h); // <-- works 
     handle_events(); 
     SDL_RenderClear(renderer); 
     SDL_RenderPresent(renderer); 

     if(resizeDone) { 
      int w, h; 
      SDL_GetWindowSize(window, &w, &h); 
      printf("SDL_GetWindowSize: %d, %d\n", w, h); 
      resizeDone = false; 
     } 
    } 
} 

int main(int, char**) { 
    SDL_Init(SDL_INIT_VIDEO); 
    uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; 
    window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); 
    windowID = SDL_GetWindowID(window); 
    renderer = SDL_CreateRenderer(window, -1, 0); 
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); 
    run(); 
    SDL_Quit(); 
    return 0; 
} 
+1

Работает для меня, но может быть зависимо от оконного менеджера (или даже композитинга). Во всяком случае, ваш 'if (resizeDone)' выглядит как лучшее место для фактического изменения размера; обработка событий должна просто поднять флаг, который необходимо изменить. – keltar

+0

@keltar: с какой системой вы это проверили? В любом случае, спасибо за предложение, я пробую это с другими оконными менеджерами. 'If ​​(resizeDone)' действительно лучшее место для изменения размера, но при моей текущей настройке окно не изменяется, чтобы скорректировать соотношение сторон, если вызов сделан оттуда. – Scam

ответ

1

Некоторые оконные менеджеры, кажется, игнорирует размер запросов, сделанных в то время как сама WM изменяет размер окна (например, в то время как кнопка мыши проведения). Напротив, SDL_GetWindowSize возвращает кешированные значения, которые в этом конкретном случае иногда случаются неправильно.

Я не вижу никакого независимого от платформы способа достижения этого, кроме постоянного вызова SDL_SetWindowSize на каждом кадре, на всякий случай. Это может быть достигнуто с использованием API-интерфейсов платформы (хотя, например, SDL_GetWindowSysWMInfo, а затем с использованием Xlib).

+0

Я быстро проверил некоторые оконные менеджеры с примером кода. GNOME и XFCE работают неправильно, работает Unity. – Scam

+0

Да, мой первоначальный тест был с openbox. – keltar

+0

Есть ли где-нибудь пример? – franck

Смежные вопросы