Merge "[Windows version] WindowImpl cleanup, fixes and improvements." into devel...
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / windows / platform-implement-win.cpp
1 /*
2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 // CLASS HEADER
19 #include <dali/internal/window-system/windows/platform-implement-win.h>
20
21 // EXTERNAL INCLUDES
22 #include <map>
23 #include <windows.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/window-system/windows/event-system-win.h>
27
28 namespace
29 {
30 constexpr float INCH = 25.4;
31 }
32
33 namespace Dali
34 {
35
36 namespace Internal
37 {
38
39 namespace Adaptor
40 {
41
42 namespace WindowsPlatform
43 {
44
45 LRESULT CALLBACK WinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
46 {
47   WindowImpl::ProcWinMessage( reinterpret_cast<uint64_t>( hWnd ), uMsg, wParam, lParam );
48
49   LRESULT ret = DefWindowProc( hWnd, uMsg, wParam, lParam );
50   return ret;
51 }
52
53 namespace
54 {
55
56 const std::string DALI_WINDOW_CLASS_NAME = "DaliWindow";
57
58 uint32_t sNumWindows = 0;
59
60 void EnsureWindowClassRegistered()
61 {
62   if (sNumWindows == 0)
63   {
64     WNDCLASS cs = { 0 };
65     cs.cbClsExtra = 0;
66     cs.cbWndExtra = 0;
67     cs.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
68     cs.hCursor = NULL;
69     cs.hIcon = NULL;
70     cs.hInstance = GetModuleHandle(NULL);
71     cs.lpfnWndProc = (WNDPROC)WinProc;
72     cs.lpszClassName = DALI_WINDOW_CLASS_NAME.c_str();
73     cs.lpszMenuName = NULL;
74     cs.style = CS_VREDRAW | CS_HREDRAW;
75     RegisterClass(&cs);
76   }
77 }
78
79 void EnsureWindowClassUnregistered()
80 {
81   if (sNumWindows == 0)
82   {
83     UnregisterClass(DALI_WINDOW_CLASS_NAME.c_str(), GetModuleHandle(NULL));
84   }
85 }
86
87 std::map<uint64_t, WindowImpl*> sHWndToListener;
88
89 void RemoveListener(uint64_t hWnd)
90 {
91   std::map<uint64_t, WindowImpl*>::iterator x = sHWndToListener.find(hWnd);
92   if (sHWndToListener.end() != x)
93   {
94     sHWndToListener.erase(x);
95   }
96 }
97
98 }
99
100 const uint32_t WindowImpl::STYLE = WS_OVERLAPPED;
101 const int32_t WindowImpl::EDGE_WIDTH = 8;
102 const int32_t WindowImpl::EDGE_HEIGHT = 18;
103
104 WindowImpl::WindowImpl()
105 {
106   colorDepth = -1;
107   mHWnd = 0;
108   mHdc = 0;
109   listener = NULL;
110 }
111
112 WindowImpl::~WindowImpl()
113 {
114   RemoveListener(mHWnd);
115 }
116
117 void WindowImpl::ProcWinMessage( uint64_t hWnd, uint32_t uMsg, uint64_t wParam, uint64_t lParam )
118 {
119   std::map<uint64_t, WindowImpl*>::iterator x = sHWndToListener.find( hWnd );
120
121   if( sHWndToListener.end() != x )
122   {
123     CallbackBase* listener = x->second->listener;
124
125     if( NULL != listener )
126     {
127       TWinEventInfo eventInfo( hWnd, uMsg, wParam, lParam );
128       CallbackBase::Execute( *listener, &eventInfo );
129     }
130   }
131 }
132
133 void WindowImpl::GetDPI( float &xDpi, float &yDpi )
134 {
135   HDC hdcScreen = GetDC( reinterpret_cast<HWND>( mHWnd ) );
136
137   int32_t iX = GetDeviceCaps( hdcScreen, HORZRES );    // pixel
138   int32_t iY = GetDeviceCaps( hdcScreen, VERTRES );    // pixel
139   int32_t iPhsX = GetDeviceCaps( hdcScreen, HORZSIZE );    // mm
140   int32_t iPhsY = GetDeviceCaps( hdcScreen, VERTSIZE );    // mm
141
142   xDpi = static_cast<float>( iX ) / static_cast<float>( iPhsX ) * INCH;
143   yDpi = static_cast<float>( iY ) / static_cast<float>( iPhsY ) * INCH;
144 }
145
146 int WindowImpl::GetColorDepth()
147 {
148   DALI_ASSERT_DEBUG( colorDepth >= 0 && "HWND hasn't been created, no color depth" );
149   return colorDepth;
150 }
151
152 uint64_t WindowImpl::CreateHwnd(
153   _In_opt_ const char *lpWindowName,
154   _In_ int X,
155   _In_ int Y,
156   _In_ int nWidth,
157   _In_ int nHeight,
158   _In_opt_ uint64_t parent )
159 {
160   EnsureWindowClassRegistered();
161   ++sNumWindows;
162
163   HWND hWnd = CreateWindow( DALI_WINDOW_CLASS_NAME.c_str(), lpWindowName, STYLE, X, Y,
164     nWidth + 2 * EDGE_WIDTH, nHeight + 2 * EDGE_HEIGHT, NULL, NULL, GetModuleHandle(NULL), NULL );
165   ::ShowWindow( hWnd, SW_SHOW );
166
167   return reinterpret_cast<uint64_t>(hWnd);
168 }
169
170 void WindowImpl::DestroyHWnd(uint64_t hWnd)
171 {
172   if (hWnd != 0)
173   {
174     ::DestroyWindow(reinterpret_cast<HWND>(hWnd));
175
176     --sNumWindows;
177     EnsureWindowClassUnregistered();
178   }
179 }
180
181 void WindowImpl::SetListener( CallbackBase *callback )
182 {
183   listener = callback;
184 }
185
186 bool WindowImpl::PostWinMessage(
187   _In_ uint32_t Msg,
188   _In_ uint64_t wParam,
189   _In_ uint64_t lParam )
190 {
191   return (bool)PostMessage( reinterpret_cast<HWND>( mHWnd ), Msg, wParam, lParam );
192 }
193
194 void WindowImpl::SetHWND( uint64_t inHWnd )
195 {
196   if (mHWnd != inHWnd)
197   {
198     RemoveListener(mHWnd);
199
200     mHWnd = inHWnd;
201     mHdc = reinterpret_cast<uint64_t>(GetDC(reinterpret_cast<HWND>(mHWnd)));
202     colorDepth = GetDeviceCaps(reinterpret_cast<HDC>(mHdc), BITSPIXEL) * GetDeviceCaps(reinterpret_cast<HDC>(mHdc), PLANES);
203
204     std::map<uint64_t, WindowImpl*>::iterator x = sHWndToListener.find(mHWnd);
205     if (sHWndToListener.end() == x)
206     {
207       sHWndToListener.insert(std::make_pair(mHWnd, this));
208     }
209     else
210     {
211       x->second = this;
212     }
213   }
214 }
215
216 void WindowImpl::SetWinProc()
217 {
218   // Sets the WinProc function.
219   LONG_PTR ret = SetWindowLongPtr((HWND)mHWnd,
220                                   GWLP_WNDPROC,
221                                   reinterpret_cast<LONG_PTR>(&WinProc));
222
223   if (0 == ret)
224   {
225     DWORD error = GetLastError();
226     return;
227   }
228
229   HMODULE module = GetModuleHandle(nullptr);
230   ret = SetWindowLongPtr((HWND)mHWnd,
231                          GWLP_HINSTANCE,
232                          reinterpret_cast<LONG_PTR>(&module));
233 }
234
235 bool PostWinThreadMessage(
236   _In_ uint32_t Msg,
237   _In_ uint64_t wParam,
238   _In_ uint64_t lParam,
239   _In_ uint64_t threadID/* = -1*/ )
240 {
241   if( -1 == threadID )
242   {
243     threadID = GetCurrentThreadId();
244   }
245
246   return (bool)PostThreadMessage( threadID, Msg, wParam, lParam );
247 }
248
249 struct TTimerCallbackInfo
250 {
251   void *data;
252   timerCallback callback;
253   HWND hWnd;
254 };
255
256 void CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT_PTR nTimerid, DWORD dwTime)
257 {
258   TTimerCallbackInfo *info = (TTimerCallbackInfo*)nTimerid;
259   info->callback( info->data );
260 }
261
262 intptr_t SetTimer(int interval, timerCallback callback, void *data)
263 {
264   TTimerCallbackInfo *callbackInfo = new TTimerCallbackInfo;
265   callbackInfo->data = data;
266   callbackInfo->callback = callback;
267   callbackInfo->hWnd = ::GetActiveWindow();
268
269   INT_PTR timerID = (INT_PTR)callbackInfo;
270   ::SetTimer( callbackInfo->hWnd, timerID, interval, TimerProc );
271
272   return timerID;
273 }
274
275 void KillTimer(intptr_t id)
276 {
277   TTimerCallbackInfo *info = (TTimerCallbackInfo*)id;
278   ::KillTimer( info->hWnd, id );
279   delete info;
280 }
281
282 const char* GetKeyName( int keyCode )
283 {
284   switch( keyCode )
285   {
286     case VK_BACK:
287     {
288       return "Backspace";
289     }
290     case VK_TAB:
291     {
292       return "Tab";
293     }
294     case VK_RETURN:
295     {
296       return "Return";
297     }
298     case VK_ESCAPE:
299     {
300       return "Escape";
301     }
302     case VK_SPACE:
303     {
304       return "Space";
305     }
306     case VK_LEFT:
307     {
308       return "Left";
309     }
310     case VK_UP:
311     {
312       return "Up";
313     }
314     case VK_RIGHT:
315     {
316       return "Right";
317     }
318     case VK_DOWN:
319     {
320       return "Down";
321     }
322     case 48:
323     {
324       return "0";
325     }
326     case 49:
327     {
328       return "1";
329     }
330     case 50:
331     {
332       return "2";
333     }
334     case 51:
335     {
336       return "3";
337     }
338     case 52:
339     {
340       return "4";
341     }
342     case 53:
343     {
344       return "5";
345     }
346     case 54:
347     {
348       return "6";
349     }
350     case 55:
351     {
352       return "7";
353     }
354     case 56:
355     {
356       return "8";
357     }
358     case 57:
359     {
360       return "9";
361     }
362     default:
363     {
364       break;
365     }
366   }
367
368   return "";
369 }
370
371 static LARGE_INTEGER cpuFrequency;
372 static LARGE_INTEGER *pCpuFrequency = NULL;
373
374 uint64_t GetCurrentThreadId()
375 {
376   return ::GetCurrentThreadId();
377 }
378
379 void GetNanoseconds( uint64_t& timeInNanoseconds )
380 {
381   if( NULL == pCpuFrequency )
382   {
383     pCpuFrequency = &cpuFrequency;
384     QueryPerformanceFrequency( pCpuFrequency );
385   }
386
387   LARGE_INTEGER curTime;
388   QueryPerformanceCounter( &curTime );
389
390   timeInNanoseconds = static_cast<double>(curTime.QuadPart) / static_cast<double>(pCpuFrequency->QuadPart) * 1000000000;
391 }
392
393 unsigned int GetCurrentMilliSeconds( void )
394 {
395   if( NULL == pCpuFrequency )
396   {
397     pCpuFrequency = &cpuFrequency;
398     QueryPerformanceFrequency( pCpuFrequency );
399   }
400
401   LARGE_INTEGER curTime;
402   QueryPerformanceCounter( &curTime );
403
404   return curTime.QuadPart * 1000 / pCpuFrequency->QuadPart;
405 }
406
407 } // namespace WindowsPlatformImplement
408
409 } // namespace Adaptor
410
411 } // namespace internal
412
413 } // namespace Dali