YSTest  PreAlpha_b500_20140530
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
Win32GUI.cpp
浏览该文件的文档.
1 /*
2  © 2013-2014 FrankHB.
3 
4  This file is part of the YSLib project, and may only be used,
5  modified, and distributed under the terms of the YSLib project
6  license, LICENSE.TXT. By continuing to use, modify, or distribute
7  this file you indicate that you have read the license and
8  understand and accept it fully.
9 */
10 
29 #include "YCLib/YModules.h"
30 #include YFM_MinGW32_YCLib_Win32GUI
31 
32 using namespace YSLib;
33 using namespace Drawing;
34 
35 namespace platform_ex
36 {
37 
38 namespace Windows
39 {
40 
41 namespace
42 {
43 
45 void
46 ResizeWindow(::HWND h_wnd, SDst w, SDst h)
47 {
48  if(YB_UNLIKELY(!::SetWindowPos(h_wnd, {}, 0, 0, w, h,
49  SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE
50  | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER)))
51  YF_Raise_Win32Exception("SetWindowPos @ ResizeWindow");
52 }
53 
55 ::RECT
56 FetchWindowRect(::HWND h_wnd)
57 {
58  ::RECT rect;
59 
60  if(YB_UNLIKELY(!::GetWindowRect(h_wnd, &rect)))
61  YF_Raise_Win32Exception("GetWindowRect");
62  return rect;
63 }
64 
66 
67 Size
68 FetchSizeFromBounds(const ::RECT& rect)
69 {
70  YAssert(rect.right - rect.left >= 0 && rect.bottom - rect.top >= 0,
71  "Invalid boundary found.");
72  return {rect.right - rect.left, rect.bottom - rect.top};
73 }
74 
75 inline Rect
76 FetchRectFromBounds(const ::RECT& rect)
77 {
78  return Rect(rect.left, rect.top, FetchSizeFromBounds(rect));
79 }
80 
81 inline ::DWORD
82 FetchWindowStyle(::HWND h_wnd)
83 {
84  return ::GetWindowLongW(h_wnd, GWL_STYLE);
85 }
86 
87 void
88 AdjustWindowBounds(::RECT& rect, ::HWND h_wnd, bool b_menu = false)
89 {
90  if(YB_UNLIKELY(!::AdjustWindowRect(&rect, FetchWindowStyle(h_wnd), b_menu)))
91  YF_Raise_Win32Exception("AdjustWindowRect");
92  YAssert(rect.right - rect.left >= 0 && rect.bottom - rect.top >= 0,
93  "Invalid boundary found.");
94 }
95 
96 void
97 SetWindowBounds(::HWND h_wnd, int x, int y, int cx, int cy)
98 {
99  if(YB_UNLIKELY(!::SetWindowPos(h_wnd, {}, x, y, cx, cy,
100  SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE
101  | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER)))
102  YF_Raise_Win32Exception("SetWindowPos @ SetWindowBounds");
103 }
105 
106 } // unnamed namespace;
107 
108 
109 Rect
110 WindowReference::GetClientBounds() const
111 {
112  return {GetClientLocation(), GetClientSize()};
113 }
114 Point
115 WindowReference::GetClientLocation() const
116 {
117  ::POINT point{0, 0};
118 
119  if(YB_UNLIKELY(!::ClientToScreen(hWindow, &point)))
120  YF_Raise_Win32Exception("ClientToScreen");
121  return {point.x, point.y};
122 }
123 Size
124 WindowReference::GetClientSize() const
125 {
126  ::RECT rect;
127 
128  if(YB_UNLIKELY(!::GetClientRect(hWindow, &rect)))
129  YF_Raise_Win32Exception("GetClientRect");
130  return {rect.right, rect.bottom};
131 }
132 Point
133 WindowReference::GetLocation() const
134 {
135  const auto& rect(FetchWindowRect(hWindow));
136 
137  return {rect.left, rect.top};
138 }
140 WindowReference::GetOpacity() const
141 {
142  ystdex::byte a;
143 
144  if(YB_UNLIKELY(!GetLayeredWindowAttributes(hWindow, {}, &a, {})))
145  YF_Raise_Win32Exception("GetLayeredWindowAttributes");
146  return a;
147 }
148 Size
149 WindowReference::GetSize() const
150 {
151  return FetchSizeFromBounds(FetchWindowRect(hWindow));
152 }
153 
154 void
155 WindowReference::SetClientBounds(const Rect& r)
156 {
157  ::RECT rect{r.X, r.Y, r.X + r.Width, r.Y + r.Height};
158 
159  AdjustWindowBounds(rect, hWindow);
160  SetWindowBounds(hWindow, rect.left, rect.top, rect.right - rect.left,
161  rect.bottom - rect.top);
162 }
163 void
164 WindowReference::SetOpacity(YSLib::Drawing::AlphaType a)
165 {
166  if(YB_UNLIKELY(!SetLayeredWindowAttributes(hWindow, 0, a, LWA_ALPHA)))
167  YF_Raise_Win32Exception("SetLayeredWindowAttributes");
168 }
169 void
170 WindowReference::SetText(const wchar_t* str)
171 {
172  if(YB_UNLIKELY(!::SetWindowTextW(hWindow, str)))
173  YF_Raise_Win32Exception("SetWindowTextW");
174 }
175 
176 void
178 {
179  if(YB_UNLIKELY(!::SendNotifyMessageW(hWindow, WM_CLOSE, 0, 0)))
180  YF_Raise_Win32Exception("SendNotifyMessageW");
181 }
182 
183 void
185 {
186  if(YB_UNLIKELY(!::InvalidateRect(hWindow, {}, false)))
187  YF_Raise_Win32Exception("InvalidateRect");
188 }
189 
190 void
191 WindowReference::Move(const Point& pt)
192 {
193  if(YB_UNLIKELY(!::SetWindowPos(hWindow, {}, pt.X, pt.Y, 0, 0,
194  SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW
195  | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER)))
196  YF_Raise_Win32Exception("SetWindowPos @ WindowReference::Move");
197 }
198 
199 void
200 WindowReference::Resize(const Size& s)
201 {
202  ResizeWindow(hWindow, s.Width, s.Height);
203 }
204 
205 void
206 WindowReference::ResizeClient(const Size& s)
207 {
208  ::RECT rect{0, 0, s.Width, s.Height};
209 
210  AdjustWindowBounds(rect, hWindow);
211  ResizeWindow(hWindow, rect.right - rect.left, rect.bottom - rect.top);
212 }
213 
214 bool
216 {
217  return ::ShowWindowAsync(hWindow, SW_SHOWNORMAL) != 0;
218 }
219 
220 
222 CreateNativeWindow(const wchar_t* class_name, const Drawing::Size& s,
223  const wchar_t* title, ::DWORD wstyle, ::DWORD wstyle_ex)
224 {
225  ::RECT rect{0, 0, s.Width, s.Height};
226 
227  ::AdjustWindowRect(&rect, wstyle, false);
228  return ::CreateWindowExW(wstyle_ex, class_name, title, wstyle,
229  CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left,
230  rect.bottom - rect.top, HWND_DESKTOP, {}, ::GetModuleHandleW({}), {});
231 }
232 
233 
234 ScreenBuffer::ScreenBuffer(const Size& s)
235  : size(s), hBitmap([this]{
236  // NOTE: Bitmap format is hard coded here for explicit buffer
237  // compatibility. %::CreateCompatibleBitmap is not fit for unknown
238  // windows.
239  ::BITMAPINFO bmi{{sizeof(::BITMAPINFOHEADER), size.Width,
240  -size.Height - 1, 1, 32, BI_RGB,
241  sizeof(PixelType) * size.Width * size.Height, 0, 0, 0, 0}, {}};
242 
243  return ::CreateDIBSection({}, &bmi, DIB_RGB_COLORS,
244  &reinterpret_cast<void*&>(pBuffer), {}, 0);
245  }())
246 {}
247 ScreenBuffer::ScreenBuffer(ScreenBuffer&& sbuf) ynothrow
248  : size(sbuf.size), hBitmap(sbuf.hBitmap)
249 {
250  sbuf.hBitmap = {};
251 }
253 {
254  ::DeleteObject(hBitmap);
255 }
256 
259 {
260  sbuf.swap(*this);
261  return *this;
262 }
263 
264 void
266 {
267  if(s != size)
268  *this = ScreenBuffer(s);
269 }
270 
271 void
272 ScreenBuffer::Premultiply(BitmapPtr buf) ynothrow
273 {
274  // NOTE: Since the stride is guaranteed equal to the width, the storage for
275  // pixels can be supposed to be contiguous.
276  std::transform(buf, buf + size.Width * size.Height, pBuffer,
277  [](const PixelType& pixel){
278  const auto a(pixel.GetA());
279 
280  return PixelType{MonoType(pixel.GetB() * a / 0xFF),
281  MonoType(pixel.GetG() * a / 0xFF),
282  MonoType(pixel.GetR() * a / 0xFF), a};
283  });
284 }
285 
286 void
288 {
289  // NOTE: Since the pitch is guaranteed equal to the width, the storage for
290  // pixels can be supposed to be contiguous.
291  YAssertNonnull(p_buf);
292  std::copy_n(p_buf, size.Width * size.Height, GetBufferPtr());
293 }
294 
295 void
297 {
298  std::swap(size, sbuf.size),
299  std::swap(pBuffer, sbuf.pBuffer),
300  std::swap(hBitmap, sbuf.hBitmap);
301 }
302 
303 
304 void
306 {
307  std::lock_guard<std::mutex> lck(mtx);
308 
310 }
311 
312 void
314  const Point& pt) ynothrow
315 {
316  std::lock_guard<std::mutex> lck(mtx);
317  GSurface<> sf(h_wnd);
318 
319  sf.UpdatePremultiplied(*this, h_wnd, a, pt);
320 }
321 
322 void
324 {
325  std::lock_guard<std::mutex> lck(mtx);
326  GSurface<> sf(h_wnd);
327 
328  sf.Update(*this, pt);
329 }
330 
331 
332 void
333 WindowMemorySurface::Update(ScreenBuffer& sbuf, const Point& pt) ynothrow
334 {
335  const auto h_old(::SelectObject(h_mem_dc, sbuf.GetNativeHandle()));
336  const auto& s(sbuf.GetSize());
337 
338  // NOTE: Unlocked intentionally for performance.
339  ::BitBlt(h_owner_dc, pt.X, pt.Y, s.Width, s.Height, h_mem_dc, 0, 0,
340  SRCCOPY);
341  ::SelectObject(h_mem_dc, h_old);
342 }
343 void
344 WindowMemorySurface::UpdatePremultiplied(ScreenBuffer& sbuf,
346  ynothrow
347 {
348  const auto h_old(::SelectObject(h_mem_dc, sbuf.GetNativeHandle()));
349  auto rect(FetchWindowRect(h_wnd));
350  ::SIZE size{rect.right - rect.left, rect.bottom - rect.top};
351  ::POINT ptx{pt.X, pt.Y};
352  ::BLENDFUNCTION bfunc{AC_SRC_OVER, 0, a, AC_SRC_ALPHA};
353 
354  // NOTE: Unlocked intentionally for performance.
355  if(YB_UNLIKELY(!::UpdateLayeredWindow(h_wnd, h_owner_dc,
356  reinterpret_cast<::POINT*>(&rect), &size, h_mem_dc, &ptx, 0, &bfunc,
357  ULW_ALPHA)))
358  {
359  // TODO: Use RAII.
360  ::SelectObject(h_mem_dc, h_old);
361  YF_Raise_Win32Exception("UpdateLayeredWindow");
362  }
363  ::SelectObject(h_mem_dc, h_old);
364 }
365 
366 
367 WindowClass::WindowClass(const wchar_t* class_name, ::WNDPROC wnd_proc,
368  ::UINT style, ::HBRUSH h_bg)
369  : h_instance(::GetModuleHandleW({}))
370 {
371  // NOTE: Intentionally no %CS_OWNDC or %CS_CLASSDC, so %::ReleaseDC
372  // is always needed.
373  const ::WNDCLASSW wnd_class{style, wnd_proc, 0, 0, h_instance,
374  ::LoadIconW({}, IDI_APPLICATION), ::LoadCursorW({}, IDC_ARROW),
375  h_bg, nullptr, class_name};
376 
377  if(YB_UNLIKELY(::RegisterClassW(&wnd_class) == 0))
378  YF_Raise_Win32Exception("RegisterClassW");
379  // TODO: Trace class name.
380  YTraceDe(Notice, "Window class registered.");
381 }
383 {
384  ::UnregisterClassW(WindowClassName, h_instance);
385  // TODO: Trace class name.
386  YTraceDe(Notice, "Window class unregistered.");
387 }
388 
389 
391  : WindowReference(h),
392  MessageMap()
393 {
394  YAssert(::IsWindow(h), "Invalid window handle found.");
395  YAssert(::GetWindowThreadProcessId(h, {}) == ::GetCurrentThreadId(),
396  "Window not created on current thread found.");
397  YAssert(::GetWindowLongPtrW(h, GWLP_USERDATA) == 0,
398  "Invalid user data of window found.");
399 
400  wchar_t buf[ystdex::arrlen(WindowClassName)];
401 
402  if(YB_UNLIKELY(!::GetClassNameW(hWindow, buf,
404  YF_Raise_Win32Exception("GetClassNameW");
405  if(std::wcscmp(buf, WindowClassName) != 0)
406  throw LoggedEvent("Wrong windows class name found.");
407  ::SetLastError(0);
408  if(YB_UNLIKELY(::SetWindowLongPtrW(hWindow, GWLP_USERDATA,
409  ::LONG_PTR(this)) == 0 && GetLastError() != 0))
410  YF_Raise_Win32Exception("SetWindowLongPtrW");
411  if(YB_UNLIKELY(!::SetWindowPos(hWindow, {}, 0, 0, 0, 0, SWP_NOACTIVATE
412  | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSENDCHANGING
413  | SWP_NOSIZE | SWP_NOZORDER)))
414  YF_Raise_Win32Exception("SetWindowPos @ HostWindow::HostWindow");
415 
416  ::RAWINPUTDEVICE rid{0x01, 0x02, 0, nullptr};
417 
418  if(YB_UNLIKELY(!::RegisterRawInputDevices(&rid, 1, sizeof(rid))))
419  YF_Raise_Win32Exception("RegisterRawInputDevices");
420  MessageMap[WM_DESTROY] += []{
422  };
423 }
424 HostWindow::~HostWindow()
425 {
426  ::SetWindowLongPtrW(hWindow, GWLP_USERDATA, ::LONG_PTR());
427  // NOTE: The window could be already destroyed in window procedure.
428  if(::IsWindow(hWindow))
429  ::DestroyWindow(hWindow);
430 }
431 
432 } // namespace Windows;
433 
434 } // namespace platform_ex;
435 
void swap(ScreenBuffer &) ynothrow
Definition: Win32GUI.cpp:296
yconstexpr wchar_t WindowClassName[]
YF_API void PostQuitMessage(int nExitCode, Messaging::Priority p=0xF0)
以优先级 p 发起 Shell 终止请求,返回 nExitCode。
Definition: yapp.cpp:83
显式区域表面:储存显式区域上的二维图形绘制状态。
size_t arrlen(_type(&)[_vN])
计算指定数组类型对象的长度。
Definition: utility.hpp:196
ScreenBuffer & operator=(ScreenBuffer &&)
Definition: Win32GUI.cpp:258
pt void UpdatePremultiplied(ScreenBuffer &, NativeWindowHandle, YSLib::Drawing::AlphaType=0xFF, const YSLib::Drawing::Point &={}) ynothrow
Definition: Win32GUI.cpp:344
YF_API void Invalidate(IWidget &, const Rect &)
无效化:使相对于部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:111
std::map<::UINT, YSLib::GEvent< void(::WPARAM,::LPARAM)> > MessageMap
窗口消息转发事件映射。
unsigned char byte
字节类型。
Definition: ydef.h:555
SDst Height
宽和高。
Definition: ygdibase.h:258
std::uint16_t SDst
屏幕坐标距离。
Definition: Video.h:39
YF_API void Show(IWidget &)
显示部件。
Definition: ywidget.cpp:206
HostWindow(NativeWindowHandle)
Definition: Win32GUI.cpp:390
hBitmap(sbuf.hBitmap)
Definition: Win32GUI.cpp:248
YF_API NativeWindowHandle CreateNativeWindow(const wchar_t *, const YSLib::Drawing::Size &, const wchar_t *=L"",::DWORD=WS_POPUP,::DWORD=WS_EX_LTRREADING)
按指定窗口类名、客户区大小、标题文本、样式和附加样式创建本机顶层窗口。
Definition: Win32GUI.cpp:222
void swap(any &x, any &y)
交换对象。
Definition: any.h:729
#define YB_UNLIKELY(expr)
分支预测提示。
Definition: ydef.h:298
ScreenBuffer(const YSLib::Drawing::Size &)
Definition: Win32GUI.cpp:234
DefGetter(ynothrow, ScreenBuffer &, ScreenBufferRef,*this) using ScreenBuffer voi UpdateFrom)(YSLib::Drawing::BitmapPtr) ynothrow
Definition: Android.h:234
#define ynothrow
YSLib 无异常抛出保证:若支持 noexcept 关键字, 指定特定的 noexcept 异常规范。
Definition: ydef.h:514
屏幕标准矩形:表示屏幕矩形区域。
Definition: ygdibase.h:416
#define YF_Raise_Win32Exception(...)
按 ::GetLastError 的结果和指定参数抛出 Windows::Win32Exception 对象。
void UpdatePremultipliedTo(NativeWindowHandle, YSLib::Drawing::AlphaType=0xFF, const YSLib::Drawing::Point &={}) ynothrow
Definition: Win32GUI.cpp:313
#define YAssertNonnull(_expr)
Definition: cassert.h:81
::ANativeWindow * NativeWindowHandle
Definition: Android.h:50
void UpdateTo(NativeWindowHandle, const YSLib::Drawing::Point &={}) ynothrow
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:269
记录日志的异常事件类。
Definition: yexcept.h:58
PixelType * BitmapPtr
Definition: Video.h:295
bounds & r
Definition: ydraw.h:220
屏幕区域大小。
Definition: ygdibase.h:249
ystdex::octet AlphaType
Definition: Video.h:186
void Close(IWidget &wgt)
Definition: ywidget.cpp:95
#define YAssert(_expr, _msg)
Definition: cassert.h:73
hBitmap DefGetter(const ynothrow, const YSLib::Drawing::Size &, Size, size) void Premultiply(YSLib void Resize(const YSLib::Drawing::Size &)
从缓冲区更新并按 Alpha 预乘。