// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)

////////////////////////////////
//~ rjf: Modern Windows SDK Functions
//
// (We must dynamically link to them, since they can be missing in older SDKs)

typedef BOOL w32_SetProcessDpiAwarenessContext_Type(void* value);
typedef UINT w32_GetDpiForWindow_Type(HWND hwnd);
#define w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4)
global w32_GetDpiForWindow_Type *w32_GetDpiForWindow_func = 0;

////////////////////////////////
//~ rjf: Basic Helpers

internal Rng2F32
os_w32_rng2f32_from_rect(RECT rect)
{
  Rng2F32 r = {0};
  r.x0 = (F32)rect.left;
  r.x1 = (F32)rect.right;
  r.y0 = (F32)rect.top;
  r.y1 = (F32)rect.bottom;
  return r;
}

////////////////////////////////
//~ rjf: Windows

internal OS_Handle
os_w32_handle_from_window(OS_W32_Window *window)
{
  OS_Handle handle = {(U64)window};
  return handle;
}

internal OS_W32_Window *
os_w32_window_from_handle(OS_Handle handle)
{
  OS_W32_Window *window = (OS_W32_Window *)handle.u64[0];
  return window;
}

internal OS_W32_Window *
os_w32_window_from_hwnd(HWND hwnd)
{
  OS_W32_Window *result = 0;
  for(OS_W32_Window *w = os_w32_gfx_state->first_window; w; w = w->next)
  {
    if(w->hwnd == hwnd)
    {
      result = w;
      break;
    }
  }
  return result;
}

internal HWND
os_w32_hwnd_from_window(OS_W32_Window *window)
{
  return window->hwnd;
}

internal OS_W32_Window *
os_w32_window_alloc(void)
{
  OS_W32_Window *result = os_w32_gfx_state->free_window;
  if(result)
  {
    SLLStackPop(os_w32_gfx_state->free_window);
  }
  else
  {
    result = push_array_no_zero(os_w32_gfx_state->arena, OS_W32_Window, 1);
  }
  MemoryZeroStruct(result);
  if(result)
  {
    DLLPushBack(os_w32_gfx_state->first_window, os_w32_gfx_state->last_window, result);
  }
  result->last_window_placement.length = sizeof(WINDOWPLACEMENT);
  return result;
}

internal void
os_w32_window_release(OS_W32_Window *window)
{
  if(window->paint_arena != 0)
  {
    arena_release(window->paint_arena);
  }
  DestroyWindow(window->hwnd);
  DLLRemove(os_w32_gfx_state->first_window, os_w32_gfx_state->last_window, window);
  SLLStackPush(os_w32_gfx_state->free_window, window);
}

internal OS_Event *
os_w32_push_event(OS_EventKind kind, OS_W32_Window *window)
{
  OS_Event *result = os_event_list_push_new(os_w32_event_arena, &os_w32_event_list, kind);
  result->window = os_w32_handle_from_window(window);
  result->flags = os_get_event_flags();
  return result;
}

internal OS_Key
os_w32_os_key_from_vkey(WPARAM vkey)
{
  local_persist B32 first = 1;
  local_persist OS_Key key_table[256];
  if (first){
    first = 0;
    MemoryZeroArray(key_table);
    
    key_table[(unsigned int)'A'] = OS_Key_A;
    key_table[(unsigned int)'B'] = OS_Key_B;
    key_table[(unsigned int)'C'] = OS_Key_C;
    key_table[(unsigned int)'D'] = OS_Key_D;
    key_table[(unsigned int)'E'] = OS_Key_E;
    key_table[(unsigned int)'F'] = OS_Key_F;
    key_table[(unsigned int)'G'] = OS_Key_G;
    key_table[(unsigned int)'H'] = OS_Key_H;
    key_table[(unsigned int)'I'] = OS_Key_I;
    key_table[(unsigned int)'J'] = OS_Key_J;
    key_table[(unsigned int)'K'] = OS_Key_K;
    key_table[(unsigned int)'L'] = OS_Key_L;
    key_table[(unsigned int)'M'] = OS_Key_M;
    key_table[(unsigned int)'N'] = OS_Key_N;
    key_table[(unsigned int)'O'] = OS_Key_O;
    key_table[(unsigned int)'P'] = OS_Key_P;
    key_table[(unsigned int)'Q'] = OS_Key_Q;
    key_table[(unsigned int)'R'] = OS_Key_R;
    key_table[(unsigned int)'S'] = OS_Key_S;
    key_table[(unsigned int)'T'] = OS_Key_T;
    key_table[(unsigned int)'U'] = OS_Key_U;
    key_table[(unsigned int)'V'] = OS_Key_V;
    key_table[(unsigned int)'W'] = OS_Key_W;
    key_table[(unsigned int)'X'] = OS_Key_X;
    key_table[(unsigned int)'Y'] = OS_Key_Y;
    key_table[(unsigned int)'Z'] = OS_Key_Z;
    
    for (U64 i = '0', j = OS_Key_0; i <= '9'; i += 1, j += 1){
      key_table[i] = (OS_Key)j;
    }
    for (U64 i = VK_NUMPAD0, j = OS_Key_0; i <= VK_NUMPAD9; i += 1, j += 1){
      key_table[i] = (OS_Key)j;
    }
    for (U64 i = VK_F1, j = OS_Key_F1; i <= VK_F24; i += 1, j += 1){
      key_table[i] = (OS_Key)j;
    }
    
    key_table[VK_SPACE]     = OS_Key_Space;
    key_table[VK_OEM_3]     = OS_Key_Tick;
    key_table[VK_OEM_MINUS] = OS_Key_Minus;
    key_table[VK_OEM_PLUS]  = OS_Key_Equal;
    key_table[VK_OEM_4]     = OS_Key_LeftBracket;
    key_table[VK_OEM_6]     = OS_Key_RightBracket;
    key_table[VK_OEM_1]     = OS_Key_Semicolon;
    key_table[VK_OEM_7]     = OS_Key_Quote;
    key_table[VK_OEM_COMMA] = OS_Key_Comma;
    key_table[VK_OEM_PERIOD]= OS_Key_Period;
    key_table[VK_OEM_2]     = OS_Key_Slash;
    key_table[VK_OEM_5]     = OS_Key_BackSlash;
    
    key_table[VK_TAB]       = OS_Key_Tab;
    key_table[VK_PAUSE]     = OS_Key_Pause;
    key_table[VK_ESCAPE]    = OS_Key_Esc;
    
    key_table[VK_UP]        = OS_Key_Up;
    key_table[VK_LEFT]      = OS_Key_Left;
    key_table[VK_DOWN]      = OS_Key_Down;
    key_table[VK_RIGHT]     = OS_Key_Right;
    
    key_table[VK_BACK]      = OS_Key_Backspace;
    key_table[VK_RETURN]    = OS_Key_Return;
    
    key_table[VK_DELETE]    = OS_Key_Delete;
    key_table[VK_INSERT]    = OS_Key_Insert;
    key_table[VK_PRIOR]     = OS_Key_PageUp;
    key_table[VK_NEXT]      = OS_Key_PageDown;
    key_table[VK_HOME]      = OS_Key_Home;
    key_table[VK_END]       = OS_Key_End;
    
    key_table[VK_CAPITAL]   = OS_Key_CapsLock;
    key_table[VK_NUMLOCK]   = OS_Key_NumLock;
    key_table[VK_SCROLL]    = OS_Key_ScrollLock;
    key_table[VK_APPS]      = OS_Key_Menu;
    
    key_table[VK_CONTROL]   = OS_Key_Ctrl;
    key_table[VK_LCONTROL]  = OS_Key_Ctrl;
    key_table[VK_RCONTROL]  = OS_Key_Ctrl;
    key_table[VK_SHIFT]     = OS_Key_Shift;
    key_table[VK_LSHIFT]    = OS_Key_Shift;
    key_table[VK_RSHIFT]    = OS_Key_Shift;
    key_table[VK_MENU]      = OS_Key_Alt;
    key_table[VK_LMENU]     = OS_Key_Alt;
    key_table[VK_RMENU]     = OS_Key_Alt;
    
    key_table[VK_DIVIDE]   = OS_Key_NumSlash;
    key_table[VK_MULTIPLY] = OS_Key_NumStar;
    key_table[VK_SUBTRACT] = OS_Key_NumMinus;
    key_table[VK_ADD]      = OS_Key_NumPlus;
    key_table[VK_DECIMAL]  = OS_Key_NumPeriod;
    
    for (U32 i = 0; i < 10; i += 1){
      key_table[VK_NUMPAD0 + i] = (OS_Key)((U64)OS_Key_Num0 + i);
    }
    
    for (U64 i = 0xDF, j = 0; i < 0xFF; i += 1, j += 1){
      key_table[i] = (OS_Key)((U64)OS_Key_Ex0 + j);
    }
  }
  
  OS_Key key = key_table[vkey&bitmask8];
  return key;
}

