summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2018-08-07 21:53:55 +0800
committerchai <chaifix@163.com>2018-08-07 21:53:55 +0800
commit926584873cd9a83458ac482c02902f4eedb1e9d3 (patch)
tree2ed019c5b8e6f391ae7a0268a200b51b7ffe293e
-rw-r--r--Thread/WindowsBased/example/test.cpp11
-rw-r--r--Thread/WindowsBased/thread.h342
-rw-r--r--test/test.sln28
-rw-r--r--test/test.vcxproj153
-rw-r--r--test/test.vcxproj.filters27
-rw-r--r--ui/ui.h56
-rw-r--r--ui/win32.h331
7 files changed, 948 insertions, 0 deletions
diff --git a/Thread/WindowsBased/example/test.cpp b/Thread/WindowsBased/example/test.cpp
new file mode 100644
index 0000000..b7b7279
--- /dev/null
+++ b/Thread/WindowsBased/example/test.cpp
@@ -0,0 +1,11 @@
+#include "../cpp-utils-master/ui/ui/ui.h"
+
+using namespace ui;
+
+int ui_main()
+{
+ window w(256, 256);
+ w << "Hello World!";
+ w.waitkey();
+ return 0;
+}
diff --git a/Thread/WindowsBased/thread.h b/Thread/WindowsBased/thread.h
new file mode 100644
index 0000000..e8bb30d
--- /dev/null
+++ b/Thread/WindowsBased/thread.h
@@ -0,0 +1,342 @@
+// mt - thread library to create C++ experiments -*- C++ -*-
+// Copyright (C) 2010, 2012 David Capello
+//
+// Distributed under the terms of the New BSD License,
+// see LICENSE.md for more details.
+
+#ifndef MT_THREAD_HEADER_FILE_INCLUDED
+#define MT_THREAD_HEADER_FILE_INCLUDED
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400 // From Windows 2000
+#endif
+
+#include <windows.h>
+
+#include <cassert>
+#include <string>
+#include <exception>
+
+namespace mt {
+
+ //////////////////////////////////////////////////////////////////////
+ // lock_guard class
+
+ template<class Mutex>
+ class lock_guard {
+ public:
+ typedef Mutex mutex_type;
+
+ explicit lock_guard(mutex_type& mutex) : m_mutex(mutex) {
+ m_mutex.lock();
+ }
+
+ ~lock_guard() {
+ m_mutex.unlock();
+ }
+
+ void lock() {
+ m_mutex.lock();
+ }
+
+ void unlock() {
+ m_mutex.unlock();
+ }
+
+ private:
+ mutex_type& m_mutex;
+
+ // Non-copyable
+ lock_guard(const lock_guard&);
+ lock_guard& operator=(const lock_guard&);
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // mutex class
+
+ class mutex {
+ public:
+ mutex() {
+ InitializeCriticalSection(&m_cs);
+ }
+
+ ~mutex() {
+ DeleteCriticalSection(&m_cs);
+ }
+
+ void lock() {
+ EnterCriticalSection(&m_cs);
+ }
+
+ bool try_lock() {
+ return TryEnterCriticalSection(&m_cs) ? true: false;
+ }
+
+ void unlock() {
+ LeaveCriticalSection(&m_cs);
+ }
+
+ private:
+ CRITICAL_SECTION m_cs;
+
+ // Non-copyable
+ mutex(const mutex&);
+ mutex& operator=(const mutex&);
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // condition_variable class
+
+ class condition_variable {
+ public:
+ condition_variable() {
+ m_waiting_queue =
+ CreateSemaphore(NULL, // Security attributes
+ 0, // Initial count
+ 1000, // Maximum number of waiters (TODO)
+ NULL); // Unnamed semaphore
+ m_waiters = 0;
+ }
+
+ ~condition_variable() {
+ // Here we could call notify_all, but, if a condition variable
+ // is destroyed, "there shall be no thread blocked on *this"
+ // (see 30.5.1 C++ working draft n3035)
+ assert(m_waiters == 0);
+
+ CloseHandle(m_waiting_queue);
+ }
+
+ void wait(lock_guard<mutex>& external_monitor) {
+ {
+ lock_guard<mutex> lock(m_monitor);
+
+ assert(m_waiters >= 0);
+
+ ++m_waiters;
+ external_monitor.unlock();
+ }
+ ::WaitForSingleObject(m_waiting_queue, INFINITE);
+ external_monitor.lock();
+ }
+
+ void notify_one() {
+ lock_guard<mutex> lock(m_monitor);
+
+ assert(m_waiters >= 0);
+
+ // If there are one or more waiters...
+ if (m_waiters > 0) {
+ // Increment semaphore count to unlock a waiting thread
+ ReleaseSemaphore(m_waiting_queue, 1, NULL);
+ --m_waiters;
+ }
+ }
+
+ void notify_all() {
+ lock_guard<mutex> lock(m_monitor);
+
+ assert(m_waiters >= 0);
+
+ // If there are one or more waiters...
+ if (m_waiters > 0) {
+ // Increment the semaphore to the number of waiting threads
+ ReleaseSemaphore(m_waiting_queue, m_waiters, NULL);
+ m_waiters = 0;
+ }
+ }
+
+ private:
+ mutex m_monitor; // To avoid running two condition_variable member function at the same time
+ HANDLE m_waiting_queue; // Queue of waiting threads
+ LONG m_waiters; // Number of waiters in the queue
+
+ // Non-copyable
+ condition_variable(const condition_variable&);
+ condition_variable& operator=(const condition_variable&);
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // ultra-simplistic thread class implementation based on C++0x
+
+ class thread {
+ public:
+ class details;
+ class id {
+ friend class thread;
+ friend class details;
+
+ DWORD m_native_id;
+ id(DWORD id) : m_native_id(id) { }
+ public:
+ id() : m_native_id(0) { }
+ bool operator==(const id& y) const { return m_native_id == y.m_native_id; }
+ bool operator!=(const id& y) const { return m_native_id != y.m_native_id; }
+ bool operator< (const id& y) const { return m_native_id < y.m_native_id; }
+ bool operator<=(const id& y) const { return m_native_id <= y.m_native_id; }
+ bool operator> (const id& y) const { return m_native_id > y.m_native_id; }
+ bool operator>=(const id& y) const { return m_native_id >= y.m_native_id; }
+
+ // TODO should we replace this with support for iostreams?
+ DWORD get_native_id() { return m_native_id; }
+ };
+
+ typedef HANDLE native_handle_type;
+
+ private:
+
+ template<class Callable>
+ struct f_wrapper0 {
+ Callable f;
+ f_wrapper0(const Callable& f) : f(f) { }
+ void operator()() { f(); }
+ };
+
+ template<class Callable, class A>
+ struct f_wrapper1 {
+ Callable f;
+ A a;
+ f_wrapper1(const Callable& f, A a) : f(f), a(a) { }
+ void operator()() { f(a); }
+ };
+
+ template<class Callable, class A, class B>
+ struct f_wrapper2 {
+ Callable f;
+ A a;
+ B b;
+ f_wrapper2(const Callable& f, A a, B b) : f(f), a(a), b(b) { }
+ void operator()() { f(a, b); }
+ };
+
+ template<class T>
+ static DWORD WINAPI thread_proxy(LPVOID data) {
+ T* t = (T*)data;
+ (*t)();
+ delete t;
+ return 0;
+ }
+
+ native_handle_type m_native_handle;
+ id m_id;
+
+ public:
+
+ // Create an instance to represent the current thread
+ thread()
+ : m_native_handle(NULL)
+ , m_id() {
+ }
+
+ // Create a new thread without arguments
+ template<class Callable>
+ thread(const Callable& f) {
+ m_native_handle =
+ CreateThread(NULL, 0,
+ thread_proxy<f_wrapper0<Callable> >,
+ (LPVOID)new f_wrapper0<Callable>(f),
+ CREATE_SUSPENDED, &m_id.m_native_id);
+ ResumeThread(m_native_handle);
+ }
+
+ // Create a new thread with one argument
+ template<class Callable, class A>
+ thread(const Callable& f, A a) {
+ m_native_handle =
+ CreateThread(NULL, 0,
+ thread_proxy<f_wrapper1<Callable, A> >,
+ (LPVOID)new f_wrapper1<Callable, A>(f, a),
+ CREATE_SUSPENDED, &m_id.m_native_id);
+ ResumeThread(m_native_handle);
+ }
+
+ // Create a new thread with two arguments
+ template<class Callable, class A, class B>
+ thread(const Callable& f, A a, B b) {
+ m_native_handle =
+ CreateThread(NULL, 0,
+ thread_proxy<f_wrapper2<Callable, A, B> >,
+ (LPVOID)new f_wrapper2<Callable, A, B>(f, a, b),
+ CREATE_SUSPENDED, &m_id.m_native_id);
+ ResumeThread(m_native_handle);
+ }
+
+ ~thread() {
+ if (joinable())
+ detach();
+ }
+
+ bool joinable() const {
+ return
+ m_native_handle != NULL &&
+ m_id.m_native_id != ::GetCurrentThreadId();
+ }
+
+ void join() {
+ if (joinable()) {
+ ::WaitForSingleObject(m_native_handle, INFINITE);
+ detach();
+ }
+ }
+
+ void detach() {
+ ::CloseHandle(m_native_handle);
+
+ m_native_handle = NULL;
+ m_id = id();
+ }
+
+ id get_id() const {
+ return m_id;
+ }
+
+ native_handle_type native_handle() {
+ return m_native_handle;
+ }
+
+ class details {
+ public:
+ static id get_current_thread_id() {
+ return id(::GetCurrentThreadId());
+ }
+ };
+
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // this_thread namespace
+
+ namespace this_thread {
+
+ inline thread::id get_id() {
+ return thread::details::get_current_thread_id();
+ }
+
+ inline void yield() {
+ ::Sleep(0);
+ }
+
+ // Simplified API (here we do not implement duration/time_point C++0x classes
+ inline void sleep_for(int milliseconds) {
+ ::Sleep(milliseconds);
+ }
+
+ } // namespace this_thread
+
+ //////////////////////////////////////////////////////////////////////
+ // thread_guard class
+
+ class thread_guard {
+ public:
+ explicit thread_guard(thread& t) : m_thread(t) { }
+ ~thread_guard() {
+ if (m_thread.joinable())
+ m_thread.join();
+ }
+ private:
+ thread& m_thread;
+ };
+
+} // namespace mt
+
+#endif // MT_THREAD_HEADER_FILE_INCLUDED
diff --git a/test/test.sln b/test/test.sln
new file mode 100644
index 0000000..118a2d3
--- /dev/null
+++ b/test/test.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{49B3D92E-711D-45D9-8E6A-2AFE796EFF82}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Debug|x64.ActiveCfg = Debug|x64
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Debug|x64.Build.0 = Debug|x64
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Debug|x86.ActiveCfg = Debug|Win32
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Debug|x86.Build.0 = Debug|Win32
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Release|x64.ActiveCfg = Release|x64
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Release|x64.Build.0 = Release|x64
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Release|x86.ActiveCfg = Release|Win32
+ {49B3D92E-711D-45D9-8E6A-2AFE796EFF82}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/test/test.vcxproj b/test/test.vcxproj
new file mode 100644
index 0000000..b25d4d2
--- /dev/null
+++ b/test/test.vcxproj
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\Thread\WindowsBased\thread.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\Thread\WindowsBased\example\test.cpp" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{49B3D92E-711D-45D9-8E6A-2AFE796EFF82}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>test</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/test/test.vcxproj.filters b/test/test.vcxproj.filters
new file mode 100644
index 0000000..91a6a78
--- /dev/null
+++ b/test/test.vcxproj.filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="源文件">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="头文件">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="资源文件">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\Thread\WindowsBased\thread.h">
+ <Filter>头文件</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\Thread\WindowsBased\example\test.cpp">
+ <Filter>源文件</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/ui/ui.h b/ui/ui.h
new file mode 100644
index 0000000..a2c0e57
--- /dev/null
+++ b/ui/ui.h
@@ -0,0 +1,56 @@
+// ui - Basic User Interface library to do experiments -*- C++ -*-
+// Copyright (C) 2010, 2012 David Capello
+//
+// Distributed under the terms of the New BSD License,
+// see LICENSE.md for more details.
+
+#ifndef UI_UI_HEADER_FILE_INCLUDED
+#define UI_UI_HEADER_FILE_INCLUDED
+
+#if WIN32
+ #include "ui/win32.h"
+#endif
+
+namespace ui {
+
+ //////////////////////////////////////////////////////////////////////
+ // window class
+
+ class window {
+ public:
+ window(int width, int height) {
+ m_impl = new window_impl(width, height);
+ }
+
+ ~window() {
+ delete m_impl;
+ }
+
+ size_t width() {
+ return m_impl->width();
+ }
+
+ size_t height() {
+ return m_impl->height();
+ }
+
+ void waitkey() {
+ m_impl->waitkey();
+ }
+
+ window& operator<<(const std::string& text) {
+ m_impl->write(text);
+ return *this;
+ }
+
+ private:
+ window_impl* m_impl;
+
+ // Non-copyable
+ window(const window&);
+ window& operator=(const window&);
+ };
+
+} // namespace ui
+
+#endif // UI_UI_HEADER_FILE_INCLUDED
diff --git a/ui/win32.h b/ui/win32.h
new file mode 100644
index 0000000..ba9e43c
--- /dev/null
+++ b/ui/win32.h
@@ -0,0 +1,331 @@
+// ui - Basic User Interface library to do experiments -*- C++ -*-
+// Copyright (C) 2010, 2012 David Capello
+//
+// Distributed under the terms of the New BSD License,
+// see LICENSE.md for more details.
+
+#ifndef UI_WIN32_HEADER_FILE_INCLUDED
+#define UI_WIN32_HEADER_FILE_INCLUDED
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400 // From Windows 2000
+#endif
+
+#include "mt/thread.h"
+#include <exception>
+#include <windows.h>
+
+namespace ui {
+
+ namespace win32 {
+
+ //////////////////////////////////////////////////////////////////////
+ // win32_details namespace
+
+ class win32_details {
+
+ template<class WindowType>
+ static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ WindowType* wnd = (WindowType*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (wnd != NULL) {
+ LRESULT result;
+ if (wnd->process_message(msg, wparam, lparam, result))
+ return result;
+ }
+
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+
+ public:
+
+ template<class WindowType>
+ static void register_window_class() {
+ HINSTANCE hinstance = ::GetModuleHandle(NULL);
+ LPCTSTR class_name = "ui_window_class";
+ WNDCLASSEX wcex;
+
+ if (!::GetClassInfoEx(hinstance, class_name, &wcex)) {
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = &wnd_proc<WindowType>;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hinstance;
+ wcex.hIcon = (HICON)NULL;
+ wcex.hCursor = (HCURSOR)::LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
+ wcex.lpszMenuName = (LPCTSTR)NULL;
+ wcex.lpszClassName = class_name;
+ wcex.hIconSm = NULL;
+
+ if (RegisterClassEx(&wcex) == 0)
+ //throw std::exception("Cannot register win32 window class");
+ throw std::exception();
+ }
+ }
+
+ template<class WindowType>
+ static HWND create_window(WindowType* wnd, int width, int height) {
+ HINSTANCE hinstance = ::GetModuleHandle(NULL);
+ HWND hwnd = CreateWindowEx(WS_EX_CONTROLPARENT,
+ "ui_window_class", "",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ // CW_USEDEFAULT, CW_USEDEFAULT,
+ width, height,
+ (HWND)NULL,
+ (HMENU)NULL,
+ hinstance,
+ NULL);
+ if (hwnd != NULL) {
+ // Set the pointer in the user-data field of the window (TODO: use an ATOM)
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)wnd);
+ }
+ return hwnd;
+ }
+
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // win32_bitmap class
+
+ class win32_bitmap {
+ HBITMAP m_hbitmap;
+ HDC m_hdc;
+
+ public:
+
+ win32_bitmap(int width, int height) {
+ assert(width > 0 && height > 0);
+
+ BITMAPINFOHEADER bhdr;
+ bhdr.biSize = sizeof(BITMAPINFOHEADER);
+ bhdr.biWidth = width;
+ bhdr.biHeight = -height;
+ bhdr.biPlanes = 1;
+ bhdr.biBitCount = 32; // 32 bpp
+ bhdr.biCompression = BI_RGB;
+ bhdr.biSizeImage = 0;
+ bhdr.biXPelsPerMeter = 0;
+ bhdr.biYPelsPerMeter = 0;
+ bhdr.biClrUsed = 0;
+ bhdr.biClrImportant = 0;
+
+ BITMAPINFO binf;
+ RGBQUAD dummy = { 0, 0, 0, 0 };
+ binf.bmiColors[0] = dummy;
+ binf.bmiHeader = bhdr;
+
+ char* bits = NULL;
+
+ HDC hdc = GetDC(GetDesktopWindow());
+ m_hbitmap = CreateDIBSection(hdc, &binf, DIB_RGB_COLORS,
+ reinterpret_cast<void**>(&bits),
+ NULL, 0);
+
+ if (m_hbitmap == NULL)
+ throw std::exception(); // TODO throw ui_exception
+
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_hbitmap);
+
+ // Clear the whole bitmap with a white background
+ {
+ HGDIOBJ oldPen = SelectObject(m_hdc, ::CreatePen(PS_NULL, 0, 0));
+ HGDIOBJ oldBrush = SelectObject(m_hdc, ::CreateSolidBrush(RGB(255, 255, 255)));
+
+ Rectangle(m_hdc, 0, 0, width, height);
+
+ DeleteObject(SelectObject(m_hdc, oldPen));
+ DeleteObject(SelectObject(m_hdc, oldBrush));
+ }
+ }
+
+ ~win32_bitmap() {
+ ::DeleteDC(m_hdc);
+ ::DeleteObject(m_hbitmap);
+ }
+
+ HBITMAP hbitmap() {
+ return m_hbitmap;
+ }
+
+ HDC hdc() {
+ return m_hdc;
+ }
+
+ };
+
+ //////////////////////////////////////////////////////////////////////
+ // win32_window class
+
+ class win32_window {
+ HWND m_handle;
+ mt::thread* m_thread;
+ bool m_destroy;
+ bool m_keypressed;
+ bool m_closed;
+ win32_bitmap m_bitmap;
+ int m_textx, m_texty;
+
+ struct create_window_wrapper {
+ win32_window* m_wnd;
+ int m_width;
+ int m_height;
+
+ create_window_wrapper(win32_window* wnd, int width, int height)
+ : m_wnd(wnd)
+ , m_width(width)
+ , m_height(height) {
+ }
+
+ void operator()() {
+ m_wnd->m_handle = win32_details::create_window(m_wnd, m_width, m_height);
+
+ MSG msg;
+
+
+ ::ShowWindow(m_wnd->m_handle, SW_SHOWNORMAL);
+ ::UpdateWindow(m_wnd->m_handle);
+
+ // Message loop while:
+ // 1) the window is not destroyed
+ // 2) the window is visible
+ // 3) the Windows message queue is still alive
+ while (!m_wnd->m_destroy &&
+ ::IsWindowVisible(m_wnd->m_handle) &&
+ ::GetMessage(&msg, m_wnd->m_handle, 0, 0)) {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+
+ // Destroy the window
+ ::DestroyWindow(m_wnd->m_handle);
+ m_wnd->m_handle = NULL;
+ }
+
+ };
+
+ friend struct create_window_wrapper;
+ friend class win32_details;
+
+ public:
+
+ win32_window(int width, int height)
+ : m_bitmap(width, height)
+ , m_textx(0)
+ , m_texty(0) {
+ win32_details::register_window_class<win32_window>();
+
+ m_destroy = false;
+ m_keypressed = false;
+ m_closed = false;
+ m_thread = new mt::thread(create_window_wrapper(this, width, height));
+
+ // TODO wait m_handle != NULL (use a notification, avoid 100% CPU wait)
+ while (m_handle == NULL)
+ ;
+ }
+
+ ~win32_window() {
+ if (m_thread) {
+ m_destroy = true;
+ m_thread->join();
+ delete m_thread;
+ }
+ }
+
+ void waitkey() {
+ // // do something
+ while (!m_keypressed && !m_closed) // TODO avoid 100% CPU wait
+ // wait_message();
+ ;
+ m_keypressed = false;
+ }
+
+ size_t width() {
+ RECT rc;
+ ::GetWindowRect(m_handle, &rc);
+ return rc.right - rc.left;
+ }
+
+ size_t height() {
+ RECT rc;
+ ::GetWindowRect(m_handle, &rc);
+ return rc.bottom - rc.top;
+ }
+
+ void write(const std::string& text) {
+ HDC hdc = m_bitmap.hdc();
+
+ // Draw the text in the bitmap
+ TextOut(hdc, m_textx, m_texty, text.c_str(), static_cast<int>(text.size()));
+
+ // Calculate the size of the string
+ RECT rc = { 0, 0, 32000, 0 };
+ DrawText(hdc, text.c_str(), static_cast<int>(text.size()), &rc, DT_CALCRECT);
+
+ m_textx += (rc.right - rc.left); // X = X + Text Width
+ if (m_textx > width()) {
+ m_texty += (rc.bottom - rc.top);
+ m_textx = 0;
+ }
+
+ ::InvalidateRect(m_handle, NULL, FALSE);
+ }
+
+ private:
+
+ // This function is used to process
+ bool process_message(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT& result)
+ {
+ switch (msg) {
+
+ case WM_KEYDOWN:
+ m_keypressed = true;
+ break;
+
+ case WM_CLOSE:
+ m_closed = true;
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC window_hdc = ::BeginPaint(m_handle, &ps);
+ HDC bitmap_hdc = m_bitmap.hdc();
+
+ if (!::IsRectEmpty(&ps.rcPaint)) {
+ BitBlt(window_hdc,
+ ps.rcPaint.left, ps.rcPaint.top, // X, Y (dst)
+ ps.rcPaint.right - ps.rcPaint.left, // Width
+ ps.rcPaint.bottom - ps.rcPaint.top, // Height
+ bitmap_hdc,
+ ps.rcPaint.left, ps.rcPaint.top, // X, Y (src)
+ SRCCOPY);
+ }
+
+ ::EndPaint(m_handle, &ps);
+
+ result = TRUE;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ };
+
+ } // namespace win32
+
+ typedef win32::win32_window window_impl;
+
+} // namespace ui
+
+#define ui_main() \
+ WINAPI WinMain(HINSTANCE hInstance, \
+ HINSTANCE hPrevInstance, \
+ LPSTR lpCmdLine, \
+ int nCmdShow) \
+
+#endif // UI_WIN32_HEADER_FILE_INCLUDED