]>
git.saurik.com Git - wxWidgets.git/blob - src/gtk1/app.cpp 
   1  /////////////////////////////////////////////////////////////////////////////    4  // Author:      Robert Roebling    6  // Copyright:   (c) 1998 Robert Roebling, Julian Smart    7  // Licence:     wxWindows licence    8  /////////////////////////////////////////////////////////////////////////////   11      #pragma implementation  "app.h"   15  #include <vms_jackets.h>   16  #undef ConnectionNumber   20  #include  "wx/gdicmn.h"   24  #include  "wx/memory.h"   26  #include  "wx/settings.h"   27  #include  "wx/dialog.h"   28  #include  "wx/msgdlg.h"   30  #include  "wx/filename.h"   31  #include  "wx/module.h"   34  #ifdef __WXUNIVERSAL__   35      #include  "wx/univ/theme.h"   36      #include  "wx/univ/renderer.h"   40      #include  "wx/thread.h"   49          // bug in the OpenBSD headers: at least in 3.1 there is no extern "C"   50          // in neither poll.h nor sys/poll.h which results in link errors later   63  // we implement poll() ourselves using select() which is supposed exist in   65      #include <sys/types.h>   68  #endif  // HAVE_POLL/!HAVE_POLL   70  #include  "wx/gtk/win_gtk.h"   75  //-----------------------------------------------------------------------------   77  //-----------------------------------------------------------------------------   79  bool    g_mainThreadLocked 