internal WPARAM
os_w32_vkey_from_os_key(OS_Key key)
{
  WPARAM result = 0;
  {
    local_persist B32 initialized = 0;
    local_persist WPARAM vkey_table[OS_Key_COUNT] = {0};
    if(initialized == 0)
    {
      initialized = 1;
      vkey_table[OS_Key_Esc] = VK_ESCAPE;
      for(OS_Key key = OS_Key_F1; key <= OS_Key_F24; key = (OS_Key)(key+1))
      {
        vkey_table[key] = VK_F1+(key-OS_Key_F1);
      }
      vkey_table[OS_Key_Tick] = VK_OEM_3;
      for(OS_Key key = OS_Key_0; key <= OS_Key_9; key = (OS_Key)(key+1))
      {
        vkey_table[key] = '0'+(key-OS_Key_0);
      }
      vkey_table[OS_Key_Minus] = VK_OEM_MINUS;
      vkey_table[OS_Key_Equal] = VK_OEM_PLUS;
      vkey_table[OS_Key_Backspace] = VK_BACK;
      vkey_table[OS_Key_Tab] = VK_TAB;
      vkey_table[OS_Key_Q] = 'Q';
      vkey_table[OS_Key_W] = 'W';
      vkey_table[OS_Key_E] = 'E';
      vkey_table[OS_Key_R] = 'R';
      vkey_table[OS_Key_T] = 'T';
      vkey_table[OS_Key_Y] = 'Y';
      vkey_table[OS_Key_U] = 'U';
      vkey_table[OS_Key_I] = 'I';
      vkey_table[OS_Key_O] = 'O';
      vkey_table[OS_Key_P] = 'P';
      vkey_table[OS_Key_LeftBracket] = VK_OEM_4;
      vkey_table[OS_Key_RightBracket] = VK_OEM_6;
      vkey_table[OS_Key_BackSlash] = VK_OEM_5;
      vkey_table[OS_Key_CapsLock] = VK_CAPITAL;
      vkey_table[OS_Key_A] = 'A';
      vkey_table[OS_Key_S] = 'S';
      vkey_table[OS_Key_D] = 'D';
      vkey_table[OS_Key_F] = 'F';
      vkey_table[OS_Key_G] = 'G';
      vkey_table[OS_Key_H] = 'H';
      vkey_table[OS_Key_J] = 'J';
      vkey_table[OS_Key_K] = 'K';
      vkey_table[OS_Key_L] = 'L';
      vkey_table[OS_Key_Semicolon] = VK_OEM_1;
      vkey_table[OS_Key_Quote] = VK_OEM_7;
      vkey_table[OS_Key_Return] = VK_RETURN;
      vkey_table[OS_Key_Shift] = VK_SHIFT;
      vkey_table[OS_Key_Z] = 'Z';
      vkey_table[OS_Key_X] = 'X';
      vkey_table[OS_Key_C] = 'C';
      vkey_table[OS_Key_V] = 'V';
      vkey_table[OS_Key_B] = 'B';
      vkey_table[OS_Key_N] = 'N';
      vkey_table[OS_Key_M] = 'M';
      vkey_table[OS_Key_Comma] = VK_OEM_COMMA;
      vkey_table[OS_Key_Period] = VK_OEM_PERIOD;
      vkey_table[OS_Key_Slash] = VK_OEM_2;
      vkey_table[OS_Key_Ctrl] = VK_CONTROL;
      vkey_table[OS_Key_Alt] = VK_MENU;
      vkey_table[OS_Key_Space] = VK_SPACE;
      vkey_table[OS_Key_Menu] = VK_APPS;
      vkey_table[OS_Key_ScrollLock] = VK_SCROLL;
      vkey_table[OS_Key_Pause] = VK_PAUSE;
      vkey_table[OS_Key_Insert] = VK_INSERT;
      vkey_table[OS_Key_Home] = VK_HOME;
      vkey_table[OS_Key_PageUp] = VK_PRIOR;
      vkey_table[OS_Key_Delete] = VK_DELETE;
      vkey_table[OS_Key_End] = VK_END;
      vkey_table[OS_Key_PageDown] = VK_NEXT;
      vkey_table[OS_Key_Up] = VK_UP;
      vkey_table[OS_Key_Left] = VK_LEFT;
      vkey_table[OS_Key_Down] = VK_DOWN;
      vkey_table[OS_Key_Right] = VK_RIGHT;
      for(OS_Key key = OS_Key_Ex0; key <= OS_Key_Ex29; key = (OS_Key)(key+1))
      {
        vkey_table[key] = 0xDF + (key-OS_Key_Ex0);
      }
      vkey_table[OS_Key_NumLock] = VK_NUMLOCK;
      vkey_table[OS_Key_NumSlash] = VK_DIVIDE;
      vkey_table[OS_Key_NumStar] = VK_MULTIPLY;
      vkey_table[OS_Key_NumMinus] = VK_SUBTRACT;
      vkey_table[OS_Key_NumPlus] = VK_ADD;
      vkey_table[OS_Key_NumPeriod] = VK_DECIMAL;
      vkey_table[OS_Key_Num0] = VK_NUMPAD0;
      vkey_table[OS_Key_Num1] = VK_NUMPAD1;
      vkey_table[OS_Key_Num2] = VK_NUMPAD2;
      vkey_table[OS_Key_Num3] = VK_NUMPAD3;
      vkey_table[OS_Key_Num4] = VK_NUMPAD4;
      vkey_table[OS_Key_Num5] = VK_NUMPAD5;
      vkey_table[OS_Key_Num6] = VK_NUMPAD6;
      vkey_table[OS_Key_Num7] = VK_NUMPAD7;
      vkey_table[OS_Key_Num8] = VK_NUMPAD8;
      vkey_table[OS_Key_Num9] = VK_NUMPAD9;
    }
    result = vkey_table[key];
  }
  return result;
}

