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