git blame: add file to help ignore cleanup commits
[blender.git] / intern / ghost / intern / GHOST_System.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup GHOST
22  */
23
24 #include "GHOST_System.h"
25
26 #include <chrono>
27 #include <stdio.h> /* just for printf */
28
29 #include "GHOST_DisplayManager.h"
30 #include "GHOST_EventManager.h"
31 #include "GHOST_TimerManager.h"
32 #include "GHOST_TimerTask.h"
33 #include "GHOST_WindowManager.h"
34
35 #ifdef WITH_INPUT_NDOF
36 #  include "GHOST_NDOFManager.h"
37 #endif
38
39 GHOST_System::GHOST_System()
40     : m_nativePixel(false),
41       m_windowFocus(true),
42       m_displayManager(NULL),
43       m_timerManager(NULL),
44       m_windowManager(NULL),
45       m_eventManager(NULL),
46 #ifdef WITH_INPUT_NDOF
47       m_ndofManager(0),
48 #endif
49       m_tabletAPI(GHOST_kTabletAutomatic),
50       m_is_debug_enabled(false)
51 {
52 }
53
54 GHOST_System::~GHOST_System()
55 {
56   exit();
57 }
58
59 GHOST_TUns64 GHOST_System::getMilliSeconds() const
60 {
61   return std::chrono::duration_cast<std::chrono::milliseconds>(
62              std::chrono::steady_clock::now().time_since_epoch())
63       .count();
64 }
65
66 GHOST_ITimerTask *GHOST_System::installTimer(GHOST_TUns64 delay,
67                                              GHOST_TUns64 interval,
68                                              GHOST_TimerProcPtr timerProc,
69                                              GHOST_TUserDataPtr userData)
70 {
71   GHOST_TUns64 millis = getMilliSeconds();
72   GHOST_TimerTask *timer = new GHOST_TimerTask(millis + delay, interval, timerProc, userData);
73   if (timer) {
74     if (m_timerManager->addTimer(timer) == GHOST_kSuccess) {
75       // Check to see whether we need to fire the timer right away
76       m_timerManager->fireTimers(millis);
77     }
78     else {
79       delete timer;
80       timer = NULL;
81     }
82   }
83   return timer;
84 }
85
86 GHOST_TSuccess GHOST_System::removeTimer(GHOST_ITimerTask *timerTask)
87 {
88   GHOST_TSuccess success = GHOST_kFailure;
89   if (timerTask) {
90     success = m_timerManager->removeTimer((GHOST_TimerTask *)timerTask);
91   }
92   return success;
93 }
94
95 GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow *window)
96 {
97   GHOST_TSuccess success;
98
99   /*
100    * Remove all pending events for the window.
101    */
102   if (m_windowManager->getWindowFound(window)) {
103     m_eventManager->removeWindowEvents(window);
104   }
105   if (window == m_windowManager->getFullScreenWindow()) {
106     success = endFullScreen();
107   }
108   else {
109     if (m_windowManager->getWindowFound(window)) {
110       success = m_windowManager->removeWindow(window);
111       if (success) {
112         delete window;
113       }
114     }
115     else {
116       success = GHOST_kFailure;
117     }
118   }
119   return success;
120 }
121
122 bool GHOST_System::validWindow(GHOST_IWindow *window)
123 {
124   return m_windowManager->getWindowFound(window);
125 }
126
127 GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting &setting,
128                                              GHOST_IWindow **window,
129                                              const bool stereoVisual,
130                                              const bool alphaBackground)
131 {
132   GHOST_TSuccess success = GHOST_kFailure;
133   GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager");
134   if (m_displayManager) {
135     if (!m_windowManager->getFullScreen()) {
136       m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay,
137                                                  m_preFullScreenSetting);
138
139       // GHOST_PRINT("GHOST_System::beginFullScreen(): activating new display settings\n");
140       success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay,
141                                                            setting);
142       if (success == GHOST_kSuccess) {
143         // GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n");
144         success = createFullScreenWindow(
145             (GHOST_Window **)window, setting, stereoVisual, alphaBackground);
146         if (success == GHOST_kSuccess) {
147           m_windowManager->beginFullScreen(*window, stereoVisual);
148         }
149         else {
150           m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay,
151                                                      m_preFullScreenSetting);
152         }
153       }
154     }
155   }
156   if (success == GHOST_kFailure) {
157     GHOST_PRINT("GHOST_System::beginFullScreen(): could not enter full-screen mode\n");
158   }
159   return success;
160 }
161
162 GHOST_TSuccess GHOST_System::updateFullScreen(const GHOST_DisplaySetting &setting,
163                                               GHOST_IWindow ** /*window*/)
164 {
165   GHOST_TSuccess success = GHOST_kFailure;
166   GHOST_ASSERT(m_windowManager, "GHOST_System::updateFullScreen(): invalid window manager");
167   if (m_displayManager) {
168     if (m_windowManager->getFullScreen()) {
169       success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay,
170                                                            setting);
171     }
172   }
173
174   return success;
175 }
176
177 GHOST_TSuccess GHOST_System::endFullScreen(void)
178 {
179   GHOST_TSuccess success = GHOST_kFailure;
180   GHOST_ASSERT(m_windowManager, "GHOST_System::endFullScreen(): invalid window manager");
181   if (m_windowManager->getFullScreen()) {
182     // GHOST_IWindow* window = m_windowManager->getFullScreenWindow();
183     // GHOST_PRINT("GHOST_System::endFullScreen(): leaving window manager full-screen mode\n");
184     success = m_windowManager->endFullScreen();
185     GHOST_ASSERT(m_displayManager, "GHOST_System::endFullScreen(): invalid display manager");
186     // GHOST_PRINT("GHOST_System::endFullScreen(): leaving full-screen mode\n");
187     success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay,
188                                                          m_preFullScreenSetting);
189   }
190   else {
191     success = GHOST_kFailure;
192   }
193   return success;
194 }
195
196 bool GHOST_System::getFullScreen(void)
197 {
198   bool fullScreen;
199   if (m_windowManager) {
200     fullScreen = m_windowManager->getFullScreen();
201   }
202   else {
203     fullScreen = false;
204   }
205   return fullScreen;
206 }
207
208 void GHOST_System::dispatchEvents()
209 {
210 #ifdef WITH_INPUT_NDOF
211   // NDOF Motion event is sent only once per dispatch, so do it now:
212   if (m_ndofManager) {
213     m_ndofManager->sendMotionEvent();
214   }
215 #endif
216
217   if (m_eventManager) {
218     m_eventManager->dispatchEvents();
219   }
220
221   m_timerManager->fireTimers(getMilliSeconds());
222 }
223
224 GHOST_TSuccess GHOST_System::addEventConsumer(GHOST_IEventConsumer *consumer)
225 {
226   GHOST_TSuccess success;
227   if (m_eventManager) {
228     success = m_eventManager->addConsumer(consumer);
229   }
230   else {
231     success = GHOST_kFailure;
232   }
233   return success;
234 }
235
236 GHOST_TSuccess GHOST_System::removeEventConsumer(GHOST_IEventConsumer *consumer)
237 {
238   GHOST_TSuccess success;
239   if (m_eventManager) {
240     success = m_eventManager->removeConsumer(consumer);
241   }
242   else {
243     success = GHOST_kFailure;
244   }
245   return success;
246 }
247
248 GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event)
249 {
250   GHOST_TSuccess success;
251   if (m_eventManager) {
252     success = m_eventManager->pushEvent(event);
253   }
254   else {
255     success = GHOST_kFailure;
256   }
257   return success;
258 }
259
260 GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const
261 {
262   GHOST_ModifierKeys keys;
263   // Get the state of all modifier keys
264   GHOST_TSuccess success = getModifierKeys(keys);
265   if (success) {
266     // Isolate the state of the key requested
267     isDown = keys.get(mask);
268   }
269   return success;
270 }
271
272 GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool &isDown) const
273 {
274   GHOST_Buttons buttons;
275   // Get the state of all mouse buttons
276   GHOST_TSuccess success = getButtons(buttons);
277   if (success) {
278     // Isolate the state of the mouse button requested
279     isDown = buttons.get(mask);
280   }
281   return success;
282 }
283
284 void GHOST_System::setTabletAPI(GHOST_TTabletAPI api)
285 {
286   m_tabletAPI = api;
287 }
288
289 GHOST_TTabletAPI GHOST_System::getTabletAPI(void)
290 {
291   return m_tabletAPI;
292 }
293
294 #ifdef WITH_INPUT_NDOF
295 void GHOST_System::setNDOFDeadZone(float deadzone)
296 {
297   if (this->m_ndofManager) {
298     this->m_ndofManager->setDeadZone(deadzone);
299   }
300 }
301 #endif
302
303 GHOST_TSuccess GHOST_System::init()
304 {
305   m_timerManager = new GHOST_TimerManager();
306   m_windowManager = new GHOST_WindowManager();
307   m_eventManager = new GHOST_EventManager();
308
309 #ifdef WITH_GHOST_DEBUG
310   if (m_eventManager) {
311     m_eventPrinter = new GHOST_EventPrinter();
312     m_eventManager->addConsumer(m_eventPrinter);
313   }
314 #endif  // WITH_GHOST_DEBUG
315
316   if (m_timerManager && m_windowManager && m_eventManager) {
317     return GHOST_kSuccess;
318   }
319   else {
320     return GHOST_kFailure;
321   }
322 }
323
324 GHOST_TSuccess GHOST_System::exit()
325 {
326   if (getFullScreen()) {
327     endFullScreen();
328   }
329
330   delete m_displayManager;
331   m_displayManager = NULL;
332
333   delete m_windowManager;
334   m_windowManager = NULL;
335
336   delete m_timerManager;
337   m_timerManager = NULL;
338
339   delete m_eventManager;
340   m_eventManager = NULL;
341
342 #ifdef WITH_INPUT_NDOF
343   delete m_ndofManager;
344   m_ndofManager = NULL;
345 #endif
346
347   return GHOST_kSuccess;
348 }
349
350 GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
351                                                     const GHOST_DisplaySetting &settings,
352                                                     const bool stereoVisual,
353                                                     const bool alphaBackground)
354 {
355   GHOST_GLSettings glSettings = {0};
356
357   if (stereoVisual)
358     glSettings.flags |= GHOST_glStereoVisual;
359   if (alphaBackground)
360     glSettings.flags |= GHOST_glAlphaBackground;
361
362   /* note: don't use getCurrentDisplaySetting() because on X11 we may
363    * be zoomed in and the desktop may be bigger than the viewport. */
364   GHOST_ASSERT(m_displayManager,
365                "GHOST_System::createFullScreenWindow(): invalid display manager");
366   // GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n");
367   *window = (GHOST_Window *)createWindow("",
368                                          0,
369                                          0,
370                                          settings.xPixels,
371                                          settings.yPixels,
372                                          GHOST_kWindowStateNormal,
373                                          GHOST_kDrawingContextTypeOpenGL,
374                                          glSettings,
375                                          true /* exclusive */);
376   return (*window == NULL) ? GHOST_kFailure : GHOST_kSuccess;
377 }
378
379 bool GHOST_System::useNativePixel(void)
380 {
381   m_nativePixel = true;
382   return 1;
383 }
384
385 void GHOST_System::useWindowFocus(const bool use_focus)
386 {
387   m_windowFocus = use_focus;
388 }
389
390 void GHOST_System::initDebug(bool is_debug_enabled)
391 {
392   m_is_debug_enabled = is_debug_enabled;
393 }
394
395 bool GHOST_System::isDebugEnabled()
396 {
397   return m_is_debug_enabled;
398 }