nux-1.14.0
|
00001 /* 00002 * Copyright 2010 Inalogic® Inc. 00003 * 00004 * This program is free software: you can redistribute it and/or modify it 00005 * under the terms of the GNU Lesser General Public License, as 00006 * published by the Free Software Foundation; either version 2.1 or 3.0 00007 * of the License. 00008 * 00009 * This program is distributed in the hope that it will be useful, but 00010 * WITHOUT ANY WARRANTY; without even the implied warranties of 00011 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 00012 * PURPOSE. See the applicable version of the GNU Lesser General Public 00013 * License for more details. 00014 * 00015 * You should have received a copy of both the GNU Lesser General Public 00016 * License along with this program. If not, see <http://www.gnu.org/licenses/> 00017 * 00018 * Authored by: Jay Taoko <jaytaoko@inalogic.com> 00019 * 00020 */ 00021 00022 00023 #include "Nux.h" 00024 #include "Layout.h" 00025 #include "NuxCore/Logger.h" 00026 #include "NuxGraphics/GraphicsEngine.h" 00027 #include "ClientArea.h" 00028 #include "WindowCompositor.h" 00029 #include "TimerProc.h" 00030 #include "SystemThread.h" 00031 #include "FloatingWindow.h" 00032 00033 #include "WindowThread.h" 00034 00035 namespace nux 00036 { 00037 namespace 00038 { 00039 logging::Logger logger("nux.windows.thread"); 00040 } 00041 00042 TimerFunctor *m_ScrollTimerFunctor; 00043 TimerHandle m_ScrollTimerHandler; 00044 00045 // Thread registration call. Hidden from the users. Implemented in Nux.cpp 00046 bool RegisterNuxThread (NThread *ThreadPtr); 00047 void UnregisterNuxThread (NThread *ThreadPtr); 00048 00049 #if (defined(NUX_OS_LINUX) || defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) && (!defined(NUX_DISABLE_GLIB_LOOP)) 00050 00051 static GMutex *gLibEventMutex = 0; 00052 static void 00053 nux_glib_threads_lock (void) 00054 { 00055 if (gLibEventMutex) 00056 g_mutex_lock (gLibEventMutex); 00057 } 00058 00059 static void 00060 nux_glib_threads_unlock (void) 00061 { 00062 if (gLibEventMutex) 00063 g_mutex_unlock (gLibEventMutex); 00064 } 00065 00066 struct NuxEventSource 00067 { 00068 GSource source; 00069 GPollFD event_poll_fd; 00070 }; 00071 00072 static gboolean 00073 nux_event_prepare (GSource *source, 00074 gint *timeout) 00075 { 00076 nux_glib_threads_lock(); 00077 00078 gboolean retval; 00079 *timeout = -1; 00080 #if defined(NUX_OS_WINDOWS) 00081 MSG msg; 00082 retval = PeekMessageW (&msg, NULL, 0, 0, PM_NOREMOVE) ? TRUE : FALSE; 00083 #elif defined(NUX_OS_LINUX) 00084 retval = GetGraphicsDisplay()->HasXPendingEvent () ? TRUE : FALSE; 00085 #else 00086 #error Not implemented. 00087 #endif 00088 00089 nux_glib_threads_unlock(); 00090 return retval; 00091 } 00092 00093 static gboolean 00094 nux_event_check (GSource *source) 00095 { 00096 nux_glib_threads_lock(); 00097 00098 gboolean retval; 00099 NuxEventSource *event_source = (NuxEventSource *) source; 00100 00101 if ( (event_source->event_poll_fd.revents & G_IO_IN) ) 00102 { 00103 #if defined(NUX_OS_WINDOWS) 00104 MSG msg; 00105 retval = PeekMessageW (&msg, NULL, 0, 0, PM_NOREMOVE) ? TRUE : FALSE; 00106 #elif defined(NUX_OS_LINUX) 00107 retval = GetGraphicsDisplay()->HasXPendingEvent () ? TRUE : FALSE; 00108 #else 00109 #error Not implemented. 00110 #endif 00111 } 00112 else 00113 retval = FALSE; 00114 00115 nux_glib_threads_unlock(); 00116 return retval; 00117 } 00118 00119 gboolean 00120 nux_event_dispatch (GSource *source, 00121 GSourceFunc callback, 00122 gpointer user_data) 00123 { 00124 nux_glib_threads_lock(); 00125 WindowThread *window_thread = NUX_STATIC_CAST (WindowThread *, user_data); 00126 t_u32 return_code = window_thread->ExecutionLoop (0); 00127 00128 if (return_code == 0 && !window_thread->IsEmbeddedWindow ()) 00129 { 00130 //g_source_destroy (source); 00131 //g_source_unref (source); 00132 g_main_loop_quit (window_thread->m_GLibLoop); 00133 } 00134 00135 nux_glib_threads_unlock(); 00136 return return_code || window_thread->IsEmbeddedWindow (); 00137 } 00138 00139 static GSourceFuncs event_funcs = 00140 { 00141 nux_event_prepare, 00142 nux_event_check, 00143 nux_event_dispatch, 00144 NULL 00145 }; 00146 00147 // Timeline source functions 00148 static gboolean 00149 nux_timeline_prepare (GSource *source, 00150 gint *timeout) 00151 { 00152 // right now we are assuming that we are vsynced, so that will handle syncronisation 00153 // we could guess how long we have to wait for the next frame but thats rather ugly 00154 // idealy we need some more api that ensures that timeline/event/relayout/draws are all in sync 00155 00156 *timeout = 0; 00157 return TRUE; 00158 } 00159 00160 static gboolean 00161 nux_timeline_check (GSource *source) 00162 { 00163 return TRUE; 00164 } 00165 00166 static gboolean 00167 nux_timeline_dispatch (GSource *source, 00168 GSourceFunc callback, 00169 gpointer user_data) 00170 { 00171 GTimeVal time_val; 00172 bool has_timelines_left = false; 00173 nux_glib_threads_lock(); 00174 g_source_get_current_time (source, &time_val); 00175 WindowThread *window_thread = NUX_STATIC_CAST (WindowThread *, user_data); 00176 00177 // pump the timelines 00178 has_timelines_left = window_thread->ProcessTimelines (&time_val); 00179 00180 if (!has_timelines_left) 00181 { 00182 // no timelines left on the stack so lets go ahead and remove the 00183 // master clock, to save on wakeups 00184 window_thread->StopMasterClock (); 00185 } 00186 00187 nux_glib_threads_unlock(); 00188 return TRUE; 00189 } 00190 00191 static GSourceFuncs timeline_funcs = 00192 { 00193 nux_timeline_prepare, 00194 nux_timeline_check, 00195 nux_timeline_dispatch, 00196 NULL 00197 }; 00198 00199 void WindowThread::InitGlibLoop() 00200 { 00201 static bool main_context_created = false; 00202 00203 GSource *source; 00204 00205 if (!IsEmbeddedWindow ()) 00206 { 00207 static bool gthread_initialized = false; 00208 00209 if (!gthread_initialized) 00210 g_thread_init (NULL); 00211 00212 gthread_initialized = true; 00213 00214 if (((m_GLibContext == 0) || (m_GLibLoop == 0)) && (main_context_created == false)) 00215 { 00216 //create a context 00217 m_GLibContext = g_main_context_default (); 00218 //create a main loop with context 00219 m_GLibLoop = g_main_loop_new (m_GLibContext, TRUE); 00220 } 00221 else 00222 { 00223 // Secondary physical windows goes in here 00224 //create a context 00225 m_GLibContext = g_main_context_new(); 00226 //create a main loop with context 00227 m_GLibLoop = g_main_loop_new (m_GLibContext, TRUE); 00228 } 00229 } 00230 00231 main_context_created = true; 00232 00233 gLibEventMutex = 0; //g_mutex_new(); 00234 00235 source = g_source_new (&event_funcs, sizeof (NuxEventSource) ); 00236 NuxEventSource *event_source = (NuxEventSource *) source; 00237 00238 g_source_set_priority (source, G_PRIORITY_DEFAULT); 00239 00240 #if defined(NUX_OS_WINDOWS) 00241 event_source->event_poll_fd.fd = G_WIN32_MSG_HANDLE; 00242 #elif defined(NUX_OS_LINUX) 00243 event_source->event_poll_fd.fd = ConnectionNumber (GetGraphicsDisplay()->GetX11Display() ); 00244 #else 00245 #error Not implemented. 00246 #endif 00247 00248 event_source->event_poll_fd.events = G_IO_IN; 00249 00250 g_source_add_poll (source, &event_source->event_poll_fd); 00251 g_source_set_can_recurse (source, TRUE); 00252 g_source_set_callback (source, 0, this, 0); 00253 00254 if (IsEmbeddedWindow ()) 00255 g_source_attach (source, NULL); 00256 else 00257 g_source_attach (source, m_GLibContext); 00258 00259 if (_Timelines->size () > 0) 00260 StartMasterClock (); 00261 00262 if (!IsEmbeddedWindow ()) 00263 { 00264 g_main_loop_run (m_GLibLoop); 00265 g_main_loop_unref (m_GLibLoop); 00266 } 00267 } 00268 00269 void WindowThread::StartMasterClock () 00270 { 00271 // if we are not embedded and don't have a context yet 00272 if (!IsEmbeddedWindow () && m_GLibContext == 0) 00273 return; 00274 00275 if (_MasterClock == NULL) 00276 { 00277 GTimeVal time_val; 00278 // make a source for our master clock 00279 _MasterClock = g_source_new (&timeline_funcs, sizeof (GSource)); 00280 00281 g_source_set_priority (_MasterClock, G_PRIORITY_DEFAULT + 10); 00282 g_source_set_callback (_MasterClock, 0, this, 0); 00283 g_source_set_can_recurse (_MasterClock, TRUE); 00284 00285 if (IsEmbeddedWindow ()) 00286 g_source_attach (_MasterClock, NULL); 00287 else if (m_GLibContext != 0) 00288 g_source_attach (_MasterClock, m_GLibContext); 00289 00290 00291 g_get_current_time (&time_val); 00292 _last_timeline_frame_time_sec = time_val.tv_sec; 00293 _last_timeline_frame_time_usec = time_val.tv_usec; 00294 } 00295 } 00296 00297 void WindowThread::StopMasterClock () 00298 { 00299 if (_MasterClock) 00300 { 00301 g_source_remove (g_source_get_id (_MasterClock)); 00302 _MasterClock = NULL; 00303 } 00304 } 00305 00306 void WindowThread::NuxMainLoopQuit () 00307 { 00308 // woo no more main loop! this is prolly bad for nux, so erm 00309 // FIXME!! - Jay take a look at this, make sure just quitting the mainloop 00310 // is an idea that makes sense (needed for testing) 00311 if (!IsEmbeddedWindow ()) 00312 g_main_loop_quit (m_GLibLoop); 00313 } 00314 00315 typedef struct 00316 { 00317 WindowThread *window_thread; 00318 t_u32 id; 00319 } TimeoutData; 00320 00321 gboolean nux_timeout_dispatch (gpointer user_data) 00322 { 00323 bool repeat = false; 00324 TimeoutData* dd = NUX_STATIC_CAST(TimeoutData*, user_data); 00325 00326 dd->window_thread->_inside_timer_loop = true; 00327 repeat = GetTimer().ExecTimerHandler(dd->id)? true : false; 00328 dd->window_thread->_inside_timer_loop = false; 00329 00330 if(dd->window_thread->IsEmbeddedWindow()) 00331 { 00332 dd->window_thread->RedrawRequested.emit(); 00333 } 00334 else 00335 { 00336 dd->window_thread->ExecutionLoop(0); 00337 } 00338 00339 if(!repeat) 00340 delete dd; 00341 00342 return repeat; 00343 } 00344 00345 t_u32 WindowThread::AddGLibTimeout(t_u32 duration) 00346 { 00347 if(IsEmbeddedWindow()) 00348 { 00349 TimeoutData* dd = new TimeoutData; 00350 dd->window_thread = this; 00351 dd->id = g_timeout_add (duration, nux_timeout_dispatch, dd); 00352 00353 return dd->id; 00354 } 00355 else 00356 { 00357 if((m_GLibContext == 0) || (m_GLibLoop == 0)) 00358 { 00359 LOG_WARNING(logger) << "Trying to set a timeout before GLib Context is created.\n" 00360 << logging::backtrace(); 00361 return 0; 00362 } 00363 00364 GSource *timeout_source; 00365 00366 //create a new time-out source 00367 timeout_source = g_timeout_source_new(duration); 00368 00369 TimeoutData* dd = new TimeoutData; 00370 dd->window_thread = this; 00371 dd->id = 0; 00372 //set the callback for this source 00373 g_source_set_callback(timeout_source, nux_timeout_dispatch, dd, NULL); 00374 00375 //attach source to context 00376 dd->id = g_source_attach(timeout_source, m_GLibContext); 00377 00378 return dd->id; 00379 } 00380 } 00381 #endif 00382 00383 NUX_IMPLEMENT_OBJECT_TYPE (WindowThread); 00384 00385 WindowThread::WindowThread (const TCHAR *WindowTitle, unsigned int width, unsigned int height, AbstractThread *Parent, bool Modal) 00386 : AbstractThread (Parent) 00387 , m_StartupWidth (width) 00388 , m_StartupHeight (height) 00389 , m_WindowTitle (WindowTitle) 00390 , m_WidgetInitialized (false) 00391 , m_WindowStyle (WINDOWSTYLE_NORMAL) 00392 , m_embedded_window (false) 00393 , m_size_configuration_event (false) 00394 , m_force_redraw (false) 00395 { 00396 // Thread specific objects 00397 _graphics_display = 0; 00398 m_window_compositor = 0; 00399 m_Painter = 0; 00400 m_TimerHandler = 0; 00401 m_Theme = 0; 00402 _main_layout = 0; 00403 _queue_main_layout = false; 00404 // Protection for ThreadCtor and ThreadDtor; 00405 m_ThreadCtorCalled = false; 00406 m_ThreadDtorCalled = false; 00407 00408 // 00409 m_bWaitForModalWindow = false; 00410 m_ModalWindowThread = 0; 00411 m_bIsModal = Modal; 00412 00413 _inside_layout_cycle = 0; 00414 _draw_requested_to_host_wm = false; 00415 m_bFirstDrawPass = true; 00416 00417 // The layout of the window is null. 00418 m_FrameRate = 0; 00419 m_FrameCounter = 0; 00420 m_FramePeriodeCounter = 0; 00421 m_PeriodeTime = 0; 00422 00423 _Timelines = new std::list<Timeline*> (); 00424 GTimeVal time_val; 00425 g_get_current_time (&time_val); 00426 _last_timeline_frame_time_sec = time_val.tv_sec; 00427 _last_timeline_frame_time_usec = time_val.tv_usec; 00428 _MasterClock = NULL; 00429 00430 #if (defined(NUX_OS_LINUX) || defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) && (!defined(NUX_DISABLE_GLIB_LOOP)) 00431 m_GLibLoop = 0; 00432 m_GLibContext = 0; 00433 #endif 00434 #if defined(NUX_OS_LINUX) 00435 _x11display = NULL; 00436 _ownx11display = false; 00437 #endif 00438 00439 _pending_wake_up_timer = false; 00440 _inside_main_loop = false; 00441 _inside_timer_loop = false; 00442 _async_wake_up_functor = new TimerFunctor(); 00443 _async_wake_up_functor->OnTimerExpired.connect (sigc::mem_fun (this, &WindowThread::AsyncWakeUpCallback) ); 00444 00445 00446 _fake_event_call_back = new TimerFunctor(); 00447 _fake_event_call_back->OnTimerExpired.connect (sigc::mem_fun (this, &WindowThread::ReadyFakeEventProcessing)); 00448 _ready_for_next_fake_event = true; 00449 _fake_event_mode = false; 00450 _processing_fake_event = false; 00451 _focused_area = NULL; 00452 } 00453 00454 WindowThread::~WindowThread() 00455 { 00456 g_source_remove_by_funcs_user_data (&event_funcs, this); 00457 00458 ThreadDtor(); 00459 std::list<Timeline*>::iterator li; 00460 for (li=_Timelines->begin (); li!=_Timelines->end (); ++li) 00461 { 00462 (*li)->UnReference (); 00463 } 00464 00465 delete _Timelines; 00466 delete _async_wake_up_functor; 00467 delete _fake_event_call_back; 00468 00469 #if defined(NUX_OS_LINUX) 00470 if (_x11display && _ownx11display) 00471 { 00472 XCloseDisplay(_x11display); 00473 } 00474 #endif 00475 } 00476 00477 void WindowThread::SetFocusedArea (Area *focused_area) 00478 { 00479 if (focused_area == _focused_area) 00480 return; 00481 00482 if (_focused_area != NULL) 00483 { 00484 _focused_area->SetFocused (false); 00485 00486 if (_focused_area_destroyed_con.empty () == false) 00487 { 00488 _focused_area_destroyed_con.disconnect (); 00489 } 00490 00491 } 00492 00493 _focused_area = focused_area; 00494 _focused_area_destroyed_con = focused_area->object_destroyed.connect (sigc::mem_fun (this, &WindowThread::OnFocusedAreaDestroyed)); 00495 00496 } 00497 00498 void WindowThread::OnFocusedAreaDestroyed (Object *object) 00499 { 00500 if (object == _focused_area) 00501 { 00502 _focused_area = NULL; 00503 } 00504 } 00505 00506 void WindowThread::AsyncWakeUpCallback (void* data) 00507 { 00508 GetTimer ().RemoveTimerHandler (_async_wake_up_timer); 00509 _pending_wake_up_timer = false; 00510 } 00511 00512 void WindowThread::SetFakeEventMode (bool enable) 00513 { 00514 _fake_event_mode = enable; 00515 } 00516 00517 bool WindowThread::InFakeEventMode () const 00518 { 00519 return _fake_event_mode; 00520 } 00521 00522 bool WindowThread::ReadyForNextFakeEvent () const 00523 { 00524 return _ready_for_next_fake_event; 00525 } 00526 00527 #if defined (NUX_OS_WINDOWS) 00528 bool WindowThread::PumpFakeEventIntoPipe (WindowThread* window_thread, INPUT *win_event) 00529 { 00530 if (!_fake_event_mode) 00531 { 00532 nuxDebugMsg (TEXT("[WindowThread::PumpFakeEventIntoPipe] Cannot register a fake event. Fake event mode is not enabled.")); 00533 return false; 00534 } 00535 00536 if (!_ready_for_next_fake_event) 00537 { 00538 nuxDebugMsg (TEXT("[WindowThread::PumpFakeEventIntoPipe] The fake event pipe is full. Only one fake event can be registered at any time.")); 00539 return false; 00540 } 00541 00542 _ready_for_next_fake_event = false; 00543 // _fake_event = *xevent; 00544 // _fake_event.xany.window = this->GetWindow ().GetWindowHandle (); 00545 _fake_event_timer = this->GetTimerHandler().AddTimerHandler (0, _fake_event_call_back, this, this); 00546 return true; 00547 } 00548 #elif defined (NUX_OS_LINUX) 00549 bool WindowThread::PumpFakeEventIntoPipe (WindowThread* window_thread, XEvent *xevent) 00550 { 00551 if (!_fake_event_mode) 00552 { 00553 nuxDebugMsg (TEXT("[WindowThread::PumpFakeEventIntoPipe] Cannot register a fake event. Fake event mode is not enabled.")); 00554 return false; 00555 } 00556 00557 if (!_ready_for_next_fake_event) 00558 { 00559 nuxDebugMsg (TEXT("[WindowThread::PumpFakeEventIntoPipe] The fake event pipe is full. Only one fake event can be registered at any time.")); 00560 return false; 00561 } 00562 00563 _ready_for_next_fake_event = false; 00564 _fake_event = *xevent; 00565 _fake_event.xany.window = this->GetWindow ().GetWindowHandle (); 00566 _fake_event_timer = this->GetTimerHandler().AddTimerHandler (0, _fake_event_call_back, this, this); 00567 return true; 00568 } 00569 #endif 00570 00571 void WindowThread::ReadyFakeEventProcessing (void* data) 00572 { 00573 nuxDebugMsg (TEXT("[WindowThread::ReadyFakeEventProcessing] Ready to process fake event.")); 00574 _processing_fake_event = true; 00575 } 00576 00577 long WindowThread::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00578 { 00579 if (m_bWaitForModalWindow) 00580 return TraverseInfo; 00581 00582 long ret = TraverseInfo; 00583 00584 if (_main_layout) 00585 ret = _main_layout->ProcessEvent (ievent, ret, ProcessEventInfo); 00586 00587 return ret; 00588 } 00589 00590 void WindowThread::ProcessDraw (GraphicsEngine &GfxContext, bool force_draw) 00591 { 00592 if (_main_layout) 00593 { 00594 bool dirty = _main_layout->IsQueuedForDraw (); 00595 00596 if (dirty) 00597 { 00598 // A main layout re computation has happen. It was not initiated physically by resizing the window. We need to draw the background to 00599 // clean any dirty region. 00600 int buffer_width = GfxContext.GetWindowWidth(); 00601 int buffer_height = GfxContext.GetWindowHeight(); 00602 GetPainter().PaintBackground (GfxContext, Geometry (0, 0, buffer_width, buffer_height) ); 00603 } 00604 00605 _main_layout->ProcessDraw (GfxContext, force_draw || dirty); 00606 } 00607 } 00608 00609 void WindowThread::RequestRedraw() 00610 { 00611 _draw_requested_to_host_wm = true; 00612 RedrawRequested.emit(); 00613 00614 if (!IsEmbeddedWindow()) 00615 { 00616 // If the system is not in embedded mode and an asynchronous request for a Draw is made, 00617 // and the system is not in a timer processing cycle (always followed by a draw cycle) 00618 // or not in the event processing cycle (also followed by a draw cycle), then we set a 0 delay 00619 // timer that will wake up the system and initiate a draw cycle. 00620 if ((_inside_main_loop == false) && (_inside_timer_loop == false) && (_pending_wake_up_timer == false)) 00621 { 00622 _pending_wake_up_timer = true; 00623 _async_wake_up_timer = GetTimer().AddTimerHandler (0, _async_wake_up_functor, this); 00624 } 00625 } 00626 } 00627 00628 void WindowThread::ClearRedrawFlag() 00629 { 00630 _draw_requested_to_host_wm = false; 00631 } 00632 00633 bool WindowThread::IsRedrawNeeded() const 00634 { 00635 return _draw_requested_to_host_wm; 00636 } 00637 00638 Layout* WindowThread::GetMainLayout() 00639 { 00640 return _main_layout; 00641 } 00642 00643 void WindowThread::SetLayout (Layout *layout) 00644 { 00645 _main_layout = layout; 00646 00647 if (_main_layout) 00648 { 00649 int w = _graphics_display->GetGraphicsEngine()->GetContextWidth(); 00650 int h = _graphics_display->GetGraphicsEngine()->GetContextHeight(); 00651 00652 _main_layout->Reference(); 00653 _main_layout->SetStretchFactor (1); 00654 00655 StartLayoutCycle (); 00656 _main_layout->SetGeometry (0, 0, w, h); 00657 _main_layout->ComputeLayout2(); 00658 _main_layout->ComputePosition2 (0, 0); 00659 StopLayoutCycle (); 00660 00661 RemoveQueuedLayout (); 00662 } 00663 } 00664 00665 void WindowThread::QueueMainLayout () 00666 { 00667 _queue_main_layout = true; 00668 RequestRedraw (); 00669 } 00670 00671 void WindowThread::ReconfigureLayout () 00672 { 00673 int w = _graphics_display->GetGraphicsEngine()->GetWindowWidth(); 00674 int h = _graphics_display->GetGraphicsEngine()->GetWindowHeight(); 00675 00676 if (_main_layout) 00677 { 00678 StartLayoutCycle (); 00679 _main_layout->SetGeometry (0, 0, w, h); 00680 _main_layout->ComputeLayout2(); 00681 _main_layout->ComputePosition2 (0, 0); 00682 StopLayoutCycle (); 00683 } 00684 00685 RemoveQueuedLayout (); 00686 _queue_main_layout = false; 00687 } 00688 00689 bool WindowThread::QueueObjectLayout (Area *area) 00690 { 00691 NUX_RETURN_VALUE_IF_NULL (area, false); 00692 00693 std::list<Area *>::iterator it; 00694 it = find (_queued_layout_list.begin(), _queued_layout_list.end(), area); 00695 if (it == _queued_layout_list.end() ) 00696 { 00697 _queued_layout_list.push_back (area); 00698 } 00699 00700 return true; 00701 } 00702 00703 void WindowThread::AddObjectToRefreshList (Area *area) 00704 { 00705 QueueObjectLayout (area); 00706 } 00707 00708 bool WindowThread::RemoveObjectFromLayoutQueue (Area *area) 00709 { 00710 NUX_RETURN_VALUE_IF_NULL (area, false); 00711 00712 std::list<Area *>::iterator it; 00713 it = find (_queued_layout_list.begin(), _queued_layout_list.end(), area); 00714 00715 if (it != _queued_layout_list.end() ) 00716 { 00717 _queued_layout_list.erase (it); 00718 return true; 00719 } 00720 return false; 00721 } 00722 00723 bool WindowThread::RemoveObjectFromRefreshList (Area *area) 00724 { 00725 return RemoveObjectFromLayoutQueue (area); 00726 } 00727 00728 void WindowThread::RemoveQueuedLayout() 00729 { 00730 _queued_layout_list.clear(); 00731 } 00732 00733 void WindowThread::ComputeQueuedLayout () 00734 { 00735 StartLayoutCycle (); 00736 std::list<Area *>::iterator it; 00737 00738 for (it = _queued_layout_list.begin(); it != _queued_layout_list.end(); it++) 00739 { 00740 Area *area = *it; 00741 00742 if (area->Type().IsDerivedFromType (View::StaticObjectType) ) 00743 { 00744 View *view = NUX_STATIC_CAST (View *, area); 00745 00746 if (!view->CanBreakLayout ()) 00747 view->QueueDraw (); 00748 } 00749 else if (area->Type().IsDerivedFromType (Layout::StaticObjectType) ) 00750 { 00751 Layout *layout = NUX_STATIC_CAST (Layout *, area); 00752 layout->QueueDraw (); 00753 } 00754 else 00755 { 00756 continue; 00757 } 00758 00759 (*it)->ComputeLayout2(); 00760 } 00761 00762 StopLayoutCycle (); 00763 00764 RemoveQueuedLayout (); 00765 } 00766 00767 void WindowThread::RefreshLayout() 00768 { 00769 ComputeQueuedLayout (); 00770 } 00771 00772 void WindowThread::StartLayoutCycle () 00773 { 00774 _inside_layout_cycle = true; 00775 } 00776 00777 void WindowThread::StopLayoutCycle () 00778 { 00779 _inside_layout_cycle = false; 00780 } 00781 00782 00783 bool WindowThread::IsInsideLayoutCycle () const 00784 { 00785 return _inside_layout_cycle; 00786 } 00787 00788 void WindowThread::ComputeElementLayout (Area *area, bool recurse_to_top_level_layout) 00789 { 00790 NUX_RETURN_IF_NULL (area); 00791 00792 bool alreadyComputingLayout = IsInsideLayoutCycle(); 00793 00794 if ((!alreadyComputingLayout) && (!recurse_to_top_level_layout)) 00795 { 00796 // When computing the layout, setting the size of widgets may cause the system to recurse 00797 // upward an look for the up most container which size is affected by its this area. 00798 // This happens in Area::InitiateResizeLayout (); 00799 // The search upward is not done if we are already in a layout cycle. 00800 StartLayoutCycle (); 00801 } 00802 00803 if (area->Type().IsDerivedFromType (View::StaticObjectType)) 00804 { 00805 View *ic = NUX_STATIC_CAST (View *, area); 00806 ic->QueueDraw (); 00807 } 00808 else if (area->Type().IsDerivedFromType (Layout::StaticObjectType)) 00809 { 00810 Layout *layout = NUX_STATIC_CAST (Layout *, area); 00811 layout->QueueDraw (); 00812 } 00813 00814 area->ComputeLayout2(); 00815 00816 if (!alreadyComputingLayout) 00817 StopLayoutCycle (); 00818 } 00819 00820 void WindowThread::AddTimeline (Timeline *timeline) 00821 { 00822 _Timelines->push_back (timeline); 00823 _Timelines->unique (); 00824 StartMasterClock (); 00825 } 00826 00827 void WindowThread::RemoveTimeline (Timeline *timeline) 00828 { 00829 _Timelines->remove (timeline); 00830 if (_Timelines->size () == 0) 00831 { 00832 StopMasterClock (); 00833 } 00834 } 00835 00836 unsigned int WindowThread::Run (void *arg) 00837 { 00838 if (m_UserInitFunc && (m_WidgetInitialized == false) ) 00839 { 00840 (*m_UserInitFunc) (this, m_InitData); 00841 m_WidgetInitialized = true; 00842 } 00843 00844 RunUserInterface(); 00845 00846 return 0; 00847 } 00848 00849 void WindowThread::RunUserInterface() 00850 { 00851 if (IsEmbeddedWindow ()) 00852 { 00853 m_window_compositor->FormatRenderTargets (_graphics_display->GetWindowWidth(), _graphics_display->GetWindowHeight() ); 00854 InitGlibLoop (); 00855 return; 00856 } 00857 else 00858 { 00859 _graphics_display->ShowWindow(); 00860 } 00861 // Called the first time so we can initialize the size of the render targets 00862 // At this stage, the size of the window is known. 00863 m_window_compositor->FormatRenderTargets (_graphics_display->GetWindowWidth(), _graphics_display->GetWindowHeight() ); 00864 00865 while (GetThreadState() != THREADSTOP) 00866 { 00867 if (GetThreadState() == THREADRUNNING) 00868 { 00869 #if (defined(NUX_OS_LINUX) || defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) && (!defined(NUX_DISABLE_GLIB_LOOP)) 00870 InitGlibLoop(); 00871 #else 00872 ExecutionLoop(); 00873 #endif 00874 00875 if (m_Parent) 00876 { 00877 if (m_Parent->Type().IsObjectType (SystemThread::StaticObjectType) ) 00878 static_cast<SystemThread *> (m_Parent)->ChildHasFinished (this); 00879 00880 if (m_Parent->Type().IsObjectType (WindowThread::StaticObjectType) ) 00881 static_cast<WindowThread *> (m_Parent)->ChildHasFinished (this); 00882 00883 { 00884 SetThreadState (THREADSTOP); 00885 TerminateAllChildThread(); 00886 } 00887 } 00888 else 00889 { 00890 SetThreadState (THREADSTOP); 00891 TerminateAllChildThread(); 00892 } 00893 } 00894 else 00895 { 00896 // Do not sleep. Just return and let the GraphicsDisplay::SwapBuffer do the sleep if necessary. 00897 } 00898 } 00899 00900 return; 00901 } 00902 00903 extern EventToNameStruct EventToName[]; 00904 00905 #if (defined(NUX_OS_LINUX) || defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) && (!defined(NUX_DISABLE_GLIB_LOOP)) 00906 t_u32 WindowThread::ExecutionLoop (t_u32 timer_id) 00907 #else 00908 t_u32 WindowThread::ExecutionLoop() 00909 #endif 00910 { 00911 IEvent event; 00912 00913 if (!IsEmbeddedWindow() && GetWindow().IsPauseThreadGraphicsRendering() ) 00914 { 00915 // Do not sleep. Just return and let the GraphicsDisplay::SwapBuffer do the sleep if necessary. 00916 return 0; 00917 } 00918 00919 WindowThread *Application = GetWindowThread (); 00920 00921 #if (!defined(NUX_OS_LINUX) && !defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) || defined(NUX_DISABLE_GLIB_LOOP) 00922 while (true) 00923 #endif 00924 { 00925 _inside_main_loop = true; 00926 if(Application->m_bFirstDrawPass) 00927 { 00928 GetTimer().StartEarlyTimerObjects (); 00929 } 00930 00931 memset(&event, 0, sizeof(IEvent)); 00932 GetWindow().GetSystemEvent(&event); 00933 00934 if ((event.e_event == NUX_DND_ENTER_WINDOW) || 00935 (event.e_event == NUX_DND_LEAVE_WINDOW)) 00936 { 00937 GetWindowCompositor().ResetDnDArea(); 00938 } 00939 00940 // Call event inspectors. 00941 CallEventInspectors (&event); 00942 00943 #if defined(NUX_OS_LINUX) 00944 // Automation and fake event inputs 00945 if (_fake_event_mode && _processing_fake_event) 00946 { 00947 // Cancel the real X event and inject the fake event instead. This is wrong and should be improved. 00948 memset(&event, 0, sizeof(IEvent)); 00949 00950 GetWindow().InjectXEvent(&event, _fake_event); 00951 00952 if (event.e_event == NUX_MOUSE_PRESSED) 00953 { 00954 nuxDebugMsg (TEXT("[WindowThread::ExecutionLoop] Fake Event: Mouse Down.")); 00955 } 00956 else if (event.e_event == NUX_MOUSE_RELEASED) 00957 { 00958 nuxDebugMsg (TEXT("[WindowThread::ExecutionLoop] Fake Event: Mouse Up.")); 00959 } 00960 } 00961 else if (_fake_event_mode) 00962 { 00963 // In fake event mode we don't allow X mouse up/down events. 00964 if ((event.e_event == NUX_MOUSE_PRESSED) || (event.e_event == NUX_MOUSE_RELEASED)) 00965 { 00966 event.e_event = NUX_NO_EVENT; 00967 } 00968 } 00969 #endif 00970 00971 if((event.e_event == NUX_TERMINATE_APP) || (this->GetThreadState() == THREADSTOP)) 00972 { 00973 return 0; 00974 } 00975 00976 if (IsEmbeddedWindow () && (event.e_event == NUX_SIZE_CONFIGURATION)) 00977 m_size_configuration_event = true; 00978 00979 int w, h; 00980 // Call gGfx_OpenGL.getWindowSize after the gGfx_OpenGL.get_event. 00981 // Otherwise, w and h may not be correct for the current frame if a resizing happened. 00982 GetWindow().GetWindowSize(w, h); 00983 00984 if((event.e_event == NUX_MOUSE_PRESSED) || 00985 (event.e_event == NUX_MOUSE_RELEASED) || 00986 (event.e_event == NUX_MOUSE_DOUBLECLICK) || 00987 (event.e_event == NUX_MOUSE_MOVE) || 00988 (event.e_event == NUX_SIZE_CONFIGURATION) || 00989 (event.e_event == NUX_KEYDOWN) || 00990 (event.e_event == NUX_KEYUP) || 00991 (event.e_event == NUX_WINDOW_CONFIGURATION) || 00992 (event.e_event == NUX_WINDOW_ENTER_FOCUS) || 00993 (event.e_event == NUX_WINDOW_EXIT_FOCUS) || 00994 (event.e_event == NUX_WINDOW_MOUSELEAVE) || 00995 (event.e_event == NUX_DND_MOVE) || 00996 (event.e_event == NUX_DND_DROP) || 00997 (event.e_event == NUX_DND_ENTER) || 00998 (event.e_event == NUX_DND_LEAVE) || 00999 (event.e_event == NUX_MOUSE_WHEEL)) 01000 { 01001 //DISPATCH EVENT HERE 01002 //event.Application = Application; 01003 m_window_compositor->ProcessEvent(event); 01004 } 01005 01006 if(event.e_event == NUX_SIZE_CONFIGURATION) 01007 { 01008 if(!GetWindow().isWindowMinimized()) 01009 { 01010 GetWindow().SetViewPort(0, 0, event.width, event.height); 01011 ReconfigureLayout (); 01012 m_window_compositor->FormatRenderTargets(event.width, event.height); 01013 } 01014 m_window_compositor->FloatingAreaConfigureNotify(event.width, event.height); 01015 m_size_configuration_event = true; 01016 } 01017 01018 // Some action may have caused layouts and areas to request a recompute. 01019 // Process them here before the Draw section. 01020 if(!GetWindow().isWindowMinimized() && !IsEmbeddedWindow ()) 01021 { 01022 if (_queue_main_layout) 01023 { 01024 ReconfigureLayout (); 01025 } 01026 else 01027 { 01028 // Compute the layouts that have been queued. 01029 ComputeQueuedLayout (); 01030 } 01031 } 01032 01033 _inside_main_loop = false; 01034 01035 // #if (defined(NUX_OS_LINUX) || defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) && (!defined(NUX_DISABLE_GLIB_LOOP)) 01036 // GetTimer().ExecTimerHandler (timer_id); 01037 // #else 01038 // GetTimer().ExecTimerHandler(); 01039 // #endif 01040 01041 01042 if (!GetWindow().IsPauseThreadGraphicsRendering() || IsEmbeddedWindow ()) 01043 { 01044 bool SwapGLBuffer = false; 01045 01046 // Warn the host window manager to initiate a draw cycle. 01047 bool request_draw_cycle_to_host_wm = false; 01048 01049 if (Application->m_bFirstDrawPass) 01050 { 01051 if (IsEmbeddedWindow ()) 01052 { 01053 request_draw_cycle_to_host_wm = true; 01054 m_force_redraw = true; 01055 } 01056 else 01057 { 01058 m_window_compositor->Draw (m_size_configuration_event, true); 01059 } 01060 Application->m_bFirstDrawPass = false; 01061 } 01062 else 01063 { 01064 bool b = (event.e_event == NUX_MOUSE_PRESSED) || 01065 (event.e_event == NUX_MOUSE_RELEASED) || 01066 (event.e_event == NUX_MOUSE_DOUBLECLICK) || 01067 //(event.e_event == NUX_MOUSE_MOVE) || 01068 (event.e_event == NUX_SIZE_CONFIGURATION) || 01069 (event.e_event == NUX_KEYDOWN) || 01070 (event.e_event == NUX_KEYUP) || 01071 (event.e_event == NUX_WINDOW_CONFIGURATION) || 01072 (event.e_event == NUX_WINDOW_ENTER_FOCUS) || 01073 (event.e_event == NUX_WINDOW_EXIT_FOCUS) || 01074 (event.e_event == NUX_WINDOW_DIRTY); 01075 01076 if (b && m_window_compositor->IsTooltipActive() ) 01077 { 01078 // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. 01079 m_window_compositor->CancelTooltip(); 01080 b |= true; 01081 } 01082 01083 if (!m_window_compositor->ValidateMouseInsideTooltipArea (event.e_x, event.e_y) && m_window_compositor->IsTooltipActive() ) 01084 { 01085 // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. 01086 m_window_compositor->CancelTooltip(); 01087 b |= true; 01088 } 01089 01090 if (b || IsRedrawNeeded()) 01091 { 01092 if (IsEmbeddedWindow ()) 01093 { 01094 request_draw_cycle_to_host_wm = true; 01095 } 01096 else 01097 { 01098 m_window_compositor->Draw (m_size_configuration_event, false); 01099 } 01100 SwapGLBuffer = true; 01101 } 01102 else if (m_window_compositor->GetWidgetDrawingOverlay() != 0) 01103 { 01104 if (IsEmbeddedWindow ()) 01105 { 01106 request_draw_cycle_to_host_wm = true; 01107 } 01108 else 01109 { 01110 m_window_compositor->Draw (m_size_configuration_event, false); 01111 } 01112 SwapGLBuffer = false; 01113 } 01114 01115 } 01116 01117 if (!IsEmbeddedWindow ()) 01118 { 01119 if (SwapGLBuffer) 01120 { 01121 // Something was rendered! Swap the rendering buffer! 01122 GetWindow().SwapBuffer (true); 01123 } 01124 01125 float frame_time = GetWindow().GetFrameTime(); 01126 01127 #if (!defined(NUX_OS_LINUX) && !defined(NUX_USE_GLIB_LOOP_ON_WINDOWS)) || defined(NUX_DISABLE_GLIB_LOOP) 01128 01129 // When we are not using the glib loop, we do sleep the thread ourselves if it took less that 16ms to render. 01130 if (16.6f - frame_time > 0) 01131 { 01132 SleepForMilliseconds (16.6f - frame_time); 01133 } 01134 #endif 01135 // The frame rate calculation below is only reliable when we are constantly rendering. 01136 // Otherwise the frame rate drops, which does not mean that we are the performance is bad. 01137 // What is happening is that rendering occurs only when there is something to render. 01138 // If nothing is happening, the application sleeps. 01139 GetWindow().ResetFrameTime(); 01140 m_PeriodeTime += frame_time; 01141 01142 m_FrameCounter++; 01143 m_FramePeriodeCounter++; 01144 01145 if (m_FramePeriodeCounter >= 10) 01146 { 01147 m_FrameRate = m_FramePeriodeCounter * 1000.0f / m_PeriodeTime; 01148 m_PeriodeTime = 0.0f; 01149 m_FramePeriodeCounter = 0; 01150 } 01151 01152 ClearRedrawFlag (); 01153 GetWindowThread ()->GetGraphicsEngine().ResetStats(); 01154 } 01155 else if (IsEmbeddedWindow () && (_draw_requested_to_host_wm == false) && request_draw_cycle_to_host_wm) 01156 { 01157 RequestRedraw (); 01158 } 01159 m_size_configuration_event = false; 01160 } 01161 } 01162 01163 #if defined(NUX_OS_LINUX) 01164 // Automation and fake event inputs 01165 if (_processing_fake_event) 01166 { 01167 _processing_fake_event = false; 01168 _ready_for_next_fake_event = true; 01169 } 01170 #endif 01171 01172 return 1; 01173 } 01174 01175 unsigned int SpawnThread (NThread &thread) 01176 { 01177 return 0; 01178 } 01179 01180 void WindowThread::AddChildThread (NThread *window) 01181 { 01182 nuxAssert (window); 01183 std::list<NThread *>::iterator it; 01184 it = find (m_ChildThread.begin(), m_ChildThread.end(), window); 01185 01186 if (it == m_ChildThread.end() ) 01187 { 01188 m_ChildThread.push_back (window); 01189 } 01190 } 01191 01192 void WindowThread::RemoveChildThread (NThread *window) 01193 { 01194 nuxAssert (window); 01195 std::list<NThread *>::iterator it; 01196 it = find (m_ChildThread.begin(), m_ChildThread.end(), window); 01197 01198 if (it != m_ChildThread.end() ) 01199 { 01200 m_ChildThread.erase (it); 01201 } 01202 } 01203 01204 void WindowThread::ChildHasFinished (NThread *thread) 01205 { 01206 RemoveChildThread (thread); 01207 01208 if (thread->Type().IsObjectType (WindowThread::StaticObjectType) ) 01209 { 01210 SuspendChildGraphics (static_cast<WindowThread *> (thread) ); 01211 } 01212 01213 thread->SetThreadState (THREADSTOP); 01214 } 01215 01216 void WindowThread::TerminateAllChildThread() 01217 { 01218 std::list<NThread *>::iterator it; 01219 01220 for (it = m_ChildThread.begin(); it != m_ChildThread.end(); it++) 01221 { 01222 (*it)->SetThreadState (THREADSTOP); 01223 } 01224 01225 m_ChildThread.clear(); 01226 } 01227 01228 ThreadState WindowThread::Start ( void *arg ) 01229 { 01230 if (!m_Parent) 01231 { 01232 return NThread::Start(); 01233 } 01234 else 01235 { 01236 if (m_Parent->Type().IsObjectType (SystemThread::StaticObjectType) ) 01237 return static_cast<SystemThread *> (m_Parent)->StartChildThread (this, true); 01238 else if (m_Parent->Type().IsObjectType (WindowThread::StaticObjectType) ) 01239 return static_cast<WindowThread *> (m_Parent)->StartChildThread (this, true); 01240 01241 nuxAssertMsg (0, TEXT ("[WindowThread::Start] This should not happen.") ); 01242 return THREAD_START_ERROR; 01243 } 01244 } 01245 01246 ThreadState WindowThread::StartChildThread (NThread *thread, bool Modal) 01247 { 01248 if (m_bWaitForModalWindow) 01249 { 01250 // This window is already waiting for a modal window. It cannot start another windows. 01251 return thread->GetThreadState(); 01252 } 01253 01254 ThreadState state = thread->NThread::Start(); 01255 //if(state == THREADRUNNING) 01256 { 01257 if (thread->Type().IsObjectType (WindowThread::StaticObjectType) ) 01258 { 01259 // While the child window is being created, the rendering is paused. 01260 // This is necessary to active OpenGL objects context sharing. 01261 // Cancel the pause by sending the message NUX_THREADMSG_START_RENDERING to this thread. 01262 //GetWindow().PauseThreadGraphicsRendering(); 01263 01264 if (static_cast<WindowThread *> (thread)->m_bIsModal) 01265 { 01266 DisableMouseKeyboardInput(); 01267 m_ModalWindowThread = static_cast<WindowThread *> (thread); 01268 // std::list<NThread*>::iterator it; 01269 // for(it = m_ChildThread.begin(); it != m_ChildThread.end(); it++) 01270 // { 01271 // static_cast<WindowThread*>(*it)->m_bWaitForModalWindow = true; 01272 // // WIN32: Disable Mouse and Keyboard inputs for all windows child of this window 01273 // ::EnableWindow(static_cast<WindowThread*>(*it)->_graphics_display->GetWindowHandle(), FALSE); 01274 // } 01275 // // WIN32 01276 // ::EnableWindow(_graphics_display->GetWindowHandle(), FALSE); 01277 // m_bWaitForModalWindow = true; 01278 } 01279 01280 static_cast<WindowThread *> (thread)->m_bWaitForModalWindow = false; 01281 01282 AddChildThread (thread); 01283 } 01284 } 01285 return state; 01286 } 01287 01288 ThreadState WindowThread::SuspendChildGraphics (WindowThread *thread) 01289 { 01290 if (m_bWaitForModalWindow) 01291 { 01292 if (m_ModalWindowThread != thread) 01293 { 01294 nuxAssertMsg (0, TEXT ("[WindowThread::SuspendChildGraphics] cannot supend thread that is not the modal window.") ); 01295 return thread->GetThreadState(); 01296 } 01297 } 01298 01299 ThreadState state = thread->GetThreadState(); 01300 01301 if (m_bWaitForModalWindow) 01302 { 01303 m_ModalWindowThread = 0; 01304 01305 EnableMouseKeyboardInput(); 01306 // std::list<NThread*>::iterator it; 01307 // for(it = m_ChildThread.begin(); it != m_ChildThread.end(); it++) 01308 // { 01309 // static_cast<WindowThread*>(*it)->m_bWaitForModalWindow = false; 01310 // 01311 // // WIN32 01312 // ::EnableWindow(static_cast<WindowThread*>(*it)->_graphics_display->GetWindowHandle(), TRUE); 01313 // } 01314 } 01315 01316 // WIN32 01317 #if defined(NUX_OS_WINDOWS) 01318 ::EnableWindow (_graphics_display->GetWindowHandle(), TRUE); 01319 #elif defined(NUX_OS_LINUX) 01320 01321 #endif 01322 return state; 01323 } 01324 01325 bool WindowThread::ProcessTimelines (GTimeVal *frame_time) 01326 { 01327 // go through our timelines and tick them 01328 // return true if we still have active timelines 01329 01330 long msecs; 01331 msecs = (frame_time->tv_sec - _last_timeline_frame_time_sec) * 1000 + 01332 (frame_time->tv_usec - _last_timeline_frame_time_usec) / 1000; 01333 01334 if (msecs < 0) 01335 { 01336 _last_timeline_frame_time_sec = frame_time->tv_sec; 01337 _last_timeline_frame_time_usec = frame_time->tv_usec; 01338 return true; 01339 } 01340 01341 if (msecs > 0) 01342 { 01343 _last_timeline_frame_time_sec += msecs / 1000; 01344 _last_timeline_frame_time_usec += msecs * 1000; 01345 } 01346 01347 std::list<Timeline*>::iterator li; 01348 std::list<Timeline*> timelines_copy; 01349 01350 for (li=_Timelines->begin (); li!=_Timelines->end (); ++li) 01351 { 01352 (*li)->Reference (); 01353 timelines_copy.push_back ((*li)); 01354 } 01355 01356 for(li=timelines_copy.begin(); li!=timelines_copy.end(); ++li) 01357 { 01358 (*li)->DoTick (msecs); 01359 } 01360 01361 // unreference again 01362 for (li=timelines_copy.begin (); li!=timelines_copy.end (); ++li) 01363 (*li)->UnReference (); 01364 01365 // return if we have any timelines left 01366 return (_Timelines->size () != 0); 01367 } 01368 01369 void WindowThread::EnableMouseKeyboardInput() 01370 { 01371 std::list<NThread *>::iterator it; 01372 01373 for (it = m_ChildThread.begin(); it != m_ChildThread.end(); it++) 01374 { 01375 if (NUX_STATIC_CAST (WindowThread *, *it)->Type().IsObjectType (WindowThread::StaticObjectType) ) 01376 { 01377 NUX_STATIC_CAST (WindowThread *, *it)->EnableMouseKeyboardInput(); 01378 } 01379 } 01380 01381 // WIN32: Enable Mouse and Keyboard inputs for all windows child of this window 01382 #if defined(NUX_OS_WINDOWS) 01383 ::EnableWindow (_graphics_display->GetWindowHandle(), TRUE); 01384 #elif defined(NUX_OS_LINUX) 01385 01386 #endif 01387 m_bWaitForModalWindow = false; 01388 } 01389 01390 void WindowThread::DisableMouseKeyboardInput() 01391 { 01392 std::list<NThread *>::iterator it; 01393 01394 for (it = m_ChildThread.begin(); it != m_ChildThread.end(); it++) 01395 { 01396 if (NUX_STATIC_CAST (WindowThread *, *it)->Type().IsObjectType (WindowThread::StaticObjectType) ) 01397 { 01398 NUX_STATIC_CAST (WindowThread *, *it)->DisableMouseKeyboardInput(); 01399 } 01400 } 01401 01402 // WIN32: Disable Mouse and Keyboard inputs for all windows child of this window 01403 #if defined(NUX_OS_WINDOWS) 01404 ::EnableWindow (_graphics_display->GetWindowHandle(), FALSE); 01405 #elif defined(NUX_OS_LINUX) 01406 01407 #endif 01408 m_bWaitForModalWindow = true; 01409 } 01410 01411 void WindowThread::TerminateThread() 01412 { 01413 SetThreadState (THREADSTOP); 01414 } 01415 01416 bool WindowThread::ThreadCtor() 01417 { 01418 nuxAssertMsg (m_ThreadCtorCalled == false, TEXT ("[WindowThread::ThreadCtor] ThreadCtor should not be called more than once.") ); 01419 NUX_RETURN_VALUE_IF_TRUE (m_ThreadCtorCalled, true); 01420 01421 #if defined(NUX_OS_WINDOWS) 01422 SetWin32ThreadName (GetThreadId(), m_WindowTitle.GetTCharPtr() ); 01423 #endif 01424 01425 if (RegisterNuxThread (this) == FALSE) 01426 { 01427 nuxDebugMsg (TEXT ("[WindowThread::ThreadCtor] Failed to register the WindowThread.") ); 01428 return false; 01429 } 01430 01431 inlSetThreadLocalStorage (ThreadLocal_InalogicAppImpl, this); 01432 GraphicsDisplay *ParentWindow = 0; 01433 01434 if (m_Parent && static_cast<WindowThread *> (m_Parent)->Type().IsObjectType (WindowThread::StaticObjectType) ) 01435 { 01436 ParentWindow = &static_cast<WindowThread *> (m_Parent)->GetWindow(); 01437 } 01438 else 01439 { 01440 ParentWindow = 0; 01441 } 01442 01443 _graphics_display = gGLWindowManager.CreateGLWindow (m_WindowTitle.GetTCharPtr(), m_StartupWidth, m_StartupHeight, m_WindowStyle, ParentWindow, false); 01444 01445 if (_graphics_display == 0) 01446 { 01447 nuxDebugMsg (TEXT ("[WindowThread::ThreadCtor] Failed to create the window.") ); 01448 return false; 01449 } 01450 01451 if (m_Parent && m_Parent->Type().IsObjectType (WindowThread::StaticObjectType) ) 01452 { 01453 // Cancel the effect of PauseThreadGraphicsRendering on the parent window. 01454 //PostThreadMessage(m_Parent->GetThreadId(), NUX_THREADMSG_START_RENDERING, (UINT_PTR)((void*)this), 0); 01455 } 01456 01457 m_Painter = new BasePainter(); 01458 m_TimerHandler = new TimerHandler(); 01459 m_window_compositor = new WindowCompositor; 01460 01461 SetThreadState (THREADRUNNING); 01462 m_ThreadCtorCalled = true; 01463 01464 return true; 01465 } 01466 01467 #if defined(NUX_OS_WINDOWS) 01468 bool WindowThread::ThreadCtor (HWND WindowHandle, HDC WindowDCHandle, HGLRC OpenGLRenderingContext) 01469 { 01470 nuxAssertMsg (m_ThreadCtorCalled == false, TEXT ("[WindowThread::ThreadCtor] ThreadCtor should not be called more than once.") ); 01471 NUX_RETURN_VALUE_IF_TRUE (m_ThreadCtorCalled, true); 01472 01473 #if defined(NUX_OS_WINDOWS) 01474 SetWin32ThreadName (GetThreadId(), m_WindowTitle.GetTCharPtr() ); 01475 #endif 01476 01477 if (RegisterNuxThread (this) == FALSE) 01478 { 01479 nuxDebugMsg (TEXT ("[WindowThread::ThreadCtor] Failed to register the WindowThread.") ); 01480 return false; 01481 } 01482 01483 inlSetThreadLocalStorage (ThreadLocal_InalogicAppImpl, this); 01484 GraphicsDisplay *ParentWindow = 0; 01485 01486 if (m_Parent && static_cast<WindowThread *> (m_Parent)->Type().IsObjectType (WindowThread::StaticObjectType) ) 01487 { 01488 ParentWindow = &static_cast<WindowThread *> (m_Parent)->GetWindow(); 01489 } 01490 else 01491 { 01492 ParentWindow = 0; 01493 } 01494 01495 _graphics_display = gGLWindowManager.CreateFromForeignWindow (WindowHandle, WindowDCHandle, OpenGLRenderingContext); 01496 01497 if (_graphics_display == 0) 01498 { 01499 nuxDebugMsg (TEXT ("[WindowThread::ThreadCtor] Failed to create the window.") ); 01500 return false; 01501 } 01502 01503 if (m_Parent && m_Parent->Type().IsObjectType (WindowThread::StaticObjectType) ) 01504 { 01505 // Cancel the effect of PauseThreadGraphicsRendering on the parent window. 01506 //PostThreadMessage(m_Parent->GetThreadId(), NUX_THREADMSG_START_RENDERING, (UINT_PTR)((void*)this), 0); 01507 } 01508 01509 m_Painter = new BasePainter(); 01510 m_TimerHandler = new TimerHandler(); 01511 m_window_compositor = new WindowCompositor; 01512 01513 SetThreadState (THREADRUNNING); 01514 m_ThreadCtorCalled = true; 01515 01516 // Set initial states 01517 int w = _graphics_display->GetWindowWidth(); 01518 int h = _graphics_display->GetWindowHeight(); 01519 01520 _graphics_display->SetViewPort (0, 0, w, h); 01521 m_window_compositor->FormatRenderTargets (w, h); 01522 m_window_compositor->FloatingAreaConfigureNotify (w, h); 01523 01524 return true; 01525 } 01526 #elif defined(NUX_OS_LINUX) 01527 bool WindowThread::ThreadCtor (Display *X11Display, Window X11Window, GLXContext OpenGLContext) 01528 { 01529 nuxAssertMsg (m_ThreadCtorCalled == false, TEXT ("[WindowThread::ThreadCtor] ThreadCtor should not be called more than once.") ); 01530 NUX_RETURN_VALUE_IF_TRUE (m_ThreadCtorCalled, true); 01531 01532 if (RegisterNuxThread (this) == FALSE) 01533 { 01534 nuxDebugMsg (TEXT ("[WindowThread::ThreadCtor] Failed to register the WindowThread.") ); 01535 return false; 01536 } 01537 01538 inlSetThreadLocalStorage (ThreadLocal_InalogicAppImpl, this); 01539 01540 if (X11Display) 01541 { 01542 _x11display = X11Display; 01543 _ownx11display = false; 01544 } 01545 else 01546 { 01547 _x11display = XOpenDisplay(NULL); 01548 _ownx11display = true; 01549 } 01550 01551 _graphics_display = gGLWindowManager.CreateFromForeignWindow (_x11display, X11Window, OpenGLContext); 01552 01553 if (_graphics_display == 0) 01554 { 01555 nuxDebugMsg (TEXT ("[WindowThread::ThreadCtor] Failed to create the window.") ); 01556 return false; 01557 } 01558 01559 if (m_Parent && m_Parent->Type().IsObjectType (WindowThread::StaticObjectType) ) 01560 { 01561 // Cancel the effect of PauseThreadGraphicsRendering on the parent window. 01562 //PostThreadMessage(m_Parent->GetThreadId(), NUX_THREADMSG_START_RENDERING, (UINT_PTR)((void*)this), 0); 01563 } 01564 01565 m_Painter = new BasePainter(); 01566 m_TimerHandler = new TimerHandler(); 01567 m_window_compositor = new WindowCompositor; 01568 01569 SetThreadState (THREADRUNNING); 01570 m_ThreadCtorCalled = true; 01571 01572 // Set initial states 01573 int w = _graphics_display->GetWindowWidth(); 01574 int h = _graphics_display->GetWindowHeight(); 01575 01576 _graphics_display->SetViewPort (0, 0, w, h); 01577 m_window_compositor->FormatRenderTargets (w, h); 01578 m_window_compositor->FloatingAreaConfigureNotify (w, h); 01579 01580 return true; 01581 } 01582 #endif 01583 01584 bool WindowThread::ThreadDtor() 01585 { 01586 NUX_RETURN_VALUE_IF_TRUE (m_ThreadDtorCalled, true); 01587 01588 // Cleanup 01589 RemoveQueuedLayout (); 01590 01591 if (_main_layout) 01592 { 01593 _main_layout->UnReference(); 01594 } 01595 01596 NUX_SAFE_DELETE (m_window_compositor); 01597 NUX_SAFE_DELETE (m_TimerHandler); 01598 NUX_SAFE_DELETE (m_Painter); 01599 NUX_SAFE_DELETE (m_Theme); 01600 NUX_SAFE_DELETE (_graphics_display); 01601 01602 #if defined(NUX_OS_WINDOWS) 01603 PostThreadMessage (NUX_GLOBAL_OBJECT_INSTANCE (NProcess).GetMainThreadID(), 01604 NUX_THREADMSG_THREAD_TERMINATED, 01605 NUX_GLOBAL_OBJECT_INSTANCE (NProcess).GetCurrentThreadID(), 01606 0); 01607 #elif defined(NUX_OS_LINUX) 01608 01609 #else 01610 #error PostThreadMessage not implemented for this platform. 01611 #endif 01612 01613 inlSetThreadLocalStorage (ThreadLocal_InalogicAppImpl, 0); 01614 UnregisterNuxThread (this); 01615 m_ThreadDtorCalled = true; 01616 return true; 01617 } 01618 01619 void WindowThread::SetWindowSize (int width, int height) 01620 { 01621 if (_graphics_display) 01622 { 01623 if (IsEmbeddedWindow ()) 01624 { 01625 // This is a passive way to set the window size through out the NuxGraphics system. This call gets the 01626 // current window size and sets its accordingly to all sub-system. 01627 _graphics_display->ResetWindowSize (); 01628 } 01629 else 01630 { 01631 _graphics_display->SetWindowSize (width, height); 01632 ReconfigureLayout (); 01633 } 01634 } 01635 } 01636 01637 void WindowThread::SetWindowBackgroundPaintLayer (AbstractPaintLayer *bkg) 01638 { 01639 if (m_window_compositor) 01640 m_window_compositor->SetBackgroundPaintLayer (bkg); 01641 } 01642 01643 void WindowThread::AddToDrawList (View *view) 01644 { 01645 Area *parent; 01646 Geometry geo, pgeo; 01647 01648 geo = view->GetAbsoluteGeometry (); 01649 parent = view->GetToplevel (); 01650 01651 if (parent && (view != parent)) 01652 { 01653 // pgeo = parent->GetGeometry(); 01654 // geo.x += pgeo.x; 01655 // geo.y += pgeo.y; 01656 01657 if (parent->Type ().IsDerivedFromType (BaseWindow::StaticObjectType)) 01658 { 01659 BaseWindow* window = NUX_STATIC_CAST (BaseWindow*, parent); 01660 window->_child_need_redraw = true; 01661 } 01662 } 01663 01664 if (view->Type().IsDerivedFromType (BaseWindow::StaticObjectType)) 01665 { 01666 // If the view is a BaseWindow, allow it to mark itself for redraw, as if it was its own child. 01667 BaseWindow* window = NUX_STATIC_CAST (BaseWindow*, view); 01668 window->_child_need_redraw = true; 01669 } 01670 01671 m_dirty_areas.push_back(geo); 01672 } 01673 01674 void WindowThread::ClearDrawList () 01675 { 01676 m_dirty_areas.clear (); 01677 } 01678 01679 std::vector<Geometry> WindowThread::GetDrawList () 01680 { 01681 return m_dirty_areas; 01682 } 01683 01684 float WindowThread::GetFrameRate() const 01685 { 01686 return m_FrameRate; 01687 } 01688 01689 t_u32 WindowThread::GetFrameCounter() const 01690 { 01691 return m_FrameCounter; 01692 } 01693 01694 t_u32 WindowThread::GetFramePeriodeCounter() const 01695 { 01696 return m_FramePeriodeCounter; 01697 } 01698 01699 bool WindowThread::IsEmbeddedWindow() 01700 { 01701 return m_embedded_window; 01702 } 01703 01704 #if defined(NUX_OS_WINDOWS) 01705 bool WindowThread::ProcessForeignEvent (HWND hWnd, MSG msg, WPARAM wParam, LPARAM lParam, void *data) 01706 #elif defined(NUX_OS_LINUX) 01707 bool WindowThread::ProcessForeignEvent (XEvent *xevent, void *data) 01708 #endif 01709 { 01710 if (GetWindow().IsPauseThreadGraphicsRendering() ) 01711 { 01712 return false; 01713 } 01714 01715 IEvent nux_event; 01716 memset (&nux_event, 0, sizeof (IEvent) ); 01717 #if defined(NUX_OS_WINDOWS) 01718 _graphics_display->ProcessForeignWin32Event (hWnd, msg, wParam, lParam, &nux_event); 01719 #elif defined(NUX_OS_LINUX) 01720 _graphics_display->ProcessForeignX11Event (xevent, &nux_event); 01721 #endif 01722 01723 if (nux_event.e_event == NUX_TERMINATE_APP || (this->GetThreadState() == THREADSTOP) ) 01724 { 01725 return false; 01726 } 01727 01728 if (nux_event.e_event == NUX_SIZE_CONFIGURATION) 01729 m_size_configuration_event = true; 01730 01731 int w, h; 01732 // Call gGfx_OpenGL.getWindowSize after the gGfx_OpenGL.get_event. 01733 // Otherwise, w and h may not be correct for the current frame if a resizing happened. 01734 GetWindow().GetWindowSize (w, h); 01735 01736 if (nux_event.e_event == NUX_MOUSE_PRESSED || 01737 (nux_event.e_event == NUX_MOUSE_RELEASED) || 01738 (nux_event.e_event == NUX_MOUSE_DOUBLECLICK) || 01739 (nux_event.e_event == NUX_MOUSE_MOVE) || 01740 (nux_event.e_event == NUX_SIZE_CONFIGURATION) || 01741 (nux_event.e_event == NUX_KEYDOWN) || 01742 (nux_event.e_event == NUX_KEYUP) || 01743 (nux_event.e_event == NUX_WINDOW_CONFIGURATION) || 01744 (nux_event.e_event == NUX_WINDOW_ENTER_FOCUS) || 01745 (nux_event.e_event == NUX_WINDOW_EXIT_FOCUS) || 01746 (nux_event.e_event == NUX_WINDOW_MOUSELEAVE) || 01747 (nux_event.e_event == NUX_MOUSE_WHEEL)) 01748 { 01749 //DISPATCH EVENT HERE 01750 //nux_event.Application = Application; 01751 m_window_compositor->ProcessEvent(nux_event); 01752 } 01753 01754 if(nux_event.e_event == NUX_SIZE_CONFIGURATION) 01755 { 01756 if(!GetWindow().isWindowMinimized()) 01757 { 01758 GetWindow().SetViewPort(0, 0, nux_event.width, nux_event.height); 01759 ReconfigureLayout (); 01760 m_window_compositor->FormatRenderTargets(nux_event.width, nux_event.height); 01761 } 01762 m_window_compositor->FloatingAreaConfigureNotify(nux_event.width, nux_event.height); 01763 m_size_configuration_event = true; 01764 } 01765 01766 // Some action may have caused layouts and areas to request a recompute. 01767 // Process them here before the Draw section. 01768 if (!GetWindow().isWindowMinimized() ) 01769 { 01770 if (_queue_main_layout) 01771 { 01772 ReconfigureLayout (); 01773 } 01774 else 01775 { 01776 // Compute the layouts that have been queued. 01777 ComputeQueuedLayout (); 01778 } 01779 } 01780 01781 // Warn the host window manager to initiate a draw cycle. 01782 bool request_draw_cycle_to_host_wm = false; 01783 01784 if (this->m_bFirstDrawPass) 01785 { 01786 request_draw_cycle_to_host_wm = true; 01787 m_force_redraw = true; 01788 //m_window_compositor->Draw(m_size_configuration_event, true); 01789 this->m_bFirstDrawPass = false; 01790 } 01791 else 01792 { 01793 bool b = (nux_event.e_event == NUX_MOUSE_PRESSED) || 01794 (nux_event.e_event == NUX_MOUSE_RELEASED) || 01795 (nux_event.e_event == NUX_MOUSE_DOUBLECLICK) || 01796 //(event.e_event == NUX_MOUSE_MOVE) || 01797 (nux_event.e_event == NUX_SIZE_CONFIGURATION) || 01798 (nux_event.e_event == NUX_KEYDOWN) || 01799 (nux_event.e_event == NUX_KEYUP) || 01800 (nux_event.e_event == NUX_WINDOW_CONFIGURATION) || 01801 (nux_event.e_event == NUX_WINDOW_ENTER_FOCUS) || 01802 (nux_event.e_event == NUX_WINDOW_EXIT_FOCUS) || 01803 (nux_event.e_event == NUX_WINDOW_DIRTY); 01804 01805 if (b && m_window_compositor->IsTooltipActive() ) 01806 { 01807 // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. 01808 m_window_compositor->CancelTooltip(); 01809 b |= true; 01810 } 01811 01812 if (!m_window_compositor->ValidateMouseInsideTooltipArea (nux_event.e_x, nux_event.e_y) && m_window_compositor->IsTooltipActive() ) 01813 { 01814 // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. 01815 m_window_compositor->CancelTooltip(); 01816 b |= true; 01817 } 01818 01819 if (b || IsRedrawNeeded() ) 01820 { 01821 request_draw_cycle_to_host_wm = true; 01822 } 01823 else if (m_window_compositor->GetWidgetDrawingOverlay() != 0) 01824 { 01825 request_draw_cycle_to_host_wm = true; 01826 } 01827 } 01828 01829 if (!_draw_requested_to_host_wm && request_draw_cycle_to_host_wm) 01830 RequestRedraw (); 01831 01832 return request_draw_cycle_to_host_wm; 01833 } 01834 01835 void WindowThread::RenderInterfaceFromForeignCmd(Geometry *clip) 01836 { 01837 nuxAssertMsg (IsEmbeddedWindow() == true, TEXT ("[WindowThread::RenderInterfaceFromForeignCmd] You can only call RenderInterfaceFromForeignCmd if the window was created with CreateFromForeignWindow.") ); 01838 01839 if (!IsEmbeddedWindow() ) 01840 return; 01841 01842 IOpenGLShaderProgram::SetShaderTracking(true); 01843 01844 // Set Nux opengl states. The other plugin in compiz have changed the GPU opengl states. 01845 // Nux keep tracks of its own opengl states and restore them before doing any drawing. 01846 GetWindowThread ()->GetGraphicsEngine().GetRenderStates().SubmitChangeStates(); 01847 01848 GetWindowThread ()->GetGraphicsEngine().SetOpenGLClippingRectangle (0, 0, GetWindowThread ()->GetGraphicsEngine().GetWindowWidth(), 01849 GetWindowThread ()->GetGraphicsEngine().GetWindowHeight() ); 01850 01851 if (GetWindow().IsPauseThreadGraphicsRendering() == false) 01852 { 01853 RefreshLayout (); 01854 01855 if (clip) 01856 GetWindowThread ()->GetGraphicsEngine().SetGlobalClippingRectangle (Rect (clip->x, clip->y, clip->width, clip->height)); 01857 01858 m_window_compositor->Draw (m_size_configuration_event, m_force_redraw); 01859 01860 if (clip) 01861 GetWindowThread ()->GetGraphicsEngine().DisableGlobalClippingRectangle (); 01862 // When rendering in embedded mode, nux does not attempt to measure the frame rate... 01863 01864 // Cleanup 01865 GetWindowThread ()->GetGraphicsEngine().ResetStats(); 01866 ClearRedrawFlag(); 01867 01868 m_size_configuration_event = false; 01869 m_force_redraw = false; 01870 } 01871 01872 CHECKGL ( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ); 01873 01874 GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer(); 01875 IOpenGLShaderProgram::SetShaderTracking(false); 01876 } 01877 01878 int WindowThread::InstallEventInspector (EventInspector function, void* data) 01879 { 01880 NUX_RETURN_VALUE_IF_NULL (function, 0); 01881 01882 std::map < int, EventInspectorStorage >::iterator it; 01883 01884 for (it = _event_inspectors_map.begin (); it != _event_inspectors_map.end (); it++) 01885 { 01886 if ((*it).second._function == function) 01887 { 01888 // The inspector has already been added. Return its unique id 01889 return (*it).second._uid; 01890 } 01891 } 01892 01893 // This is a new Event Inspector 01894 EventInspectorStorage new_inspector; 01895 new_inspector._function = function; 01896 new_inspector._data = data; 01897 new_inspector._uid = NUX_GLOBAL_OBJECT_INSTANCE (UniqueIndex).GetUniqueIndex (); 01898 01899 _event_inspectors_map [new_inspector._uid] = new_inspector; 01900 return new_inspector._uid; 01901 } 01902 01903 bool WindowThread::RemoveEventInspector (int event_inspector_id) 01904 { 01905 NUX_RETURN_VALUE_IF_NULL (event_inspector_id, false); 01906 01907 std::map < int, EventInspectorStorage >::iterator it; 01908 01909 for (it = _event_inspectors_map.begin (); it != _event_inspectors_map.end (); it++) 01910 { 01911 if ((*it).second._uid == event_inspector_id) 01912 { 01913 _event_inspectors_map.erase (it); 01914 return true; 01915 } 01916 } 01917 return false; 01918 } 01919 01920 bool WindowThread::RemoveEventInspector (EventInspector function) 01921 { 01922 NUX_RETURN_VALUE_IF_NULL (function, false); 01923 01924 std::map < int, EventInspectorStorage >::iterator it; 01925 01926 for (it = _event_inspectors_map.begin (); it != _event_inspectors_map.end (); it++) 01927 { 01928 if ((*it).second._function == function) 01929 { 01930 _event_inspectors_map.erase (it); 01931 return true; 01932 } 01933 } 01934 return false; 01935 } 01936 01937 bool WindowThread::CallEventInspectors (Event* event) 01938 { 01939 int n = _event_inspectors_map.size(); 01940 if (n == 0) 01941 { 01942 // No event inspector installed. 01943 return false; 01944 } 01945 01946 bool discard_event = false; 01947 std::map < int, EventInspectorStorage >::iterator it; 01948 01949 for (it = _event_inspectors_map.begin (); it != _event_inspectors_map.end (); it++) 01950 { 01951 EventInspector callback = (*it).second._function; 01952 01953 if (callback == 0) 01954 continue; 01955 01956 int ret = callback (0, event, (*it).second._data); 01957 01958 if (ret) 01959 { 01960 discard_event = true; 01961 } 01962 } 01963 01964 return discard_event; 01965 } 01966 01967 01968 UXTheme& WindowThread::GetTheme() const 01969 { 01970 if (!m_Theme) 01971 { 01972 LOG_INFO(logger) << "Lazily creating nux::UXTheme"; 01973 const_cast<WindowThread*>(this)->m_Theme = new UXTheme(); 01974 } 01975 return *m_Theme; 01976 } 01977 01978 } 01979