]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/app.cpp
Added default constructor to wxGLCanvas.
[wxWidgets.git] / src / gtk1 / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "app.h"
12 #endif
13
14 #include "wx/app.h"
15 #include "wx/gdicmn.h"
16 #include "wx/utils.h"
17 #include "wx/intl.h"
18 #include "wx/log.h"
19 #include "wx/memory.h"
20 #include "wx/font.h"
21 #include "wx/settings.h"
22 #include "wx/dialog.h"
23
24 #if wxUSE_WX_RESOURCES
25 #include "wx/resource.h"
26 #endif
27
28 #include "wx/module.h"
29 #include "wx/image.h"
30
31 #if wxUSE_THREADS
32 #include "wx/thread.h"
33 #endif
34
35 #include <unistd.h>
36
37 #include <glib.h>
38 #include <gdk/gdk.h>
39 #include <gtk/gtk.h>
40
41 #include "wx/gtk/win_gtk.h"
42
43 //-----------------------------------------------------------------------------
44 // global data
45 //-----------------------------------------------------------------------------
46
47 wxApp *wxTheApp = (wxApp *) NULL;
48 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
49
50 extern bool g_isIdle;
51
52 //-----------------------------------------------------------------------------
53 // local functions
54 //-----------------------------------------------------------------------------
55
56 /* forward declaration */
57 gint wxapp_idle_callback( gpointer WXUNUSED(data) );
58 void wxapp_install_idle_handler();
59
60 #if wxUSE_THREADS
61 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) );
62 #endif
63
64 //-----------------------------------------------------------------------------
65 // wxExit
66 //-----------------------------------------------------------------------------
67
68 void wxExit()
69 {
70 gtk_main_quit();
71 }
72
73 //-----------------------------------------------------------------------------
74 // wxYield
75 //-----------------------------------------------------------------------------
76
77 bool wxYield()
78 {
79 bool has_idle = (wxTheApp->m_idleTag != 0);
80
81 if (has_idle)
82 {
83 /* We need to temporarily remove idle callbacks or the loop will
84 never finish. */
85 gtk_idle_remove( wxTheApp->m_idleTag );
86 wxTheApp->m_idleTag = 0;
87 }
88
89 while (gtk_events_pending())
90 gtk_main_iteration();
91
92 /* it's necessary to call ProcessIdle() to update the frames sizes which
93 might have been changed (it also will update other things set from
94 OnUpdateUI() which is a nice (and desired) side effect) */
95 while (wxTheApp->ProcessIdle()) { }
96
97 if (has_idle)
98 {
99 /* re-add idle handler */
100 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
101 }
102
103 return TRUE;
104 }
105
106 //-----------------------------------------------------------------------------
107 // wxWakeUpIdle
108 //-----------------------------------------------------------------------------
109
110 void wxWakeUpIdle()
111 {
112 if (g_isIdle)
113 wxapp_install_idle_handler();
114 }
115
116 //-----------------------------------------------------------------------------
117 // local functions
118 //-----------------------------------------------------------------------------
119
120 gint wxapp_idle_callback( gpointer WXUNUSED(data) )
121 {
122 if (!wxTheApp) return TRUE;
123
124 #if (GTK_MINOR_VERSION > 0)
125 /* when getting called from GDK's idle handler we
126 are no longer within GDK's grab on the GUI
127 thread so we must lock it here ourselves */
128 GDK_THREADS_ENTER ();
129 #endif
130
131 /* sent idle event to all who request them */
132 while (wxTheApp->ProcessIdle()) { }
133
134 /* we don't want any more idle events until the next event is
135 sent to wxGTK */
136 gtk_idle_remove( wxTheApp->m_idleTag );
137 wxTheApp->m_idleTag = 0;
138
139 /* indicate that we are now in idle mode - even so deeply
140 in idle mode that we don't get any idle events anymore.
141 this is like wxMSW where an idle event is sent only
142 once each time after the event queue has been completely
143 emptied */
144 g_isIdle = TRUE;
145
146 #if (GTK_MINOR_VERSION > 0)
147 /* release lock again */
148 GDK_THREADS_LEAVE ();
149 #endif
150
151 return TRUE;
152 }
153
154 void wxapp_install_idle_handler()
155 {
156 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
157
158 /* This routine gets called by all event handlers
159 indicating that the idle is over. It may also
160 get called from other thread for sending events
161 to the main thread (and processing these in
162 idle time). */
163
164 #if wxUSE_THREADS
165 if (!wxThread::IsMain())
166 GDK_THREADS_ENTER ();
167 #endif
168
169 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
170
171 g_isIdle = FALSE;
172
173 #if wxUSE_THREADS
174 if (!wxThread::IsMain())
175 GDK_THREADS_LEAVE ();
176 #endif
177 }
178
179 #if wxUSE_THREADS
180
181 void wxapp_install_thread_wakeup()
182 {
183 if (wxTheApp->m_wakeUpTimerTag) return;
184
185 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 100, wxapp_wakeup_timerout_callback, (gpointer) NULL );
186 }
187
188 void wxapp_uninstall_thread_wakeup()
189 {
190 if (!wxTheApp->m_wakeUpTimerTag) return;
191
192 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
193 wxTheApp->m_wakeUpTimerTag = 0;
194 }
195
196 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
197 {
198 wxapp_uninstall_thread_wakeup();
199
200 #if (GTK_MINOR_VERSION > 0)
201 // when getting called from GDK's time-out handler
202 // we are no longer within GDK's grab on the GUI
203 // thread so we must lock it here ourselves
204 GDK_THREADS_ENTER ();
205 #endif
206
207 // unblock other threads wishing to do some GUI things
208 wxMutexGuiLeave();
209
210 // wake up other threads
211 wxUsleep( 1 );
212
213 // block other thread again
214 wxMutexGuiEnter();
215
216 #if (GTK_MINOR_VERSION > 0)
217 // release lock again
218 GDK_THREADS_LEAVE ();
219 #endif
220
221 wxapp_install_thread_wakeup();
222
223 return TRUE;
224 }
225
226 #endif // wxUSE_THREADS
227
228 //-----------------------------------------------------------------------------
229 // wxApp
230 //-----------------------------------------------------------------------------
231
232 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
233
234 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
235 EVT_IDLE(wxApp::OnIdle)
236 END_EVENT_TABLE()
237
238 wxApp::wxApp()
239 {
240 wxTheApp = this;
241
242 m_topWindow = (wxWindow *) NULL;
243 m_exitOnFrameDelete = TRUE;
244
245 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
246
247 #if wxUSE_THREADS
248 m_wakeUpTimerTag = 0;
249 wxapp_install_thread_wakeup();
250 #endif
251
252 m_colorCube = (unsigned char*) NULL;
253 }
254
255 wxApp::~wxApp()
256 {
257 if (m_idleTag) gtk_idle_remove( m_idleTag );
258
259 #if wxUSE_THREADS
260 wxapp_uninstall_thread_wakeup();
261 #endif
262
263 if (m_colorCube) free(m_colorCube);
264 }
265
266 bool wxApp::OnInitGui()
267 {
268 GdkVisual *visual = gdk_visual_get_system();
269
270 /* on some machines, the default visual is just 256 colours, so
271 we make sure we get the best. this can sometimes be wasteful,
272 of course, but what do these guys pay $30.000 for? */
273 /*
274 if (gdk_visual_get_best() != gdk_visual_get_system())
275 {
276 GdkVisual* vis = gdk_visual_get_best();
277 gtk_widget_set_default_visual( vis );
278
279 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
280 gtk_widget_set_default_colormap( colormap );
281
282 visual = vis;
283 }
284 */
285
286 /* Nothing to do for 15, 16, 24, 32 bit displays */
287 if (visual->depth > 8) return TRUE;
288
289 /* initialize color cube for 8-bit color reduction dithering */
290
291 GdkColormap *cmap = gtk_widget_get_default_colormap();
292
293 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
294
295 for (int r = 0; r < 32; r++)
296 {
297 for (int g = 0; g < 32; g++)
298 {
299 for (int b = 0; b < 32; b++)
300 {
301 int rr = (r << 3) | (r >> 2);
302 int gg = (g << 3) | (g >> 2);
303 int bb = (b << 3) | (b >> 2);
304
305 int index = -1;
306
307 GdkColor *colors = cmap->colors;
308 if (colors)
309 {
310 int max = 3 * 65536;
311
312 for (int i = 0; i < cmap->size; i++)
313 {
314 int rdiff = ((rr << 8) - colors[i].red);
315 int gdiff = ((gg << 8) - colors[i].green);
316 int bdiff = ((bb << 8) - colors[i].blue);
317 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
318 if (sum < max)
319 {
320 index = i; max = sum;
321 }
322 }
323 }
324 else
325 {
326 #if (GTK_MINOR_VERSION > 0)
327 /* assume 8-bit true or static colors. this really
328 exists. */
329 GdkVisual* vis = gdk_colormap_get_visual( cmap );
330 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
331 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
332 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
333 #else
334 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
335 #endif
336 }
337 m_colorCube[ (r*1024) + (g*32) + b ] = index;
338 }
339 }
340 }
341
342 return TRUE;
343 }
344
345 bool wxApp::ProcessIdle()
346 {
347 wxIdleEvent event;
348 event.SetEventObject( this );
349 ProcessEvent( event );
350
351 return event.MoreRequested();
352 }
353
354 void wxApp::OnIdle( wxIdleEvent &event )
355 {
356 static bool s_inOnIdle = FALSE;
357
358 /* Avoid recursion (via ProcessEvent default case) */
359 if (s_inOnIdle)
360 return;
361
362 s_inOnIdle = TRUE;
363
364 /* Resend in the main thread events which have been prepared in other
365 threads */
366 ProcessPendingEvents();
367
368 /* 'Garbage' collection of windows deleted with Close(). */
369 DeletePendingObjects();
370
371 /* flush the logged messages if any */
372 #if wxUSE_LOG
373 wxLog *log = wxLog::GetActiveTarget();
374 if (log != NULL && log->HasPendingMessages())
375 log->Flush();
376 #endif // wxUSE_LOG
377
378 /* Send OnIdle events to all windows */
379 bool needMore = SendIdleEvents();
380
381 if (needMore)
382 event.RequestMore(TRUE);
383
384 s_inOnIdle = FALSE;
385 }
386
387 bool wxApp::SendIdleEvents()
388 {
389 bool needMore = FALSE;
390
391 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
392 while (node)
393 {
394 wxWindow* win = node->GetData();
395 if (SendIdleEvents(win))
396 needMore = TRUE;
397 node = node->GetNext();
398 }
399
400 return needMore;
401 }
402
403 bool wxApp::SendIdleEvents( wxWindow* win )
404 {
405 bool needMore = FALSE;
406
407 wxIdleEvent event;
408 event.SetEventObject(win);
409
410 win->ProcessEvent(event);
411
412 win->OnInternalIdle();
413
414 if (event.MoreRequested())
415 needMore = TRUE;
416
417 wxNode* node = win->GetChildren().First();
418 while (node)
419 {
420 wxWindow* win = (wxWindow*) node->Data();
421 if (SendIdleEvents(win))
422 needMore = TRUE;
423
424 node = node->Next();
425 }
426 return needMore ;
427 }
428
429 int wxApp::MainLoop()
430 {
431 gtk_main();
432 return 0;
433 }
434
435 void wxApp::ExitMainLoop()
436 {
437 if (gtk_main_level() > 0)
438 gtk_main_quit();
439 }
440
441 bool wxApp::Initialized()
442 {
443 return m_initialized;
444 }
445
446 bool wxApp::Pending()
447 {
448 return (gtk_events_pending() > 0);
449 }
450
451 void wxApp::Dispatch()
452 {
453 gtk_main_iteration();
454 }
455
456 void wxApp::DeletePendingObjects()
457 {
458 wxNode *node = wxPendingDelete.First();
459 while (node)
460 {
461 wxObject *obj = (wxObject *)node->Data();
462
463 delete obj;
464
465 if (wxPendingDelete.Find(obj))
466 delete node;
467
468 node = wxPendingDelete.First();
469 }
470 }
471
472 bool wxApp::Initialize()
473 {
474 wxBuffer = new wxChar[BUFSIZ + 512];
475
476 wxClassInfo::InitializeClasses();
477
478 wxSystemSettings::Init();
479
480 // GL: I'm annoyed ... I don't know where to put this and I don't want to
481 // create a module for that as it's part of the core.
482 #if wxUSE_THREADS
483 wxPendingEvents = new wxList();
484 wxPendingEventsLocker = new wxCriticalSection();
485 #endif
486
487 /*
488 wxTheFontNameDirectory = new wxFontNameDirectory;
489 wxTheFontNameDirectory->Initialize();
490 */
491
492 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
493 wxTheColourDatabase->Initialize();
494
495 wxInitializeStockLists();
496 wxInitializeStockObjects();
497
498 wxModule::RegisterModules();
499 if (!wxModule::InitializeModules()) return FALSE;
500
501 return TRUE;
502 }
503
504 void wxApp::CleanUp()
505 {
506 wxModule::CleanUpModules();
507
508 if (wxTheColourDatabase)
509 delete wxTheColourDatabase;
510 wxTheColourDatabase = (wxColourDatabase*) NULL;
511
512 /*
513 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
514 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
515 */
516
517 wxDeleteStockObjects();
518
519 wxDeleteStockLists();
520
521 delete wxTheApp;
522 wxTheApp = (wxApp*) NULL;
523
524 // GL: I'm annoyed ... I don't know where to put this and I don't want to
525 // create a module for that as it's part of the core.
526 #if wxUSE_THREADS
527 delete wxPendingEvents;
528 delete wxPendingEventsLocker;
529 #endif
530
531 wxSystemSettings::Done();
532
533 delete[] wxBuffer;
534
535 wxClassInfo::CleanUpClasses();
536
537 // check for memory leaks
538 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
539 if (wxDebugContext::CountObjectsLeft() > 0)
540 {
541 wxLogDebug(wxT("There were memory leaks.\n"));
542 wxDebugContext::Dump();
543 wxDebugContext::PrintStatistics();
544 }
545 #endif // Debug
546
547 #if wxUSE_LOG
548 // do this as the very last thing because everything else can log messages
549 wxLog::DontCreateOnDemand();
550
551 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
552 if (oldLog)
553 delete oldLog;
554 #endif // wxUSE_LOG
555 }
556
557 //-----------------------------------------------------------------------------
558 // wxEntry
559 //-----------------------------------------------------------------------------
560
561 int wxEntry( int argc, char *argv[] )
562 {
563 gtk_set_locale();
564
565 #if wxUSE_WCHAR_T
566 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
567 #else
568 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
569 #endif
570
571 gtk_init( &argc, &argv );
572
573 wxSetDetectableAutoRepeat( TRUE );
574
575 if (!wxApp::Initialize())
576 return -1;
577
578 if (!wxTheApp)
579 {
580 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
581 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
582
583 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
584
585 wxObject *test_app = app_ini();
586
587 wxTheApp = (wxApp*) test_app;
588 }
589
590 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
591
592 wxTheApp->argc = argc;
593 #if wxUSE_UNICODE
594 wxTheApp->argv = new wxChar*[argc+1];
595 int mb_argc = 0;
596 while (mb_argc < argc) {
597 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
598 mb_argc++;
599 }
600 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
601 #else
602 wxTheApp->argv = argv;
603 #endif
604
605 wxString name(wxFileNameFromPath(argv[0]));
606 wxStripExtension( name );
607 wxTheApp->SetAppName( name );
608
609 int retValue = 0;
610
611 if ( !wxTheApp->OnInitGui() )
612 retValue = -1;
613
614 // Here frames insert themselves automatically into wxTopLevelWindows by
615 // getting created in OnInit().
616 if ( retValue == 0 )
617 {
618 if ( !wxTheApp->OnInit() )
619 retValue = -1;
620 }
621
622 if ( retValue == 0 )
623 {
624 /* delete pending toplevel windows (typically a single
625 dialog) so that, if there isn't any left, we don't
626 call OnRun() */
627 wxTheApp->DeletePendingObjects();
628
629 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
630
631 if (wxTheApp->Initialized())
632 {
633 retValue = wxTheApp->OnRun();
634
635 wxWindow *topWindow = wxTheApp->GetTopWindow();
636 if (topWindow)
637 {
638 /* Forcibly delete the window. */
639 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
640 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
641 {
642 topWindow->Close( TRUE );
643 wxTheApp->DeletePendingObjects();
644 }
645 else
646 {
647 delete topWindow;
648 wxTheApp->SetTopWindow( (wxWindow*) NULL );
649 }
650 }
651 wxTheApp->OnExit();
652 }
653 }
654
655 #if wxUSE_LOG
656 // flush the logged messages if any
657 wxLog *log = wxLog::GetActiveTarget();
658 if (log != NULL && log->HasPendingMessages())
659 log->Flush();
660
661 // continuing to use user defined log target is unsafe from now on because
662 // some resources may be already unavailable, so replace it by something
663 // more safe
664 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
665 if ( oldlog )
666 delete oldlog;
667 #endif // wxUSE_LOG
668
669 wxApp::CleanUp();
670
671 return retValue;
672 }
673
674 #include "wx/gtk/info.xpm"
675 #include "wx/gtk/error.xpm"
676 #include "wx/gtk/question.xpm"
677 #include "wx/gtk/warning.xpm"
678
679 wxIcon
680 wxApp::GetStdIcon(int which) const
681 {
682 switch(which)
683 {
684 case wxICON_INFORMATION:
685 return wxIcon(info_xpm);
686
687 case wxICON_QUESTION:
688 return wxIcon(question_xpm);
689
690 case wxICON_EXCLAMATION:
691 return wxIcon(warning_xpm);
692
693 default:
694 wxFAIL_MSG(wxT("requested non existent standard icon"));
695 // still fall through
696
697 case wxICON_HAND:
698 return wxIcon(error_xpm);
699 }
700 }