]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk1/app.cpp
EVT_TEXT_UPDATED bug fixed, text ctrl callbacks simplified
[wxWidgets.git] / src / gtk1 / app.cpp
... / ...
CommitLineData
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
45wxApp *wxTheApp = (wxApp *) NULL;
46wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
47
48extern wxList wxPendingDelete;
49#if wxUSE_THREADS
50extern wxList wxPendingEvents;
51extern wxCriticalSection wxPendingEventsLocker;
52#endif
53extern wxResourceCache *wxTheResourceCache;
54
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,
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
127extern void wxFlushResources(void);
128
129//-----------------------------------------------------------------------------
130// global functions
131//-----------------------------------------------------------------------------
132
133void wxExit()
134{
135 gtk_main_quit();
136}
137
138bool wxYield()
139{
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
154 return TRUE;
155}
156
157//-----------------------------------------------------------------------------
158// wxApp
159//-----------------------------------------------------------------------------
160
161IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
162
163BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
164 EVT_IDLE(wxApp::OnIdle)
165END_EVENT_TABLE()
166
167gint wxapp_idle_callback( gpointer WXUNUSED(data) )
168{
169 if (wxTheApp)
170 {
171 while (wxTheApp->ProcessIdle())
172 {
173 }
174 }
175
176 wxMutexGuiLeave();
177 wxUsleep(10);
178 wxMutexGuiEnter();
179
180 return TRUE;
181}
182
183wxApp::wxApp()
184{
185 wxTheApp = this;
186
187 m_topWindow = (wxWindow *) NULL;
188 m_exitOnFrameDelete = TRUE;
189
190 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
191
192 m_colorCube = (unsigned char*) NULL;
193}
194
195wxApp::~wxApp()
196{
197 gtk_idle_remove( m_idleTag );
198
199 if (m_colorCube) free(m_colorCube);
200}
201
202bool wxApp::OnInitGui()
203{
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;
208
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... */
215
216 /*
217 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
218
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 }
229
230 gtk_widget_set_default_colormap( cmap );
231 */
232
233 /* initialize color cube for 8-bit color reduction dithering */
234
235 GdkColormap *cmap = gtk_widget_get_default_colormap();
236
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);
248
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 }
261
262 m_colorCube[ (r*1024) + (g*32) + b ] = index;
263 }
264 }
265 }
266
267
268 return TRUE;
269}
270
271bool wxApp::ProcessIdle()
272{
273 wxIdleEvent event;
274 event.SetEventObject( this );
275 ProcessEvent( event );
276
277 return event.MoreRequested();
278}
279
280void wxApp::OnIdle( wxIdleEvent &event )
281{
282 static bool inOnIdle = FALSE;
283
284 /* Avoid recursion (via ProcessEvent default case) */
285 if (inOnIdle)
286 return;
287
288 inOnIdle = TRUE;
289
290 /* Resend in the main thread events which have been prepared in other
291 threads */
292 ProcessPendingEvents();
293
294 /* 'Garbage' collection of windows deleted with Close(). */
295 DeletePendingObjects();
296
297 /* flush the logged messages if any */
298 wxLog *log = wxLog::GetActiveTarget();
299 if (log != NULL && log->HasPendingMessages())
300 log->Flush();
301
302 /* Send OnIdle events to all windows */
303 bool needMore = SendIdleEvents();
304
305 if (needMore)
306 event.RequestMore(TRUE);
307
308 inOnIdle = FALSE;
309}
310
311bool wxApp::SendIdleEvents()
312{
313 bool needMore = FALSE;
314
315 wxNode* node = wxTopLevelWindows.First();
316 while (node)
317 {
318 wxWindow* win = (wxWindow*) node->Data();
319 if (SendIdleEvents(win))
320 needMore = TRUE;
321 node = node->Next();
322 }
323 return needMore;
324}
325
326bool wxApp::SendIdleEvents( wxWindow* win )
327{
328 bool needMore = FALSE;
329
330 wxIdleEvent event;
331 event.SetEventObject(win);
332
333 win->OnInternalIdle();
334
335 win->ProcessEvent(event);
336
337 if (event.MoreRequested())
338 needMore = TRUE;
339
340 wxNode* node = win->GetChildren().First();
341 while (node)
342 {
343 wxWindow* win = (wxWindow*) node->Data();
344 if (SendIdleEvents(win))
345 needMore = TRUE;
346
347 node = node->Next();
348 }
349 return needMore ;
350}
351
352int wxApp::MainLoop()
353{
354 gtk_main();
355 return 0;
356}
357
358void wxApp::ExitMainLoop()
359{
360 gtk_main_quit();
361}
362
363bool wxApp::Initialized()
364{
365 return m_initialized;
366}
367
368bool wxApp::Pending()
369{
370 return FALSE;
371}
372
373void wxApp::Dispatch()
374{
375}
376
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
396void wxApp::DeletePendingObjects()
397{
398 wxNode *node = wxPendingDelete.First();
399 while (node)
400 {
401 wxObject *obj = (wxObject *)node->Data();
402
403 delete obj;
404
405 if (wxPendingDelete.Member(obj))
406 delete node;
407
408 node = wxPendingDelete.First();
409 }
410}
411
412wxWindow *wxApp::GetTopWindow()
413{
414 if (m_topWindow) return m_topWindow;
415 wxNode *node = wxTopLevelWindows.First();
416 if (!node) return (wxWindow *) NULL;
417 return (wxWindow*)node->Data();
418}
419
420void wxApp::SetTopWindow( wxWindow *win )
421{
422 m_topWindow = win;
423}
424
425bool wxApp::Initialize()
426{
427 wxBuffer = new char[BUFSIZ + 512];
428
429 wxClassInfo::InitializeClasses();
430
431 wxSystemSettings::Init();
432
433/*
434 wxTheFontNameDirectory = new wxFontNameDirectory;
435 wxTheFontNameDirectory->Initialize();
436*/
437
438 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
439 wxTheColourDatabase->Initialize();
440
441 wxInitializeStockLists();
442 wxInitializeStockObjects();
443
444#if wxUSE_WX_RESOURCES
445 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
446
447 wxInitializeResourceSystem();
448#endif
449
450 wxImage::InitStandardHandlers();
451
452 /* no global cursor under X
453 g_globalCursor = new wxCursor; */
454
455 wxModule::RegisterModules();
456 if (!wxModule::InitializeModules()) return FALSE;
457
458 return TRUE;
459}
460
461void wxApp::CleanUp()
462{
463 wxModule::CleanUpModules();
464
465#if wxUSE_WX_RESOURCES
466 wxFlushResources();
467
468 if (wxTheResourceCache)
469 delete wxTheResourceCache;
470 wxTheResourceCache = (wxResourceCache*) NULL;
471
472 wxCleanUpResourceSystem();
473#endif
474
475 if (wxTheColourDatabase)
476 delete wxTheColourDatabase;
477 wxTheColourDatabase = (wxColourDatabase*) NULL;
478
479/*
480 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
481 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
482*/
483
484 wxDeleteStockObjects();
485
486 wxDeleteStockLists();
487
488 wxImage::CleanUpHandlers();
489
490 delete wxTheApp;
491 wxTheApp = (wxApp*) NULL;
492
493 wxSystemSettings::Done();
494
495 delete[] wxBuffer;
496
497 wxClassInfo::CleanUpClasses();
498
499 // check for memory leaks
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
509 // do this as the very last thing because everything else can log messages
510 wxLog::DontCreateOnDemand();
511
512 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
513 if (oldLog)
514 delete oldLog;
515}
516
517wxLog *wxApp::CreateLogTarget()
518{
519 return new wxLogGui;
520}
521
522//-----------------------------------------------------------------------------
523// wxEntry
524//-----------------------------------------------------------------------------
525
526int wxEntry( int argc, char *argv[] )
527{
528 gtk_set_locale();
529
530 gtk_init( &argc, &argv );
531
532 if (!wxApp::Initialize())
533 return -1;
534
535 if (!wxTheApp)
536 {
537 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
538 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
539
540 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
541
542 wxObject *test_app = app_ini();
543
544 wxTheApp = (wxApp*) test_app;
545 }
546
547 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
548
549 wxTheApp->argc = argc;
550 wxTheApp->argv = argv;
551
552 char name[200];
553 strcpy( name, argv[0] );
554 strcpy( name, wxFileNameFromPath(name) );
555 wxStripExtension( name );
556 wxTheApp->SetAppName( name );
557
558 if (!wxTheApp->OnInitGui())
559 return 0;
560
561 /* Here frames insert themselves automatically
562 * into wxTopLevelWindows by getting created
563 * in OnInit(). */
564
565 if (!wxTheApp->OnInit())
566 return 0;
567
568 wxTheApp->m_initialized = (wxTopLevelWindows.Number() > 0);
569
570 int retValue = 0;
571
572 if (wxTheApp->Initialized())
573 retValue = wxTheApp->OnRun();
574
575 wxWindow *topWindow = wxTheApp->GetTopWindow();
576 if (topWindow)
577 {
578 // Forcibly delete the window.
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 }
590 }
591
592 wxTheApp->OnExit();
593
594 // flush the logged messages if any
595 wxLog *log = wxLog::GetActiveTarget();
596 if (log != NULL && log->HasPendingMessages())
597 log->Flush();
598
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
606 wxApp::CleanUp();
607
608 return retValue;
609}
610