Then I wanted multiple windows and thread safety. So instead of opting for something massive like Qt, GTK, or wx, I just ported what was familiar.

Oh, and it's thread safe!
Code: Select all
#include <string>
#include <map>
#include <deque>
#include <ctime>
#include <windows.h>
LONG globPgdkWndLock = 0;
std::map<DWORD, std::deque<UINT> > globPgdkWndMap;
LRESULT _pgdk_Window_DefWndCallback(HWND hWnd, UINT uMsg, WPARAM wParam,
   LPARAM lParam)
{
   switch (uMsg) {
      // Do not evaluate null messages
      case WM_NULL:
      break;
      // Priory messages
      case WM_CLOSE:
      case WM_DESTROY:
         globPgdkWndMap[GetCurrentThreadId()].push_front(uMsg);
      break;
      default:
         globPgdkWndMap[GetCurrentThreadId()].push_back(uMsg);
      break;
   }
   
   switch (uMsg) {
      case WM_CLOSE:
         return 1;
   }
   
   return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
UINT windowEvent() {
  typedef HANDLE (WINAPI *(pOpenThread))(DWORD,BOOL,DWORD);
  UINT result = WM_NULL;
  MSG msg;
  DWORD threadID = 0;
  DWORD currentThreadID = GetCurrentThreadId();
  HANDLE hThread = 0;
  HMODULE hLib = 0;
  pOpenThread ptr = 0;
  DWORD exitCode = 0;
  
   do {
      Sleep(1);
   } while (InterlockedCompareExchange(&globPgdkWndLock, 1, 0) == 0);
   
   // Purge any thread deques which no longer exist
   for (std::map<DWORD, std::deque<UINT> >::const_iterator iter =
      globPgdkWndMap.begin(); iter != globPgdkWndMap.end(); iter++)
   {
      threadID = iter->first;
      
      if (!ptr) {
         hLib = GetModuleHandle("kernel32.dll");
         ptr = (pOpenThread)GetProcAddress(hLib, "OpenThread");
      }
      
      // Win2k and up
      if (ptr)
         hThread = ptr(THREAD_QUERY_INFORMATION, 0, currentThreadID);
      
      GetExitCodeThread(hThread, &exitCode);
      
      if (exitCode != STILL_ACTIVE) {
         globPgdkWndMap.erase(threadID);
         
         if (hThread)
            CloseHandle(hThread);
      }
   }
   
   if (!globPgdkWndMap[currentThreadID].empty()) {
      result = globPgdkWndMap[currentThreadID].front();
      globPgdkWndMap[currentThreadID].pop_front();
   }
  
   if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
  
  InterlockedCompareExchange(&globPgdkWndLock, 0, 1);
  
  return result;
}
UINT waitWindowEvent(int delay) {
   int elapsedStart;
   UINT event;
   
   elapsedStart = time(0);
   do {
      event = windowEvent();
      Sleep(delay);
   }
   while (!event && time(0) - elapsedStart < delay);
   
   return event;
}
HWND openWindow(int x, int y, int width, int height, std::string title,
   int style = WS_OVERLAPPED | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU |
      WS_CLIPCHILDREN | WS_VISIBLE, bool centered = false)
{
   WNDCLASS Wnd;
   RECT rect;
   HWND hWnd;
   HINSTANCE hInstance = GetModuleHandle(0);
   const char* className = "wndclass";
   
   Wnd.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
   Wnd.lpfnWndProc = (WNDPROC)_pgdk_Window_DefWndCallback;
   Wnd.cbClsExtra = 0;
   Wnd.cbWndExtra = 0;
   Wnd.hInstance = hInstance;
   Wnd.hIcon = LoadIcon(NULL, IDI_WINLOGO);
   Wnd.hCursor = LoadCursor(NULL, IDC_ARROW); 
   Wnd.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
   Wnd.lpszMenuName = 0;
   Wnd.lpszClassName = className;
   
   RegisterClass(&Wnd);
   
   SetRect(&rect, 0, 0, width, height);
   AdjustWindowRectEx(&rect, style, 0, WS_EX_WINDOWEDGE);
   
   if (centered) {
      x = GetSystemMetrics(SM_CXSCREEN)/2 - (rect.right - rect.left)/2;
      y = GetSystemMetrics(SM_CYSCREEN)/2 - (rect.bottom - rect.top)/2;
   }
   
   hWnd = CreateWindowEx(WS_EX_WINDOWEDGE, className, title.c_str(), style, x,
      y, rect.right - rect.left, rect.bottom - rect.top, 0, 0, hInstance, 0);
   
   if (!hWnd)
      return 0;
   
   // Paint window
   UpdateWindow(hWnd);
   return hWnd;
}




