aboutsummaryrefslogtreecommitdiff
path: root/src/win/native/ui_application.cpp
blob: c2d3ac2c67d5f8bb97e679c3f6667b9d37016168 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "cru/win/native/ui_application.hpp"

#include "../debug_logger.hpp"
#include "cru/common/logger.hpp"
#include "cru/win/graph/direct/graph_factory.hpp"
#include "cru/win/native/exception.hpp"
#include "cru/win/native/god_window.hpp"
#include "cru/win/native/native_window.hpp"
#include "god_window_message.hpp"
#include "timer.hpp"
#include "window_manager.hpp"

#include <VersionHelpers.h>
#include <cassert>

namespace cru::platform::native::win {
namespace {
WinUiApplication* instance = nullptr;
}
}  // namespace cru::platform::native::win

namespace cru::platform::native {
UiApplication* UiApplication::CreateInstance() {
  auto& i =
      ::cru::platform::native::win::instance;  // avoid long namespace prefix
  assert(i == nullptr);
  i = new win::WinUiApplication(::GetModuleHandleW(nullptr));
  return i;
}

UiApplication* UiApplication::GetInstance() {
  return ::cru::platform::native::win::instance;
}
}  // namespace cru::platform::native

namespace cru::platform::native::win {
WinUiApplication* WinUiApplication::GetInstance() { return instance; }

WinUiApplication::WinUiApplication(HINSTANCE h_instance)
    : h_instance_(h_instance) {
  assert(instance == nullptr);

  log::Logger::GetInstance()->AddSource(
      new ::cru::platform::win::WinDebugLoggerSource());

  if (!::IsWindows8OrGreater())
    throw std::runtime_error("Must run on Windows 8 or later.");

  const auto graph_factory = graph::GraphFactory::CreateInstance();
  graph_factory->SetAutoDelete(true);

  god_window_ = std::make_shared<GodWindow>(this);
  timer_manager_ = std::make_shared<TimerManager>(god_window_.get());
  window_manager_ = std::make_shared<WindowManager>(this);

  cursor_manager_.reset(new WinCursorManager());
}

WinUiApplication::~WinUiApplication() { instance = nullptr; }

int WinUiApplication::Run() {
  MSG msg;
  while (GetMessageW(&msg, nullptr, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
  }

  for (const auto& handler : quit_handlers_) handler();

  if (auto_delete_) delete this;

  return static_cast<int>(msg.wParam);
}

void WinUiApplication::Quit(const int quit_code) {
  ::PostQuitMessage(quit_code);
}

void WinUiApplication::AddOnQuitHandler(const std::function<void()>& handler) {
  quit_handlers_.push_back(handler);
}

void WinUiApplication::InvokeLater(const std::function<void()>& action) {
  // copy the action to a safe place
  auto p_action_copy = new std::function<void()>(action);

  if (PostMessageW(GetGodWindow()->GetHandle(), invoke_later_message_id,
                   reinterpret_cast<WPARAM>(p_action_copy), 0) == 0)
    throw Win32Error(::GetLastError(), "InvokeLater failed to post message.");
}

unsigned long WinUiApplication::SetTimeout(
    std::chrono::milliseconds milliseconds,
    const std::function<void()>& action) {
  return static_cast<unsigned long>(timer_manager_->CreateTimer(
      static_cast<UINT>(milliseconds.count()), false, action));
}

unsigned long WinUiApplication::SetInterval(
    std::chrono::milliseconds milliseconds,
    const std::function<void()>& action) {
  return static_cast<unsigned long>(timer_manager_->CreateTimer(
      static_cast<UINT>(milliseconds.count()), true, action));
}

void WinUiApplication::CancelTimer(unsigned long id) {
  timer_manager_->KillTimer(static_cast<UINT_PTR>(id));
}

std::vector<NativeWindow*> WinUiApplication::GetAllWindow() {
  const auto&& windows = window_manager_->GetAllWindows();
  std::vector<NativeWindow*> result;
  for (const auto w : windows) {
    result.push_back(static_cast<NativeWindow*>(w));
  }
  return result;
}

NativeWindow* WinUiApplication::CreateWindow(NativeWindow* parent) {
  WinNativeWindow* p = nullptr;
  if (parent != nullptr) {
    p = dynamic_cast<WinNativeWindow*>(parent);
    assert(p);
  }
  return new WinNativeWindow(this, window_manager_->GetGeneralWindowClass(),
                             WS_OVERLAPPEDWINDOW, p);
}

WinCursorManager* WinUiApplication::GetCursorManager() {
  return cursor_manager_.get();
}
}  // namespace cru::platform::native::win