internal LRESULT
os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  ProfBeginFunction();
  LRESULT result = 0;
  B32 good = 1;
  if(os_w32_event_arena == 0)
  {
    result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
    good = 0;
  }
  if(good)
  {
    OS_W32_Window *window = os_w32_window_from_hwnd(hwnd);
    OS_Handle window_handle = os_w32_handle_from_window(window);
    B32 release = 0;
    
    switch(uMsg)
    {
      default:
      {
        result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
      }break;
      
      case WM_ENTERSIZEMOVE:
      {
        os_w32_resizing = 1;
      }break;
      
      case WM_EXITSIZEMOVE:
      {
        os_w32_resizing = 0;
      }break;
      
      case WM_SIZE:
      case WM_PAINT:
      {
        if(window->repaint != 0)
        {
          PAINTSTRUCT ps = {0};
          BeginPaint(hwnd, &ps);
          window->repaint(os_w32_handle_from_window(window), window->repaint_user_data);
          EndPaint(hwnd, &ps);
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      }break;
      
      case WM_CLOSE:
      {
        os_w32_push_event(OS_EventKind_WindowClose, window);
      }break;
      
      case WM_LBUTTONUP:
      case WM_MBUTTONUP:
      case WM_RBUTTONUP:
      {
        release = 1;
      } // fallthrough;
      case WM_LBUTTONDOWN:
      case WM_MBUTTONDOWN:
      case WM_RBUTTONDOWN:
      {
        OS_Event *event = os_w32_push_event(release ? OS_EventKind_Release : OS_EventKind_Press, window);
        switch (uMsg)
        {
          case WM_LBUTTONUP: case WM_LBUTTONDOWN:
          {
            event->key = OS_Key_LeftMouseButton;
          }break;
          case WM_MBUTTONUP: case WM_MBUTTONDOWN:
          {
            event->key = OS_Key_MiddleMouseButton;
          }break;
          case WM_RBUTTONUP: case WM_RBUTTONDOWN:
          {
            event->key = OS_Key_RightMouseButton;
          }break;
        }
        event->pos.x = (F32)(S16)LOWORD(lParam);
        event->pos.y = (F32)(S16)HIWORD(lParam);
        if(release)
        {
          ReleaseCapture();
        }
        else
        {
          SetCapture(hwnd);
        }
      }break;
      
      case WM_MOUSEMOVE:
      {
        OS_Event *event = os_w32_push_event(OS_EventKind_MouseMove, window);
        event->pos.x = (F32)(S16)LOWORD(lParam);
        event->pos.y = (F32)(S16)HIWORD(lParam);
      }break;
      
      case WM_MOUSEWHEEL:
      {
        S16 wheel_delta = HIWORD(wParam);
        OS_Event *event = os_w32_push_event(OS_EventKind_Scroll, window);
        POINT p;
        p.x = (S32)(S16)LOWORD(lParam);
        p.y = (S32)(S16)HIWORD(lParam);
        ScreenToClient(window->hwnd, &p);
        event->pos.x = (F32)p.x;
        event->pos.y = (F32)p.y;
        event->delta = v2f32(0.f, -(F32)wheel_delta);
      }break;
      
      case WM_MOUSEHWHEEL:
      {
        S16 wheel_delta = HIWORD(wParam);
        OS_Event *event = os_w32_push_event(OS_EventKind_Scroll, window);
        POINT p;
        p.x = (S32)(S16)LOWORD(lParam);
        p.y = (S32)(S16)HIWORD(lParam);
        ScreenToClient(window->hwnd, &p);
        event->pos.x = (F32)p.x;
        event->pos.y = (F32)p.y;
        event->delta = v2f32((F32)wheel_delta, 0.f);
      }break;
      
      case WM_SYSKEYDOWN: case WM_SYSKEYUP:
      {
        if(wParam != VK_MENU && (wParam < VK_F1 || VK_F24 < wParam || wParam == VK_F4))
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      } // fallthrough;
      case WM_KEYDOWN: case WM_KEYUP:
      {
        B32 was_down = (lParam & bit31);
        B32 is_down  = !(lParam & bit32);
        
        B32 is_repeat = 0;
        if(!is_down)
        {
          release = 1;
        }
        else if(was_down)
        {
          is_repeat = 1;
        }
        
        B32 right_sided = 0;
        if ((lParam & bit25) &&
            (wParam == VK_CONTROL || wParam == VK_RCONTROL ||
             wParam == VK_MENU || wParam == VK_RMENU ||
             wParam == VK_SHIFT || wParam == VK_RSHIFT))
        {
          right_sided = 1;
        }
        
        OS_Event *event = os_w32_push_event(release ? OS_EventKind_Release : OS_EventKind_Press, window);
        event->key = os_w32_os_key_from_vkey(wParam);
        event->repeat_count = lParam & bitmask16;
        event->is_repeat = is_repeat;
        event->right_sided = right_sided;
        if(event->key == OS_Key_Alt   && event->flags & OS_EventFlag_Alt)   { event->flags &= ~OS_EventFlag_Alt; }
        if(event->key == OS_Key_Ctrl  && event->flags & OS_EventFlag_Ctrl)  { event->flags &= ~OS_EventFlag_Ctrl; }
        if(event->key == OS_Key_Shift && event->flags & OS_EventFlag_Shift) { event->flags &= ~OS_EventFlag_Shift; }
      }break;
      
      case WM_SYSCHAR:
      {
        result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
      }break;
      
      case WM_CHAR:
      {
        U32 character = wParam;
        if(character >= 32 && character != 127)
        {
          OS_Event *event = os_w32_push_event(OS_EventKind_Text, window);
          if(lParam & bit29)
          {
            event->flags |= OS_EventFlag_Alt;
          }
          event->character = character;
        }
      }break;
      
      case WM_KILLFOCUS:
      {
        os_w32_push_event(OS_EventKind_WindowLoseFocus, window);
        ReleaseCapture();
      }break;
      
      case WM_SETCURSOR:
      {
        Rng2F32 window_rect = os_client_rect_from_window(window_handle);
        Vec2F32 mouse = os_mouse_from_window(window_handle);
        B32 on_border = 0;
        DWORD window_style = window ? GetWindowLong(window->hwnd, GWL_STYLE) : 0;
        B32 is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
        if(window != 0 && window->custom_border && !is_fullscreen)
        {
          B32 on_border_x = (mouse.x <= window->custom_border_edge_thickness || window_rect.x1-window->custom_border_edge_thickness <= mouse.x);
          B32 on_border_y = (mouse.y <= window->custom_border_edge_thickness || window_rect.y1-window->custom_border_edge_thickness <= mouse.y);
          on_border = on_border_x || on_border_y;
        }
        if(!os_w32_resizing && !on_border && contains_2f32(window_rect, mouse))
        {
          SetCursor(os_w32_gfx_state->hCursor);
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      }break;
      
      case WM_DPICHANGED:
      {
        F32 new_dpi = (F32)(wParam & 0xffff);
        window->dpi = new_dpi;
      }break;
      
      //- rjf: [file drop]
      case WM_DROPFILES:
      {
        HDROP drop = (HDROP)wParam;
        POINT drop_pt = {0};
        DragQueryPoint(drop, &drop_pt);
        ScreenToClient(window->hwnd, &drop_pt);
        U64 num_files_dropped = DragQueryFile(drop, 0xffffffff, 0, 0);
        OS_Event *event = os_w32_push_event(OS_EventKind_FileDrop, window);
        event->pos = v2f32((F32)drop_pt.x, (F32)drop_pt.y);
        for(U64 idx = 0; idx < num_files_dropped; idx += 1)
        {
          U64 name_size = DragQueryFile(drop, idx, 0, 0) + 1;
          U8 *name_ptr = push_array(os_w32_event_arena, U8, name_size);
          DragQueryFile(drop, idx, name_ptr, name_size);
          str8_list_push(os_w32_event_arena, &event->strings, str8(name_ptr, name_size));
        }
        DragFinish(drop);
      }break;
      
      //- rjf: [custom border]
      case WM_NCPAINT:
      {
        if(window != 0 && window->custom_border && !window->custom_border_composition_enabled)
        {
          result = 0;
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      }break;
      case WM_DWMCOMPOSITIONCHANGED:
      {
        if(window != 0 && window->custom_border)
        {
          BOOL enabled = 0;
          DwmIsCompositionEnabled(&enabled);
          window->custom_border_composition_enabled = enabled;
          if(enabled)
          {
            MARGINS m = { 0, 0, 1, 0 };
            DwmExtendFrameIntoClientArea(hwnd, &m);
            DWORD dwmncrp_enabled = DWMNCRP_ENABLED;
            DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &enabled, sizeof(dwmncrp_enabled));
          }
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      }break;
      case WM_WINDOWPOSCHANGED:
      {
        result = 0;
      }break;
      case WM_NCUAHDRAWCAPTION:
      case WM_NCUAHDRAWFRAME:
      {
        // NOTE(rjf): undocumented messages for drawing themed window borders.
        if(window != 0 && window->custom_border)
        {
          result = 0;
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      }break;
      case WM_SETICON:
      case WM_SETTEXT:
      {
        if(window && window->custom_border && !window->custom_border_composition_enabled)
        {
          // NOTE(rjf):
          // https://blogs.msdn.microsoft.com/wpfsdk/2008/09/08/custom-window-chrome-in-wpf/
          LONG_PTR old_style = GetWindowLongPtrW(hwnd, GWL_STYLE);
          SetWindowLongPtrW(hwnd, GWL_STYLE, old_style & ~WS_VISIBLE);
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
          SetWindowLongPtrW(hwnd, GWL_STYLE, old_style);
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
      }break;
      
      //- rjf: [custom border] activation - without this `result`, stuff flickers.
      case WM_NCACTIVATE:
      {
        if(window == 0 || window->custom_border == 0)
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
        else
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, -1);
        }
      }break;
      
      //- rjf: [custom border] client/window size calculation
      case WM_NCCALCSIZE:
      if(window != 0)
      {
        if(window->custom_border == 0)
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
        else
        {
          MARGINS m = {0, 0, 0, 0};
          RECT *r = (RECT *)lParam;
          DWORD window_style = window ? GetWindowLong(window->hwnd, GWL_STYLE) : 0;
          B32 is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
          if(IsZoomed(hwnd) && !is_fullscreen)
          {
            int x_push_in = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
            int y_push_in = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
            r->left   += x_push_in;
            r->top    += y_push_in;
            r->bottom -= x_push_in;
            r->right  -= y_push_in;
            m.cxLeftWidth = m.cxRightWidth = x_push_in;
            m.cyTopHeight = m.cyBottomHeight = y_push_in;
          }
          DwmExtendFrameIntoClientArea(hwnd, &m);
        }
      }break;
      
      //- rjf: [custom border] client/window hit testing (mapping mouse -> action)
      case WM_NCHITTEST:
      {
        DWORD window_style = window ? GetWindowLong(window->hwnd, GWL_STYLE) : 0;
        B32 is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
        if(window == 0 || window->custom_border == 0 || is_fullscreen)
        {
          result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
        }
        else
        {
          POINT pos_monitor;
          pos_monitor.x = GET_X_LPARAM(lParam);
          pos_monitor.y = GET_Y_LPARAM(lParam);
          POINT pos_client = pos_monitor;
          ScreenToClient(hwnd, &pos_client);
          
          //- rjf: check against window boundaries
          RECT frame_rect;
          GetWindowRect(hwnd, &frame_rect);
          B32 is_over_window = (frame_rect.left <= pos_monitor.x && pos_monitor.x < frame_rect.right &&
                                frame_rect.top <= pos_monitor.y && pos_monitor.y < frame_rect.bottom);
          
          //- rjf: check against borders
          B32 is_over_left   = 0;
          B32 is_over_right  = 0;
          B32 is_over_top    = 0;
          B32 is_over_bottom = 0;
          {
            RECT rect;
            GetClientRect(hwnd, &rect);
            if(!IsZoomed(hwnd))
            {
              if(rect.left <= pos_client.x && pos_client.x < rect.left + window->custom_border_edge_thickness)
              {
                is_over_left = 1;
              }
              if(rect.right - window->custom_border_edge_thickness <= pos_client.x && pos_client.x < rect.right)
              {
                is_over_right = 1;
              }
              if(rect.bottom - window->custom_border_edge_thickness <= pos_client.y && pos_client.y < rect.bottom)
              {
                is_over_bottom = 1;
              }
              if(rect.top <= pos_client.y && pos_client.y < rect.top + window->custom_border_edge_thickness)
              {
                is_over_top = 1;
              }
            }
          }
          
          //- rjf: check against title bar
          B32 is_over_title_bar = 0;
          {
            RECT rect;
            GetClientRect(hwnd, &rect);
            is_over_title_bar = (rect.left <= pos_client.x && pos_client.x < rect.right &&
                                 rect.top <= pos_client.y && pos_client.y < rect.top + window->custom_border_title_thickness);
          }
          
          //- rjf: check against title bar client areas
          B32 is_over_title_bar_client_area = 0;
          for(OS_W32_TitleBarClientArea *area = window->first_title_bar_client_area;
              area != 0;
              area = area->next)
          {
            Rng2F32 rect = area->rect;
            if(rect.x0 <= pos_client.x && pos_client.x < rect.x1 &&
               rect.y0 <= pos_client.y && pos_client.y < rect.y1)
            {
              is_over_title_bar_client_area = 1;
              break;
            }
          }
          
          //- rjf: resolve hovering to result
          result = HTNOWHERE;
          if(is_over_window)
          {
            // rjf: default to client area
            result = HTCLIENT;
            
            // rjf: title bar
            if(is_over_title_bar)
            {
              result = HTCAPTION;
            }
            
            // rjf: normal edges
            if(is_over_left)   { result = HTLEFT; }
            if(is_over_right)  { result = HTRIGHT; }
            if(is_over_top)    { result = HTTOP; }
            if(is_over_bottom) { result = HTBOTTOM; }
            
            // rjf: corners
            if(is_over_left  && is_over_top)    { result = HTTOPLEFT; }
            if(is_over_left  && is_over_bottom) { result = HTBOTTOMLEFT; }
            if(is_over_right && is_over_top)    { result = HTTOPRIGHT; }
            if(is_over_right && is_over_bottom) { result = HTBOTTOMRIGHT; }
            
            // rjf: title bar client area
            if(is_over_title_bar_client_area)
            {
              result = HTCLIENT;
            }
          }
        }
      }break;
    }
  }
  ProfEnd();
  return result;
}

////////////////////////////////
//~ rjf: Monitors

internal BOOL
os_w32_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr)
{
  OS_W32_MonitorGatherBundle *bundle = (OS_W32_MonitorGatherBundle *)bundle_ptr;
  OS_Handle handle = {(U64)monitor};
  os_handle_list_push(bundle->arena, bundle->list, handle);
  return 1;
}

////////////////////////////////
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)

