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