OSDN Git Service

サムネイル・ツールバーを実装してみた。
[wintimer/wintimer.git] / wintimer / sf_windows.h
1 #pragma once
2 /*
3 */
4 // Windows Header Files:
5 #include "exception.h"
6 #include "base_window.h"
7 #include "dpi.h"
8 #define XBYAK64
9 #include "xbyak.h"
10 // DLLのリンク
11 #pragma comment(lib,"d2d1.lib")
12 #pragma comment(lib,"winmm.lib")
13 #pragma comment(lib,"dwrite.lib")
14 #pragma comment(lib,"dwmapi.lib")
15
16 //#include "input.h"
17
18 _COM_SMARTPTR_TYPEDEF(ID2D1Factory,__uuidof(ID2D1Factory));
19 _COM_SMARTPTR_TYPEDEF(IWICImagingFactory, __uuidof(IWICImagingFactory));
20 _COM_SMARTPTR_TYPEDEF(IDWriteFactory , __uuidof(IDWriteFactory));
21 _COM_SMARTPTR_TYPEDEF(IDWriteGdiInterop , __uuidof(IDWriteGdiInterop));
22 _COM_SMARTPTR_TYPEDEF(IDWriteFontFace , __uuidof(IDWriteFontFace));
23 _COM_SMARTPTR_TYPEDEF(IDWriteFont , __uuidof(IDWriteFont));
24 _COM_SMARTPTR_TYPEDEF(IDWriteFontFamily , __uuidof(IDWriteFontFamily));
25 _COM_SMARTPTR_TYPEDEF(IDWriteFontCollection , __uuidof(IDWriteFontCollection));
26 _COM_SMARTPTR_TYPEDEF(IDWriteLocalizedStrings , __uuidof(IDWriteLocalizedStrings));
27 _COM_SMARTPTR_TYPEDEF(ID2D1HwndRenderTarget , __uuidof(ID2D1HwndRenderTarget));
28 _COM_SMARTPTR_TYPEDEF(ID2D1BitmapRenderTarget , __uuidof(ID2D1BitmapRenderTarget));
29 _COM_SMARTPTR_TYPEDEF(ID2D1GdiInteropRenderTarget , __uuidof(ID2D1GdiInteropRenderTarget));
30 _COM_SMARTPTR_TYPEDEF(ID2D1DCRenderTarget , __uuidof(ID2D1DCRenderTarget));
31 _COM_SMARTPTR_TYPEDEF(IDWriteTextFormat, __uuidof(IDWriteTextFormat));
32 _COM_SMARTPTR_TYPEDEF(IDWriteTextLayout, __uuidof(IDWriteTextLayout));
33 _COM_SMARTPTR_TYPEDEF(ID2D1PathGeometry , __uuidof(ID2D1PathGeometry));
34 _COM_SMARTPTR_TYPEDEF(ID2D1LinearGradientBrush , __uuidof(ID2D1LinearGradientBrush));
35 _COM_SMARTPTR_TYPEDEF(ID2D1GradientStopCollection , __uuidof(ID2D1GradientStopCollection));
36 _COM_SMARTPTR_TYPEDEF(ID2D1SolidColorBrush , __uuidof(ID2D1SolidColorBrush));
37 _COM_SMARTPTR_TYPEDEF(ID2D1BitmapBrush , __uuidof(ID2D1BitmapBrush));
38 _COM_SMARTPTR_TYPEDEF(ID2D1Bitmap , __uuidof(ID2D1Bitmap));
39 _COM_SMARTPTR_TYPEDEF(IWICBitmapDecoder,__uuidof(IWICBitmapDecoder));
40 _COM_SMARTPTR_TYPEDEF(IWICBitmapFrameDecode,__uuidof(IWICBitmapFrameDecode));
41 _COM_SMARTPTR_TYPEDEF(IWICStream,__uuidof(IWICStream));
42 _COM_SMARTPTR_TYPEDEF(IWICFormatConverter,__uuidof(IWICFormatConverter));
43 _COM_SMARTPTR_TYPEDEF(IWICBitmapScaler,__uuidof(IWICBitmapScaler));
44 _COM_SMARTPTR_TYPEDEF(ITaskbarList3,__uuidof(ITaskbarList3));
45
46 template <class COM_SMART_PTR > inline void safe_release(COM_SMART_PTR& ptr)
47 {
48   if(ptr)
49   {
50     ptr.Release();
51   }
52 };
53
54 namespace sf{
55
56   template <class Exc = win32_error_exception> struct throw_if_err
57   {
58     void operator()(HRESULT hr) {if(hr != S_OK){throw Exc(hr);}}
59   };
60
61  /* inline template <class Exc = win32_error_exception> void throw_if_err<>()(HRESULT hr)
62   {
63     if(hr != S_OK){throw Exc(hr);}
64   };*/
65
66
67   ID2D1BitmapPtr load_bitmap_from_file(
68     ID2D1HwndRenderTargetPtr render_target,
69     IWICImagingFactoryPtr wic_factory,
70     std::wstring uri,
71     uint32_t destination_width = 0,
72     uint32_t destination_height = 0
73     );
74
75   /** WNDCLASSEXラッパクラス */
76   struct window_class_ex
77   {
78     window_class_ex(
79       const wchar_t*  menu_name ,
80       const std::wstring&  class_name ,
81       HINSTANCE   hInstance = NULL,
82       WNDPROC     lpfnWndProc = ::DefWindowProcW,
83       uint32_t        style = CS_HREDRAW | CS_VREDRAW,
84       boost::int32_t     cbClsExtra  = 0,
85       HICON       hIcon = ::LoadIcon(NULL,IDI_APPLICATION),
86       HCURSOR     hCursor = ::LoadCursor(NULL, IDC_ARROW),
87       HBRUSH      hbrBackground = ::CreateSolidBrush(0xff000000),
88       HICON       hIconSm = NULL
89       ) : is_register_(false)
90     {
91
92       if(::GetClassInfoExW(hInstance,class_name.c_str(),&wndclass_) == 0)
93       {
94         if(::GetLastError() == ERROR_CLASS_DOES_NOT_EXIST)
95         { 
96           ::ZeroMemory(&wndclass_,sizeof(wndclass_));
97           wndclass_.lpszMenuName = (LPCWSTR)menu_name;
98           wndclass_.lpszClassName = class_name.c_str();
99           wndclass_.cbSize = sizeof(::WNDCLASSEXW);
100           wndclass_.cbWndExtra = sizeof(LONG_PTR);
101           wndclass_.hInstance = hInstance;
102           wndclass_.lpfnWndProc = lpfnWndProc;
103           wndclass_.style = style;
104           wndclass_.cbClsExtra = cbClsExtra;
105           wndclass_.hIcon = hIcon;
106           wndclass_.hCursor = hCursor;
107           wndclass_.hbrBackground = hbrBackground;
108           wndclass_.hIconSm = hIconSm;
109           atom_ = ::RegisterClassExW(&wndclass_) ;
110           BOOST_ASSERT(atom_ != 0);
111           is_register_ = true;
112         } else {
113           throw win32_error_exception();
114         }
115       } else {
116         is_register_ = false;
117       }
118     };
119
120     ~window_class_ex()
121     {
122       if(is_register_){
123         ::UnregisterClassW(wndclass_.lpszClassName,wndclass_.hInstance);
124       }
125     }
126
127   private:
128     bool is_register_;
129     ATOM atom_;
130     ::WNDCLASSEXW wndclass_;
131   };
132
133   struct get_dc {
134     get_dc(HWND hwnd) : hwnd_(hwnd),hdc_(GetDC(hwnd)) {}
135     HDC get(){return hdc_;}
136     ~get_dc(){::ReleaseDC(hwnd_,hdc_);}
137   private:
138     HDC hdc_;
139     HWND hwnd_;
140   };
141
142   struct compatible_dc {
143     compatible_dc(HDC hdc) : hdc_(::CreateCompatibleDC(hdc)){}; 
144     ~compatible_dc(){::DeleteDC(hdc_);};
145     HDC get() { return hdc_;};
146   private:
147     HDC hdc_;
148   };
149
150   struct ref_dc {
151     ref_dc(HDC& hdc) : hdc_(hdc) {};
152     ~ref_dc(){};
153     HDC get() { return hdc_;};
154   private:
155     HDC& hdc_;
156   };
157
158   struct d2_dc {
159     d2_dc(ID2D1GdiInteropRenderTargetPtr& ptr,D2D1_DC_INITIALIZE_MODE mode) :hdc_(0),ptr_(ptr)
160     {
161       hr_ = ptr->GetDC(mode,&hdc_);
162     };
163     ~d2_dc(){ptr_->ReleaseDC(NULL);};
164     HDC get() { return hdc_;};
165   private:
166     HRESULT hr_;
167     HDC hdc_;
168     ID2D1GdiInteropRenderTargetPtr& ptr_;
169   };
170
171   template <typename Holder>
172   struct device_context
173   {
174     explicit device_context(Holder* holder) : holder_(holder){};
175     ~device_context() {}
176     operator HDC(){return holder_->get();}
177   private:
178     std::unique_ptr<Holder> holder_;
179   };
180
181   //struct handle_holder : boost::noncopyable
182   //{
183   //  explicit handle_holder(HANDLE handle) : handle_(handle) {};
184   //  ~handle_holder(){if(handle_) ::CloseHandle(handle_);}
185   //  operator HANDLE(){return handle_;}
186   //private:
187   //  HANDLE handle_;
188   //};
189
190   
191   
192   struct handle_deleter {
193     typedef HANDLE pointer;
194     void operator ()(HANDLE handle) {
195         if (handle != INVALID_HANDLE_VALUE) {
196             CloseHandle(handle);
197         }
198     }
199   };
200
201   struct HBITMAP_deleter {
202     typedef HBITMAP pointer;
203     void operator ()(HBITMAP handle) {
204         if (handle) {
205            ::DeleteObject(handle);
206         }
207     }
208   };
209
210   //template <typename Handle,typename Handle_Deleter>
211   //struct handle_holder {
212   //  typedef boost::unique_ptr<Handle,Handle_Deleter> holder_type;
213   //  handle_holder(Handle handle) : holder_(handle) {}
214   //  operator Handle(){return holder_->get();}
215   //private:
216   //  holder_type holder_;
217   //};
218
219   typedef std::unique_ptr<HANDLE,handle_deleter> handle_holder;
220   typedef std::unique_ptr<HBITMAP,HBITMAP_deleter> bitmap_holder;
221
222   typedef device_context<d2_dc> d2_dc_type;
223
224   struct paint_struct 
225   {
226     paint_struct(HWND hwnd) : hwnd_(hwnd)
227     {
228       ::BeginPaint(hwnd,&paintstruct_);
229     }
230     ~paint_struct() {::EndPaint(hwnd_,&paintstruct_);}
231     PAINTSTRUCT* operator->(){return &paintstruct_;}
232   private:
233     HWND hwnd_;
234     PAINTSTRUCT paintstruct_;
235   };
236
237   // GDI オブジェクト管理テンプレート
238   template <class GdiObject> 
239     struct gdi_object: boost::noncopyable
240   {
241     explicit gdi_object(GdiObject obj) : gdiobj_(obj) {}
242     ~gdi_object(){::DeleteObject(gdiobj_);}
243     operator GdiObject(){return gdiobj_;}
244   private:
245     GdiObject gdiobj_;
246   };
247
248   //
249   struct select_object 
250   {
251     select_object(HDC dc,HGDIOBJ o) : dc_(dc),o_(::SelectObject(dc,o)) {}
252     ~select_object(){::SelectObject(dc_,o_);}
253   private:
254     HDC dc_;
255     HGDIOBJ o_;
256   };
257   
258   // Direct2D BeginDrawヘルパ関数
259   template <typename T >
260   struct begin_draw
261   {
262     typedef std::function<void(HRESULT hr)> err_handler_type;
263
264     begin_draw(T& render_target,err_handler_type& handler)
265       : render_target_(render_target) ,
266         is_end_(false),handler_(handler)
267     {render_target->BeginDraw();}
268
269     ~begin_draw(){ 
270       HRESULT hr = S_OK;
271       hr = render_target_->EndDraw();
272       if( hr != S_OK)
273       {
274         handler_(hr);
275       }
276     }
277   private:
278     T& render_target_;
279     err_handler_type handler_;
280   };
281
282   struct mouse
283   {
284     mouse() : x_(0.0f),y_(0.0f),left_button_(false),middle_button_(false),right_button_(false){}
285   private:
286     float x_,y_;
287     bool left_button_,middle_button_,right_button_;
288   };
289
290
291   /** window ベースクラス */
292   struct base_win32_window : public base_window 
293   {
294     typedef boost::signals2::signal<LRESULT (HWND,uint32_t,WPARAM, LPARAM) > on_message_type;
295     on_message_type on_message;
296     
297     operator HWND() const {return hwnd_;};
298     
299     virtual void * raw_handle() const {return hwnd_;};
300 //    virtual void show(uint32_t show_flag);
301
302     virtual void show() {
303       ::ShowWindow(hwnd_,SW_SHOW);
304       ::GetWindowPlacement(hwnd_,&wp_);
305     }
306
307     // Window を画面から隠す
308     virtual bool is_show() {
309       return ( wp_.showCmd == SW_SHOWMAXIMIZED 
310         || wp_.showCmd == SW_SHOWMINIMIZED
311         || wp_.showCmd == SW_SHOWNORMAL );
312     };
313
314     //
315     virtual void hide()
316     {
317       ::ShowWindow(hwnd_,SW_HIDE);
318       ::GetWindowPlacement(hwnd_,&wp_);
319     };
320
321     virtual void text(std::wstring& text)
322     {
323       ::SetWindowTextW(*this,text.c_str());
324     };
325
326     virtual void update();
327
328   protected:
329     
330     base_win32_window(
331       const std::wstring& title,
332       const std::wstring& name,bool fit_to_display,
333       float width,float height);
334     
335     ~base_win32_window();
336
337     void register_class (
338       const wchar_t* menu_name,
339       uint32_t style, 
340       boost::int32_t     cbClsExtra  = 0,
341       HICON       hIcon = ::LoadIcon(NULL,IDI_APPLICATION),
342       HCURSOR     hCursor = ::LoadCursor(NULL, IDC_ARROW),
343       HBRUSH      hbrBackground = ::CreateSolidBrush(0xff000000),
344       HICON       hIconSm = NULL
345       );                
346
347     /** デフォルト設定 */
348     void register_class();
349     void create_window();
350
351     // SetWindowLong API
352     void set_long(int index,long data)
353     {
354       SetLastError(0);
355       if(::SetWindowLongW(hwnd_,index,data) == 0)
356       {
357         long err = 0;
358         if( (err = GetLastError()) != 0){
359           SetLastError(err);
360           throw sf::win32_error_exception();
361         }
362       };
363     }
364
365     bool invalidate_rect(bool erase = false,const RECT * rect_ptr = 0)
366     {
367       return ::InvalidateRect(*this,rect_ptr,erase) == TRUE;
368     }
369
370   public:
371     virtual LRESULT window_proc(HWND hwnd,uint32_t message, WPARAM wParam, LPARAM lParam);
372   protected:
373     static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
374     {
375       base_win32_window* ptr = reinterpret_cast<base_win32_window*>(hwnd);
376       hwnd = ptr->hwnd_;
377       return ptr->window_proc(hwnd,message,wParam,lParam);
378     };
379
380     // thisとhwndをつなぐthunkクラス
381     struct hwnd_this_thunk : public Xbyak::CodeGenerator {
382       hwnd_this_thunk(base_win32_window* impl,WNDPROC proc)
383       {
384         // rcxにhwndが格納されているので、それをimpl->hwndに保存
385         mov(qword[&(impl->hwnd_)],rcx);
386         // 代わりにthisのアドレスをrcxに格納
387         mov(rcx,(LONG_PTR)impl);
388         // r10にproc(Window プロシージャ)へのアドレスを格納
389         mov(r10,(LONG_PTR)proc);
390         // Window プロシージャへへジャンプ
391         jmp(r10);
392       }
393     };
394
395     HWND hwnd_;
396     hwnd_this_thunk thunk_;
397     std::wstring title_;
398     std::wstring name_;
399     float width_,height_;
400     bool fit_to_display_;
401     std::shared_ptr<sf::window_class_ex> wnd_class_;
402     WNDPROC thunk_proc_;
403     dpi dpi_;
404     WINDOWPLACEMENT wp_;
405    };
406   
407   struct av_mm_thread_characteristics
408   {
409     av_mm_thread_characteristics(std::wstring& str) : task_name_(str)
410     {
411       handle_ = ::AvSetMmThreadCharacteristicsW(str.c_str(),(LPDWORD)&task_index_);
412     }
413
414     bool set_priority(AVRT_PRIORITY p){return (::AvSetMmThreadPriority(handle_,p) == TRUE);}
415
416     ~av_mm_thread_characteristics()
417     {
418       ::AvRevertMmThreadCharacteristics(handle_);
419     }
420
421   private:
422     std::wstring task_name_;
423     uint32_t task_index_;
424     HANDLE handle_;
425     std::wstring title_;
426     std::wstring name_;
427     float width_,height_;
428     bool fit_to_display_;
429     WINDOWPLACEMENT wp_;//
430   };
431
432   struct widget
433   {
434     void draw();
435     float x_,y_;
436   };
437
438   typedef sf::begin_draw<ID2D1BitmapRenderTargetPtr> begin_draw_bitmap;
439   typedef sf::begin_draw<ID2D1HwndRenderTargetPtr> begin_draw_hwnd;
440   
441 }