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