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