internal void
os_gfx_init(void)
{
  //- rjf: set up base shared state
  Arena *arena = arena_alloc();
  os_w32_gfx_state = push_array(arena, OS_W32_GfxState, 1);
  os_w32_gfx_state->arena = arena;
  os_w32_gfx_state->gfx_thread_tid = (U32)GetCurrentThreadId();
  os_w32_gfx_state->hInstance = GetModuleHandle(0);
  
  //- rjf: set dpi awareness
  w32_SetProcessDpiAwarenessContext_Type *SetProcessDpiAwarenessContext_func = 0;
  HMODULE module = LoadLibraryA("user32.dll");
  if(module != 0)
  {
    SetProcessDpiAwarenessContext_func =
    (w32_SetProcessDpiAwarenessContext_Type*)GetProcAddress(module, "SetProcessDpiAwarenessContext");
    w32_GetDpiForWindow_func =
    (w32_GetDpiForWindow_Type*)GetProcAddress(module, "GetDpiForWindow");
    FreeLibrary(module);
  }
  if(SetProcessDpiAwarenessContext_func != 0)
  {
    SetProcessDpiAwarenessContext_func(w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
  }
  
  //- rjf: register graphical-window class
  {
    WNDCLASSEXW wndclass = {sizeof(wndclass)};
    wndclass.lpfnWndProc = os_w32_wnd_proc;
    wndclass.hInstance = os_w32_gfx_state->hInstance;
    wndclass.lpszClassName = L"graphical-window";
    wndclass.hCursor = LoadCursorA(0, IDC_ARROW);
    wndclass.hIcon = LoadIcon(os_w32_gfx_state->hInstance, MAKEINTRESOURCE(1));
    wndclass.style = CS_VREDRAW|CS_HREDRAW;
    ATOM wndatom = RegisterClassExW(&wndclass);
    (void)wndatom;
  }
  
  //- rjf: grab graphics system info
  {
    os_w32_gfx_state->gfx_info.double_click_time = GetDoubleClickTime()/1000.f;
    os_w32_gfx_state->gfx_info.caret_blink_time = GetCaretBlinkTime()/1000.f;
    DEVMODEW devmodew = {0};
    if(EnumDisplaySettingsW(0, ENUM_CURRENT_SETTINGS, &devmodew))
    {
      os_w32_gfx_state->gfx_info.default_refresh_rate = (F32)devmodew.dmDisplayFrequency;
    }
  }
  
  //- rjf: set initial cursor
  os_set_cursor(OS_Cursor_Pointer);
  
  //- rjf: fill vkey -> OS_Key table
  {
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'A'] = OS_Key_A;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'B'] = OS_Key_B;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'C'] = OS_Key_C;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'D'] = OS_Key_D;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'E'] = OS_Key_E;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'F'] = OS_Key_F;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'G'] = OS_Key_G;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'H'] = OS_Key_H;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'I'] = OS_Key_I;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'J'] = OS_Key_J;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'K'] = OS_Key_K;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'L'] = OS_Key_L;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'M'] = OS_Key_M;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'N'] = OS_Key_N;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'O'] = OS_Key_O;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'P'] = OS_Key_P;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'Q'] = OS_Key_Q;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'R'] = OS_Key_R;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'S'] = OS_Key_S;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'T'] = OS_Key_T;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'U'] = OS_Key_U;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'V'] = OS_Key_V;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'W'] = OS_Key_W;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'X'] = OS_Key_X;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'Y'] = OS_Key_Y;
    os_w32_gfx_state->key_from_vkey_table[(unsigned int)'Z'] = OS_Key_Z;
    
    for(U64 i = '0', j = OS_Key_0; i <= '9'; i += 1, j += 1)
    {
      os_w32_gfx_state->key_from_vkey_table[i] = (OS_Key)j;
    }
    for(U64 i = VK_NUMPAD0, j = OS_Key_0; i <= VK_NUMPAD9; i += 1, j += 1)
    {
      os_w32_gfx_state->key_from_vkey_table[i] = (OS_Key)j;
    }
    for(U64 i = VK_F1, j = OS_Key_F1; i <= VK_F24; i += 1, j += 1)
    {
      os_w32_gfx_state->key_from_vkey_table[i] = (OS_Key)j;
    }
    
    os_w32_gfx_state->key_from_vkey_table[VK_SPACE]     = OS_Key_Space;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_3]     = OS_Key_Tick;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_MINUS] = OS_Key_Minus;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_PLUS]  = OS_Key_Equal;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_4]     = OS_Key_LeftBracket;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_6]     = OS_Key_RightBracket;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_1]     = OS_Key_Semicolon;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_7]     = OS_Key_Quote;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_COMMA] = OS_Key_Comma;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_PERIOD]= OS_Key_Period;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_2]     = OS_Key_Slash;
    os_w32_gfx_state->key_from_vkey_table[VK_OEM_5]     = OS_Key_BackSlash;
    
    os_w32_gfx_state->key_from_vkey_table[VK_TAB]       = OS_Key_Tab;
    os_w32_gfx_state->key_from_vkey_table[VK_PAUSE]     = OS_Key_Pause;
    os_w32_gfx_state->key_from_vkey_table[VK_ESCAPE]    = OS_Key_Esc;
    
    os_w32_gfx_state->key_from_vkey_table[VK_UP]        = OS_Key_Up;
    os_w32_gfx_state->key_from_vkey_table[VK_LEFT]      = OS_Key_Left;
    os_w32_gfx_state->key_from_vkey_table[VK_DOWN]      = OS_Key_Down;
    os_w32_gfx_state->key_from_vkey_table[VK_RIGHT]     = OS_Key_Right;
    
    os_w32_gfx_state->key_from_vkey_table[VK_BACK]      = OS_Key_Backspace;
    os_w32_gfx_state->key_from_vkey_table[VK_RETURN]    = OS_Key_Return;
    
    os_w32_gfx_state->key_from_vkey_table[VK_DELETE]    = OS_Key_Delete;
    os_w32_gfx_state->key_from_vkey_table[VK_INSERT]    = OS_Key_Insert;
    os_w32_gfx_state->key_from_vkey_table[VK_PRIOR]     = OS_Key_PageUp;
    os_w32_gfx_state->key_from_vkey_table[VK_NEXT]      = OS_Key_PageDown;
    os_w32_gfx_state->key_from_vkey_table[VK_HOME]      = OS_Key_Home;
    os_w32_gfx_state->key_from_vkey_table[VK_END]       = OS_Key_End;
    
    os_w32_gfx_state->key_from_vkey_table[VK_CAPITAL]   = OS_Key_CapsLock;
    os_w32_gfx_state->key_from_vkey_table[VK_NUMLOCK]   = OS_Key_NumLock;
    os_w32_gfx_state->key_from_vkey_table[VK_SCROLL]    = OS_Key_ScrollLock;
    os_w32_gfx_state->key_from_vkey_table[VK_APPS]      = OS_Key_Menu;
    
    os_w32_gfx_state->key_from_vkey_table[VK_CONTROL]   = OS_Key_Ctrl;
    os_w32_gfx_state->key_from_vkey_table[VK_LCONTROL]  = OS_Key_Ctrl;
    os_w32_gfx_state->key_from_vkey_table[VK_RCONTROL]  = OS_Key_Ctrl;
    os_w32_gfx_state->key_from_vkey_table[VK_SHIFT]     = OS_Key_Shift;
    os_w32_gfx_state->key_from_vkey_table[VK_LSHIFT]    = OS_Key_Shift;
    os_w32_gfx_state->key_from_vkey_table[VK_RSHIFT]    = OS_Key_Shift;
    os_w32_gfx_state->key_from_vkey_table[VK_MENU]      = OS_Key_Alt;
    os_w32_gfx_state->key_from_vkey_table[VK_LMENU]     = OS_Key_Alt;
    os_w32_gfx_state->key_from_vkey_table[VK_RMENU]     = OS_Key_Alt;
    
    os_w32_gfx_state->key_from_vkey_table[VK_DIVIDE]   = OS_Key_NumSlash;
    os_w32_gfx_state->key_from_vkey_table[VK_MULTIPLY] = OS_Key_NumStar;
    os_w32_gfx_state->key_from_vkey_table[VK_SUBTRACT] = OS_Key_NumMinus;
    os_w32_gfx_state->key_from_vkey_table[VK_ADD]      = OS_Key_NumPlus;
    os_w32_gfx_state->key_from_vkey_table[VK_DECIMAL]  = OS_Key_NumPeriod;
    
    for(U32 i = 0; i < 10; i += 1)
    {
      os_w32_gfx_state->key_from_vkey_table[VK_NUMPAD0 + i] = (OS_Key)((U64)OS_Key_Num0 + i);
    }
    
    for(U64 i = 0xDF, j = 0; i < 0xFF; i += 1, j += 1)
    {
      os_w32_gfx_state->key_from_vkey_table[i] = (OS_Key)((U64)OS_Key_Ex0 + j);
    }
  }
}

