nux-1.14.0
WindowThread.cpp
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 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends