]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/app.cpp
* Changed "wxPendingEvents" to pointers (tested on GTK)
[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 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 #if wxUSE_THREADS
291 /* Resend in the main thread events which have been prepared in other
292 threads */
293 ProcessPendingEvents();
294 #endif
295
296 /* 'Garbage' collection of windows deleted with Close(). */
297 DeletePendingObjects();
298
299 /* flush the logged messages if any */
300 wxLog *log = wxLog::GetActiveTarget();
301 if (log != NULL && log->HasPendingMessages())
302 log->Flush();
303
304 /* Send OnIdle events to all windows */
305 bool needMore = SendIdleEvents();
306
307 if (needMore)
308 event.RequestMore(TRUE);
309
310 inOnIdle = FALSE;
311 }
312
313 bool wxApp::SendIdleEvents()
314 {
315 bool needMore = FALSE;
316
317 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
318 while (node)
319 {
320 wxWindow* win = node->GetData();
321 if (SendIdleEvents(win))
322 needMore = TRUE;
323 node = node->GetNext();
324 }
325
326 return needMore;
327 }
328
329 bool wxApp::SendIdleEvents( wxWindow* win )
330 {
331 bool needMore = FALSE;
332
333 wxIdleEvent event;
334 event.SetEventObject(win);
335
336 win->OnInternalIdle();
337
338 win->ProcessEvent(event);
339
340 if (event.MoreRequested())
341 needMore = TRUE;
342
343 wxNode* node = win->GetChildren().First();
344 while (node)
345 {
346 wxWindow* win = (wxWindow*) node->Data();
347 if (SendIdleEvents(win))
348 needMore = TRUE;
349
350 node = node->Next();
351 }
352 return needMore ;
353 }
354
355 int wxApp::MainLoop()
356 {
357 gtk_main();
358 return 0;
359 }
360
361 void wxApp::ExitMainLoop()
362 {
363 gtk_main_quit();
364 }
365
366 bool wxApp::Initialized()
367 {
368 return m_initialized;
369 }
370
371 bool wxApp::Pending()
372 {
373 return FALSE;
374 }
375
376 void wxApp::Dispatch()
377 {
378 }
379
380 #if wxUSE_THREADS
381 void wxApp::ProcessPendingEvents()
382 {
383 wxNode *node = wxPendingEvents->First();
384 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
385
386 while (node)
387 {
388 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
389
390 handler->ProcessPendingEvents();
391
392 delete node;
393
394 node = wxPendingEvents->First();
395 }
396 }
397 #endif
398
399 void wxApp::DeletePendingObjects()
400 {
401 wxNode *node = wxPendingDelete.First();
402 while (node)
403 {
404 wxObject *obj = (wxObject *)node->Data();
405
406 delete obj;
407
408 if (wxPendingDelete.Member(obj))
409 delete node;
410
411 node = wxPendingDelete.First();
412 }
413 }
414
415 wxWindow *wxApp::GetTopWindow()
416 {
417 if (m_topWindow)
418 return m_topWindow;
419 else if (wxTopLevelWindows.GetCount() > 0)
420 return wxTopLevelWindows.GetFirst()->GetData();
421 else
422 return NULL;
423 }
424
425 void wxApp::SetTopWindow( wxWindow *win )
426 {
427 m_topWindow = win;
428 }
429
430 bool wxApp::Initialize()
431 {
432 wxBuffer = new char[BUFSIZ + 512];
433
434 wxClassInfo::InitializeClasses();
435
436 wxSystemSettings::Init();
437
438 // GL: I'm annoyed ... I don't know where to put this and I don't want to
439 // create a module for that as it's part of the core.
440 #if wxUSE_THREADS
441 wxPendingEvents = new wxList();
442 wxPendingEventsLocker = new wxCriticalSection();
443 #endif
444
445 /*
446 wxTheFontNameDirectory = new wxFontNameDirectory;
447 wxTheFontNameDirectory->Initialize();
448 */
449
450 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
451 wxTheColourDatabase->Initialize();
452
453 wxInitializeStockLists();
454 wxInitializeStockObjects();
455
456 #if wxUSE_WX_RESOURCES
457 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
458
459 wxInitializeResourceSystem();
460 #endif
461
462 wxImage::InitStandardHandlers();
463
464 /* no global cursor under X
465 g_globalCursor = new wxCursor; */
466
467 wxModule::RegisterModules();
468 if (!wxModule::InitializeModules()) return FALSE;
469
470 return TRUE;
471 }
472
473 void wxApp::CleanUp()
474 {
475 wxModule::CleanUpModules();
476
477 #if wxUSE_WX_RESOURCES
478 wxFlushResources();
479
480 if (wxTheResourceCache)
481 delete wxTheResourceCache;
482 wxTheResourceCache = (wxResourceCache*) NULL;
483
484 wxCleanUpResourceSystem();
485 #endif
486
487 if (wxTheColourDatabase)
488 delete wxTheColourDatabase;
489 wxTheColourDatabase = (wxColourDatabase*) NULL;
490
491 /*
492 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
493 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
494 */
495
496 wxDeleteStockObjects();
497
498 wxDeleteStockLists();
499
500 wxImage::CleanUpHandlers();
501
502 delete wxTheApp;
503 wxTheApp = (wxApp*) NULL;
504
505 // GL: I'm annoyed ... I don't know where to put this and I don't want to
506 // create a module for that as it's part of the core.
507 #if wxUSE_THREADS
508 delete wxPendingEvents;
509 delete wxPendingEventsLocker;
510 #endif
511
512 wxSystemSettings::Done();
513
514 delete[] wxBuffer;
515
516 wxClassInfo::CleanUpClasses();
517
518 // check for memory leaks
519 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
520 if (wxDebugContext::CountObjectsLeft() > 0)
521 {
522 wxLogDebug("There were memory leaks.\n");
523 wxDebugContext::Dump();
524 wxDebugContext::PrintStatistics();
525 }
526 #endif
527
528 // do this as the very last thing because everything else can log messages
529 wxLog::DontCreateOnDemand();
530
531 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
532 if (oldLog)
533 delete oldLog;
534 }
535
536 wxLog *wxApp::CreateLogTarget()
537 {
538 return new wxLogGui;
539 }
540
541 //-----------------------------------------------------------------------------
542 // wxEntry
543 //-----------------------------------------------------------------------------
544
545 int wxEntry( int argc, char *argv[] )
546 {
547 gtk_set_locale();
548
549 gtk_init( &argc, &argv );
550
551 if (!wxApp::Initialize())
552 return -1;
553
554 if (!wxTheApp)
555 {
556 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
557 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
558
559 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
560
561 wxObject *test_app = app_ini();
562
563 wxTheApp = (wxApp*) test_app;
564 }
565
566 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
567
568 wxTheApp->argc = argc;
569 wxTheApp->argv = argv;
570
571 char name[200];
572 strcpy( name, argv[0] );
573 strcpy( name, wxFileNameFromPath(name) );
574 wxStripExtension( name );
575 wxTheApp->SetAppName( name );
576
577 if (!wxTheApp->OnInitGui())
578 return 0;
579
580 /* Here frames insert themselves automatically
581 * into wxTopLevelWindows by getting created
582 * in OnInit(). */
583
584 if (!wxTheApp->OnInit())
585 return 0;
586
587 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
588
589 int retValue = 0;
590
591 if (wxTheApp->Initialized())
592 retValue = wxTheApp->OnRun();
593
594 wxWindow *topWindow = wxTheApp->GetTopWindow();
595 if (topWindow)
596 {
597 // Forcibly delete the window.
598 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
599 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
600 {
601 topWindow->Close( TRUE );
602 wxTheApp->DeletePendingObjects();
603 }
604 else
605 {
606 delete topWindow;
607 wxTheApp->SetTopWindow( (wxWindow*) NULL );
608 }
609 }
610
611 wxTheApp->OnExit();
612
613 // flush the logged messages if any
614 wxLog *log = wxLog::GetActiveTarget();
615 if (log != NULL && log->HasPendingMessages())
616 log->Flush();
617
618 // continuing to use user defined log target is unsafe from now on because
619 // some resources may be already unavailable, so replace it by something
620 // more safe
621 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
622 if ( oldlog )
623 delete oldlog;
624
625 wxApp::CleanUp();
626
627 return retValue;
628 }
629