]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/app.cpp
wxGTK's built-in dockable menu now give their
[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 // 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 gtk_events_pending();
382 }
383
384 void wxApp::Dispatch()
385 {
386 gtk_main_iteration();
387 }
388
389 #if wxUSE_THREADS
390 void wxApp::ProcessPendingEvents()
391 {
392 wxNode *node = wxPendingEvents->First();
393 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
394
395 while (node)
396 {
397 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
398
399 handler->ProcessPendingEvents();
400
401 delete node;
402
403 node = wxPendingEvents->First();
404 }
405 }
406 #endif // wxUSE_THREADS
407
408 void wxApp::DeletePendingObjects()
409 {
410 wxNode *node = wxPendingDelete.First();
411 while (node)
412 {
413 wxObject *obj = (wxObject *)node->Data();
414
415 delete obj;
416
417 if (wxPendingDelete.Member(obj))
418 delete node;
419
420 node = wxPendingDelete.First();
421 }
422 }
423
424 wxWindow *wxApp::GetTopWindow()
425 {
426 if (m_topWindow)
427 return m_topWindow;
428 else if (wxTopLevelWindows.GetCount() > 0)
429 return wxTopLevelWindows.GetFirst()->GetData();
430 else
431 return NULL;
432 }
433
434 void wxApp::SetTopWindow( wxWindow *win )
435 {
436 m_topWindow = win;
437 }
438
439 bool wxApp::Initialize()
440 {
441 wxBuffer = new wxChar[BUFSIZ + 512];
442
443 wxClassInfo::InitializeClasses();
444
445 wxSystemSettings::Init();
446
447 // GL: I'm annoyed ... I don't know where to put this and I don't want to
448 // create a module for that as it's part of the core.
449 #if wxUSE_THREADS
450 wxPendingEvents = new wxList();
451 wxPendingEventsLocker = new wxCriticalSection();
452 #endif
453
454 /*
455 wxTheFontNameDirectory = new wxFontNameDirectory;
456 wxTheFontNameDirectory->Initialize();
457 */
458
459 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
460 wxTheColourDatabase->Initialize();
461
462 wxInitializeStockLists();
463 wxInitializeStockObjects();
464
465 #if wxUSE_WX_RESOURCES
466 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
467
468 wxInitializeResourceSystem();
469 #endif
470
471 wxImage::InitStandardHandlers();
472
473 /* no global cursor under X
474 g_globalCursor = new wxCursor; */
475
476 wxModule::RegisterModules();
477 if (!wxModule::InitializeModules()) return FALSE;
478
479 return TRUE;
480 }
481
482 void wxApp::CleanUp()
483 {
484 wxModule::CleanUpModules();
485
486 #if wxUSE_WX_RESOURCES
487 wxFlushResources();
488
489 if (wxTheResourceCache)
490 delete wxTheResourceCache;
491 wxTheResourceCache = (wxResourceCache*) NULL;
492
493 wxCleanUpResourceSystem();
494 #endif
495
496 if (wxTheColourDatabase)
497 delete wxTheColourDatabase;
498 wxTheColourDatabase = (wxColourDatabase*) NULL;
499
500 /*
501 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
502 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
503 */
504
505 wxDeleteStockObjects();
506
507 wxDeleteStockLists();
508
509 wxImage::CleanUpHandlers();
510
511 delete wxTheApp;
512 wxTheApp = (wxApp*) NULL;
513
514 // GL: I'm annoyed ... I don't know where to put this and I don't want to
515 // create a module for that as it's part of the core.
516 #if wxUSE_THREADS
517 delete wxPendingEvents;
518 delete wxPendingEventsLocker;
519 #endif
520
521 wxSystemSettings::Done();
522
523 delete[] wxBuffer;
524
525 wxClassInfo::CleanUpClasses();
526
527 // check for memory leaks
528 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
529 if (wxDebugContext::CountObjectsLeft() > 0)
530 {
531 wxLogDebug(_T("There were memory leaks.\n"));
532 wxDebugContext::Dump();
533 wxDebugContext::PrintStatistics();
534 }
535 #endif // Debug
536
537 // do this as the very last thing because everything else can log messages
538 wxLog::DontCreateOnDemand();
539
540 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
541 if (oldLog)
542 delete oldLog;
543 }
544
545 wxLog *wxApp::CreateLogTarget()
546 {
547 return new wxLogGui;
548 }
549
550 //-----------------------------------------------------------------------------
551 // wxEntry
552 //-----------------------------------------------------------------------------
553
554 int wxEntry( int argc, char *argv[] )
555 {
556 gtk_set_locale();
557
558 gtk_init( &argc, &argv );
559
560 if (!wxApp::Initialize())
561 return -1;
562
563 if (!wxTheApp)
564 {
565 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
566 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
567
568 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
569
570 wxObject *test_app = app_ini();
571
572 wxTheApp = (wxApp*) test_app;
573 }
574
575 wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
576
577 wxTheApp->argc = argc;
578 wxTheApp->argv = argv;
579
580 wxString name(wxFileNameFromPath(argv[0]));
581 wxStripExtension( name );
582 wxTheApp->SetAppName( name );
583
584 if (!wxTheApp->OnInitGui())
585 return 0;
586
587 // Here frames insert themselves automatically into wxTopLevelWindows by
588 // getting created in OnInit().
589 if (!wxTheApp->OnInit())
590 return 0;
591
592 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
593
594 int retValue = 0;
595
596 if (wxTheApp->Initialized())
597 retValue = wxTheApp->OnRun();
598
599 wxWindow *topWindow = wxTheApp->GetTopWindow();
600 if (topWindow)
601 {
602 // Forcibly delete the window.
603 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
604 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
605 {
606 topWindow->Close( TRUE );
607 wxTheApp->DeletePendingObjects();
608 }
609 else
610 {
611 delete topWindow;
612 wxTheApp->SetTopWindow( (wxWindow*) NULL );
613 }
614 }
615
616 wxTheApp->OnExit();
617
618 // flush the logged messages if any
619 wxLog *log = wxLog::GetActiveTarget();
620 if (log != NULL && log->HasPendingMessages())
621 log->Flush();
622
623 // continuing to use user defined log target is unsafe from now on because
624 // some resources may be already unavailable, so replace it by something
625 // more safe
626 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
627 if ( oldlog )
628 delete oldlog;
629
630 wxApp::CleanUp();
631
632 return retValue;
633 }
634