=====================================================
SDL源代碼分析系列文章列表:
SDL2源代碼分析1:初始化(SDL_Init())
SDL2源代碼分析2:窗口(SDL_Window)
SDL2源代碼分析3:渲染器(SDL_Renderer)
SDL2源代碼分析4:紋理(SDL_Texture)
SDL2源代碼分析5:更新紋理(SDL_UpdateTexture())
SDL2源代碼分析6:複製到渲染器(SDL_RenderCopy())
SDL2源代碼分析7:顯示(SDL_RenderPresent())
SDL2源代碼分析8:視頻顯示總結
=====================================================
上一篇文章分析了SDL的初始化函數SDL_Init()。這篇文章繼續分析SDL的源代碼。本文分析SDL的窗口(SDL_Window)。
SDL播放視頻的代碼流程如下所示。
初始化:
SDL_Init(): 初始化SDL。
SDL_CreateWindow(): 創建窗口(Window)。
SDL_CreateRenderer(): 基於窗口創建渲染器(Render)。
SDL_CreateTexture(): 創建紋理(Texture)。
循環渲染數據:
SDL_UpdateTexture(): 設置紋理的數據。
SDL_RenderCopy(): 紋理複製給渲染器。
SDL_RenderPresent(): 顯示。
上篇文章分析了該流程中的第一個函數SDL_Init()。本文繼續分析該流程中的第二個函數SDL_CreateWindow()。
SDL_Window
SDL_Window結構體定義了一個SDL2中的窗口。如果直接使用SDL2編譯好的SDK的話,是看不到它的內部結構的。有關它的定義在頭文件中只有一行代碼,但是這一行定義前面的註釋非常之多,如下所示:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
typedef struct SDL_Window SDL_Window;
在源代碼工程中可以看到它的定義,位於video\SDL_sysvideo.h文件中。它的定義如下。
-
-
struct SDL_Window
-
{
-
const void *magic;
-
Uint32 id;
-
char *title;
-
SDL_Surface *icon;
-
int x, y;
-
int w, h;
-
int min_w, min_h;
-
int max_w, max_h;
-
Uint32 flags;
-
Uint32 last_fullscreen_flags;
-
-
-
-
SDL_Rect windowed;
-
-
-
SDL_DisplayMode fullscreen_mode;
-
-
-
float brightness;
-
Uint16 *gamma;
-
Uint16 *saved_gamma;
-
-
-
SDL_Surface *surface;
-
SDL_bool surface_valid;
-
-
-
SDL_bool is_destroying;
-
-
-
SDL_WindowShaper *shaper;
-
-
-
SDL_WindowUserData *data;
-
-
-
void *driverdata;
-
-
-
SDL_Window *prev;
-
SDL_Window *next;
-
};
可以看出其中包含了一個“窗口”應該包含的各種屬性。這個結構體中的各個變量還沒有深入研究,暫不詳細分析。下面來看看如何創建這個SDL_Window。
SDL_CreateWindow()
函數簡介
SDL_CreateWindow()用於創建一個視頻播放的窗口。SDL_CreateWindow()的原型如下。
-
SDL_Window * SDLCALL SDL_CreateWindow(const char *title,
-
int x, int y, int w,
-
int h, Uint32 flags);
參數含義如下。
title
:窗口標題
x
:窗口位置x座標。也可以設置爲SDL_WINDOWPOS_CENTERED或SDL_WINDOWPOS_UNDEFINED。
y
:窗口位置y座標。同上。
w
:窗口的寬
h
:窗口的高
flags :支持下列標識。包括了窗口的是否最大化、最小化,能否調整邊界等等屬性。
::SDL_WINDOW_FULLSCREEN, ::SDL_WINDOW_OPENGL,
::SDL_WINDOW_HIDDEN, ::SDL_WINDOW_BORDERLESS,
::SDL_WINDOW_RESIZABLE, ::SDL_WINDOW_MAXIMIZED,
::SDL_WINDOW_MINIMIZED, ::SDL_WINDOW_INPUT_GRABBED,
::SDL_WINDOW_ALLOW_HIGHDPI.
返回創建完成的窗口的ID。如果創建失敗則返回0。
函數調用關係圖
SDL_ CreateWindow ()關鍵函數的調用關係可以用下圖表示。
上面的函數調用關係圖本來是一張高清大圖,但是由於博客對圖片尺寸有限制,因而顯得不太清晰。相冊裏面上傳了一份原始的大圖片:
http://my.csdn.net/leixiaohua1020/album/detail/1793195
打開上述相冊裏面的圖片,右鍵選擇“另存爲”即可保存原始圖片。
源代碼分析
SDL_CreateWindow()的源代碼位於video\SDL_video.c中,如下所示。
-
SDL_Window * SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
-
{
-
SDL_Window *window;
-
const char *hint;
-
-
-
if (!_this) {
-
-
if (SDL_VideoInit(NULL) < 0) {
-
return NULL;
-
}
-
}
-
-
-
-
if (w < 1) {
-
w = 1;
-
}
-
if (h < 1) {
-
h = 1;
-
}
-
-
-
-
#if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__
-
flags |= SDL_WINDOW_OPENGL;
-
#endif
-
if (flags & SDL_WINDOW_OPENGL) {
-
if (!_this->GL_CreateContext) {
-
SDL_SetError("No OpenGL support in video driver");
-
return NULL;
-
}
-
if (SDL_GL_LoadLibrary(NULL) < 0) {
-
return NULL;
-
}
-
}
-
-
-
-
-
-
if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
-
hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
-
if (hint && SDL_atoi(hint) > 0) {
-
flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
-
}
-
}
-
-
-
window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
-
if (!window) {
-
SDL_OutOfMemory();
-
return NULL;
-
}
-
window->magic = &_this->window_magic;
-
window->id = _this->next_object_id++;
-
window->x = x;
-
window->y = y;
-
window->w = w;
-
window->h = h;
-
if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
-
SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
-
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
-
int displayIndex;
-
SDL_Rect bounds;
-
-
-
displayIndex = SDL_GetIndexOfDisplay(display);
-
SDL_GetDisplayBounds(displayIndex, &bounds);
-
if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
-
window->x = bounds.x + (bounds.w - w) / 2;
-
}
-
if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
-
window->y = bounds.y + (bounds.h - h) / 2;
-
}
-
}
-
window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
-
window->last_fullscreen_flags = window->flags;
-
window->brightness = 1.0f;
-
window->next = _this->windows;
-
window->is_destroying = SDL_FALSE;
-
-
-
if (_this->windows) {
-
_this->windows->prev = window;
-
}
-
_this->windows = window;
-
-
-
if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
-
SDL_DestroyWindow(window);
-
return NULL;
-
}
-
-
-
if (title) {
-
SDL_SetWindowTitle(window, title);
-
}
-
SDL_FinishWindowCreation(window, flags);
-
-
-
-
SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
-
-
-
return window;
-
}
下面總結一下SDL_CreateWindow()的大致流程。
1. 一些爲了保證各個平臺的兼容性的初始化工作。各個平臺創建窗口的條件不同。例如,某些平臺不支持創建大小爲0的窗口。再例如,某些平臺默認開啓OpenGL。
2. 調用SDL_calloc()爲SDL_Window結構體分配一塊內存。同時設置一些基本屬性,例如窗口的寬高,位置等等。
PS:上篇文章中已經提過,在這裏重複一下SDL中內存分配函數的知識。在SDL中分配內存使用SDL_malloc(),SDL_calloc(),這些函數實際上就是malloc(),calloc()。它們的定義位於stdlib\SDL_malloc.c文件中。如下所示:
-
#define memset SDL_memset
-
#define memcpy SDL_memcpy
-
#define malloc SDL_malloc
-
#define calloc SDL_calloc
-
#define realloc SDL_realloc
-
#define free SDL_free
3.
調用VideoDevice的CreateWindow()方法創建窗口。這是創建窗口這個函數中最關鍵的一環。在這裏有一點需要注意,SDL中有一個SDL_VideoDevice類型的靜態全局變量_this。SDL調用視頻驅動的功能都是通過調用該指針完成的。定義如下。
-
static SDL_VideoDevice *_this = NULL;
該_this變量代表了當前視頻驅動設備。該變量在SDL_Init()中被賦值。如果是Windows下使用,則會被賦值爲“Windows視頻驅動”;Android下使用,則會被賦值爲“Android視頻驅動”。這是上篇文章中的內容,不再重複記錄。
下面我們以“Windows視頻驅動”爲例,看看CreateWindow()都會執行哪些函數。
首先回顧一下上篇文章中的一個知識。從上一篇文章的SDL_Init()函數的分析中我們可以得知,Windows視頻驅動初始化的時候會給SDL_VideoDevice一系列的函數指針賦值,如下所示。
-
static SDL_VideoDevice *WIN_CreateDevice(int devindex)
-
{
-
SDL_VideoDevice *device;
-
SDL_VideoData *data;
-
-
-
SDL_RegisterApp(NULL, 0, NULL);
-
-
-
-
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
-
if (device) {
-
data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
-
} else {
-
data = NULL;
-
}
-
if (!data) {
-
SDL_free(device);
-
SDL_OutOfMemory();
-
return NULL;
-
}
-
device->driverdata = data;
-
-
-
data->userDLL = SDL_LoadObject("USER32.DLL");
-
if (data->userDLL) {
-
data->CloseTouchInputHandle = (BOOL (WINAPI *)( HTOUCHINPUT )) SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");
-
data->GetTouchInputInfo = (BOOL (WINAPI *)( HTOUCHINPUT, UINT, PTOUCHINPUT, int )) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");
-
data->RegisterTouchWindow = (BOOL (WINAPI *)( HWND, ULONG )) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
-
}
-
-
-
-
device->VideoInit = WIN_VideoInit;
-
device->VideoQuit = WIN_VideoQuit;
-
device->GetDisplayBounds = WIN_GetDisplayBounds;
-
device->GetDisplayModes = WIN_GetDisplayModes;
-
device->SetDisplayMode = WIN_SetDisplayMode;
-
device->PumpEvents = WIN_PumpEvents;
-
-
-
#undef CreateWindow
-
device->CreateWindow = WIN_CreateWindow;
-
device->CreateWindowFrom = WIN_CreateWindowFrom;
-
device->SetWindowTitle = WIN_SetWindowTitle;
-
device->SetWindowIcon = WIN_SetWindowIcon;
-
device->SetWindowPosition = WIN_SetWindowPosition;
-
device->SetWindowSize = WIN_SetWindowSize;
-
device->ShowWindow = WIN_ShowWindow;
-
device->HideWindow = WIN_HideWindow;
-
device->RaiseWindow = WIN_RaiseWindow;
-
device->MaximizeWindow = WIN_MaximizeWindow;
-
device->MinimizeWindow = WIN_MinimizeWindow;
-
device->RestoreWindow = WIN_RestoreWindow;
-
device->SetWindowBordered = WIN_SetWindowBordered;
-
device->SetWindowFullscreen = WIN_SetWindowFullscreen;
-
device->SetWindowGammaRamp = WIN_SetWindowGammaRamp;
-
device->GetWindowGammaRamp = WIN_GetWindowGammaRamp;
-
device->SetWindowGrab = WIN_SetWindowGrab;
-
device->DestroyWindow = WIN_DestroyWindow;
-
device->GetWindowWMInfo = WIN_GetWindowWMInfo;
-
device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer;
-
device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer;
-
device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer;
-
device->OnWindowEnter = WIN_OnWindowEnter;
-
-
-
device->shape_driver.CreateShaper = Win32_CreateShaper;
-
device->shape_driver.SetWindowShape = Win32_SetWindowShape;
-
device->shape_driver.ResizeWindowShape = Win32_ResizeWindowShape;
-
-
-
#if SDL_VIDEO_OPENGL_WGL
-
device->GL_LoadLibrary = WIN_GL_LoadLibrary;
-
device->GL_GetProcAddress = WIN_GL_GetProcAddress;
-
device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
-
device->GL_CreateContext = WIN_GL_CreateContext;
-
device->GL_MakeCurrent = WIN_GL_MakeCurrent;
-
device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
-
device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
-
device->GL_SwapWindow = WIN_GL_SwapWindow;
-
device->GL_DeleteContext = WIN_GL_DeleteContext;
-
#endif
-
device->StartTextInput = WIN_StartTextInput;
-
device->StopTextInput = WIN_StopTextInput;
-
device->SetTextInputRect = WIN_SetTextInputRect;
-
-
-
device->SetClipboardText = WIN_SetClipboardText;
-
device->GetClipboardText = WIN_GetClipboardText;
-
device->HasClipboardText = WIN_HasClipboardText;
-
-
-
device->free = WIN_DeleteDevice;
-
-
-
return device;
-
}
從上文中可以看出,“Windows視頻驅動”初始化之後,調用該SDL_VideoDevice的CreateWindow()實際上就等同於調用WIN_CreateWindow()這個函數。因此,我們來看一下WIN_CreateWindow()這個函數的定義(位於video\windows\SDL_windowswindow.c)。
-
int WIN_CreateWindow(_THIS, SDL_Window * window)
-
{
-
HWND hwnd;
-
RECT rect;
-
DWORD style = STYLE_BASIC;
-
int x, y;
-
int w, h;
-
-
-
style |= GetWindowStyle(window);
-
-
-
-
rect.left = window->x;
-
rect.top = window->y;
-
rect.right = window->x + window->w;
-
rect.bottom = window->y + window->h;
-
AdjustWindowRectEx(&rect, style, FALSE, 0);
-
x = rect.left;
-
y = rect.top;
-
w = (rect.right - rect.left);
-
h = (rect.bottom - rect.top);
-
-
-
hwnd =
-
CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL,
-
SDL_Instance, NULL);
-
if (!hwnd) {
-
return WIN_SetError("Couldn't create window");
-
}
-
-
-
WIN_PumpEvents(_this);
-
-
-
if (SetupWindowData(_this, window, hwnd, SDL_TRUE) < 0) {
-
DestroyWindow(hwnd);
-
return -1;
-
}
-
-
-
#if SDL_VIDEO_OPENGL_WGL
-
-
if (window->flags & SDL_WINDOW_OPENGL) {
-
WIN_GL_InitExtensions(_this);
-
}
-
#endif
-
-
-
#if SDL_VIDEO_OPENGL_ES2
-
if ((window->flags & SDL_WINDOW_OPENGL) &&
-
_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
-
#if SDL_VIDEO_OPENGL_WGL
-
&& (!_this->gl_data || !_this->gl_data->HAS_WGL_EXT_create_context_es2_profile)
-
#endif
-
) {
-
#if SDL_VIDEO_OPENGL_EGL
-
if (WIN_GLES_SetupWindow(_this, window) < 0) {
-
WIN_DestroyWindow(_this, window);
-
return -1;
-
}
-
#else
-
return SDL_SetError("Could not create GLES window surface (no EGL support available)");
-
#endif /* SDL_VIDEO_OPENGL_EGL */
-
} else
-
#endif /* SDL_VIDEO_OPENGL_ES2 */
-
-
-
#if SDL_VIDEO_OPENGL_WGL
-
if (window->flags & SDL_WINDOW_OPENGL) {
-
if (WIN_GL_SetupWindow(_this, window) < 0) {
-
WIN_DestroyWindow(_this, window);
-
return -1;
-
}
-
}
-
#endif
-
-
-
return 0;
-
}
從該函數的代碼中我們可以看到很多的Win32的API。最核心的函數只有一個,就是CreateWindow()。正是這個Win32的API最終創建了SDL的窗口。當然,爲了創建出來的窗口更“優質”,包含了一些初始化的工作,例如AdjustWindowRectEx();以及一些收尾工作,例如SetupWindowData()(該函數主要用於設置SDL_Window的參數)。
4.
完成一些收尾工作。例如設置窗口的標題,如果是“全屏模式”則設置全屏顯示等等。在這裏簡單介紹幾個函數。
SDL_SetWindowTitle()用於設置窗口的標題,它的定義如下。
-
void SDL_SetWindowTitle(SDL_Window * window, const char *title)
-
{
-
CHECK_WINDOW_MAGIC(window, );
-
-
-
if (title == window->title) {
-
return;
-
}
-
SDL_free(window->title);
-
if (title && *title) {
-
window->title = SDL_strdup(title);
-
} else {
-
window->title = NULL;
-
}
-
-
-
if (_this->SetWindowTitle) {
-
_this->SetWindowTitle(_this, window);
-
}
-
}
該函數調用了SDL_VideoDevice的SetWindowTitle()。在“Windows視頻驅動”中,實際的執行函數是WIN_SetWindowTitle()。該函數的定義如下。
-
void WIN_SetWindowTitle(_THIS, SDL_Window * window)
-
{
-
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
-
LPTSTR title;
-
-
-
if (window->title) {
-
title = WIN_UTF8ToString(window->title);
-
} else {
-
title = NULL;
-
}
-
SetWindowText(hwnd, title ? title : TEXT(""));
-
SDL_free(title);
-
}
從代碼中可以看出,該函數調用了Win32的API函數SetWindowText()設置窗口的標題。
SDL_FinishWindowCreation()完成一些窗口的收尾工作。該函數的定義如下。
-
static void SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
-
{
-
window->windowed.x = window->x;
-
window->windowed.y = window->y;
-
window->windowed.w = window->w;
-
window->windowed.h = window->h;
-
-
-
if (flags & SDL_WINDOW_MAXIMIZED) {
-
SDL_MaximizeWindow(window);
-
}
-
if (flags & SDL_WINDOW_MINIMIZED) {
-
SDL_MinimizeWindow(window);
-
}
-
if (flags & SDL_WINDOW_FULLSCREEN) {
-
SDL_SetWindowFullscreen(window, flags);
-
}
-
if (flags & SDL_WINDOW_INPUT_GRABBED) {
-
SDL_SetWindowGrab(window, SDL_TRUE);
-
}
-
if (!(flags & SDL_WINDOW_HIDDEN)) {
-
SDL_ShowWindow(window);
-
}
-
}
從代碼中可以看出,如果創建窗口的時候:
指定了“最大化”,則會執行SDL_MaximizeWindow();
指定了“最小化”,則會執行SDL_MinimizeWindow();
指定了“全屏”,則會執行SDL_SetWindowFullscreen();
指定了“抓取”(這個沒有試過),則會執行SDL_SetWindowGrab();
指定了“隱藏”,則會執行SDL_ShowWindow()。
下面分別看一下SDL_MaximizeWindow(),SDL_MinimizeWindow(),SDL_SetWindowFullscreen(),SDL_ShowWindow()的代碼。
SDL_MaximizeWindow()定義如下。
-
void SDL_MaximizeWindow(SDL_Window * window)
-
{
-
CHECK_WINDOW_MAGIC(window, );
-
-
-
if (window->flags & SDL_WINDOW_MAXIMIZED) {
-
return;
-
}
-
-
-
-
-
-
if (_this->MaximizeWindow) {
-
_this->MaximizeWindow(_this, window);
-
}
-
}
從代碼中可以看出,SDL_MaximizeWindow()調用了SDL_VideoDevice的MaximizeWindow()函數。在“Windows視頻驅動”下,實際上調用了WIN_MaximizeWindow()函數,該函數的定義如下。
-
void WIN_MaximizeWindow(_THIS, SDL_Window * window)
-
{
-
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
-
HWND hwnd = data->hwnd;
-
data->expected_resize = TRUE;
-
ShowWindow(hwnd, SW_MAXIMIZE);
-
data->expected_resize = FALSE;
-
}
從上述代碼中可以看出WIN_MaximizeWindow()調用了Win32的API函數ShowWindow()。
SDL_MinimizeWindow()定義如下。
-
void SDL_MinimizeWindow(SDL_Window * window)
-
{
-
CHECK_WINDOW_MAGIC(window, );
-
-
-
if (window->flags & SDL_WINDOW_MINIMIZED) {
-
return;
-
}
-
-
-
SDL_UpdateFullscreenMode(window, SDL_FALSE);
-
-
-
if (_this->MinimizeWindow) {
-
_this->MinimizeWindow(_this, window);
-
}
-
}
從代碼中可以看出,SDL_MinimizeWindow()調用了SDL_VideoDevice的MinimizeWindow()函數。在“Windows視頻驅動”下,實際上調用了WIN_MinimizeWindow()函數,該函數的定義如下。
-
void WIN_MinimizeWindow(_THIS, SDL_Window * window)
-
{
-
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
-
ShowWindow(hwnd, SW_MINIMIZE);
-
}
從上述代碼中可以看出WIN_MinimizeWindow()調用了Win32的API函數ShowWindow()。
SDL_SetWindowFullscreen()定義如下。
-
int SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
-
{
-
CHECK_WINDOW_MAGIC(window, -1);
-
-
-
flags &= FULLSCREEN_MASK;
-
-
-
if ( flags == (window->flags & FULLSCREEN_MASK) ) {
-
return 0;
-
}
-
-
-
-
window->flags &= ~FULLSCREEN_MASK;
-
window->flags |= flags;
-
-
-
SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
-
-
-
return 0;
-
}
從代碼中可以看出,SDL_SetWindowFullscreen()調用了SDL_UpdateFullscreenMode()函數,該函數的定義如下。
-
static void SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
-
{
-
SDL_VideoDisplay *display;
-
SDL_Window *other;
-
-
-
#ifdef __MACOSX__
-
if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
-
window->last_fullscreen_flags = window->flags;
-
return;
-
}
-
#endif
-
-
-
display = SDL_GetDisplayForWindow(window);
-
-
-
if (fullscreen) {
-
-
if (display->fullscreen_window &&
-
display->fullscreen_window != window) {
-
SDL_MinimizeWindow(display->fullscreen_window);
-
}
-
}
-
-
-
-
if ((display->fullscreen_window == window) == fullscreen) {
-
if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
-
return;
-
}
-
}
-
-
-
-
for (other = _this->windows; other; other = other->next) {
-
SDL_bool setDisplayMode = SDL_FALSE;
-
-
-
if (other == window) {
-
setDisplayMode = fullscreen;
-
} else if (FULLSCREEN_VISIBLE(other) &&
-
SDL_GetDisplayForWindow(other) == display) {
-
setDisplayMode = SDL_TRUE;
-
}
-
-
-
if (setDisplayMode) {
-
SDL_DisplayMode fullscreen_mode;
-
-
-
if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
-
SDL_bool resized = SDL_TRUE;
-
-
-
if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
-
resized = SDL_FALSE;
-
}
-
-
-
-
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
-
SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
-
} else {
-
SDL_SetDisplayModeForDisplay(display, NULL);
-
}
-
-
-
if (_this->SetWindowFullscreen) {
-
_this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
-
}
-
display->fullscreen_window = other;
-
-
-
-
if (resized) {
-
SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
-
fullscreen_mode.w, fullscreen_mode.h);
-
} else {
-
SDL_OnWindowResized(other);
-
}
-
-
-
SDL_RestoreMousePosition(other);
-
-
-
window->last_fullscreen_flags = window->flags;
-
return;
-
}
-
}
-
}
-
-
-
-
SDL_SetDisplayModeForDisplay(display, NULL);
-
-
-
if (_this->SetWindowFullscreen) {
-
_this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
-
}
-
display->fullscreen_window = NULL;
-
-
-
-
SDL_OnWindowResized(window);
-
-
-
-
SDL_RestoreMousePosition(window);
-
-
-
window->last_fullscreen_flags = window->flags;
-
}
SDL_UpdateFullscreenMode()代碼很長,在這裏我們只選擇最關鍵的代碼進行分析。SDL_UpdateFullscreenMode()最關鍵的地方在於它調用了SDL_VideoDevice的SetWindowFullscreen()函數。在“Windows視頻驅動”下,實際上調用了WIN_SetWindowFullscreen()函數,該函數的定義如下。
-
void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
-
{
-
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
-
HWND hwnd = data->hwnd;
-
RECT rect;
-
SDL_Rect bounds;
-
DWORD style;
-
HWND top;
-
BOOL menu;
-
int x, y;
-
int w, h;
-
-
-
if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
-
top = HWND_TOPMOST;
-
} else {
-
top = HWND_NOTOPMOST;
-
}
-
-
-
style = GetWindowLong(hwnd, GWL_STYLE);
-
style &= ~STYLE_MASK;
-
style |= GetWindowStyle(window);
-
-
-
WIN_GetDisplayBounds(_this, display, &bounds);
-
-
-
if (fullscreen) {
-
x = bounds.x;
-
y = bounds.y;
-
w = bounds.w;
-
h = bounds.h;
-
} else {
-
rect.left = 0;
-
rect.top = 0;
-
rect.right = window->windowed.w;
-
rect.bottom = window->windowed.h;
-
menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
-
AdjustWindowRectEx(&rect, style, menu, 0);
-
w = (rect.right - rect.left);
-
h = (rect.bottom - rect.top);
-
x = window->windowed.x + rect.left;
-
y = window->windowed.y + rect.top;
-
}
-
SetWindowLong(hwnd, GWL_STYLE, style);
-
data->expected_resize = TRUE;
-
SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
-
data->expected_resize = FALSE;
-
}
從代碼中可以看出,該函數通過WIN_GetDisplayBounds()獲得屏幕的尺寸,然後通過SetWindowPos()函數設置全屏窗口的大小和位置。
SDL_ShowWindow()的定義如下。
-
void SDL_ShowWindow(SDL_Window * window)
-
{
-
CHECK_WINDOW_MAGIC(window, );
-
-
-
if (window->flags & SDL_WINDOW_SHOWN) {
-
return;
-
}
-
-
-
if (_this->ShowWindow) {
-
_this->ShowWindow(_this, window);
-
}
-
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
-
}
SDL_ShowWindow ()調用了SDL_VideoDevice的ShowWindow()函數。在“Windows視頻驅動”下,實際上調用了WIN_ShowWindow()函數,該函數的定義如下。
-
void WIN_ShowWindow(_THIS, SDL_Window * window)
-
{
-
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
-
ShowWindow(hwnd, SW_SHOW);
-
}
該函數比較簡單,直接調用了Win32中的ShowWindow()方法。