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