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