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