////////////////////////////////
//~ rjf: @os_hooks Graphics System Info (Implemented Per-OS)

internal OS_GfxInfo *
os_get_gfx_info(void)
{
  return &os_w32_gfx_state->gfx_info;
}

////////////////////////////////
//~ rjf: @os_hooks Clipboards (Implemented Per-OS)

internal void
os_set_clipboard_text(String8 string)
{
  if(OpenClipboard(0))
  {
    EmptyClipboard();
    HANDLE string_copy_handle = GlobalAlloc(GMEM_MOVEABLE, string.size+1);
    if(string_copy_handle)
    {
      U8 *copy_buffer = (U8 *)GlobalLock(string_copy_handle);
      MemoryCopy(copy_buffer, string.str, string.size);
      copy_buffer[string.size] = 0;
      GlobalUnlock(string_copy_handle);
      SetClipboardData(CF_TEXT, string_copy_handle);
    }
    CloseClipboard();
  }
}

internal String8
os_get_clipboard_text(Arena *arena)
{
  String8 result = {0};
  if(IsClipboardFormatAvailable(CF_TEXT) &&
     OpenClipboard(0))
  {
    HANDLE data_handle = GetClipboardData(CF_TEXT);
    if(data_handle)
    {
      U8 *buffer = (U8 *)GlobalLock(data_handle);
      if(buffer)
      {
        U64 size = cstring8_length(buffer);
        result = push_str8_copy(arena, str8(buffer, size));
        GlobalUnlock(data_handle);
      }
    }
    CloseClipboard();
  }
  return result;
}

