]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/app.cpp
Fixed doubled-up key effects in wxTextCtrl by resetting m_lastMsg to 0
[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)
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{
383 wxNode *node = wxPendingEvents.First();
384 wxCriticalSectionLocker locker(wxPendingEventsLocker);
385
386 while (node)
387 {
388 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
389
390 handler->ProcessPendingEvents();
e146b8c8 391
7214297d
GL
392 delete node;
393
394 node = wxPendingEvents.First();
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
36b3b54a 438/*
0d2a2b60
RR
439 wxTheFontNameDirectory = new wxFontNameDirectory;
440 wxTheFontNameDirectory->Initialize();
36b3b54a 441*/
c801d85f 442
0d2a2b60
RR
443 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
444 wxTheColourDatabase->Initialize();
a3622daa 445
0d2a2b60
RR
446 wxInitializeStockLists();
447 wxInitializeStockObjects();
c801d85f 448
06cfab17 449#if wxUSE_WX_RESOURCES
0d2a2b60 450 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
60acb947 451
0d2a2b60 452 wxInitializeResourceSystem();
f5abe911 453#endif
0cf2cb36 454
0d2a2b60 455 wxImage::InitStandardHandlers();
e0253070 456
0d2a2b60
RR
457 /* no global cursor under X
458 g_globalCursor = new wxCursor; */
60acb947 459
0d2a2b60
RR
460 wxModule::RegisterModules();
461 if (!wxModule::InitializeModules()) return FALSE;
60acb947 462
0d2a2b60 463 return TRUE;
ff7b1510 464}
c801d85f 465
60acb947 466void wxApp::CleanUp()
c801d85f 467{
0d2a2b60 468 wxModule::CleanUpModules();
0cf2cb36 469
06cfab17 470#if wxUSE_WX_RESOURCES
ec758a20 471 wxFlushResources();
a3622daa 472
60acb947
VZ
473 if (wxTheResourceCache)
474 delete wxTheResourceCache;
bbe0af5b 475 wxTheResourceCache = (wxResourceCache*) NULL;
60acb947 476
f5abe911
RR
477 wxCleanUpResourceSystem();
478#endif
a3622daa 479
60acb947
VZ
480 if (wxTheColourDatabase)
481 delete wxTheColourDatabase;
0d2a2b60 482 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 483
36b3b54a 484/*
0d2a2b60
RR
485 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
486 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
36b3b54a 487*/
60acb947 488
0d2a2b60
RR
489 wxDeleteStockObjects();
490
ec758a20 491 wxDeleteStockLists();
a3622daa 492
ec758a20 493 wxImage::CleanUpHandlers();
0cf2cb36 494
0d2a2b60
RR
495 delete wxTheApp;
496 wxTheApp = (wxApp*) NULL;
497
3e61c765 498 wxSystemSettings::Done();
60acb947 499
3e61c765
RR
500 delete[] wxBuffer;
501
502 wxClassInfo::CleanUpClasses();
60acb947
VZ
503
504 // check for memory leaks
0d2a2b60
RR
505#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
506 if (wxDebugContext::CountObjectsLeft() > 0)
507 {
508 wxLogDebug("There were memory leaks.\n");
509 wxDebugContext::Dump();
510 wxDebugContext::PrintStatistics();
511 }
512#endif
513
60acb947 514 // do this as the very last thing because everything else can log messages
0d2a2b60 515 wxLog::DontCreateOnDemand();
60acb947 516
0d2a2b60 517 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
518 if (oldLog)
519 delete oldLog;
ff7b1510 520}
0cf2cb36 521
c801d85f
KB
522wxLog *wxApp::CreateLogTarget()
523{
0d2a2b60 524 return new wxLogGui;
c801d85f
KB
525}
526
527//-----------------------------------------------------------------------------
528// wxEntry
529//-----------------------------------------------------------------------------
530
531int wxEntry( int argc, char *argv[] )
532{
0d2a2b60 533 gtk_set_locale();
c801d85f 534
0d2a2b60 535 gtk_init( &argc, &argv );
0cf2cb36 536
60acb947
VZ
537 if (!wxApp::Initialize())
538 return -1;
0cf2cb36 539
ec758a20 540 if (!wxTheApp)
c801d85f 541 {
60acb947
VZ
542 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
543 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
0cf2cb36 544
ec758a20 545 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 546
ec758a20 547 wxObject *test_app = app_ini();
0cf2cb36 548
ec758a20
RR
549 wxTheApp = (wxApp*) test_app;
550 }
0cf2cb36 551
60acb947 552 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
c801d85f 553
ec758a20
RR
554 wxTheApp->argc = argc;
555 wxTheApp->argv = argv;
0cf2cb36 556
ec758a20
RR
557 char name[200];
558 strcpy( name, argv[0] );
559 strcpy( name, wxFileNameFromPath(name) );
560 wxStripExtension( name );
561 wxTheApp->SetAppName( name );
e0253070 562
60acb947
VZ
563 if (!wxTheApp->OnInitGui())
564 return 0;
c801d85f 565
0d2a2b60
RR
566 /* Here frames insert themselves automatically
567 * into wxTopLevelWindows by getting created
568 * in OnInit(). */
0cf2cb36 569
60acb947
VZ
570 if (!wxTheApp->OnInit())
571 return 0;
c801d85f 572
e146b8c8 573 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 574
ec758a20 575 int retValue = 0;
0cf2cb36 576
60acb947
VZ
577 if (wxTheApp->Initialized())
578 retValue = wxTheApp->OnRun();
0cf2cb36 579
0d2a2b60
RR
580 wxWindow *topWindow = wxTheApp->GetTopWindow();
581 if (topWindow)
ec758a20 582 {
60acb947 583 // Forcibly delete the window.
0d2a2b60
RR
584 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
585 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
586 {
587 topWindow->Close( TRUE );
588 wxTheApp->DeletePendingObjects();
589 }
590 else
591 {
592 delete topWindow;
593 wxTheApp->SetTopWindow( (wxWindow*) NULL );
594 }
ec758a20 595 }
e0253070 596
0d2a2b60 597 wxTheApp->OnExit();
0cf2cb36 598
60acb947 599 // flush the logged messages if any
0d2a2b60
RR
600 wxLog *log = wxLog::GetActiveTarget();
601 if (log != NULL && log->HasPendingMessages())
602 log->Flush();
603
60acb947
VZ
604 // continuing to use user defined log target is unsafe from now on because
605 // some resources may be already unavailable, so replace it by something
606 // more safe
607 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
608 if ( oldlog )
609 delete oldlog;
610
0d2a2b60 611 wxApp::CleanUp();
184b5d99 612
ec758a20 613 return retValue;
ff7b1510 614}
1a56f55c 615