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