////////////////////////////////
//~ rjf: @os_hooks Windows (Implemented Per-OS)

internal OS_Handle
os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title)
{
  //- rjf: make hwnd
  HWND hwnd = 0;
  {
    Temp scratch = scratch_begin(0, 0);
    String16 title16 = str16_from_8(scratch.arena, title);
    hwnd = CreateWindowExW(WS_EX_APPWINDOW,
                           L"graphical-window",
                           (WCHAR*)title16.str,
                           WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
                           CW_USEDEFAULT, CW_USEDEFAULT,
                           (int)resolution.x,
                           (int)resolution.y,
                           0, 0,
                           os_w32_gfx_state->hInstance,
                           0);
    DragAcceptFiles(hwnd, 1);
    scratch_end(scratch);
  }
  
  //- rjf- make/fill window
  OS_W32_Window *window = os_w32_window_alloc();
  {
    window->hwnd = hwnd;
    if (w32_GetDpiForWindow_func != 0){
      window->dpi = (F32)w32_GetDpiForWindow_func(hwnd);
    }
    else{
      window->dpi = 96.f;
    }
  }
  
  //- rjf: early detection of composition
  {
    BOOL enabled = 0;
    DwmIsCompositionEnabled(&enabled);
    window->custom_border_composition_enabled = enabled;
  }
  
  //- rjf: custom border
  if(flags & OS_WindowFlag_CustomBorder)
  {
    window->custom_border = 1;
    window->paint_arena = arena_alloc();
  }
  
  //- rjf: convert to handle + return
  OS_Handle result = os_w32_handle_from_window(window);
  return result;
}