=  FALSE
;   80  gint   g_pendingTag 
=  0 ;   82  static  GtkWidget 
* gs_RootWindow 
= ( GtkWidget
*)  NULL
;   84  //-----------------------------------------------------------------------------   86  //-----------------------------------------------------------------------------   90  void  wxapp_install_idle_handler ();   92  //-----------------------------------------------------------------------------   94  //-----------------------------------------------------------------------------   96  // not static because used by textctrl.cpp   99  bool  wxIsInsideYield 
=  FALSE
;  101  bool  wxApp :: Yield ( bool  onlyIfNeeded
)  103      if  (  wxIsInsideYield 
)  107              wxFAIL_MSG (  wxT ( "wxYield called recursively"  ) );  114      if  ( ! wxThread :: IsMain () )  116          // can't call gtk_main_iteration() from other threads like this  119  #endif  // wxUSE_THREADS  121      wxIsInsideYield 
=  TRUE
;  125          // We need to remove idle callbacks or the loop will  127          gtk_idle_remove (  m_idleTag 
);  132      // disable log flushing from here because a call to wxYield() shouldn't  133      // normally result in message boxes popping up &c  136      while  ( gtk_events_pending ())  137          gtk_main_iteration ();  139      // It's necessary to call ProcessIdle() to update the frames sizes which  140      // might have been changed (it also will update other things set from  141      // OnUpdateUI() which is a nice (and desired) side effect). But we  142      // call ProcessIdle() only once since this is not meant for longish  143      // background jobs (controlled by wxIdleEvent::RequestMore() and the  144      // return value of Processidle().  147      // let the logs be flashed again  150      wxIsInsideYield 
=  FALSE
;  155  //-----------------------------------------------------------------------------  157  //-----------------------------------------------------------------------------  159  void  wxApp :: WakeUpIdle ()  162      if  (! wxThread :: IsMain ())  167          wxapp_install_idle_handler ();  170      if  (! wxThread :: IsMain ())  175  //-----------------------------------------------------------------------------  177  //-----------------------------------------------------------------------------  179  // the callback functions must be extern "C" to comply with GTK+ declarations  183  static  gint 
wxapp_pending_callback (  gpointer 
WXUNUSED ( data
) )  185      if  (! wxTheApp
)  return  TRUE
;  187      // When getting called from GDK's time-out handler  188      // we are no longer within GDK's grab on the GUI  189      // thread so we must lock it here ourselves.  192      // Sent idle event to all who request them.  193      wxTheApp
-> ProcessPendingEvents ();  197      // Flush the logged messages if any.  199      wxLog :: FlushActive ();  202      // Release lock again  205      // Return FALSE to indicate that no more idle events are  206      // to be sent (single shot instead of continuous stream)  210  static  gint 
wxapp_idle_callback (  gpointer 
WXUNUSED ( data
) )  216      // don't generate the idle events while the assert modal dialog is shown,  217      // this completely confuses the apps which don't expect to be reentered  218      // from some safely-looking functions  219      if  (  wxTheApp
-> IsInAssert () )  221          // But repaint the assertion message if necessary  222          if  ( wxTopLevelWindows
. GetCount () >  0 )  224              wxWindow
*  win 
= ( wxWindow
*)  wxTopLevelWindows
. GetLast ()-> GetData ();  226              if  ( win
-> IsKindOf ( CLASSINFO ( wxMessageDialog
)))  228              if  ( win
-> IsKindOf ( CLASSINFO ( wxGenericMessageDialog
)))  230                  win
-> OnInternalIdle ();  234  #endif  // __WXDEBUG__  236      // When getting called from GDK's time-out handler  237      // we are no longer within GDK's grab on the GUI  238      // thread so we must lock it here ourselves.  241      // Indicate that we are now in idle mode and event handlers  242      // will have to reinstall the idle handler again.  244      wxTheApp
-> m_idleTag 
=  0 ;  246      // Send idle event to all who request them as long as  247      // no events have popped up in the event queue.  248      while  ( wxTheApp
-> ProcessIdle () && ( gtk_events_pending () ==  0 ))  251      // Release lock again  254      // Return FALSE to indicate that no more idle events are  255      // to be sent (single shot instead of continuous stream).  263      #define wxPollFd pollfd  266  typedef  GPollFD wxPollFd
;  268  int  wxPoll ( wxPollFd 
* ufds
,  unsigned int  nfds
,  int  timeout
)  270      // convert timeout from ms to struct timeval (s/us)  272      tv_timeout
. tv_sec 
=  timeout
/ 1000 ;  273      tv_timeout
. tv_usec 
= ( timeout%1000
)* 1000 ;  275      // remember the highest fd used here  278      // and fill the sets for select()  287      for  (  i 
=  0 ;  i 
<  nfds
;  i
++ )  289          wxASSERT_MSG (  ufds
[ i
]. fd 
<  FD_SETSIZE
,  _T ( "fd out of range" ) );  291          if  (  ufds
[ i
]. events 
&  G_IO_IN 
)  292              FD_SET ( ufds
[ i
]. fd
, & readfds
);  294          if  (  ufds
[ i
]. events 
&  G_IO_PRI 
)  295              FD_SET ( ufds
[ i
]. fd
, & exceptfds
);  297          if  (  ufds
[ i
]. events 
&  G_IO_OUT 
)  298              FD_SET ( ufds
[ i
]. fd
, & writefds
);  300          if  (  ufds
[ i
]. fd 
>  fdMax 
)  305      int  res 
=  select ( fdMax
, & readfds
, & writefds
, & exceptfds
, & tv_timeout
);  307      // translate the results back  308      for  (  i 
=  0 ;  i 
<  nfds
;  i
++ )  312          if  (  FD_ISSET ( ufds
[ i
]. fd
, & readfds 
) )  313              ufds
[ i
]. revents 
|=  G_IO_IN
;  315          if  (  FD_ISSET ( ufds
[ i
]. fd
, & exceptfds 
) )  316              ufds
[ i
]. revents 
|=  G_IO_PRI
;  318          if  (  FD_ISSET ( ufds
[ i
]. fd
, & writefds 
) )  319              ufds
[ i
]. revents 
|=  G_IO_OUT
;  325  #endif  // HAVE_POLL/!HAVE_POLL  327  static  gint 
wxapp_poll_func (  GPollFD 
* ufds
,  guint nfds
,  gint timeout 
)  332      g_mainThreadLocked 
=  TRUE
;  334      // we rely on the fact that glib GPollFD struct is really just pollfd but  335      // I wonder how wise is this in the long term (VZ)  336      gint res 
=  wxPoll ( ( wxPollFd 
*)  ufds
,  nfds
,  timeout 
);  339      g_mainThreadLocked 
=  FALSE
;  346  #endif  // wxUSE_THREADS  350  void  wxapp_install_idle_handler ()  352      // GD: this assert is raised when using the thread sample (which works)  353      //     so the test is probably not so easy. Can widget callbacks be  354      //     triggered from child threads and, if so, for which widgets?  355      // wxASSERT_MSG( wxThread::IsMain() || gs_WakeUpIdle, wxT("attempt to install idle handler from widget callback in child thread (should be exclusively from wxWakeUpIdle)") );  357      wxASSERT_MSG (  wxTheApp
-> m_idleTag 
==  0 ,  wxT ( "attempt to install idle handler twice" ) );  361      if  ( g_pendingTag 
==  0 )  362          g_pendingTag 
=  gtk_idle_add_priority (  900 ,  wxapp_pending_callback
, ( gpointer
)  NULL 
);  364      // This routine gets called by all event handlers  365      // indicating that the idle is over. It may also  366      // get called from other thread for sending events  367      // to the main thread (and processing these in  368      // idle time). Very low priority.  369      wxTheApp
-> m_idleTag 
=  gtk_idle_add_priority (  1000 ,  wxapp_idle_callback
, ( gpointer
)  NULL 
);  372  //-----------------------------------------------------------------------------  373  // Access to the root window global  374  //-----------------------------------------------------------------------------  376  GtkWidget
*  wxGetRootWindow ()  378      if  ( gs_RootWindow 
==  NULL
)  380          gs_RootWindow 
=  gtk_window_new (  GTK_WINDOW_TOPLEVEL 
);  381          gtk_widget_realize (  gs_RootWindow 
);  383      return  gs_RootWindow
;  386  //-----------------------------------------------------------------------------  388  //-----------------------------------------------------------------------------  390  IMPLEMENT_DYNAMIC_CLASS ( wxApp
, wxEvtHandler
)  392  BEGIN_EVENT_TABLE ( wxApp
,  wxEvtHandler
)  393      EVT_IDLE ( wxApp :: OnIdle
)  398      m_initialized 
=  FALSE
;  400      m_isInAssert 
=  FALSE
;  401  #endif  // __WXDEBUG__  404      wxapp_install_idle_handler ();  407      g_main_set_poll_func (  wxapp_poll_func 
);  410      m_colorCube 
= ( unsigned char *)  NULL
;  412      // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp  413      m_glVisualInfo 
= ( void  *)  NULL
;  418      if  ( m_idleTag
)  gtk_idle_remove (  m_idleTag 
);  420      if  ( m_colorCube
)  free ( m_colorCube
);  423  bool  wxApp :: OnInitGui ()  425      if  ( ! wxAppBase :: OnInitGui () )  428      GdkVisual 
* visual 
=  gdk_visual_get_system ();  430      // if this is a wxGLApp (derived from wxApp), and we've already  431      // chosen a specific visual, then derive the GdkVisual from that  432      if  ( m_glVisualInfo 
!=  NULL
)  435          // seems gtk_widget_set_default_visual no longer exists?  436          GdkVisual
*  vis 
=  gtk_widget_get_default_visual ();  438          GdkVisual
*  vis 
=  gdkx_visual_get (  439              (( XVisualInfo 
*)  m_glVisualInfo
) -> visualid 
);  440          gtk_widget_set_default_visual (  vis 
);  443          GdkColormap 
* colormap 
=  gdk_colormap_new (  vis
,  FALSE 
);  444          gtk_widget_set_default_colormap (  colormap 
);  449      // On some machines, the default visual is just 256 colours, so  450      // we make sure we get the best. This can sometimes be wasteful.  453      if  (( gdk_visual_get_best () !=  gdk_visual_get_system ()) && ( m_useBestVisual
))  456          /* seems gtk_widget_set_default_visual no longer exists? */  457          GdkVisual
*  vis 
=  gtk_widget_get_default_visual ();  459          GdkVisual
*  vis 
=  gdk_visual_get_best ();  460          gtk_widget_set_default_visual (  vis 
);  463          GdkColormap 
* colormap 
=  gdk_colormap_new (  vis
,  FALSE 
);  464          gtk_widget_set_default_colormap (  colormap 
);  469      // Nothing to do for 15, 16, 24, 32 bit displays  470      if  ( visual
-> depth 
>  8 )  return  TRUE
;  472      // initialize color cube for 8-bit color reduction dithering  474      GdkColormap 
* cmap 
=  gtk_widget_get_default_colormap ();  476      m_colorCube 
= ( unsigned char *) malloc ( 32  *  32  *  32 );  478      for  ( int  r 
=  0 ;  r 
<  32 ;  r
++)  480          for  ( int  g 
=  0 ;  g 
<  32 ;  g
++)  482              for  ( int  b 
=  0 ;  b 
<  32 ;  b
++)  484                  int  rr 
= ( r 
<<  3 ) | ( r 
>>  2 );  485                  int  gg 
= ( g 
<<  3 ) | ( g 
>>  2 );  486                  int  bb 
= ( b 
<<  3 ) | ( b 
>>  2 );  490                  GdkColor 
* colors 
=  cmap
-> colors
;  495                      for  ( int  i 
=  0 ;  i 
<  cmap
-> size
;  i
++)  497                          int  rdiff 
= (( rr 
<<  8 ) -  colors
[ i
]. red
);  498                          int  gdiff 
= (( gg 
<<  8 ) -  colors
[ i
]. green
);  499                          int  bdiff 
= (( bb 
<<  8 ) -  colors
[ i
]. blue
);  500                          int  sum 
=  ABS  ( rdiff
) +  ABS  ( gdiff
) +  ABS  ( bdiff
);  503                              index 
=  i
;  max 
=  sum
;  509                      // assume 8-bit true or static colors. this really exists  510                      GdkVisual
*  vis 
=  gdk_colormap_get_visual (  cmap 
);  511                      index 
= ( r 
>> ( 5  -  vis
-> red_prec
)) <<  vis
-> red_shift
;  512                      index 
|= ( g 
>> ( 5  -  vis
-> green_prec
)) <<  vis
-> green_shift
;  513                      index 
|= ( b 
>> ( 5  -  vis
-> blue_prec
)) <<  vis
-> blue_shift
;  515                  m_colorCube
[ ( r
* 1024 ) + ( g
* 32 ) +  b 
] =  index
;  523  GdkVisual 
* wxApp :: GetGdkVisual ()  525      GdkVisual 
* visual 
=  NULL
;  528          visual 
=  gdkx_visual_get ( (( XVisualInfo 
*)  m_glVisualInfo
)-> visualid 
);  530          visual 
=  gdk_window_get_visual (  wxGetRootWindow ()-> window 
);  537  bool  wxApp :: ProcessIdle ()  539      wxWindowList :: Node
*  node 
=  wxTopLevelWindows
. GetFirst ();  540      node 
=  wxTopLevelWindows
. GetFirst ();  543          wxWindow
*  win 
=  node
-> GetData ();  544          CallInternalIdle (  win 
);  546          node 
=  node
-> GetNext ();  550      event
. SetEventObject (  this  );  551      ProcessEvent (  event 
);  553      wxUpdateUIEvent :: ResetUpdateTime ();  555      return  event
. MoreRequested ();  558  void  wxApp :: OnIdle (  wxIdleEvent 
& event 
)  560      static bool  s_inOnIdle 
=  FALSE
;  562      // Avoid recursion (via ProcessEvent default case)  568      // Resend in the main thread events which have been prepared in other  570      ProcessPendingEvents ();  572      // 'Garbage' collection of windows deleted with Close()  573      DeletePendingObjects ();  575      // Send OnIdle events to all windows  576      bool  needMore 
=  SendIdleEvents ();  579          event
. RequestMore ( TRUE
);  584  bool  wxApp :: SendIdleEvents ()  586      bool  needMore 
=  FALSE
;  588      wxWindowList :: Node
*  node 
=  wxTopLevelWindows
. GetFirst ();  591          wxWindow
*  win 
=  node
-> GetData ();  592          if  ( SendIdleEvents ( win
))  595          node 
=  node
-> GetNext ();  601  bool  wxApp :: CallInternalIdle (  wxWindow
*  win 
)  603      win
-> OnInternalIdle ();  605      wxWindowList :: Node  
* node 
=  win
-> GetChildren (). GetFirst ();  608          wxWindow    
* win 
=  node
-> GetData ();  610          CallInternalIdle (  win 
);  611          node 
=  node
-> GetNext ();  617  bool  wxApp :: SendIdleEvents (  wxWindow
*  win 
)  619      bool  needMore 
=  FALSE
;  622      event
. SetEventObject ( win
);  624      win
-> GetEventHandler ()-> ProcessEvent ( event
);  626      if  ( event
. MoreRequested ())  629      wxWindowList :: Node  
* node 
=  win
-> GetChildren (). GetFirst ();  632          wxWindow    
* win 
=  node
-> GetData ();  634          if  ( SendIdleEvents ( win
))  636          node 
=  node
-> GetNext ();  642  int  wxApp :: MainLoop ()  650      // VZ: no idea why is it different from ExitMainLoop() but this is what  651      //     wxExit() used to do  655  void  wxApp :: ExitMainLoop ()  657      if  ( gtk_main_level () >  0 )  661  bool  wxApp :: Initialized ()  663      return  m_initialized
;  666  bool  wxApp :: Pending ()  668      return  ( gtk_events_pending () >  0 );  671  void  wxApp :: Dispatch ()  673      gtk_main_iteration ();  676  bool  wxApp :: Initialize ( int &  argc
,  wxChar 
** argv
)  679      // GTK 1.2 up to version 1.2.3 has broken threads  680      if  (( gtk_major_version 
==  1 ) &&  681          ( gtk_minor_version 
==  2 ) &&  682          ( gtk_micro_version 
<  4 ))  684          printf (  "wxWindows warning: GUI threading disabled due to outdated GTK version \n "  );  690  #endif  // wxUSE_THREADS  694      // We should have the wxUSE_WCHAR_T test on the _outside_  696      #if defined(__WXGTK20__)  697          // gtk+ 2.0 supports Unicode through UTF-8 strings  698          wxConvCurrent 
= & wxConvUTF8
;  701              wxConvCurrent 
= & wxConvLocal
;  703  #else  // !wxUSE_WCHAR_T  705          wxConvCurrent 
= ( wxMBConv
*)  NULL
;  706  #endif  // wxUSE_WCHAR_T/!wxUSE_WCHAR_T  709      // gtk_init() wants UTF-8, not wchar_t, so convert  711      char  ** argvGTK 
=  new  char  *[ argc 
+  1 ];  712      for  (  i 
=  0 ;  i 
<  argc
;  i
++ )  714          argvGTK
[ i
] =  wxStrdupA ( wxConvUTF8
. cWX2MB ( argv
[ i
]));  717      argvGTK
[ argc
] =  NULL
;  720      gtk_init ( & argcGTK
, & argvGTK 
);  722      if  (  argcGTK 
!=  argc 
)  724          // we have to drop the parameters which were consumed by GTK+  725          for  (  i 
=  0 ;  i 
<  argcGTK
;  i
++ )  727              while  (  strcmp ( wxConvUTF8
. cWX2MB ( argv
[ i
]),  argvGTK
[ i
]) !=  0  )  729                  memmove ( argv 
+  i
,  argv 
+  i 
+  1 ,  argc 
-  i
);  735      //else: gtk_init() didn't modify our parameters  738      for  (  i 
=  0 ;  i 
<  argcGTK
;  i
++ )  744  #else  // !wxUSE_UNICODE  745  // gtk_init() shouldn't actually change argv itself (just its contents) so  746      // it's ok to pass pointer to it  747      gtk_init ( & argc
, & argv 
);  748  #endif  // wxUSE_UNICODE/!wxUSE_UNICODE  750      // we can not enter threads before gtk_init is done  753      if  ( ! wxAppBase :: Initialize ( argc
,  argv
) )  760      wxSetDetectableAutoRepeat (  TRUE 
);  763      wxFont :: SetDefaultEncoding ( wxLocale :: GetSystemEncoding ());  771  void  wxApp :: CleanUp ()  775      wxAppBase :: CleanUp ();  780  void  wxApp :: OnAssert ( const  wxChar 
* file
,  int  line
,  const  wxChar
*  cond
,  const  wxChar 
* msg
)  784      wxAppBase :: OnAssert ( file
,  line
,  cond
,  msg
);  786      m_isInAssert 
=  FALSE
;  789  #endif  // __WXDEBUG__