]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/app.cpp
::GetWindowText() -> wxGetWindowText
[wxWidgets.git] / src / gtk1 / 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
60acb947 138bool wxYield()
c801d85f 139{
5f12ae5c
VZ
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)
e146b8c8 143 for ( wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
5f12ae5c
VZ
144 node;
145 node = node->GetNext() )
146 {
e146b8c8 147 wxWindow *win = node->GetData();
5f12ae5c
VZ
148 win->OnInternalIdle();
149 }
150
151 while (gtk_events_pending() > 0)
152 gtk_main_iteration();
153
ec758a20 154 return TRUE;
ff7b1510 155}
c801d85f
KB
156
157//-----------------------------------------------------------------------------
158// wxApp
159//-----------------------------------------------------------------------------
160
161IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
162
53010e52
RR
163BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
164 EVT_IDLE(wxApp::OnIdle)
165END_EVENT_TABLE()
166
c801d85f
KB
167gint wxapp_idle_callback( gpointer WXUNUSED(data) )
168{
afb74891
VZ
169 if (wxTheApp)
170 {
171 while (wxTheApp->ProcessIdle())
172 {
173 }
174 }
175
f3855ef0 176 wxMutexGuiLeave();
afb74891 177 wxUsleep(10);
f3855ef0 178 wxMutexGuiEnter();
afb74891 179
ec758a20 180 return TRUE;
ff7b1510 181}
c801d85f
KB
182
183wxApp::wxApp()
184{
0d2a2b60 185 wxTheApp = this;
60acb947 186
ec758a20
RR
187 m_topWindow = (wxWindow *) NULL;
188 m_exitOnFrameDelete = TRUE;
60acb947 189
0d2a2b60 190 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
60acb947 191
f6fcbb63 192 m_colorCube = (unsigned char*) NULL;
ff7b1510 193}
c801d85f 194
60acb947 195wxApp::~wxApp()
c801d85f 196{
ec758a20 197 gtk_idle_remove( m_idleTag );
60acb947 198
f6fcbb63 199 if (m_colorCube) free(m_colorCube);
ff7b1510 200}
c801d85f 201
0d2a2b60 202bool wxApp::OnInitGui()
c801d85f 203{
f6fcbb63
RR
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;
60acb947 208
0d2a2b60
RR
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... */
bbe0af5b 215
0d2a2b60
RR
216 /*
217 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
bbe0af5b 218
0d2a2b60
RR
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 }
60acb947 229
0d2a2b60
RR
230 gtk_widget_set_default_colormap( cmap );
231 */
60acb947 232
f6fcbb63 233 /* initialize color cube for 8-bit color reduction dithering */
60acb947 234
f6fcbb63 235 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 236
f6fcbb63
RR
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);
60acb947 248
f6fcbb63
RR
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 }
60acb947 261
f6fcbb63
RR
262 m_colorCube[ (r*1024) + (g*32) + b ] = index;
263 }
264 }
265 }
c801d85f 266
60acb947 267
bbe0af5b
RR
268 return TRUE;
269}
270
60acb947 271bool wxApp::ProcessIdle()
53010e52 272{
ec758a20
RR
273 wxIdleEvent event;
274 event.SetEventObject( this );
275 ProcessEvent( event );
0cf2cb36 276
ec758a20 277 return event.MoreRequested();
ff7b1510 278}
53010e52
RR
279
280void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 281{
ec758a20 282 static bool inOnIdle = FALSE;
53010e52 283
d524867f 284 /* Avoid recursion (via ProcessEvent default case) */
ec758a20
RR
285 if (inOnIdle)
286 return;
53010e52 287
ec758a20 288 inOnIdle = TRUE;
53010e52 289
d345e841 290#if wxUSE_THREADS
7214297d
GL
291 /* Resend in the main thread events which have been prepared in other
292 threads */
293 ProcessPendingEvents();
d345e841 294#endif
7214297d 295
d524867f 296 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 297 DeletePendingObjects();
53010e52 298
d524867f
RR
299 /* flush the logged messages if any */
300 wxLog *log = wxLog::GetActiveTarget();
301 if (log != NULL && log->HasPendingMessages())
302 log->Flush();
53010e52 303
d524867f 304 /* Send OnIdle events to all windows */
ec758a20 305 bool needMore = SendIdleEvents();
53010e52 306
ec758a20
RR
307 if (needMore)
308 event.RequestMore(TRUE);
53010e52 309
ec758a20 310 inOnIdle = FALSE;
ff7b1510 311}
53010e52 312
60acb947 313bool wxApp::SendIdleEvents()
53010e52
RR
314{
315 bool needMore = FALSE;
e0253070 316
e146b8c8 317 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
318 while (node)
319 {
e146b8c8 320 wxWindow* win = node->GetData();
f3855ef0 321 if (SendIdleEvents(win))
53010e52 322 needMore = TRUE;
e146b8c8 323 node = node->GetNext();
ec758a20 324 }
e146b8c8 325
53010e52 326 return needMore;
ff7b1510 327}
53010e52
RR
328
329bool wxApp::SendIdleEvents( wxWindow* win )
330{
331 bool needMore = FALSE;
332
8bbe427f
VZ
333 wxIdleEvent event;
334 event.SetEventObject(win);
60acb947 335
9390a202 336 win->OnInternalIdle();
60acb947 337
8bbe427f 338 win->ProcessEvent(event);
53010e52
RR
339
340 if (event.MoreRequested())
341 needMore = TRUE;
342
8bbe427f
VZ
343 wxNode* node = win->GetChildren().First();
344 while (node)
345 {
346 wxWindow* win = (wxWindow*) node->Data();
347 if (SendIdleEvents(win))
53010e52
RR
348 needMore = TRUE;
349
8bbe427f
VZ
350 node = node->Next();
351 }
53010e52 352 return needMore ;
ff7b1510 353}
c801d85f 354
60acb947 355int wxApp::MainLoop()
c801d85f 356{
ec758a20
RR
357 gtk_main();
358 return 0;
ff7b1510 359}
c801d85f 360
60acb947 361void wxApp::ExitMainLoop()
c801d85f 362{
ec758a20 363 gtk_main_quit();
ff7b1510 364}
c801d85f 365
60acb947 366bool wxApp::Initialized()
c801d85f 367{
ec758a20 368 return m_initialized;
ff7b1510 369}
c801d85f 370
60acb947 371bool wxApp::Pending()
c801d85f 372{
ec758a20 373 return FALSE;
ff7b1510 374}
c801d85f 375
60acb947 376void wxApp::Dispatch()
c801d85f 377{
ff7b1510 378}
c801d85f 379
7214297d
GL
380#if wxUSE_THREADS
381void wxApp::ProcessPendingEvents()
382{
4d3a259a
GL
383 wxNode *node = wxPendingEvents->First();
384 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
7214297d
GL
385
386 while (node)
387 {
388 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
389
390 handler->ProcessPendingEvents();
e146b8c8 391
7214297d
GL
392 delete node;
393
4d3a259a 394 node = wxPendingEvents->First();
7214297d
GL
395 }
396}
397#endif
398
60acb947 399void wxApp::DeletePendingObjects()
c801d85f 400{
ec758a20
RR
401 wxNode *node = wxPendingDelete.First();
402 while (node)
403 {
404 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 405
ec758a20 406 delete obj;
c801d85f 407
ec758a20
RR
408 if (wxPendingDelete.Member(obj))
409 delete node;
c801d85f 410
ec758a20
RR
411 node = wxPendingDelete.First();
412 }
ff7b1510 413}
c801d85f 414
60acb947 415wxWindow *wxApp::GetTopWindow()
c801d85f 416{
e146b8c8
VZ
417 if (m_topWindow)
418 return m_topWindow;
419 else if (wxTopLevelWindows.GetCount() > 0)
420 return wxTopLevelWindows.GetFirst()->GetData();
421 else
422 return NULL;
ff7b1510 423}
c801d85f
KB
424
425void wxApp::SetTopWindow( wxWindow *win )
426{
ec758a20 427 m_topWindow = win;
ff7b1510 428}
c801d85f 429
60acb947 430bool wxApp::Initialize()
c801d85f 431{
0d2a2b60
RR
432 wxBuffer = new char[BUFSIZ + 512];
433
434 wxClassInfo::InitializeClasses();
60acb947 435
0d2a2b60 436 wxSystemSettings::Init();
60acb947 437
4d3a259a
GL
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
36b3b54a 445/*
0d2a2b60
RR
446 wxTheFontNameDirectory = new wxFontNameDirectory;
447 wxTheFontNameDirectory->Initialize();
36b3b54a 448*/
c801d85f 449
0d2a2b60
RR
450 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
451 wxTheColourDatabase->Initialize();
a3622daa 452
0d2a2b60
RR
453 wxInitializeStockLists();
454 wxInitializeStockObjects();
c801d85f 455
06cfab17 456#if wxUSE_WX_RESOURCES
0d2a2b60 457 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
60acb947 458
0d2a2b60 459 wxInitializeResourceSystem();
f5abe911 460#endif
0cf2cb36 461
0d2a2b60 462 wxImage::InitStandardHandlers();
e0253070 463
0d2a2b60
RR
464 /* no global cursor under X
465 g_globalCursor = new wxCursor; */
60acb947 466
0d2a2b60
RR
467 wxModule::RegisterModules();
468 if (!wxModule::InitializeModules()) return FALSE;
60acb947 469
0d2a2b60 470 return TRUE;
ff7b1510 471}
c801d85f 472
60acb947 473void wxApp::CleanUp()
c801d85f 474{
0d2a2b60 475 wxModule::CleanUpModules();
0cf2cb36 476
06cfab17 477#if wxUSE_WX_RESOURCES
ec758a20 478 wxFlushResources();
a3622daa 479
60acb947
VZ
480 if (wxTheResourceCache)
481 delete wxTheResourceCache;
bbe0af5b 482 wxTheResourceCache = (wxResourceCache*) NULL;
60acb947 483
f5abe911
RR
484 wxCleanUpResourceSystem();
485#endif
a3622daa 486
60acb947
VZ
487 if (wxTheColourDatabase)
488 delete wxTheColourDatabase;
0d2a2b60 489 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 490
36b3b54a 491/*
0d2a2b60
RR
492 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
493 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
36b3b54a 494*/
60acb947 495
0d2a2b60
RR
496 wxDeleteStockObjects();
497
ec758a20 498 wxDeleteStockLists();
a3622daa 499
ec758a20 500 wxImage::CleanUpHandlers();
0cf2cb36 501
0d2a2b60
RR
502 delete wxTheApp;
503 wxTheApp = (wxApp*) NULL;
504
4d3a259a
GL
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
3e61c765 512 wxSystemSettings::Done();
60acb947 513
3e61c765
RR
514 delete[] wxBuffer;
515
516 wxClassInfo::CleanUpClasses();
60acb947
VZ
517
518 // check for memory leaks
0d2a2b60
RR
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
60acb947 528 // do this as the very last thing because everything else can log messages
0d2a2b60 529 wxLog::DontCreateOnDemand();
60acb947 530
0d2a2b60 531 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
532 if (oldLog)
533 delete oldLog;
ff7b1510 534}
0cf2cb36 535
c801d85f
KB
536wxLog *wxApp::CreateLogTarget()
537{
0d2a2b60 538 return new wxLogGui;
c801d85f
KB
539}
540
541//-----------------------------------------------------------------------------
542// wxEntry
543//-----------------------------------------------------------------------------
544
545int wxEntry( int argc, char *argv[] )
546{
0d2a2b60 547 gtk_set_locale();
c801d85f 548
0d2a2b60 549 gtk_init( &argc, &argv );
0cf2cb36 550
60acb947
VZ
551 if (!wxApp::Initialize())
552 return -1;
0cf2cb36 553
ec758a20 554 if (!wxTheApp)
c801d85f 555 {
60acb947
VZ
556 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
557 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
0cf2cb36 558
ec758a20 559 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 560
ec758a20 561 wxObject *test_app = app_ini();
0cf2cb36 562
ec758a20
RR
563 wxTheApp = (wxApp*) test_app;
564 }
0cf2cb36 565
60acb947 566 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
c801d85f 567
ec758a20
RR
568 wxTheApp->argc = argc;
569 wxTheApp->argv = argv;
0cf2cb36 570
ec758a20
RR
571 char name[200];
572 strcpy( name, argv[0] );
573 strcpy( name, wxFileNameFromPath(name) );
574 wxStripExtension( name );
575 wxTheApp->SetAppName( name );
e0253070 576
60acb947
VZ
577 if (!wxTheApp->OnInitGui())
578 return 0;
c801d85f 579
0d2a2b60
RR
580 /* Here frames insert themselves automatically
581 * into wxTopLevelWindows by getting created
582 * in OnInit(). */
0cf2cb36 583
60acb947
VZ
584 if (!wxTheApp->OnInit())
585 return 0;
c801d85f 586
e146b8c8 587 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 588
ec758a20 589 int retValue = 0;
0cf2cb36 590
60acb947
VZ
591 if (wxTheApp->Initialized())
592 retValue = wxTheApp->OnRun();
0cf2cb36 593
0d2a2b60
RR
594 wxWindow *topWindow = wxTheApp->GetTopWindow();
595 if (topWindow)
ec758a20 596 {
60acb947 597 // Forcibly delete the window.
0d2a2b60
RR
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 }
ec758a20 609 }
e0253070 610
0d2a2b60 611 wxTheApp->OnExit();
0cf2cb36 612
60acb947 613 // flush the logged messages if any
0d2a2b60
RR
614 wxLog *log = wxLog::GetActiveTarget();
615 if (log != NULL && log->HasPendingMessages())
616 log->Flush();
617
60acb947
VZ
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
0d2a2b60 625 wxApp::CleanUp();
184b5d99 626
ec758a20 627 return retValue;
ff7b1510 628}
1a56f55c 629