internal void
os_window_close(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  os_w32_window_release(window);
}

internal void
os_window_first_paint(OS_Handle window_handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(window_handle);
  window->first_paint_done = 1;
  ShowWindow(window->hwnd, SW_SHOW);
  if(window->maximized)
  {
    ShowWindow(window->hwnd, SW_MAXIMIZE);
  }
}

internal void
os_window_equip_repaint(OS_Handle handle, OS_WindowRepaintFunctionType *repaint, void *user_data)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  window->repaint = repaint;
  window->repaint_user_data = user_data;
}

internal void
os_window_focus(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  SetForegroundWindow(window->hwnd);
  SetFocus(window->hwnd);
}

internal B32
os_window_is_focused(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  HWND active_hwnd = GetActiveWindow();
  return active_hwnd == window->hwnd;
}

internal B32
os_window_is_fullscreen(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  DWORD window_style = GetWindowLong(window->hwnd, GWL_STYLE);
  return !(window_style & WS_OVERLAPPEDWINDOW);
}

internal void
os_window_set_fullscreen(OS_Handle handle, B32 fullscreen)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  OS_WindowRepaintFunctionType *repaint = window->repaint;
  window->repaint = 0;
  DWORD window_style = GetWindowLong(window->hwnd, GWL_STYLE);
  B32 is_fullscreen_already = os_window_is_fullscreen(handle);
  if(fullscreen)
  {
    if(!is_fullscreen_already)
    {
      GetWindowPlacement(window->hwnd, &window->last_window_placement);
    }
    MONITORINFO monitor_info = {sizeof(monitor_info)};
    if(GetMonitorInfo(MonitorFromWindow(window->hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info))
    {
      SetWindowLong(window->hwnd, GWL_STYLE, window_style & ~WS_OVERLAPPEDWINDOW);
      SetWindowPos(window->hwnd, HWND_TOP,
                   monitor_info.rcMonitor.left,
                   monitor_info.rcMonitor.top,
                   monitor_info.rcMonitor.right - monitor_info.rcMonitor.left,
                   monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top,
                   SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }
  }
  else
  {
    SetWindowLong(window->hwnd, GWL_STYLE, window_style | WS_OVERLAPPEDWINDOW);
    SetWindowPlacement(window->hwnd, &window->last_window_placement);
    SetWindowPos(window->hwnd, 0, 0, 0, 0, 0,
                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
                 SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
  }
  window->repaint = repaint;
}

internal B32
os_window_is_maximized(OS_Handle handle)
{
  B32 result = 0;
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window)
  {
    result = !!(IsZoomed(window->hwnd));
  }
  return result;
}

internal void
os_window_set_maximized(OS_Handle handle, B32 maximized)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window != 0)
  {
    if(window->first_paint_done)
    {
      switch(maximized)
      {
        default:
        case 0:{ShowWindow(window->hwnd, SW_RESTORE);}break;
        case 1:{ShowWindow(window->hwnd, SW_MAXIMIZE);}break;
      }
    }
    else
    {
      window->maximized = maximized;
    }
  }
}

internal void
os_window_minimize(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window != 0)
  {
    ShowWindow(window->hwnd, SW_MINIMIZE);
  }
}

internal void
os_window_bring_to_front(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window != 0)
  {
    BringWindowToTop(window->hwnd);
  }
}

internal void
os_window_set_monitor(OS_Handle window_handle, OS_Handle monitor)
{
  OS_W32_Window *window = os_w32_window_from_handle(window_handle);
  HMONITOR hmonitor = (HMONITOR)monitor.u64[0];
  {
    MONITORINFOEXW info;
    info.cbSize = sizeof(MONITORINFOEXW);
    if(GetMonitorInfoW(hmonitor, (MONITORINFO *)&info))
    {
      Rng2F32 existing_rect = os_rect_from_window(window_handle);
      Vec2F32 window_size = dim_2f32(existing_rect);
      SetWindowPos(window->hwnd, HWND_TOP,
                   (info.rcWork.left + info.rcWork.right)/2 - window_size.x/2,
                   (info.rcWork.top + info.rcWork.bottom)/2 - window_size.y/2,
                   window_size.x,
                   window_size.y, 0);
    }
  }
}

internal void
os_window_clear_custom_border_data(OS_Handle handle)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window->custom_border)
  {
    arena_clear(window->paint_arena);
    window->first_title_bar_client_area = window->last_title_bar_client_area = 0;
    window->custom_border_title_thickness = 0;
    window->custom_border_edge_thickness = 0;
  }
}

internal void
os_window_push_custom_title_bar(OS_Handle handle, F32 thickness)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  window->custom_border_title_thickness = thickness;
}

internal void
os_window_push_custom_edges(OS_Handle handle, F32 thickness)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  window->custom_border_edge_thickness = thickness;
}

internal void
os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect)
{
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window->custom_border)
  {
    OS_W32_TitleBarClientArea *area = push_array(window->paint_arena, OS_W32_TitleBarClientArea, 1);
    if(area != 0)
    {
      area->rect = rect;
      SLLQueuePush(window->first_title_bar_client_area, window->last_title_bar_client_area, area);
    }
  }
}

internal Rng2F32
os_rect_from_window(OS_Handle handle)
{
  Rng2F32 r = {0};
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window)
  {
    RECT rect = {0};
    GetWindowRect(os_w32_hwnd_from_window(window), &rect);
    r = os_w32_rng2f32_from_rect(rect);
  }
  return r;
}

internal Rng2F32
os_client_rect_from_window(OS_Handle handle)
{
  Rng2F32 r = {0};
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window)
  {
    RECT rect = {0};
    GetClientRect(os_w32_hwnd_from_window(window), &rect);
    r = os_w32_rng2f32_from_rect(rect);
  }
  return r;
}

internal F32
os_dpi_from_window(OS_Handle handle)
{
  F32 result = 96.f;
  OS_W32_Window *window = os_w32_window_from_handle(handle);
  if(window != 0)
  {
    result = window->dpi;
  }
  return result;
}

////////////////////////////////
//~ rjf: @os_hooks Monitors (Implemented Per-OS)

