]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/app.cpp
Another one bites the dust.
[wxWidgets.git] / src / gtk / app.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: app.cpp
3// Purpose:
4// Author: Robert Roebling
32e9da8b 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
8bbe427f 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
afb74891 11 #pragma implementation "app.h"
c801d85f
KB
12#endif
13
14#include "wx/app.h"
15#include "wx/gdicmn.h"
16#include "wx/utils.h"
c801d85f
KB
17#include "wx/intl.h"
18#include "wx/log.h"
46dc76ba 19#include "wx/memory.h"
a3622daa
VZ
20#include "wx/font.h"
21#include "wx/settings.h"
0d2a2b60 22#include "wx/dialog.h"
afb74891 23
06cfab17 24#if wxUSE_WX_RESOURCES
afb74891 25 #include "wx/resource.h"
f5abe911 26#endif
afb74891 27
031b2a7b 28#include "wx/module.h"
4bc67cc5 29#include "wx/image.h"
afb74891 30
f3855ef0 31#include "wx/thread.h"
afb74891 32
c801d85f
KB
33#include "unistd.h"
34
afb74891
VZ
35#include <glib.h>
36#include <gdk/gdk.h>
37#include <gtk/gtk.h>
24178e4a 38
83624f79
RR
39#include "wx/gtk/win_gtk.h"
40
c801d85f
KB
41//-----------------------------------------------------------------------------
42// global data
43//-----------------------------------------------------------------------------
44
c67daf87 45wxApp *wxTheApp = (wxApp *) NULL;
c801d85f
KB
46wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
47
48extern wxList wxPendingDelete;
7214297d 49#if wxUSE_THREADS
4d3a259a
GL
50extern wxList *wxPendingEvents;
51extern wxCriticalSection *wxPendingEventsLocker;
7214297d 52#endif
a3622daa 53extern wxResourceCache *wxTheResourceCache;
c801d85f 54
01111366
RR
55unsigned 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,
e0253070 105 0xf0, 0xa8, 0xef,
01111366
RR
106 0xd0, 0x88, 0xd0,
107 0xaf, 0x66, 0xaf,
108 0x8e, 0x44, 0x8e,
109 0x6d, 0x22, 0x6d,
e0253070 110 0x4b, 0x0, 0x4b,
01111366
RR
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
c801d85f
KB
123//-----------------------------------------------------------------------------
124// local functions
125//-----------------------------------------------------------------------------
126
127extern void wxFlushResources(void);
128
129//-----------------------------------------------------------------------------
130// global functions
131//-----------------------------------------------------------------------------
132
60acb947 133void wxExit()
c801d85f 134{
ec758a20 135 gtk_main_quit();
ff7b1510 136}
c801d85f 137
53a8af59
KB
138// forward decl
139gint wxapp_idle_callback( gpointer WXUNUSED(data) );
140
60acb947 141bool wxYield()
c801d85f 142{
5f12ae5c
VZ
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)
e146b8c8 146 for ( wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
5f12ae5c
VZ
147 node;
148 node = node->GetNext() )
149 {
e146b8c8 150 wxWindow *win = node->GetData();
5f12ae5c
VZ
151 win->OnInternalIdle();
152 }
153
53a8af59
KB
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())
5f12ae5c
VZ
159 gtk_main_iteration();
160
53a8af59 161 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
ec758a20 162 return TRUE;
ff7b1510 163}
c801d85f
KB
164
165//-----------------------------------------------------------------------------
166// wxApp
167//-----------------------------------------------------------------------------
168
169IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
170
53010e52
RR
171BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
172 EVT_IDLE(wxApp::OnIdle)
173END_EVENT_TABLE()
174
c801d85f
KB
175gint wxapp_idle_callback( gpointer WXUNUSED(data) )
176{
afb74891
VZ
177 if (wxTheApp)
178 {
179 while (wxTheApp->ProcessIdle())
180 {
181 }
182 }
183
f3855ef0 184 wxMutexGuiLeave();
afb74891 185 wxUsleep(10);
f3855ef0 186 wxMutexGuiEnter();
afb74891 187
ec758a20 188 return TRUE;
ff7b1510 189}
c801d85f
KB
190
191wxApp::wxApp()
192{
0d2a2b60 193 wxTheApp = this;
60acb947 194
ec758a20
RR
195 m_topWindow = (wxWindow *) NULL;
196 m_exitOnFrameDelete = TRUE;
60acb947 197
0d2a2b60 198 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
60acb947 199
f6fcbb63 200 m_colorCube = (unsigned char*) NULL;
ff7b1510 201}
c801d85f 202
60acb947 203wxApp::~wxApp()
c801d85f 204{
ec758a20 205 gtk_idle_remove( m_idleTag );
60acb947 206
f6fcbb63 207 if (m_colorCube) free(m_colorCube);
ff7b1510 208}
c801d85f 209
0d2a2b60 210bool wxApp::OnInitGui()
c801d85f 211{
f6fcbb63
RR
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;
60acb947 216
0d2a2b60
RR
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... */
bbe0af5b 223
0d2a2b60
RR
224 /*
225 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
bbe0af5b 226
0d2a2b60
RR
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 }
60acb947 237
0d2a2b60
RR
238 gtk_widget_set_default_colormap( cmap );
239 */
60acb947 240
f6fcbb63 241 /* initialize color cube for 8-bit color reduction dithering */
60acb947 242
f6fcbb63 243 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 244
f6fcbb63
RR
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);
60acb947 256
f6fcbb63
RR
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 }
60acb947 269
f6fcbb63
RR
270 m_colorCube[ (r*1024) + (g*32) + b ] = index;
271 }
272 }
273 }
c801d85f 274
60acb947 275
bbe0af5b
RR
276 return TRUE;
277}
278
60acb947 279bool wxApp::ProcessIdle()
53010e52 280{
ec758a20
RR
281 wxIdleEvent event;
282 event.SetEventObject( this );
283 ProcessEvent( event );
0cf2cb36 284
ec758a20 285 return event.MoreRequested();
ff7b1510 286}
53010e52
RR
287
288void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 289{
ec758a20 290 static bool inOnIdle = FALSE;
53010e52 291
d524867f 292 /* Avoid recursion (via ProcessEvent default case) */
ec758a20
RR
293 if (inOnIdle)
294 return;
53010e52 295
ec758a20 296 inOnIdle = TRUE;
53010e52 297
d345e841 298#if wxUSE_THREADS
7214297d
GL
299 /* Resend in the main thread events which have been prepared in other
300 threads */
301 ProcessPendingEvents();
d345e841 302#endif
7214297d 303
d524867f 304 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 305 DeletePendingObjects();
53010e52 306
d524867f
RR
307 /* flush the logged messages if any */
308 wxLog *log = wxLog::GetActiveTarget();
309 if (log != NULL && log->HasPendingMessages())
310 log->Flush();
53010e52 311
d524867f 312 /* Send OnIdle events to all windows */
ec758a20 313 bool needMore = SendIdleEvents();
53010e52 314
ec758a20
RR
315 if (needMore)
316 event.RequestMore(TRUE);
53010e52 317
ec758a20 318 inOnIdle = FALSE;
ff7b1510 319}
53010e52 320
60acb947 321bool wxApp::SendIdleEvents()
53010e52
RR
322{
323 bool needMore = FALSE;
e0253070 324
e146b8c8 325 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
326 while (node)
327 {
e146b8c8 328 wxWindow* win = node->GetData();
f3855ef0 329 if (SendIdleEvents(win))
53010e52 330 needMore = TRUE;
e146b8c8 331 node = node->GetNext();
ec758a20 332 }
e146b8c8 333
53010e52 334 return needMore;
ff7b1510 335}
53010e52
RR
336
337bool wxApp::SendIdleEvents( wxWindow* win )
338{
339 bool needMore = FALSE;
340
8bbe427f
VZ
341 wxIdleEvent event;
342 event.SetEventObject(win);
60acb947 343
9390a202 344 win->OnInternalIdle();
60acb947 345
8bbe427f 346 win->ProcessEvent(event);
53010e52
RR
347
348 if (event.MoreRequested())
349 needMore = TRUE;
350
8bbe427f
VZ
351 wxNode* node = win->GetChildren().First();
352 while (node)
353 {
354 wxWindow* win = (wxWindow*) node->Data();
355 if (SendIdleEvents(win))
53010e52
RR
356 needMore = TRUE;
357
8bbe427f
VZ
358 node = node->Next();
359 }
53010e52 360 return needMore ;
ff7b1510 361}
c801d85f 362
60acb947 363int wxApp::MainLoop()
c801d85f 364{
ec758a20
RR
365 gtk_main();
366 return 0;
ff7b1510 367}
c801d85f 368
60acb947 369void wxApp::ExitMainLoop()
c801d85f 370{
ec758a20 371 gtk_main_quit();
ff7b1510 372}
c801d85f 373
60acb947 374bool wxApp::Initialized()
c801d85f 375{
ec758a20 376 return m_initialized;
ff7b1510 377}
c801d85f 378
60acb947 379bool wxApp::Pending()
c801d85f 380{
ec758a20 381 return FALSE;
ff7b1510 382}
c801d85f 383
60acb947 384void wxApp::Dispatch()
c801d85f 385{
ff7b1510 386}
c801d85f 387
7214297d
GL
388#if wxUSE_THREADS
389void wxApp::ProcessPendingEvents()
390{
4d3a259a
GL
391 wxNode *node = wxPendingEvents->First();
392 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
7214297d
GL
393
394 while (node)
395 {
396 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
397
398 handler->ProcessPendingEvents();
e146b8c8 399
7214297d
GL
400 delete node;
401
4d3a259a 402 node = wxPendingEvents->First();
7214297d
GL
403 }
404}
405#endif
406
60acb947 407void wxApp::DeletePendingObjects()
c801d85f 408{
ec758a20
RR
409 wxNode *node = wxPendingDelete.First();
410 while (node)
411 {
412 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 413
ec758a20 414 delete obj;
c801d85f 415
ec758a20
RR
416 if (wxPendingDelete.Member(obj))
417 delete node;
c801d85f 418
ec758a20
RR
419 node = wxPendingDelete.First();
420 }
ff7b1510 421}
c801d85f 422
60acb947 423wxWindow *wxApp::GetTopWindow()
c801d85f 424{
e146b8c8
VZ
425 if (m_topWindow)
426 return m_topWindow;
427 else if (wxTopLevelWindows.GetCount() > 0)
428 return wxTopLevelWindows.GetFirst()->GetData();
429 else
430 return NULL;
ff7b1510 431}
c801d85f
KB
432
433void wxApp::SetTopWindow( wxWindow *win )
434{
ec758a20 435 m_topWindow = win;
ff7b1510 436}
c801d85f 437
60acb947 438bool wxApp::Initialize()
c801d85f 439{
0d2a2b60
RR
440 wxBuffer = new char[BUFSIZ + 512];
441
442 wxClassInfo::InitializeClasses();
60acb947 443
0d2a2b60 444 wxSystemSettings::Init();
60acb947 445
4d3a259a
GL
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
36b3b54a 453/*
0d2a2b60
RR
454 wxTheFontNameDirectory = new wxFontNameDirectory;
455 wxTheFontNameDirectory->Initialize();
36b3b54a 456*/
c801d85f 457
0d2a2b60
RR
458 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
459 wxTheColourDatabase->Initialize();
a3622daa 460
0d2a2b60
RR
461 wxInitializeStockLists();
462 wxInitializeStockObjects();
c801d85f 463
06cfab17 464#if wxUSE_WX_RESOURCES
0d2a2b60 465 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
60acb947 466
0d2a2b60 467 wxInitializeResourceSystem();
f5abe911 468#endif
0cf2cb36 469
0d2a2b60 470 wxImage::InitStandardHandlers();
e0253070 471
0d2a2b60
RR
472 /* no global cursor under X
473 g_globalCursor = new wxCursor; */
60acb947 474
0d2a2b60
RR
475 wxModule::RegisterModules();
476 if (!wxModule::InitializeModules()) return FALSE;
60acb947 477
0d2a2b60 478 return TRUE;
ff7b1510 479}
c801d85f 480
60acb947 481void wxApp::CleanUp()
c801d85f 482{
0d2a2b60 483 wxModule::CleanUpModules();
0cf2cb36 484
06cfab17 485#if wxUSE_WX_RESOURCES
ec758a20 486 wxFlushResources();
a3622daa 487
60acb947
VZ
488 if (wxTheResourceCache)
489 delete wxTheResourceCache;
bbe0af5b 490 wxTheResourceCache = (wxResourceCache*) NULL;
60acb947 491
f5abe911
RR
492 wxCleanUpResourceSystem();
493#endif
a3622daa 494
60acb947
VZ
495 if (wxTheColourDatabase)
496 delete wxTheColourDatabase;
0d2a2b60 497 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 498
36b3b54a 499/*
0d2a2b60
RR
500 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
501 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
36b3b54a 502*/
60acb947 503
0d2a2b60
RR
504 wxDeleteStockObjects();
505
ec758a20 506 wxDeleteStockLists();
a3622daa 507
ec758a20 508 wxImage::CleanUpHandlers();
0cf2cb36 509
0d2a2b60
RR
510 delete wxTheApp;
511 wxTheApp = (wxApp*) NULL;
512
4d3a259a
GL
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
3e61c765 520 wxSystemSettings::Done();
60acb947 521
3e61c765
RR
522 delete[] wxBuffer;
523
524 wxClassInfo::CleanUpClasses();
60acb947
VZ
525
526 // check for memory leaks
0d2a2b60
RR
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
60acb947 536 // do this as the very last thing because everything else can log messages
0d2a2b60 537 wxLog::DontCreateOnDemand();
60acb947 538
0d2a2b60 539 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
540 if (oldLog)
541 delete oldLog;
ff7b1510 542}
0cf2cb36 543
c801d85f
KB
544wxLog *wxApp::CreateLogTarget()
545{
0d2a2b60 546 return new wxLogGui;
c801d85f
KB
547}
548
549//-----------------------------------------------------------------------------
550// wxEntry
551//-----------------------------------------------------------------------------
552
553int wxEntry( int argc, char *argv[] )
554{
0d2a2b60 555 gtk_set_locale();
c801d85f 556
0d2a2b60 557 gtk_init( &argc, &argv );
0cf2cb36 558
60acb947
VZ
559 if (!wxApp::Initialize())
560 return -1;
0cf2cb36 561
ec758a20 562 if (!wxTheApp)
c801d85f 563 {
60acb947
VZ
564 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
565 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
0cf2cb36 566
ec758a20 567 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 568
ec758a20 569 wxObject *test_app = app_ini();
0cf2cb36 570
ec758a20
RR
571 wxTheApp = (wxApp*) test_app;
572 }
0cf2cb36 573
60acb947 574 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
c801d85f 575
ec758a20
RR
576 wxTheApp->argc = argc;
577 wxTheApp->argv = argv;
0cf2cb36 578
ec758a20
RR
579 char name[200];
580 strcpy( name, argv[0] );
581 strcpy( name, wxFileNameFromPath(name) );
582 wxStripExtension( name );
583 wxTheApp->SetAppName( name );
e0253070 584
60acb947
VZ
585 if (!wxTheApp->OnInitGui())
586 return 0;
c801d85f 587
0d2a2b60
RR
588 /* Here frames insert themselves automatically
589 * into wxTopLevelWindows by getting created
590 * in OnInit(). */
0cf2cb36 591
60acb947
VZ
592 if (!wxTheApp->OnInit())
593 return 0;
c801d85f 594
e146b8c8 595 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 596
ec758a20 597 int retValue = 0;
0cf2cb36 598
60acb947
VZ
599 if (wxTheApp->Initialized())
600 retValue = wxTheApp->OnRun();
0cf2cb36 601
0d2a2b60
RR
602 wxWindow *topWindow = wxTheApp->GetTopWindow();
603 if (topWindow)
ec758a20 604 {
60acb947 605 // Forcibly delete the window.
0d2a2b60
RR
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 }
ec758a20 617 }
e0253070 618
0d2a2b60 619 wxTheApp->OnExit();
0cf2cb36 620
60acb947 621 // flush the logged messages if any
0d2a2b60
RR
622 wxLog *log = wxLog::GetActiveTarget();
623 if (log != NULL && log->HasPendingMessages())
624 log->Flush();
625
60acb947
VZ
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
0d2a2b60 633 wxApp::CleanUp();
184b5d99 634
ec758a20 635 return retValue;
ff7b1510 636}
1a56f55c 637