]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/app.cpp
-1 is kept -1 as a wxWindowID
[wxWidgets.git] / src / gtk / 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
197 wxMutexGuiLeave();
198 wxUsleep(0);
199 wxMutexGuiEnter();
200
201 return TRUE;
202 }
203
204 void wxapp_install_idle_handler()
205 {
206 /* this routine gets called by all event handlers
207 indicating that the idle is over. */
208
209 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
210
211 g_isIdle = FALSE;
212 }
213
214 //-----------------------------------------------------------------------------
215 // wxApp
216 //-----------------------------------------------------------------------------
217
218 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
219
220 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
221 EVT_IDLE(wxApp::OnIdle)
222 END_EVENT_TABLE()
223
224 wxApp::wxApp()
225 {
226 wxTheApp = this;
227
228 m_topWindow = (wxWindow *) NULL;
229 m_exitOnFrameDelete = TRUE;
230
231 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
232
233 m_colorCube = (unsigned char*) NULL;
234 }
235
236 wxApp::~wxApp()
237 {
238 if (m_idleTag) gtk_idle_remove( m_idleTag );
239
240 if (m_colorCube) free(m_colorCube);
241 }
242
243 bool wxApp::OnInitGui()
244 {
245 /* Nothing to do for 15, 16, 24, 32 bit displays */
246
247 GdkVisual *visual = gdk_visual_get_system();
248 if (visual->depth > 8) return TRUE;
249
250 /* this initiates the standard palette as defined by GdkImlib
251 in the GNOME libraries. it ensures that all GNOME applications
252 use the same 64 colormap entries on 8-bit displays so you
253 can use several rather graphics-heavy applications at the
254 same time.
255 NOTE: this doesn't really seem to work this way... */
256
257 /*
258 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
259
260 for (int i = 0; i < 64; i++)
261 {
262 GdkColor col;
263 col.red = g_palette[i*3 + 0] << 8;
264 col.green = g_palette[i*3 + 1] << 8;
265 col.blue = g_palette[i*3 + 2] << 8;
266 col.pixel = 0;
267
268 gdk_color_alloc( cmap, &col );
269 }
270
271 gtk_widget_set_default_colormap( cmap );
272 */
273
274 /* initialize color cube for 8-bit color reduction dithering */
275
276 GdkColormap *cmap = gtk_widget_get_default_colormap();
277
278 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
279
280 for (int r = 0; r < 32; r++)
281 {
282 for (int g = 0; g < 32; g++)
283 {
284 for (int b = 0; b < 32; b++)
285 {
286 int rr = (r << 3) | (r >> 2);
287 int gg = (g << 3) | (g >> 2);
288 int bb = (b << 3) | (b >> 2);
289
290 int index = -1;
291
292 GdkColor *colors = cmap->colors;
293 if(colors)
294 {
295 int max = 3 * 65536;
296
297 for (int i = 0; i < cmap->size; i++)
298 {
299 int rdiff = ((rr << 8) - colors[i].red);
300 int gdiff = ((gg << 8) - colors[i].green);
301 int bdiff = ((bb << 8) - colors[i].blue);
302 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
303 if (sum < max)
304 {
305 index = i; max = sum;
306 }
307 }
308 }
309
310 m_colorCube[ (r*1024) + (g*32) + b ] = index;
311 }
312 }
313 }
314
315 return TRUE;
316 }
317
318 bool wxApp::ProcessIdle()
319 {
320 wxIdleEvent event;
321 event.SetEventObject( this );
322 ProcessEvent( event );
323
324 return event.MoreRequested();
325 }
326
327 void wxApp::OnIdle( wxIdleEvent &event )
328 {
329 static bool inOnIdle = FALSE;
330
331 /* Avoid recursion (via ProcessEvent default case) */
332 if (inOnIdle)
333 return;
334
335 inOnIdle = TRUE;
336
337 #if wxUSE_THREADS
338 /* Resend in the main thread events which have been prepared in other
339 threads */
340 ProcessPendingEvents();
341 #endif
342
343 /* 'Garbage' collection of windows deleted with Close(). */
344 DeletePendingObjects();
345
346 /* flush the logged messages if any */
347 wxLog *log = wxLog::GetActiveTarget();
348 if (log != NULL && log->HasPendingMessages())
349 log->Flush();
350
351 /* Send OnIdle events to all windows */
352 bool needMore = SendIdleEvents();
353
354 if (needMore)
355 event.RequestMore(TRUE);
356
357 inOnIdle = FALSE;
358 }
359
360 bool wxApp::SendIdleEvents()
361 {
362 bool needMore = FALSE;
363
364 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
365 while (node)
366 {
367 wxWindow* win = node->GetData();
368 if (SendIdleEvents(win))
369 needMore = TRUE;
370 node = node->GetNext();
371 }
372
373 return needMore;
374 }
375
376 bool wxApp::SendIdleEvents( wxWindow* win )
377 {
378 bool needMore = FALSE;
379
380 wxIdleEvent event;
381 event.SetEventObject(win);
382
383 win->OnInternalIdle();
384
385 win->ProcessEvent(event);
386
387 if (event.MoreRequested())
388 needMore = TRUE;
389
390 wxNode* node = win->GetChildren().First();
391 while (node)
392 {
393 wxWindow* win = (wxWindow*) node->Data();
394 if (SendIdleEvents(win))
395 needMore = TRUE;
396
397 node = node->Next();
398 }
399 return needMore ;
400 }
401
402 int wxApp::MainLoop()
403 {
404 gtk_main();
405 return 0;
406 }
407
408 void wxApp::ExitMainLoop()
409 {
410 gtk_main_quit();
411 }
412
413 bool wxApp::Initialized()
414 {
415 return m_initialized;
416 }
417
418 bool wxApp::Pending()
419 {
420 return (gtk_events_pending() > 0);
421 }
422
423 void wxApp::Dispatch()
424 {
425 gtk_main_iteration();
426 }
427
428 #if wxUSE_THREADS
429 void wxApp::ProcessPendingEvents()
430 {
431 wxNode *node = wxPendingEvents->First();
432 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
433
434 while (node)
435 {
436 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
437
438 handler->ProcessPendingEvents();
439
440 delete node;
441
442 node = wxPendingEvents->First();
443 }
444 }
445 #endif // wxUSE_THREADS
446
447 void wxApp::DeletePendingObjects()
448 {
449 wxNode *node = wxPendingDelete.First();
450 while (node)
451 {
452 wxObject *obj = (wxObject *)node->Data();
453
454 delete obj;
455
456 if (wxPendingDelete.Find(obj))
457 delete node;
458
459 node = wxPendingDelete.First();
460 }
461 }
462
463 wxWindow *wxApp::GetTopWindow()
464 {
465 if (m_topWindow)
466 return m_topWindow;
467 else if (wxTopLevelWindows.GetCount() > 0)
468 return wxTopLevelWindows.GetFirst()->GetData();
469 else
470 return NULL;
471 }
472
473 void wxApp::SetTopWindow( wxWindow *win )
474 {
475 m_topWindow = win;
476 }
477
478 bool wxApp::Initialize()
479 {
480 wxBuffer = new wxChar[BUFSIZ + 512];
481
482 wxClassInfo::InitializeClasses();
483
484 wxSystemSettings::Init();
485
486 // GL: I'm annoyed ... I don't know where to put this and I don't want to
487 // create a module for that as it's part of the core.
488 #if wxUSE_THREADS
489 wxPendingEvents = new wxList();
490 wxPendingEventsLocker = new wxCriticalSection();
491 #endif
492
493 /*
494 wxTheFontNameDirectory = new wxFontNameDirectory;
495 wxTheFontNameDirectory->Initialize();
496 */
497
498 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
499 wxTheColourDatabase->Initialize();
500
501 wxInitializeStockLists();
502 wxInitializeStockObjects();
503
504 #if wxUSE_WX_RESOURCES
505 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
506
507 wxInitializeResourceSystem();
508 #endif
509
510 wxImage::InitStandardHandlers();
511
512 /* no global cursor under X
513 g_globalCursor = new wxCursor; */
514
515 wxModule::RegisterModules();
516 if (!wxModule::InitializeModules()) return FALSE;
517
518 return TRUE;
519 }
520
521 void wxApp::CleanUp()
522 {
523 wxModule::CleanUpModules();
524
525 #if wxUSE_WX_RESOURCES
526 wxFlushResources();
527
528 if (wxTheResourceCache)
529 delete wxTheResourceCache;
530 wxTheResourceCache = (wxResourceCache*) NULL;
531
532 wxCleanUpResourceSystem();
533 #endif
534
535 if (wxTheColourDatabase)
536 delete wxTheColourDatabase;
537 wxTheColourDatabase = (wxColourDatabase*) NULL;
538
539 /*
540 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
541 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
542 */
543
544 wxDeleteStockObjects();
545
546 wxDeleteStockLists();
547
548 wxImage::CleanUpHandlers();
549
550 delete wxTheApp;
551 wxTheApp = (wxApp*) NULL;
552
553 // GL: I'm annoyed ... I don't know where to put this and I don't want to
554 // create a module for that as it's part of the core.
555 #if wxUSE_THREADS
556 delete wxPendingEvents;
557 delete wxPendingEventsLocker;
558 #endif
559
560 wxSystemSettings::Done();
561
562 delete[] wxBuffer;
563
564 wxClassInfo::CleanUpClasses();
565
566 // check for memory leaks
567 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
568 if (wxDebugContext::CountObjectsLeft() > 0)
569 {
570 wxLogDebug(_T("There were memory leaks.\n"));
571 wxDebugContext::Dump();
572 wxDebugContext::PrintStatistics();
573 }
574 #endif // Debug
575
576 // do this as the very last thing because everything else can log messages
577 wxLog::DontCreateOnDemand();
578
579 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
580 if (oldLog)
581 delete oldLog;
582 }
583
584 wxLog *wxApp::CreateLogTarget()
585 {
586 return new wxLogGui;
587 }
588
589 //-----------------------------------------------------------------------------
590 // wxEntry
591 //-----------------------------------------------------------------------------
592
593 int wxEntry( int argc, char *argv[] )
594 {
595 gtk_set_locale();
596
597 gtk_init( &argc, &argv );
598
599 if (!wxApp::Initialize())
600 return -1;
601
602 if (!wxTheApp)
603 {
604 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
605 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
606
607 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
608
609 wxObject *test_app = app_ini();
610
611 wxTheApp = (wxApp*) test_app;
612 }
613
614 wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
615
616 wxTheApp->argc = argc;
617 wxTheApp->argv = argv;
618
619 wxString name(wxFileNameFromPath(argv[0]));
620 wxStripExtension( name );
621 wxTheApp->SetAppName( name );
622
623 int retValue = 0;
624
625 if ( !wxTheApp->OnInitGui() )
626 retValue = -1;
627
628 // Here frames insert themselves automatically into wxTopLevelWindows by
629 // getting created in OnInit().
630 if ( retValue == 0 )
631 {
632 if ( !wxTheApp->OnInit() )
633 retValue = -1;
634 }
635
636 if ( retValue == 0 )
637 {
638 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
639
640 if (wxTheApp->Initialized())
641 retValue = wxTheApp->OnRun();
642
643 wxWindow *topWindow = wxTheApp->GetTopWindow();
644 if (topWindow)
645 {
646 // Forcibly delete the window.
647 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
648 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
649 {
650 topWindow->Close( TRUE );
651 wxTheApp->DeletePendingObjects();
652 }
653 else
654 {
655 delete topWindow;
656 wxTheApp->SetTopWindow( (wxWindow*) NULL );
657 }
658 }
659
660 wxTheApp->OnExit();
661 }
662
663 // flush the logged messages if any
664 wxLog *log = wxLog::GetActiveTarget();
665 if (log != NULL && log->HasPendingMessages())
666 log->Flush();
667
668 // continuing to use user defined log target is unsafe from now on because
669 // some resources may be already unavailable, so replace it by something
670 // more safe
671 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
672 if ( oldlog )
673 delete oldlog;
674
675 wxApp::CleanUp();
676
677 return retValue;
678 }
679