internal OS_HandleArray
os_push_monitors_array(Arena *arena)
{
  Temp scratch = scratch_begin(&arena, 1);
  OS_HandleList list = {0};
  {
    OS_W32_MonitorGatherBundle bundle = {arena, &list};
    EnumDisplayMonitors(0, 0, os_w32_monitor_gather_enum_proc, (LPARAM)&bundle);
  }
  OS_HandleArray array = os_handle_array_from_list(arena, &list);
  scratch_end(scratch);
  return array;
}

internal OS_Handle
os_primary_monitor(void)
{
  POINT zero_pt = {0, 0};
  HMONITOR monitor = MonitorFromPoint(zero_pt, MONITOR_DEFAULTTOPRIMARY);
  OS_Handle result = {(U64)monitor};
  return result;
}

internal OS_Handle
os_monitor_from_window(OS_Handle window)
{
  OS_W32_Window *w = os_w32_window_from_handle(window);
  HMONITOR handle = MonitorFromWindow(w->hwnd, MONITOR_DEFAULTTOPRIMARY);
  OS_Handle result = {(U64)handle};
  return result;
}

internal String8
os_name_from_monitor(Arena *arena, OS_Handle monitor)
{
  String8 result = {0};
  HMONITOR monitor_handle = (HMONITOR)monitor.u64[0];
  MONITORINFOEXW info;
  info.cbSize = sizeof(MONITORINFOEXW);
  if(GetMonitorInfoW(monitor_handle, (MONITORINFO *)&info))
  {
    String16 result16 = str16_cstring((U16 *)info.szDevice);
    result = str8_from_16(arena, result16);
  }
  return result;
}

internal Vec2F32
os_dim_from_monitor(OS_Handle monitor)
{
  Vec2F32 result = {0};
  HMONITOR monitor_handle = (HMONITOR)monitor.u64[0];
  MONITORINFO info = {0};
  info.cbSize = sizeof(MONITORINFO);
  if(GetMonitorInfoW(monitor_handle, &info))
  {
    result.x = info.rcWork.right - info.rcWork.left;
    result.y = info.rcWork.bottom - info.rcWork.top;
  }
  return result;
}

////////////////////////////////
//~ rjf: @os_hooks Events (Implemented Per-OS)

internal void
os_send_wakeup_event(void)
{
  PostThreadMessageA(os_w32_gfx_state->gfx_thread_tid, 0x401, 0, 0);
}

internal OS_EventList
os_get_events(Arena *arena, B32 wait)
{
  os_w32_event_arena = arena;
  MemoryZeroStruct(&os_w32_event_list);
  MSG msg = {0};
  if(!wait || GetMessage(&msg, 0, 0, 0))
  {
    B32 first_wait = wait;
    for(;first_wait || PeekMessage(&msg, 0, 0, 0, PM_REMOVE); first_wait = 0)
    {
      DispatchMessage(&msg);
      TranslateMessage(&msg);
      if(msg.message == WM_QUIT)
      {
        os_w32_push_event(OS_EventKind_WindowClose, 0);
      }
    }
  }
  return os_w32_event_list;
}

internal OS_EventFlags
os_get_event_flags(void)
{
  OS_EventFlags flags = 0;
  if(GetKeyState(VK_CONTROL) & 0x8000)
  {
    flags |= OS_EventFlag_Ctrl;
  }
  if(GetKeyState(VK_SHIFT) & 0x8000)
  {
    flags |= OS_EventFlag_Shift;
  }
  if(GetKeyState(VK_MENU) & 0x8000)
  {
    flags |= OS_EventFlag_Alt;
  }
  return(flags);
}

internal Vec2F32
os_mouse_from_window(OS_Handle handle)
{
  ProfBeginFunction();
  Vec2F32 v = {0};
  POINT p;
  if(GetCursorPos(&p))
  {
    OS_W32_Window *window = os_w32_window_from_handle(handle);
    ScreenToClient(window->hwnd, &p);
    v.x = (F32)p.x;
    v.y = (F32)p.y;
  }
  ProfEnd();
  return v;
}

////////////////////////////////
//~ rjf: @os_hooks Cursors (Implemented Per-OS)

internal void
os_set_cursor(OS_Cursor cursor)
{
  B32 valid_cursor = 1;
  HCURSOR hcursor = 0;
  switch(cursor)
  {
    default: {valid_cursor = 0;}break;
#define Win32CursorXList(X) \
X(Pointer, IDC_ARROW) \
X(IBar, IDC_IBEAM) \
X(LeftRight, IDC_SIZEWE) \
X(UpDown, IDC_SIZENS) \
X(DownRight, IDC_SIZENWSE) \
X(UpRight, IDC_SIZENESW) \
X(UpDownLeftRight, IDC_SIZEALL) \
X(HandPoint, IDC_HAND)\
X(Disabled, IDC_NO)
#define CursorCase(E,R) case OS_Cursor_##E:{ \
local_persist HCURSOR curs = 0; \
if (curs == 0){ curs = LoadCursor(NULL, R); } \
hcursor = curs; }break;
    Win32CursorXList(CursorCase)
#undef CursorCase
#undef Win32CursorXList
  }
  if(valid_cursor && !os_w32_resizing)
  {
    if(hcursor != os_w32_gfx_state->hCursor)
    {
      PostMessage(0, WM_SETCURSOR, 0, 0);
      POINT p = {0};
      GetCursorPos(&p);
      SetCursorPos(p.x, p.y);
    }
    os_w32_gfx_state->hCursor = hcursor;
  }
}

////////////////////////////////
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)

internal void
os_graphical_message(B32 error, String8 title, String8 message)
{
  Temp scratch = scratch_begin(0, 0);
  String16 title16 = str16_from_8(scratch.arena, title);
  String16 message16 = str16_from_8(scratch.arena, message);
  MessageBoxW(0, (WCHAR *)message16.str, (WCHAR *)title16.str, MB_OK|(!!error*MB_ICONERROR));
  scratch_end(scratch);
}

////////////////////////////////
//~ rjf: @os_hooks Shell Operations

internal void
os_show_in_filesystem_ui(String8 path)
{
  Temp scratch = scratch_begin(0, 0);
  String8 path_copy = push_str8_copy(scratch.arena, path);
  for(U64 idx = 0; idx < path_copy.size; idx += 1)
  {
    if(path_copy.str[idx] == '/')
    {
      path_copy.str[idx] = '\\';
    }
  }
  String16 path16 = str16_from_8(scratch.arena, path_copy);
  SFGAOF flags = 0;
  PIDLIST_ABSOLUTE list = 0;
  if(path16.size != 0 && SUCCEEDED(SHParseDisplayName(path16.str, 0, &list, 0, &flags)))
  {
    HRESULT hr = SHOpenFolderAndSelectItems(list, 0, 0, 0);
    CoTaskMemFree(list);
    (void)hr;
  }
  scratch_end(scratch);
}
