# HG changeset patch # User dewyatt # Date 1277933360 14400 # Node ID bb189d44af167817ac9c7d93f96d75cd1b4ad8ad # Parent abf528de6d2eafafae3b061f247726aed68884dd Added GLIMM (using IMM instead of TSF) Uses small bit of TSF to fully disable cicero (TSF for non-TSF enabled apps) diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/GLIMM.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/GLIMM.sln Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLIMM", "GLIMM.vcproj", "{F21B830F-20A9-4473-B67A-21D1743C6E19}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Debug|Win32.ActiveCfg = Debug|Win32 + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Debug|Win32.Build.0 = Debug|Win32 + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Release|Win32.ActiveCfg = Release|Win32 + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/GLIMM.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/GLIMM.vcproj Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/include/App.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/App.hpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,36 @@ +#ifndef APP_HPP +#define APP_HPP + +#include "Window.hpp" + +class App : public Window_Listener +{ +public: + App(); + virtual ~App(); + + void Initialize(); + void Finalize(); + + void Run(); + + virtual void On_Close(); + virtual void On_Key_Down(int Key); + virtual void On_Key_Up(int Key); + virtual void On_Char(unsigned int Char); + virtual void On_Resized(unsigned int Width, unsigned int Height); + +private: + void Update(); + void Draw(); + + static const int Width = 800; + static const int Height = 600; + static const int Bits_Per_Pixel = 32; + static const bool Fullscreen = false; + + Window my_Window; + bool my_Done; +}; + +#endif diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/include/IMM.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/IMM.hpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,30 @@ +#ifndef IMM_HPP +#define IMM_HPP + +#define WIN32_LEAN_AND_MEAN +#include +#include + +class IMM +{ +public: + IMM(); + ~IMM(); + + void Initialize(HWND Window); + void Finalize(); + + LRESULT Handle_Message(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam, bool &Ate); + +private: + void Update_Input_Locale(); + + bool my_COM_Initialized; + ITfThreadMgr *my_Thread_Manager; + HWND my_Window; + HIMC my_Context; + HKL my_HKL; + bool my_Vertical_Candidates; +}; + +#endif diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/include/Video_Mode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/Video_Mode.hpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,30 @@ +#ifndef VIDEO_MODE_HPP +#define VIDEO_MODE_HPP + +#include + +class Video_Mode +{ +public: + Video_Mode(); + Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel); + + static Video_Mode Get_Desktop_Mode(); + + static std::size_t Get_Mode_Count(); + static Video_Mode Get_Mode(std::size_t Index); + + bool Is_Valid() const; + + bool operator==(const Video_Mode &Mode) const; + bool operator!=(const Video_Mode &Mode) const; + + unsigned int Width; + unsigned int Height; + unsigned int Bits_Per_Pixel; + +private: + static void Initialize_Modes(); +}; + +#endif diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/include/Window.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/Window.hpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,62 @@ +#ifndef WINDOW_HPP +#define WINDOW_HPP + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +#include "Video_Mode.hpp" +#include "Window_Listener.hpp" +#include "IMM.hpp" + +class Window +{ +public: + Window(); + ~Window(); + + void Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen); + void Finalize(); + + void Set_Listener(Window_Listener *Listener); + + void Show(); + void Hide(); + + void Handle_Events(); + void Display(); + + void Show_Cursor(); + void Hide_Cursor(); + + HWND Get_Handle(); + +private: + static const wchar_t *Window_Class_Name; + + void Register_Class(); + void Unregister_Class(); + + void Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen); + void Destroy_Window(); + + void Create_Context(const Video_Mode &Mode); + void Destroy_Context(); + + void Switch_To_Fullscreen(const Video_Mode &Mode); + + LRESULT Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam); + + HWND my_Handle; + Video_Mode my_Video_Mode; + bool my_Fullscreen; + HDC my_Device_Context; + HGLRC my_GL_Context; + bool my_Class_Registered; + Window_Listener *my_Listener; + IMM my_IMM; +}; + +#endif diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/include/Window_Listener.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/Window_Listener.hpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,14 @@ +#ifndef WINDOW_LISTENER_HPP +#define WINDOW_LISTENER_HPP + +class Window_Listener +{ +public: + virtual void On_Close(){} + virtual void On_Key_Down(int Key){} + virtual void On_Key_Up(int Key){} + virtual void On_Char(unsigned int Char){} + virtual void On_Resized(unsigned int Width, unsigned int Height){} +}; + +#endif diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/src/App.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/App.cpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,103 @@ +#include "App.hpp" +#include +#include + +#pragma comment(lib, "glu32.lib") + +GLfloat Rotation = 0.0f; + +App::App() : my_Done(false) +{ + +} + +App::~App() +{ + Finalize(); +} + +void App::Initialize() +{ + Finalize(); + + my_Window.Initialize(L"GLTSF", Video_Mode(Width, Height, Bits_Per_Pixel), Fullscreen); + my_Window.Set_Listener(this); + my_Window.Show(); + my_Window.Hide_Cursor(); +} + +void App::Finalize() +{ + my_Window.Finalize(); +} + +void App::Run() +{ + Initialize(); + while (!my_Done) + { + my_Window.Handle_Events(); + + Update(); + Draw(); + my_Window.Display(); + } +} + +void App::On_Close() +{ + my_Done = true; + my_Window.Hide(); +} + +void App::On_Key_Down(int Key) +{ + switch (Key) + { + case VK_ESCAPE: + On_Close(); + break; + } +} + +void App::On_Key_Up(int Key) +{ + +} + +void App::On_Char(unsigned int Char) +{ + printf("Char: U+%04X\n", Char); +} + +void App::On_Resized(unsigned int Width, unsigned int Height) +{ + glViewport(0, 0, Width, Height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void App::Update() +{ + Rotation += 0.2f; +} + +void App::Draw() +{ + glClear(GL_COLOR_BUFFER_BIT); + + glLoadIdentity(); + glRotatef(Rotation, 0.0f, 0.0f, -1.0f); + + glBegin(GL_TRIANGLES); + glColor3f(0.7f, 0.0f, 0.0f); + glVertex3f(0.0f, 0.5f, 0.0f); + glColor3f(0.0f, 0.7f, 0.0f); + glVertex3f(-0.5f, -0.5f, 0.0f); + glColor3f(0.0f, 0.0f, 0.7f); + glVertex3f(0.5f, -0.5f, 0.0f); + glEnd(); +} diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/src/IMM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/IMM.cpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,165 @@ +#include "IMM.hpp" +#include + +IMM::IMM() : my_COM_Initialized(false), + my_Thread_Manager(0), + my_Window(0), + my_Context(0), + my_HKL(0), + my_Vertical_Candidates(false) +{ + +} + +IMM::~IMM() +{ + Finalize(); +} + +void IMM::Initialize(HWND Window) +{ + Finalize(); + + my_Window = Window; + + if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + my_COM_Initialized = true; + if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast(&my_Thread_Manager)))) + { + ITfDocumentMgr *Document_Manager = 0; + if (FAILED(my_Thread_Manager->AssociateFocus(Window, NULL, &Document_Manager))) + printf("Warning: ITfThreadMgr->AssociateFocus failed\n"); + + if (Document_Manager) + Document_Manager->Release(); + } + else + printf("Warning: Failed to create ITfThreadMgr instance\n"); + } + else + printf("Warning: Failed to initialize COM\n"); + + ImmDisableTextFrameService(-1); + + my_Context = ImmGetContext(my_Window); + if (!ImmReleaseContext(my_Window, my_Context)) + throw std::runtime_error("Error releasing context"); + + if (!my_Context) + throw std::runtime_error("No context"); + + Update_Input_Locale(); +} + +void IMM::Finalize() +{ + if (my_Thread_Manager) + { + my_Thread_Manager->Release(); + my_Thread_Manager = 0; + } + if (my_COM_Initialized) + { + CoUninitialize(); + my_COM_Initialized = false; + } +} + +#define GET_LANG(hkl) LOWORD((hkl)) +#define GET_PRIMLANG(hkl) ((WORD)PRIMARYLANGID(GET_LANG((hkl)))) +#define GET_SUBLANG(hkl) SUBLANGID(GET_LANG((hkl))) + +void IMM::Update_Input_Locale() +{ + static HKL Previous_HKL = 0; + my_HKL = GetKeyboardLayout(0); + if (Previous_HKL == my_HKL) + return; + + Previous_HKL = my_HKL; + my_Vertical_Candidates = false; + switch (GET_PRIMLANG(my_HKL)) + { + case LANG_CHINESE: + my_Vertical_Candidates = true; + switch (GET_SUBLANG(my_HKL)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + my_Vertical_Candidates = false; + break; + } + break; + case LANG_JAPANESE: + my_Vertical_Candidates = true; + break; + } +} + +LRESULT IMM::Handle_Message(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam, bool &Ate) +{ + Ate = false; + switch (Message) + { + case WM_INPUTLANGCHANGE: + Update_Input_Locale(); + break; + case WM_IME_SETCONTEXT: + lParam = 0; + return DefWindowProcW(my_Window, Message, wParam, lParam); + break; + case WM_IME_STARTCOMPOSITION: + Ate = true; + break; + case WM_IME_COMPOSITION: + { + Ate = true; + HIMC Context = ImmGetContext(Window); + if (!Context) + break; + + if (lParam & GCS_RESULTSTR) + { + LONG Length = ImmGetCompositionStringW(Context, GCS_RESULTSTR, 0, 0); + std::wstring Composition(Length / sizeof(wchar_t), 0); + Length = ImmGetCompositionStringW(Context, GCS_RESULTSTR, &Composition[0], Composition.size() * sizeof(Composition[0])); + printf("GCS_RESULTSTR: "); + for (LONG i = 0; i < Length / sizeof(wchar_t); ++i) + printf("U+%04X ", Composition[i]); + + printf("\n"); + } + if (lParam & GCS_COMPSTR) + { + LONG Length = ImmGetCompositionStringW(Context, GCS_COMPSTR, 0, 0); + std::wstring Composition(Length / sizeof(wchar_t), 0); + Length = ImmGetCompositionStringW(Context, GCS_COMPSTR, &Composition[0], Composition.size() * sizeof(Composition[0])); + printf("GCS_COMPSTR: "); + for (LONG i = 0; i < Length / sizeof(wchar_t); ++i) + printf("U+%04X ", Composition[i]); + + printf("\n"); + } + ImmReleaseContext(Window, Context); + } + break; + case WM_IME_ENDCOMPOSITION: + break; + case WM_IME_NOTIFY: + switch (wParam) + { + case IMN_SETCONVERSIONMODE: + + break; + case IMN_SETOPENSTATUS: + Update_Input_Locale(); + break; + case IMN_OPENCANDIDATE: + case IMN_CHANGECANDIDATE: + Ate = true; + break; + } + break; + } + return 0; +} diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/src/Main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/Main.cpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,24 @@ +#include "App.hpp" +#include + +int main(int argc, char *argv[]) +{ + int Result = EXIT_SUCCESS; + try + { + App theApp; + theApp.Run(); + } + catch (const std::exception& e) + { + printf("Error: %s\n", e.what()); + Result = EXIT_FAILURE; + } + catch (...) + { + printf("Unhandled exception\n"); + Result = EXIT_FAILURE; + } + system("PAUSE"); + return Result; +} diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/src/Video_Mode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/Video_Mode.cpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,100 @@ +#include "Video_Mode.hpp" +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + +namespace +{ + + typedef std::vector Video_Mode_List; + Video_Mode_List Supported_Modes; + + struct Compare_Modes + { + bool operator()(const Video_Mode &Mode_1, const Video_Mode &Mode_2) const + { + if (Mode_1.Bits_Per_Pixel > Mode_2.Bits_Per_Pixel) + return true; + else if (Mode_1.Bits_Per_Pixel < Mode_2.Bits_Per_Pixel) + return false; + else if (Mode_1.Width > Mode_2.Width) + return true; + else if (Mode_1.Width < Mode_2.Width) + return false; + else + return Mode_1.Height > Mode_2.Height; + } + }; + +} + +Video_Mode::Video_Mode() : Width(0), + Height(0), + Bits_Per_Pixel(0) +{ + +} + +Video_Mode::Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel) + : Width(The_Width), + Height(The_Height), + Bits_Per_Pixel(The_Bits_Per_Pixel) +{ + +} + +Video_Mode Video_Mode::Get_Desktop_Mode() +{ + DEVMODE Device_Mode = {0}; + Device_Mode.dmSize = sizeof(Device_Mode); + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &Device_Mode); + return Video_Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel); +} + +std::size_t Video_Mode::Get_Mode_Count() +{ + Initialize_Modes(); + return Supported_Modes.size(); +} + +Video_Mode Video_Mode::Get_Mode(std::size_t Index) +{ + Initialize_Modes(); + return Supported_Modes[Index]; +} + +bool Video_Mode::Is_Valid() const +{ + Initialize_Modes(); + return Supported_Modes.end() != std::find(Supported_Modes.begin(), Supported_Modes.end(), *this); +} + +bool Video_Mode::operator==(const Video_Mode &Mode) const +{ + return (Width == Mode.Width + && Height == Mode.Height + && Bits_Per_Pixel == Mode.Bits_Per_Pixel); +} + +bool Video_Mode::operator!=(const Video_Mode &Mode) const +{ + return !(*this == Mode); +} + +void Video_Mode::Initialize_Modes() +{ + static bool Initialized = false; + if (!Initialized) + { + DEVMODE Device_Mode = {0}; + Device_Mode.dmSize = sizeof(Device_Mode); + for (std::size_t i = 0; 0 != EnumDisplaySettings(NULL, i, &Device_Mode); ++i) + { + Video_Mode Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel); + if (Supported_Modes.end() == std::find(Supported_Modes.begin(), Supported_Modes.end(), Mode)) + Supported_Modes.push_back(Mode); + } + std::sort(Supported_Modes.begin(), Supported_Modes.end(), Compare_Modes()); + } +} diff -r abf528de6d2e -r bb189d44af16 EXCLUDE/GLIMM/src/Window.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/Window.cpp Wed Jun 30 17:29:20 2010 -0400 @@ -0,0 +1,293 @@ +#include "Window.hpp" +#include + +#pragma comment(lib, "opengl32.lib") + +const wchar_t *Window::Window_Class_Name = L"GLTSF"; + +Window::Window() : my_Handle(0), + my_Device_Context(0), + my_GL_Context(0), + my_Class_Registered(false), + my_Listener(0) +{ + +} + +Window::~Window() +{ + Finalize(); + Show_Cursor(); +} + +void Window::Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen) +{ + Finalize(); + + my_Video_Mode = Mode; + if (!my_Video_Mode.Is_Valid()) + throw std::runtime_error("Invalid video mode"); + + my_Fullscreen = Fullscreen; + Register_Class(); + Create_Window(Title, Mode, Fullscreen); + my_IMM.Initialize(my_Handle); +} + +void Window::Finalize() +{ + my_IMM.Finalize(); + Destroy_Window(); + Unregister_Class(); +} + +void Window::Set_Listener(Window_Listener *Listener) +{ + my_Listener = Listener; +} + +void Window::Show() +{ + if (my_Handle) + ShowWindow(my_Handle, SW_SHOW); +} + +void Window::Hide() +{ + if (my_Handle) + ShowWindow(my_Handle, SW_HIDE); +} + +void Window::Handle_Events() +{ + MSG Message = {0}; + while (PeekMessageW(&Message, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&Message); + DispatchMessageW(&Message); + } +} + +void Window::Display() +{ + if (my_Device_Context && my_GL_Context) + SwapBuffers(my_Device_Context); +} + +void Window::Show_Cursor() +{ + ShowCursor(TRUE); +} + +void Window::Hide_Cursor() +{ + ShowCursor(FALSE); +} + +HWND Window::Get_Handle() +{ + return my_Handle; +} + +void Window::Register_Class() +{ + WNDCLASSEXW Window_Class = {0}; + Window_Class.cbSize = sizeof(Window_Class); + Window_Class.style = 0; + Window_Class.lpfnWndProc = &Window::Window_Procedure; + Window_Class.cbClsExtra = 0; + Window_Class.cbWndExtra = 0; + Window_Class.hInstance = GetModuleHandle(NULL); + Window_Class.hIcon = NULL; + Window_Class.hCursor = NULL; + Window_Class.hbrBackground = NULL; + Window_Class.lpszMenuName = NULL; + Window_Class.lpszClassName = Window_Class_Name; + Window_Class.hIconSm = NULL; + if (0 == RegisterClassExW(&Window_Class)) + throw std::runtime_error("Failed to register window class"); + + my_Class_Registered = true; +} + +void Window::Unregister_Class() +{ + if (my_Class_Registered) + { + if (0 == UnregisterClassW(Window_Class_Name, GetModuleHandle(NULL))) + printf("Warning: Failed to unregister window class\n"); + + my_Class_Registered = false; + } +} + +void Window::Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen) +{ + HDC Screen_DC = GetDC(NULL); + int Left = (GetDeviceCaps(Screen_DC, HORZRES) - my_Video_Mode.Width) / 2; + int Top = (GetDeviceCaps(Screen_DC, VERTRES) - my_Video_Mode.Height) / 2; + int Width = my_Video_Mode.Width; + int Height = my_Video_Mode.Height; + ReleaseDC(NULL, Screen_DC); + + DWORD Style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; + if (!my_Fullscreen) + { + RECT Rect = {0, 0, Width, Height}; + AdjustWindowRect(&Rect, Style, false); + Width = Rect.right - Rect.left; + Height = Rect.bottom - Rect.top; + } + my_Handle = CreateWindowW(Window_Class_Name, Title.c_str(), Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this); + if (!my_Handle) + throw std::runtime_error("Failed to create window"); + + if (Fullscreen) + Switch_To_Fullscreen(Mode); + + Create_Context(Mode); + + RECT Rect = {0}; + GetClientRect(my_Handle, &Rect); + //TODO: ... +} + +void Window::Destroy_Window() +{ + Destroy_Context(); + if (my_Handle) + { + DestroyWindow(my_Handle); + my_Handle = 0; + + if (my_Fullscreen) + ChangeDisplaySettings(NULL, 0); + } +} + +void Window::Create_Context(const Video_Mode &Mode) +{ + my_Device_Context = GetDC(my_Handle); + if (!my_Device_Context) + throw std::runtime_error("Failed to get device context"); + + PIXELFORMATDESCRIPTOR Pixel_Descriptor = {0}; + Pixel_Descriptor.nSize = sizeof(Pixel_Descriptor); + Pixel_Descriptor.nVersion = 1; + Pixel_Descriptor.iLayerType = PFD_MAIN_PLANE; + Pixel_Descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + Pixel_Descriptor.iPixelType = PFD_TYPE_RGBA; + Pixel_Descriptor.cColorBits = static_cast(Mode.Bits_Per_Pixel); + Pixel_Descriptor.cDepthBits = 24; + Pixel_Descriptor.cStencilBits = 8; + Pixel_Descriptor.cAlphaBits = Mode.Bits_Per_Pixel == 32 ? 8 : 0; + + int Best_Format = ChoosePixelFormat(my_Device_Context, &Pixel_Descriptor); + if (0 == Best_Format) + throw std::runtime_error("Failed to find suitable pixel format"); + + PIXELFORMATDESCRIPTOR Actual_Format = {0}; + Actual_Format.nSize = sizeof(Actual_Format); + Actual_Format.nVersion = 1; + DescribePixelFormat(my_Device_Context, Best_Format, sizeof(Actual_Format), &Actual_Format); + if (!SetPixelFormat(my_Device_Context, Best_Format, &Actual_Format)) + throw std::runtime_error("Failed to set device pixel format"); + + my_GL_Context = wglCreateContext(my_Device_Context); + if (!my_GL_Context) + throw std::runtime_error("Failed to create OpenGL context"); + + wglMakeCurrent(my_Device_Context, my_GL_Context); +} + +void Window::Destroy_Context() +{ + if (my_GL_Context) + { + wglDeleteContext(my_GL_Context); + my_GL_Context = 0; + } + if (my_Device_Context) + { + ReleaseDC(my_Handle, my_Device_Context); + my_Device_Context = 0; + } +} + +void Window::Switch_To_Fullscreen(const Video_Mode &Mode) +{ + DEVMODE Device_Mode = {0}; + Device_Mode.dmSize = sizeof(Device_Mode); + Device_Mode.dmPelsWidth = Mode.Width; + Device_Mode.dmPelsHeight = Mode.Height; + Device_Mode.dmBitsPerPel = Mode.Bits_Per_Pixel; + Device_Mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; + + if (DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&Device_Mode, CDS_FULLSCREEN)) + throw std::runtime_error("Failed to change to fullscreen mode"); + + SetWindowLong(my_Handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + SetWindowLong(my_Handle, GWL_EXSTYLE, WS_EX_APPWINDOW); + + SetWindowPos(my_Handle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED); +} + +LRESULT CALLBACK Window::Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam) +{ + switch (Message) + { + case WM_CREATE: + { + LONG This = reinterpret_cast(reinterpret_cast(lParam)->lpCreateParams); + SetWindowLongPtr(Handle, GWLP_USERDATA, This); + return 0; + } + break; + case WM_DESTROY: + PostQuitMessage(0); + return 0; + break; + default: + { + Window* Win = reinterpret_cast(GetWindowLongPtr(Handle, GWLP_USERDATA)); + if (Win) + return Win->Handle_Message(Handle, Message, wParam, lParam); + } + break; + } + return DefWindowProcW(Handle, Message, wParam, lParam); +} + +#define Call_Listener(x)\ + if (my_Listener) my_Listener->x + +LRESULT Window::Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam) +{ + bool IMM_Message = false; + LRESULT Result = my_IMM.Handle_Message(Handle, Message, wParam, lParam, IMM_Message); + if (IMM_Message) + return Result; + + switch (Message) + { + case WM_SIZE: + Call_Listener(On_Resized(LOWORD(lParam), HIWORD(lParam))); + break; + case WM_CLOSE: + Call_Listener(On_Close()); + break; + case WM_KEYDOWN: + Call_Listener(On_Key_Down(wParam)); + break; + case WM_KEYUP: + Call_Listener(On_Key_Up(wParam)); + break; + case WM_CHAR: + Call_Listener(On_Char(wParam)); + break; + default: + return DefWindowProcW(Handle, Message, wParam, lParam); + break; + } + return 0; +}