Back to index

libsfml  1.6+dfsg2
WindowImplWin32.cpp
Go to the documentation of this file.
00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #define _WIN32_WINDOWS 0x0501
00029 #define _WIN32_WINNT   0x0501
00030 #include <SFML/Window/Win32/WindowImplWin32.hpp>
00031 #include <SFML/Window/WindowSettings.hpp>
00032 #include <SFML/Window/WindowStyle.hpp>
00033 #include <GL/gl.h>
00034 #include <SFML/Window/glext/wglext.h>
00035 #include <SFML/Window/glext/glext.h>
00036 #include <iostream>
00037 #include <vector>
00038 
00039 // MinGW lacks the definition of some Win32 constants
00040 #ifndef XBUTTON1
00041     #define XBUTTON1 0x0001
00042 #endif
00043 #ifndef XBUTTON2
00044     #define XBUTTON2 0x0002
00045 #endif
00046 #ifndef MAPVK_VK_TO_VSC
00047     #define MAPVK_VK_TO_VSC (0)
00048 #endif
00049 
00050 
00051 namespace sf
00052 {
00053 namespace priv
00054 {
00056 // Static member data
00058 unsigned int     WindowImplWin32::ourWindowCount      = 0;
00059 const char*      WindowImplWin32::ourClassNameA       = "SFML_Window";
00060 const wchar_t*   WindowImplWin32::ourClassNameW       = L"SFML_Window";
00061 WindowImplWin32* WindowImplWin32::ourFullscreenWindow = NULL;
00062 
00063 
00068 WindowImplWin32::WindowImplWin32() :
00069 myHandle          (NULL),
00070 myCallback        (0),
00071 myCursor          (NULL),
00072 myIcon            (NULL),
00073 myKeyRepeatEnabled(true),
00074 myIsCursorIn      (false)
00075 {
00076     // Register the window class at first call
00077     if (ourWindowCount == 0)
00078         RegisterWindowClass();
00079 
00080     // Use small dimensions
00081     myWidth  = 1;
00082     myHeight = 1;
00083 
00084     // Create a dummy window (disabled and hidden)
00085     if (HasUnicodeSupport())
00086     {
00087         myHandle = CreateWindowW(ourClassNameW, L"", WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL);
00088     }
00089     else
00090     {
00091         myHandle = CreateWindowA(ourClassNameA, "", WS_POPUP | WS_DISABLED, 0, 0, myWidth, myHeight, NULL, NULL, GetModuleHandle(NULL), NULL);
00092     }
00093     ShowWindow(myHandle, SW_HIDE);
00094 
00095     // Create the rendering context
00096     if (myHandle)
00097     {
00098         WindowSettings Params(0, 0, 0);
00099         CreateContext(VideoMode(myWidth, myHeight, 32), Params);
00100 
00101         // Don't activate by default
00102         SetActive(false);
00103     }
00104 }
00105 
00106 
00110 WindowImplWin32::WindowImplWin32(WindowHandle Handle, WindowSettings& Params) :
00111 myHandle          (NULL),
00112 myCallback        (0),
00113 myCursor          (NULL),
00114 myIcon            (NULL),
00115 myKeyRepeatEnabled(true),
00116 myIsCursorIn      (false)
00117 {
00118     // Save window handle
00119     myHandle = static_cast<HWND>(Handle);
00120 
00121     if (myHandle)
00122     {
00123         // Get window client size
00124         RECT Rect;
00125         GetClientRect(myHandle, &Rect);
00126         myWidth  = Rect.right - Rect.left;
00127         myHeight = Rect.bottom - Rect.top;
00128 
00129         // Create the rendering context
00130         VideoMode Mode(myWidth, myHeight, VideoMode::GetDesktopMode().BitsPerPixel);
00131         CreateContext(Mode, Params);
00132 
00133         // We change the event procedure of the control (it is important to save the old one)
00134         SetWindowLongPtr(myHandle, GWLP_USERDATA, reinterpret_cast<long>(this));
00135         myCallback = SetWindowLongPtr(myHandle, GWLP_WNDPROC, reinterpret_cast<long>(&WindowImplWin32::GlobalOnEvent));
00136     }
00137 }
00138 
00139 
00143 WindowImplWin32::WindowImplWin32(VideoMode Mode, const std::string& Title, unsigned long WindowStyle, WindowSettings& Params) :
00144 myHandle          (NULL),
00145 myCallback        (0),
00146 myCursor          (NULL),
00147 myIcon            (NULL),
00148 myKeyRepeatEnabled(true),
00149 myIsCursorIn      (false)
00150 {
00151     // Register the window class at first call
00152     if (ourWindowCount == 0)
00153         RegisterWindowClass();
00154 
00155     // Compute position and size
00156     HDC ScreenDC = GetDC(NULL);
00157     int Left   = (GetDeviceCaps(ScreenDC, HORZRES) - Mode.Width)  / 2;
00158     int Top    = (GetDeviceCaps(ScreenDC, VERTRES) - Mode.Height) / 2;
00159     int Width  = myWidth  = Mode.Width;
00160     int Height = myHeight = Mode.Height;
00161     ReleaseDC(NULL, ScreenDC);
00162 
00163     // Choose the window style according to the Style parameter
00164     DWORD Win32Style = WS_VISIBLE;
00165     if (WindowStyle == Style::None)
00166     {
00167         Win32Style |= WS_POPUP;
00168     }
00169     else
00170     {
00171         if (WindowStyle & Style::Titlebar) Win32Style |= WS_CAPTION | WS_MINIMIZEBOX;
00172         if (WindowStyle & Style::Resize)   Win32Style |= WS_THICKFRAME | WS_MAXIMIZEBOX;
00173         if (WindowStyle & Style::Close)    Win32Style |= WS_SYSMENU;
00174     }
00175 
00176     // In windowed mode, adjust width and height so that window will have the requested client area
00177     bool Fullscreen = (WindowStyle & Style::Fullscreen) != 0;
00178     if (!Fullscreen)
00179     {
00180         RECT Rect = {0, 0, Width, Height};
00181         AdjustWindowRect(&Rect, Win32Style, false);
00182         Width  = Rect.right - Rect.left;
00183         Height = Rect.bottom - Rect.top;
00184     }
00185 
00186     // Create the window
00187     if (HasUnicodeSupport())
00188     {
00189         wchar_t WTitle[256];
00190         int NbChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Title.c_str(), static_cast<int>(Title.size()), WTitle, sizeof(WTitle) / sizeof(*WTitle));
00191         WTitle[NbChars] = L'\0';
00192         myHandle = CreateWindowW(ourClassNameW, WTitle, Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
00193     }
00194     else
00195     {
00196         myHandle = CreateWindowA(ourClassNameA, Title.c_str(), Win32Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
00197     }
00198 
00199     // Switch to fullscreen if requested
00200     if (Fullscreen)
00201         SwitchToFullscreen(Mode);
00202 
00203     // Create the rendering context
00204     if (myHandle)
00205         CreateContext(Mode, Params);
00206 
00207     // Increment window count
00208     ourWindowCount++;
00209 
00210     // Get the actual size of the window, which can be smaller even after the call to AdjustWindowRect
00211     // This happens when the window is bigger than the desktop
00212     RECT ActualRect;
00213     GetClientRect(myHandle, &ActualRect);
00214     myWidth  = ActualRect.right - ActualRect.left;
00215     myHeight = ActualRect.bottom - ActualRect.top;
00216 }
00217 
00218 
00222 WindowImplWin32::~WindowImplWin32()
00223 {
00224     // Destroy the custom icon, if any
00225     if (myIcon)
00226         DestroyIcon(myIcon);
00227 
00228     if (!myCallback)
00229     {
00230         // Destroy the window
00231         if (myHandle)
00232             DestroyWindow(myHandle);
00233 
00234         // Decrement the window count
00235         ourWindowCount--;
00236 
00237         // Unregister window class if we were the last window
00238         if (ourWindowCount == 0)
00239         {
00240             if (HasUnicodeSupport())
00241             {
00242                 UnregisterClassW(ourClassNameW, GetModuleHandle(NULL));
00243             }
00244             else
00245             {
00246                 UnregisterClassA(ourClassNameA, GetModuleHandle(NULL));
00247             }
00248         }
00249     }
00250     else
00251     {
00252         // The window is external : remove the hook on its message callback
00253         SetWindowLongPtr(myHandle, GWLP_WNDPROC, myCallback);
00254     }
00255 }
00256 
00257 
00261 bool WindowImplWin32::IsContextActive()
00262 {
00263     return wglGetCurrentContext() != NULL;
00264 }
00265 
00266 
00270 void WindowImplWin32::ProcessEvents()
00271 {
00272     // We update the window only if we own it
00273     if (!myCallback)
00274     {
00275         MSG Message;
00276         while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
00277         {
00278             TranslateMessage(&Message);
00279             DispatchMessage(&Message);
00280         }
00281     }
00282 }
00283 
00284 
00288 void WindowImplWin32::Display()
00289 {
00290     if (myDeviceContext && myGLContext)
00291         SwapBuffers(myDeviceContext);
00292 }
00293 
00294 
00298 void WindowImplWin32::SetActive(bool Active) const
00299 {
00300     if (Active)
00301     {
00302         if (myDeviceContext && myGLContext && (wglGetCurrentContext() != myGLContext))
00303             wglMakeCurrent(myDeviceContext, myGLContext);
00304     }
00305     else
00306     {
00307         if (wglGetCurrentContext() == myGLContext)
00308             wglMakeCurrent(NULL, NULL);
00309     }
00310 }
00311 
00312 
00316 void WindowImplWin32::UseVerticalSync(bool Enabled)
00317 {
00318     PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
00319     if (wglSwapIntervalEXT)
00320         wglSwapIntervalEXT(Enabled ? 1 : 0);
00321 }
00322 
00323 
00327 void WindowImplWin32::ShowMouseCursor(bool Show)
00328 {
00329     if (Show)
00330         myCursor = LoadCursor(NULL, IDC_ARROW);
00331     else
00332         myCursor = NULL;
00333 
00334     SetCursor(myCursor);
00335 }
00336 
00337 
00341 void WindowImplWin32::SetCursorPosition(unsigned int Left, unsigned int Top)
00342 {
00343     POINT Pos = {Left, Top};
00344     ClientToScreen(myHandle, &Pos);
00345     SetCursorPos(Pos.x, Pos.y);
00346 }
00347 
00348 
00352 void WindowImplWin32::SetPosition(int Left, int Top)
00353 {
00354     SetWindowPos(myHandle, NULL, Left, Top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
00355 }
00356 
00357 
00361 void WindowImplWin32::SetSize(unsigned int Width, unsigned int Height)
00362 {
00363     // SetWindowPos wants the total size of the window (including title bar and borders),
00364     // so we have to compute it
00365     RECT Rect = {0, 0, Width, Height};
00366     AdjustWindowRect(&Rect, GetWindowLong(myHandle, GWL_STYLE), false);
00367     Width  = Rect.right - Rect.left;
00368     Height = Rect.bottom - Rect.top;
00369 
00370     SetWindowPos(myHandle, NULL, 0, 0, Width, Height, SWP_NOMOVE | SWP_NOZORDER);
00371 }
00372 
00373 
00377 void WindowImplWin32::Show(bool State)
00378 {
00379     ShowWindow(myHandle, State ? SW_SHOW : SW_HIDE);
00380 }
00381 
00382 
00386 void WindowImplWin32::EnableKeyRepeat(bool Enabled)
00387 {
00388     myKeyRepeatEnabled = Enabled;
00389 }
00390 
00391 
00395 void WindowImplWin32::SetIcon(unsigned int Width, unsigned int Height, const Uint8* Pixels)
00396 {
00397     // First destroy the previous one
00398     if (myIcon)
00399         DestroyIcon(myIcon);
00400 
00401     // Windows wants BGRA pixels : swap red and blue channels
00402     std::vector<Uint8> IconPixels(Width * Height * 4);
00403     for (std::size_t i = 0; i < IconPixels.size() / 4; ++i)
00404     {
00405         IconPixels[i * 4 + 0] = Pixels[i * 4 + 2];
00406         IconPixels[i * 4 + 1] = Pixels[i * 4 + 1];
00407         IconPixels[i * 4 + 2] = Pixels[i * 4 + 0];
00408         IconPixels[i * 4 + 3] = Pixels[i * 4 + 3];
00409     }
00410 
00411     // Create the icon from the pixels array
00412     myIcon = CreateIcon(GetModuleHandle(NULL), Width, Height, 1, 32, NULL, &IconPixels[0]);
00413 
00414     // Set it as both big and small icon of the window
00415     if (myIcon)
00416     {
00417         SendMessage(myHandle, WM_SETICON, ICON_BIG,   (LPARAM)myIcon);
00418         SendMessage(myHandle, WM_SETICON, ICON_SMALL, (LPARAM)myIcon);
00419     }
00420     else
00421     {
00422         std::cerr << "Failed to set the window's icon" << std::endl;
00423     }
00424 }
00425 
00426 
00430 void WindowImplWin32::RegisterWindowClass()
00431 {
00432     if (HasUnicodeSupport())
00433     {
00434         WNDCLASSW WindowClass;
00435         WindowClass.style         = 0;
00436         WindowClass.lpfnWndProc   = &WindowImplWin32::GlobalOnEvent;
00437         WindowClass.cbClsExtra    = 0;
00438         WindowClass.cbWndExtra    = 0;
00439         WindowClass.hInstance     = GetModuleHandle(NULL);
00440         WindowClass.hIcon         = NULL;
00441         WindowClass.hCursor       = 0;
00442         WindowClass.hbrBackground = 0;
00443         WindowClass.lpszMenuName  = NULL;
00444         WindowClass.lpszClassName = ourClassNameW;
00445         RegisterClassW(&WindowClass);
00446     }
00447     else
00448     {
00449         WNDCLASSA WindowClass;
00450         WindowClass.style         = 0;
00451         WindowClass.lpfnWndProc   = &WindowImplWin32::GlobalOnEvent;
00452         WindowClass.cbClsExtra    = 0;
00453         WindowClass.cbWndExtra    = 0;
00454         WindowClass.hInstance     = GetModuleHandle(NULL);
00455         WindowClass.hIcon         = NULL;
00456         WindowClass.hCursor       = 0;
00457         WindowClass.hbrBackground = 0;
00458         WindowClass.lpszMenuName  = NULL;
00459         WindowClass.lpszClassName = ourClassNameA;
00460         RegisterClassA(&WindowClass);
00461     }
00462 }
00463 
00464 
00468 void WindowImplWin32::SwitchToFullscreen(const VideoMode& Mode)
00469 {
00470     DEVMODE DevMode;
00471     DevMode.dmSize       = sizeof(DEVMODE);
00472     DevMode.dmPelsWidth  = Mode.Width;
00473     DevMode.dmPelsHeight = Mode.Height;
00474     DevMode.dmBitsPerPel = Mode.BitsPerPixel;
00475     DevMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
00476 
00477     // Apply fullscreen mode
00478     if (ChangeDisplaySettings(&DevMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
00479     {
00480         std::cerr << "Failed to change display mode for fullscreen" << std::endl;
00481         return;
00482     }
00483 
00484     // Make the window flags compatible with fullscreen mode
00485     SetWindowLong(myHandle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
00486     SetWindowLong(myHandle, GWL_EXSTYLE, WS_EX_APPWINDOW);
00487 
00488     // Resize the window so that it fits the entire screen
00489     SetWindowPos(myHandle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
00490     ShowWindow(myHandle, SW_SHOW);
00491 
00492     // Set "this" as the current fullscreen window
00493     ourFullscreenWindow = this;
00494 }
00495 
00496 
00500 void WindowImplWin32::CreateContext(const VideoMode& Mode, WindowSettings& Params)
00501 {
00502     // Get the device context attached to the window
00503     myDeviceContext = GetDC(myHandle);
00504     if (myDeviceContext == NULL)
00505     {
00506         std::cerr << "Failed to get device context of window -- cannot create OpenGL context" << std::endl;
00507         return;
00508     }
00509 
00510     // Let's find a suitable pixel format -- first try with antialiasing
00511     int BestFormat = 0;
00512     if (Params.AntialiasingLevel > 0)
00513     {
00514         // Get the wglChoosePixelFormatARB function (it is an extension)
00515         PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
00516         if (wglChoosePixelFormatARB)
00517         {
00518             // Define the basic attributes we want for our window
00519             int IntAttributes[] =
00520             {
00521                 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
00522                       WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
00523                       WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
00524                       WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
00525                 WGL_SAMPLE_BUFFERS_ARB, (Params.AntialiasingLevel ? GL_TRUE : GL_FALSE),
00526                       WGL_SAMPLES_ARB,        Params.AntialiasingLevel,
00527                       0,                      0
00528             };
00529 
00530             // Let's check how many formats are supporting our requirements
00531             int   Formats[128];
00532                UINT  NbFormats;
00533                float FloatAttributes[] = {0, 0};
00534                bool  IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0;
00535             if (!IsValid || (NbFormats == 0))
00536             {
00537                 if (Params.AntialiasingLevel > 2)
00538                 {
00539                     // No format matching our needs : reduce the multisampling level
00540                     std::cerr << "Failed to find a pixel format supporting "
00541                               << Params.AntialiasingLevel << " antialiasing levels ; trying with 2 levels" << std::endl;
00542 
00543                     Params.AntialiasingLevel = IntAttributes[11] = 2;
00544                        IsValid = wglChoosePixelFormatARB(myDeviceContext, IntAttributes, FloatAttributes, sizeof(Formats) / sizeof(*Formats), Formats, &NbFormats) != 0;
00545                 }
00546 
00547                 if (!IsValid || (NbFormats == 0))
00548                 {
00549                     // Cannot find any pixel format supporting multisampling ; disabling antialiasing
00550                     std::cerr << "Failed to find a pixel format supporting antialiasing ; antialiasing will be disabled" << std::endl;
00551                     Params.AntialiasingLevel = 0;
00552                 }
00553             }
00554 
00555             // Get the best format among the returned ones
00556             if (IsValid && (NbFormats > 0))
00557             {
00558                 int BestScore = 0xFFFF;
00559                 for (UINT i = 0; i < NbFormats; ++i)
00560                 {
00561                     // Get the current format's attributes
00562                     PIXELFORMATDESCRIPTOR Attribs;
00563                     Attribs.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
00564                     Attribs.nVersion = 1;
00565                     DescribePixelFormat(myDeviceContext, Formats[i], sizeof(PIXELFORMATDESCRIPTOR), &Attribs);
00566 
00567                     // Evaluate the current configuration
00568                     int Color = Attribs.cRedBits + Attribs.cGreenBits + Attribs.cBlueBits + Attribs.cAlphaBits;
00569                     int Score = EvaluateConfig(Mode, Params, Color, Attribs.cDepthBits, Attribs.cStencilBits, Params.AntialiasingLevel);
00570 
00571                     // Keep it if it's better than the current best
00572                     if (Score < BestScore)
00573                     {
00574                         BestScore  = Score;
00575                         BestFormat = Formats[i];
00576                     }
00577                 }
00578             }
00579         }
00580         else
00581         {
00582             // wglChoosePixelFormatARB not supported ; disabling antialiasing
00583             std::cerr << "Antialiasing is not supported ; it will be disabled" << std::endl;
00584             Params.AntialiasingLevel = 0;
00585         }
00586     }
00587 
00588     // Find a pixel format with no antialiasing, if not needed or not supported
00589     if (BestFormat == 0)
00590     {
00591         // Setup a pixel format descriptor from the rendering settings
00592         PIXELFORMATDESCRIPTOR PixelDescriptor;
00593         ZeroMemory(&PixelDescriptor, sizeof(PIXELFORMATDESCRIPTOR));
00594         PixelDescriptor.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
00595         PixelDescriptor.nVersion     = 1;
00596         PixelDescriptor.iLayerType   = PFD_MAIN_PLANE;
00597         PixelDescriptor.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
00598         PixelDescriptor.iPixelType   = PFD_TYPE_RGBA;
00599         PixelDescriptor.cColorBits   = static_cast<BYTE>(Mode.BitsPerPixel);
00600         PixelDescriptor.cDepthBits   = static_cast<BYTE>(Params.DepthBits);
00601         PixelDescriptor.cStencilBits = static_cast<BYTE>(Params.StencilBits);
00602         PixelDescriptor.cAlphaBits   = Mode.BitsPerPixel == 32 ? 8 : 0;
00603 
00604         // Get the pixel format that best matches our requirements
00605         BestFormat = ChoosePixelFormat(myDeviceContext, &PixelDescriptor);
00606         if (BestFormat == 0)
00607         {
00608             std::cerr << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
00609             return;
00610         }
00611     }
00612 
00613     // Extract the depth and stencil bits from the chosen format
00614     PIXELFORMATDESCRIPTOR ActualFormat;
00615     ActualFormat.nSize    = sizeof(PIXELFORMATDESCRIPTOR);
00616     ActualFormat.nVersion = 1;
00617     DescribePixelFormat(myDeviceContext, BestFormat, sizeof(PIXELFORMATDESCRIPTOR), &ActualFormat);
00618     Params.DepthBits   = ActualFormat.cDepthBits;
00619     Params.StencilBits = ActualFormat.cStencilBits;
00620 
00621     // Set the chosen pixel format
00622     if (!SetPixelFormat(myDeviceContext, BestFormat, &ActualFormat))
00623     {
00624         std::cerr << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
00625         return;
00626     }
00627 
00628     // Create the OpenGL context from the device context
00629     myGLContext = wglCreateContext(myDeviceContext);
00630     if (myGLContext == NULL)
00631     {
00632         std::cerr << "Failed to create an OpenGL context for this window" << std::endl;
00633         return;
00634     }
00635 
00636     // Share display lists with other contexts
00637     HGLRC CurrentContext = wglGetCurrentContext();
00638     if (CurrentContext)
00639         wglShareLists(CurrentContext, myGLContext);
00640 
00641     // Activate the context
00642     SetActive(true);
00643 
00644     // Enable multisampling
00645     if (Params.AntialiasingLevel > 0)
00646         glEnable(GL_MULTISAMPLE_ARB);
00647 }
00648 
00649 
00653 void WindowImplWin32::Cleanup()
00654 {
00655     // Restore the previous video mode (in case we were running in fullscreen)
00656     if (ourFullscreenWindow == this)
00657     {
00658         ChangeDisplaySettings(NULL, 0);
00659         ourFullscreenWindow = NULL;
00660     }
00661 
00662     // Unhide the mouse cursor (in case it was hidden)
00663     ShowMouseCursor(true);
00664 
00665     // Destroy the OpenGL context
00666     if (myGLContext)
00667     {
00668         // Unbind the context before destroying it
00669         SetActive(false);
00670 
00671         wglDeleteContext(myGLContext);
00672         myGLContext = NULL;
00673     }
00674     if (myDeviceContext)
00675     {
00676         ReleaseDC(myHandle, myDeviceContext);
00677         myDeviceContext = NULL;
00678     }
00679 }
00680 
00681 
00685 void WindowImplWin32::ProcessEvent(UINT Message, WPARAM WParam, LPARAM LParam)
00686 {
00687     // Don't process any message until window is created
00688     if (myHandle == NULL)
00689         return;
00690 
00691     switch (Message)
00692     {
00693         // Destroy event
00694         case WM_DESTROY :
00695         {
00696             // Here we must cleanup resources !
00697             Cleanup();
00698             break;
00699         }
00700 
00701         // Set cursor event
00702         case WM_SETCURSOR :
00703         {
00704             // The mouse has moved, if the cursor is in our window we must refresh the cursor
00705             if (LOWORD(LParam) == HTCLIENT)
00706                 SetCursor(myCursor);
00707 
00708             break;
00709         }
00710 
00711         // Close event
00712         case WM_CLOSE :
00713         {
00714             Event Evt;
00715             Evt.Type = Event::Closed;
00716             SendEvent(Evt);
00717             break;
00718         }
00719 
00720         // Resize event
00721         case WM_SIZE :
00722         {
00723             // Update window size
00724             RECT Rect;
00725             GetClientRect(myHandle, &Rect);
00726             myWidth  = Rect.right - Rect.left;
00727             myHeight = Rect.bottom - Rect.top;
00728 
00729             Event Evt;
00730             Evt.Type        = Event::Resized;
00731             Evt.Size.Width  = myWidth;
00732             Evt.Size.Height = myHeight;
00733             SendEvent(Evt);
00734             break;
00735         }
00736 
00737         // Gain focus event
00738         case WM_SETFOCUS :
00739         {
00740             Event Evt;
00741             Evt.Type = Event::GainedFocus;
00742             SendEvent(Evt);
00743             break;
00744         }
00745 
00746         // Lost focus event
00747         case WM_KILLFOCUS :
00748         {
00749             Event Evt;
00750             Evt.Type = Event::LostFocus;
00751             SendEvent(Evt);
00752             break;
00753         }
00754 
00755         // Text event
00756         case WM_CHAR :
00757         {
00758             if (myKeyRepeatEnabled || ((LParam & (1 << 30)) == 0))
00759             {
00760                 Event Evt;
00761                 Evt.Type = Event::TextEntered;
00762                 Evt.Text.Unicode = static_cast<Uint32>(WParam);
00763                 SendEvent(Evt);
00764             }
00765             break;
00766         }
00767 
00768         // Keydown event
00769         case WM_KEYDOWN :
00770         case WM_SYSKEYDOWN :
00771         {
00772             if (myKeyRepeatEnabled || ((HIWORD(LParam) & KF_REPEAT) == 0))
00773             {
00774                 Event Evt;
00775                 Evt.Type        = Event::KeyPressed;
00776                 Evt.Key.Alt     = HIWORD(GetAsyncKeyState(VK_MENU))    != 0;
00777                 Evt.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
00778                 Evt.Key.Shift   = HIWORD(GetAsyncKeyState(VK_SHIFT))   != 0;
00779                 Evt.Key.Code    = VirtualKeyCodeToSF(WParam, LParam);
00780                 SendEvent(Evt);
00781             }
00782             break;
00783         }
00784 
00785         // Keyup event
00786         case WM_KEYUP :
00787         case WM_SYSKEYUP :
00788         {
00789             Event Evt;
00790             Evt.Type        = Event::KeyReleased;
00791             Evt.Key.Alt     = HIWORD(GetAsyncKeyState(VK_MENU))    != 0;
00792             Evt.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
00793             Evt.Key.Shift   = HIWORD(GetAsyncKeyState(VK_SHIFT))   != 0;
00794             Evt.Key.Code    = VirtualKeyCodeToSF(WParam, LParam);
00795             SendEvent(Evt);
00796 
00797             break;
00798         }
00799 
00800         // Mouse wheel event
00801         case WM_MOUSEWHEEL :
00802         {
00803             Event Evt;
00804             Evt.Type = Event::MouseWheelMoved;
00805             Evt.MouseWheel.Delta = static_cast<Int16>(HIWORD(WParam)) / 120;
00806             SendEvent(Evt);
00807             break;
00808         }
00809 
00810         // Mouse left button down event
00811         case WM_LBUTTONDOWN :
00812         {
00813             Event Evt;
00814             Evt.Type               = Event::MouseButtonPressed;
00815             Evt.MouseButton.Button = Mouse::Left;
00816             Evt.MouseButton.X      = LOWORD(LParam);
00817             Evt.MouseButton.Y      = HIWORD(LParam);
00818             SendEvent(Evt);
00819             break;
00820         }
00821 
00822         // Mouse left button up event
00823         case WM_LBUTTONUP :
00824         {
00825             Event Evt;
00826             Evt.Type               = Event::MouseButtonReleased;
00827             Evt.MouseButton.Button = Mouse::Left;
00828             Evt.MouseButton.X      = LOWORD(LParam);
00829             Evt.MouseButton.Y      = HIWORD(LParam);
00830             SendEvent(Evt);
00831             break;
00832         }
00833 
00834         // Mouse right button down event
00835         case WM_RBUTTONDOWN :
00836         {
00837             Event Evt;
00838             Evt.Type               = Event::MouseButtonPressed;
00839             Evt.MouseButton.Button = Mouse::Right;
00840             Evt.MouseButton.X      = LOWORD(LParam);
00841             Evt.MouseButton.Y      = HIWORD(LParam);
00842             SendEvent(Evt);
00843             break;
00844         }
00845 
00846         // Mouse right button up event
00847         case WM_RBUTTONUP :
00848         {
00849             Event Evt;
00850             Evt.Type               = Event::MouseButtonReleased;
00851             Evt.MouseButton.Button = Mouse::Right;
00852             Evt.MouseButton.X      = LOWORD(LParam);
00853             Evt.MouseButton.Y      = HIWORD(LParam);
00854             SendEvent(Evt);
00855             break;
00856         }
00857 
00858         // Mouse wheel button down event
00859         case WM_MBUTTONDOWN :
00860         {
00861             Event Evt;
00862             Evt.Type               = Event::MouseButtonPressed;
00863             Evt.MouseButton.Button = Mouse::Middle;
00864             Evt.MouseButton.X      = LOWORD(LParam);
00865             Evt.MouseButton.Y      = HIWORD(LParam);
00866             SendEvent(Evt);
00867             break;
00868         }
00869 
00870         // Mouse wheel button up event
00871         case WM_MBUTTONUP :
00872         {
00873             Event Evt;
00874             Evt.Type               = Event::MouseButtonReleased;
00875             Evt.MouseButton.Button = Mouse::Middle;
00876             Evt.MouseButton.X      = LOWORD(LParam);
00877             Evt.MouseButton.Y      = HIWORD(LParam);
00878             SendEvent(Evt);
00879             break;
00880         }
00881 
00882         // Mouse X button down event
00883         case WM_XBUTTONDOWN :
00884         {
00885             Event Evt;
00886             Evt.Type               = Event::MouseButtonPressed;
00887             Evt.MouseButton.Button = HIWORD(WParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2;
00888             Evt.MouseButton.X      = LOWORD(LParam);
00889             Evt.MouseButton.Y      = HIWORD(LParam);
00890             SendEvent(Evt);
00891             break;
00892         }
00893 
00894         // Mouse X button up event
00895         case WM_XBUTTONUP :
00896         {
00897             Event Evt;
00898             Evt.Type               = Event::MouseButtonReleased;
00899             Evt.MouseButton.Button = HIWORD(WParam) == XBUTTON1 ? Mouse::XButton1 : Mouse::XButton2;
00900             Evt.MouseButton.X      = LOWORD(LParam);
00901             Evt.MouseButton.Y      = HIWORD(LParam);
00902             SendEvent(Evt);
00903             break;
00904         }
00905 
00906         // Mouse move event
00907         case WM_MOUSEMOVE :
00908         {
00909             // Check if we need to generate a MouseEntered event
00910             if (!myIsCursorIn)
00911             {
00912                 TRACKMOUSEEVENT MouseEvent;
00913                 MouseEvent.cbSize    = sizeof(TRACKMOUSEEVENT);
00914                 MouseEvent.hwndTrack = myHandle;
00915                 MouseEvent.dwFlags   = TME_LEAVE;
00916                 TrackMouseEvent(&MouseEvent);
00917 
00918                 myIsCursorIn = true;
00919 
00920                 Event Evt;
00921                 Evt.Type = Event::MouseEntered;
00922                 SendEvent(Evt);
00923             }
00924 
00925             Event Evt;
00926             Evt.Type        = Event::MouseMoved;
00927             Evt.MouseMove.X = LOWORD(LParam);
00928             Evt.MouseMove.Y = HIWORD(LParam);
00929             SendEvent(Evt);
00930             break;
00931         }
00932 
00933         // Mouse leave event
00934         case WM_MOUSELEAVE :
00935         {
00936             myIsCursorIn = false;
00937 
00938             Event Evt;
00939             Evt.Type = Event::MouseLeft;
00940             SendEvent(Evt);
00941             break;
00942         }
00943     }
00944 }
00945 
00946 
00950 Key::Code WindowImplWin32::VirtualKeyCodeToSF(WPARAM VirtualKey, LPARAM Flags)
00951 {
00952     switch (VirtualKey)
00953     {
00954         // Check the scancode to distinguish between left and right shift
00955         case VK_SHIFT :
00956         {
00957             static UINT LShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
00958             UINT scancode = (Flags & (0xFF << 16)) >> 16;
00959             return scancode == LShift ? Key::LShift : Key::RShift;
00960         }
00961 
00962         // Check the "extended" flag to distinguish between left and right alt
00963         case VK_MENU : return (HIWORD(Flags) & KF_EXTENDED) ? Key::RAlt : Key::LAlt;
00964 
00965         // Check the "extended" flag to distinguish between left and right control
00966         case VK_CONTROL : return (HIWORD(Flags) & KF_EXTENDED) ? Key::RControl : Key::LControl;
00967 
00968         // Other keys are reported properly
00969         case VK_LWIN :       return Key::LSystem;
00970         case VK_RWIN :       return Key::RSystem;
00971         case VK_APPS :       return Key::Menu;
00972         case VK_OEM_1 :      return Key::SemiColon;
00973         case VK_OEM_2 :      return Key::Slash;
00974         case VK_OEM_PLUS :   return Key::Equal;
00975         case VK_OEM_MINUS :  return Key::Dash;
00976         case VK_OEM_4 :      return Key::LBracket;
00977         case VK_OEM_6 :      return Key::RBracket;
00978         case VK_OEM_COMMA :  return Key::Comma;
00979         case VK_OEM_PERIOD : return Key::Period;
00980         case VK_OEM_7 :      return Key::Quote;
00981         case VK_OEM_5 :      return Key::BackSlash;
00982         case VK_OEM_3 :      return Key::Tilde;
00983         case VK_ESCAPE :     return Key::Escape;
00984         case VK_SPACE :      return Key::Space;
00985         case VK_RETURN :     return Key::Return;
00986         case VK_BACK :       return Key::Back;
00987         case VK_TAB :        return Key::Tab;
00988         case VK_PRIOR :      return Key::PageUp;
00989         case VK_NEXT :       return Key::PageDown;
00990         case VK_END :        return Key::End;
00991         case VK_HOME :       return Key::Home;
00992         case VK_INSERT :     return Key::Insert;
00993         case VK_DELETE :     return Key::Delete;
00994         case VK_ADD :        return Key::Add;
00995         case VK_SUBTRACT :   return Key::Subtract;
00996         case VK_MULTIPLY :   return Key::Multiply;
00997         case VK_DIVIDE :     return Key::Divide;
00998         case VK_PAUSE :      return Key::Pause;
00999         case VK_F1 :         return Key::F1;
01000         case VK_F2 :         return Key::F2;
01001         case VK_F3 :         return Key::F3;
01002         case VK_F4 :         return Key::F4;
01003         case VK_F5 :         return Key::F5;
01004         case VK_F6 :         return Key::F6;
01005         case VK_F7 :         return Key::F7;
01006         case VK_F8 :         return Key::F8;
01007         case VK_F9 :         return Key::F9;
01008         case VK_F10 :        return Key::F10;
01009         case VK_F11 :        return Key::F11;
01010         case VK_F12 :        return Key::F12;
01011         case VK_F13 :        return Key::F13;
01012         case VK_F14 :        return Key::F14;
01013         case VK_F15 :        return Key::F15;
01014         case VK_LEFT :       return Key::Left;
01015         case VK_RIGHT :      return Key::Right;
01016         case VK_UP :         return Key::Up;
01017         case VK_DOWN :       return Key::Down;
01018         case VK_NUMPAD0 :    return Key::Numpad0;
01019         case VK_NUMPAD1 :    return Key::Numpad1;
01020         case VK_NUMPAD2 :    return Key::Numpad2;
01021         case VK_NUMPAD3 :    return Key::Numpad3;
01022         case VK_NUMPAD4 :    return Key::Numpad4;
01023         case VK_NUMPAD5 :    return Key::Numpad5;
01024         case VK_NUMPAD6 :    return Key::Numpad6;
01025         case VK_NUMPAD7 :    return Key::Numpad7;
01026         case VK_NUMPAD8 :    return Key::Numpad8;
01027         case VK_NUMPAD9 :    return Key::Numpad9;
01028         case 'A' :           return Key::A;
01029         case 'Z' :           return Key::Z;
01030         case 'E' :           return Key::E;
01031         case 'R' :           return Key::R;
01032         case 'T' :           return Key::T;
01033         case 'Y' :           return Key::Y;
01034         case 'U' :           return Key::U;
01035         case 'I' :           return Key::I;
01036         case 'O' :           return Key::O;
01037         case 'P' :           return Key::P;
01038         case 'Q' :           return Key::Q;
01039         case 'S' :           return Key::S;
01040         case 'D' :           return Key::D;
01041         case 'F' :           return Key::F;
01042         case 'G' :           return Key::G;
01043         case 'H' :           return Key::H;
01044         case 'J' :           return Key::J;
01045         case 'K' :           return Key::K;
01046         case 'L' :           return Key::L;
01047         case 'M' :           return Key::M;
01048         case 'W' :           return Key::W;
01049         case 'X' :           return Key::X;
01050         case 'C' :           return Key::C;
01051         case 'V' :           return Key::V;
01052         case 'B' :           return Key::B;
01053         case 'N' :           return Key::N;
01054         case '0' :           return Key::Num0;
01055         case '1' :           return Key::Num1;
01056         case '2' :           return Key::Num2;
01057         case '3' :           return Key::Num3;
01058         case '4' :           return Key::Num4;
01059         case '5' :           return Key::Num5;
01060         case '6' :           return Key::Num6;
01061         case '7' :           return Key::Num7;
01062         case '8' :           return Key::Num8;
01063         case '9' :           return Key::Num9;
01064     }
01065 
01066     return Key::Code(0);
01067 }
01068 
01069 
01075 bool WindowImplWin32::HasUnicodeSupport()
01076 {
01077     OSVERSIONINFO VersionInfo;
01078     ZeroMemory(&VersionInfo, sizeof(VersionInfo));
01079     VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
01080 
01081     if (GetVersionEx(&VersionInfo))
01082     {
01083         return VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
01084     }
01085     else
01086     {
01087         return false;
01088     }
01089 }
01090 
01091 
01095 LRESULT CALLBACK WindowImplWin32::GlobalOnEvent(HWND Handle, UINT Message, WPARAM WParam, LPARAM LParam)
01096 {
01097     // Associate handle and Window instance when the creation message is received
01098     if (Message == WM_CREATE)
01099     {
01100         // Get WindowImplWin32 instance (it was passed as the last argument of CreateWindow)
01101         long This = reinterpret_cast<long>(reinterpret_cast<CREATESTRUCT*>(LParam)->lpCreateParams);
01102 
01103         // Set as the "user data" parameter of the window
01104         SetWindowLongPtr(Handle, GWLP_USERDATA, This);
01105     }
01106 
01107     // Get the WindowImpl instance corresponding to the window handle
01108     WindowImplWin32* Window = reinterpret_cast<WindowImplWin32*>(GetWindowLongPtr(Handle, GWLP_USERDATA));
01109 
01110     // Forward the event to the appropriate function
01111     if (Window)
01112     {
01113         Window->ProcessEvent(Message, WParam, LParam);
01114 
01115         if (Window->myCallback)
01116             return CallWindowProc(reinterpret_cast<WNDPROC>(Window->myCallback), Handle, Message, WParam, LParam);
01117     }
01118 
01119     // We don't forward the WM_CLOSE message to prevent the OS from automatically destroying the window
01120     if (Message == WM_CLOSE)
01121         return 0;
01122 
01123     static const bool HasUnicode = HasUnicodeSupport();
01124     return HasUnicode ? DefWindowProcW(Handle, Message, WParam, LParam) :
01125                         DefWindowProcA(Handle, Message, WParam, LParam);
01126 }
01127 
01128 } // namespace priv
01129 
01130 } // namespace sf