]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/app.cpp
wxYield() calls OnInternalIdle() of all top level windows
[wxWidgets.git] / src / gtk1 / app.cpp
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
45 wxApp *wxTheApp = (wxApp *) NULL;
46 wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
47
48 extern wxList wxPendingDelete;
49 extern wxResourceCache *wxTheResourceCache;
50
51 unsigned char g_palette[64*3] =
52 {
53 0x0, 0x0, 0x0,
54 0xff, 0xff, 0xff,
55 0xff, 0x0, 0x0,
56 0xff, 0xff, 0x0,
57 0x0, 0xff, 0x0,
58 0x0, 0x0, 0xff,
59 0x0, 0xff, 0xff,
60 0x99, 0x99, 0x99,
61 0xff, 0x88, 0x0,
62 0x88, 0x0, 0x0,
63 0x0, 0x88, 0x88,
64 0x88, 0x88, 0x0,
65 0xff, 0xcc, 0x97,
66 0xbb, 0xbb, 0xbb,
67 0x9f, 0x6b, 0x42,
68 0x55, 0x55, 0x55,
69 0xdd, 0xdd, 0xdd,
70 0x77, 0x77, 0x77,
71 0x33, 0x33, 0x33,
72 0xcc, 0x0, 0x0,
73 0xff, 0x44, 0x0,
74 0xff, 0xcc, 0x0,
75 0xcc, 0xcc, 0x0,
76 0x60, 0x60, 0x0,
77 0x0, 0x43, 0x0,
78 0x0, 0x7f, 0x0,
79 0x0, 0xcc, 0x0,
80 0x0, 0x44, 0x44,
81 0x0, 0x0, 0x44,
82 0x0, 0x0, 0x88,
83 0xef, 0xb1, 0x7b,
84 0xdf, 0x98, 0x5f,
85 0xbf, 0x87, 0x56,
86 0x7f, 0x57, 0x26,
87 0x5f, 0x39, 0xc,
88 0x3f, 0x1c, 0x0,
89 0x21, 0x0, 0x0,
90 0x0, 0x43, 0x87,
91 0x2d, 0x70, 0xaf,
92 0x5a, 0x9e, 0xd7,
93 0x87, 0xcc, 0xff,
94 0xff, 0xe0, 0xba,
95 0x21, 0x43, 0xf,
96 0x3d, 0x5d, 0x25,
97 0x59, 0x78, 0x3a,
98 0x75, 0x93, 0x4f,
99 0x91, 0xae, 0x64,
100 0xad, 0xc8, 0x7a,
101 0xf0, 0xa8, 0xef,
102 0xd0, 0x88, 0xd0,
103 0xaf, 0x66, 0xaf,
104 0x8e, 0x44, 0x8e,
105 0x6d, 0x22, 0x6d,
106 0x4b, 0x0, 0x4b,
107 0xff, 0xc0, 0xbc,
108 0xff, 0x93, 0x91,
109 0xff, 0x66, 0x67,
110 0xd8, 0xf2, 0xbf,
111 0xff, 0xc9, 0x68,
112 0xff, 0x96, 0x67,
113 0xa5, 0x60, 0xff,
114 0x51, 0xff, 0x99,
115 0x3f, 0xa5, 0x63,
116 0x98, 0x90, 0x67
117 };
118
119 //-----------------------------------------------------------------------------
120 // local functions
121 //-----------------------------------------------------------------------------
122
123 extern void wxFlushResources(void);
124
125 //-----------------------------------------------------------------------------
126 // global functions
127 //-----------------------------------------------------------------------------
128
129 void wxExit()
130 {
131 gtk_main_quit();
132 }
133
134 bool wxYield()
135 {
136 // it's necessary to call ProcessIdle() to update the frames sizes which
137 // might have been changed (it also will update other things set from
138 // OnUpdateUI() which is a nice (and desired) side effect)
139 for ( wxNode *node = wxTopLevelWindows.GetFirst();
140 node;
141 node = node->GetNext() )
142 {
143 wxWindow *win = ((wxWindow*)node->GetData());
144 win->OnInternalIdle();
145 }
146
147 while (gtk_events_pending() > 0)
148 gtk_main_iteration();
149
150 return TRUE;
151 }
152
153 //-----------------------------------------------------------------------------
154 // wxApp
155 //-----------------------------------------------------------------------------
156
157 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
158
159 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
160 EVT_IDLE(wxApp::OnIdle)
161 END_EVENT_TABLE()
162
163 gint wxapp_idle_callback( gpointer WXUNUSED(data) )
164 {
165 if (wxTheApp)
166 {
167 while (wxTheApp->ProcessIdle())
168 {
169 }
170 }
171
172 wxMutexGuiLeave();
173 wxUsleep(10);
174 wxMutexGuiEnter();
175
176 return TRUE;
177 }
178
179 wxApp::wxApp()
180 {
181 wxTheApp = this;
182
183 m_topWindow = (wxWindow *) NULL;
184 m_exitOnFrameDelete = TRUE;
185
186 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
187
188 m_colorCube = (unsigned char*) NULL;
189 }
190
191 wxApp::~wxApp()
192 {
193 gtk_idle_remove( m_idleTag );
194
195 if (m_colorCube) free(m_colorCube);
196 }
197
198 bool wxApp::OnInitGui()
199 {
200 /* Nothing to do for 15, 16, 24, 32 bit displays */
201
202 GdkVisual *visual = gdk_visual_get_system();
203 if (visual->depth > 8) return TRUE;
204
205 /* this initiates the standard palette as defined by GdkImlib
206 in the GNOME libraries. it ensures that all GNOME applications
207 use the same 64 colormap entries on 8-bit displays so you
208 can use several rather graphics-heavy applications at the
209 same time.
210 NOTE: this doesn't really seem to work this way... */
211
212 /*
213 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
214
215 for (int i = 0; i < 64; i++)
216 {
217 GdkColor col;
218 col.red = g_palette[i*3 + 0] << 8;
219 col.green = g_palette[i*3 + 1] << 8;
220 col.blue = g_palette[i*3 + 2] << 8;
221 col.pixel = 0;
222
223 gdk_color_alloc( cmap, &col );
224 }
225
226 gtk_widget_set_default_colormap( cmap );
227 */
228
229 /* initialize color cube for 8-bit color reduction dithering */
230
231 GdkColormap *cmap = gtk_widget_get_default_colormap();
232
233 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
234
235 for (int r = 0; r < 32; r++)
236 {
237 for (int g = 0; g < 32; g++)
238 {
239 for (int b = 0; b < 32; b++)
240 {
241 int rr = (r << 3) | (r >> 2);
242 int gg = (g << 3) | (g >> 2);
243 int bb = (b << 3) | (b >> 2);
244
245 GdkColor *colors = cmap->colors;
246 int max = 3 * (65536);
247 int index = -1;
248
249 for (int i = 0; i < cmap->size; i++)
250 {
251 int rdiff = ((rr << 8) - colors[i].red);
252 int gdiff = ((gg << 8)- colors[i].green);
253 int bdiff = ((bb << 8)- colors[i].blue);
254 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
255 if (sum < max) { index = i; max = sum; }
256 }
257
258 m_colorCube[ (r*1024) + (g*32) + b ] = index;
259 }
260 }
261 }
262
263
264 return TRUE;
265 }
266
267 bool wxApp::ProcessIdle()
268 {
269 wxIdleEvent event;
270 event.SetEventObject( this );
271 ProcessEvent( event );
272
273 return event.MoreRequested();
274 }
275
276 void wxApp::OnIdle( wxIdleEvent &event )
277 {
278 static bool inOnIdle = FALSE;
279
280 /* Avoid recursion (via ProcessEvent default case) */
281 if (inOnIdle)
282 return;
283
284 inOnIdle = TRUE;
285
286 /* 'Garbage' collection of windows deleted with Close(). */
287 DeletePendingObjects();
288
289 /* flush the logged messages if any */
290 wxLog *log = wxLog::GetActiveTarget();
291 if (log != NULL && log->HasPendingMessages())
292 log->Flush();
293
294 /* Send OnIdle events to all windows */
295 bool needMore = SendIdleEvents();
296
297 if (needMore)
298 event.RequestMore(TRUE);
299
300 inOnIdle = FALSE;
301 }
302
303 bool wxApp::SendIdleEvents()
304 {
305 bool needMore = FALSE;
306
307 wxNode* node = wxTopLevelWindows.First();
308 while (node)
309 {
310 wxWindow* win = (wxWindow*) node->Data();
311 if (SendIdleEvents(win))
312 needMore = TRUE;
313 node = node->Next();
314 }
315 return needMore;
316 }
317
318 bool wxApp::SendIdleEvents( wxWindow* win )
319 {
320 bool needMore = FALSE;
321
322 wxIdleEvent event;
323 event.SetEventObject(win);
324
325 win->OnInternalIdle();
326
327 win->ProcessEvent(event);
328
329 if (event.MoreRequested())
330 needMore = TRUE;
331
332 wxNode* node = win->GetChildren().First();
333 while (node)
334 {
335 wxWindow* win = (wxWindow*) node->Data();
336 if (SendIdleEvents(win))
337 needMore = TRUE;
338
339 node = node->Next();
340 }
341 return needMore ;
342 }
343
344 int wxApp::MainLoop()
345 {
346 gtk_main();
347 return 0;
348 }
349
350 void wxApp::ExitMainLoop()
351 {
352 gtk_main_quit();
353 }
354
355 bool wxApp::Initialized()
356 {
357 return m_initialized;
358 }
359
360 bool wxApp::Pending()
361 {
362 return FALSE;
363 }
364
365 void wxApp::Dispatch()
366 {
367 }
368
369 void wxApp::DeletePendingObjects()
370 {
371 wxNode *node = wxPendingDelete.First();
372 while (node)
373 {
374 wxObject *obj = (wxObject *)node->Data();
375
376 delete obj;
377
378 if (wxPendingDelete.Member(obj))
379 delete node;
380
381 node = wxPendingDelete.First();
382 }
383 }
384
385 wxWindow *wxApp::GetTopWindow()
386 {
387 if (m_topWindow) return m_topWindow;
388 wxNode *node = wxTopLevelWindows.First();
389 if (!node) return (wxWindow *) NULL;
390 return (wxWindow*)node->Data();
391 }
392
393 void wxApp::SetTopWindow( wxWindow *win )
394 {
395 m_topWindow = win;
396 }
397
398 bool wxApp::Initialize()
399 {
400 wxBuffer = new char[BUFSIZ + 512];
401
402 wxClassInfo::InitializeClasses();
403
404 wxSystemSettings::Init();
405
406 /*
407 wxTheFontNameDirectory = new wxFontNameDirectory;
408 wxTheFontNameDirectory->Initialize();
409 */
410
411 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
412 wxTheColourDatabase->Initialize();
413
414 wxInitializeStockLists();
415 wxInitializeStockObjects();
416
417 #if wxUSE_WX_RESOURCES
418 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
419
420 wxInitializeResourceSystem();
421 #endif
422
423 wxImage::InitStandardHandlers();
424
425 /* no global cursor under X
426 g_globalCursor = new wxCursor; */
427
428 wxModule::RegisterModules();
429 if (!wxModule::InitializeModules()) return FALSE;
430
431 return TRUE;
432 }
433
434 void wxApp::CleanUp()
435 {
436 wxModule::CleanUpModules();
437
438 #if wxUSE_WX_RESOURCES
439 wxFlushResources();
440
441 if (wxTheResourceCache)
442 delete wxTheResourceCache;
443 wxTheResourceCache = (wxResourceCache*) NULL;
444
445 wxCleanUpResourceSystem();
446 #endif
447
448 if (wxTheColourDatabase)
449 delete wxTheColourDatabase;
450 wxTheColourDatabase = (wxColourDatabase*) NULL;
451
452 /*
453 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
454 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
455 */
456
457 wxDeleteStockObjects();
458
459 wxDeleteStockLists();
460
461 wxImage::CleanUpHandlers();
462
463 delete wxTheApp;
464 wxTheApp = (wxApp*) NULL;
465
466 wxSystemSettings::Done();
467
468 delete[] wxBuffer;
469
470 wxClassInfo::CleanUpClasses();
471
472 // check for memory leaks
473 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
474 if (wxDebugContext::CountObjectsLeft() > 0)
475 {
476 wxLogDebug("There were memory leaks.\n");
477 wxDebugContext::Dump();
478 wxDebugContext::PrintStatistics();
479 }
480 #endif
481
482 // do this as the very last thing because everything else can log messages
483 wxLog::DontCreateOnDemand();
484
485 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
486 if (oldLog)
487 delete oldLog;
488 }
489
490 wxLog *wxApp::CreateLogTarget()
491 {
492 return new wxLogGui;
493 }
494
495 //-----------------------------------------------------------------------------
496 // wxEntry
497 //-----------------------------------------------------------------------------
498
499 int wxEntry( int argc, char *argv[] )
500 {
501 gtk_set_locale();
502
503 gtk_init( &argc, &argv );
504
505 if (!wxApp::Initialize())
506 return -1;
507
508 if (!wxTheApp)
509 {
510 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
511 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
512
513 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
514
515 wxObject *test_app = app_ini();
516
517 wxTheApp = (wxApp*) test_app;
518 }
519
520 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
521
522 wxTheApp->argc = argc;
523 wxTheApp->argv = argv;
524
525 char name[200];
526 strcpy( name, argv[0] );
527 strcpy( name, wxFileNameFromPath(name) );
528 wxStripExtension( name );
529 wxTheApp->SetAppName( name );
530
531 if (!wxTheApp->OnInitGui())
532 return 0;
533
534 /* Here frames insert themselves automatically
535 * into wxTopLevelWindows by getting created
536 * in OnInit(). */
537
538 if (!wxTheApp->OnInit())
539 return 0;
540
541 wxTheApp->m_initialized = (wxTopLevelWindows.Number() > 0);
542
543 int retValue = 0;
544
545 if (wxTheApp->Initialized())
546 retValue = wxTheApp->OnRun();
547
548 wxWindow *topWindow = wxTheApp->GetTopWindow();
549 if (topWindow)
550 {
551 // Forcibly delete the window.
552 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
553 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
554 {
555 topWindow->Close( TRUE );
556 wxTheApp->DeletePendingObjects();
557 }
558 else
559 {
560 delete topWindow;
561 wxTheApp->SetTopWindow( (wxWindow*) NULL );
562 }
563 }
564
565 wxTheApp->OnExit();
566
567 // flush the logged messages if any
568 wxLog *log = wxLog::GetActiveTarget();
569 if (log != NULL && log->HasPendingMessages())
570 log->Flush();
571
572 // continuing to use user defined log target is unsafe from now on because
573 // some resources may be already unavailable, so replace it by something
574 // more safe
575 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
576 if ( oldlog )
577 delete oldlog;
578
579 wxApp::CleanUp();
580
581 return retValue;
582 }
583