]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/app.cpp
wxUsleep() introduced (and documented) to try to work around usleep() bug in
[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 while (gtk_events_pending() > 0) gtk_main_iteration();
137 return TRUE;
138 }
139
140 //-----------------------------------------------------------------------------
141 // wxApp
142 //-----------------------------------------------------------------------------
143
144 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
145
146 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
147 EVT_IDLE(wxApp::OnIdle)
148 END_EVENT_TABLE()
149
150 gint wxapp_idle_callback( gpointer WXUNUSED(data) )
151 {
152 if (wxTheApp)
153 {
154 while (wxTheApp->ProcessIdle())
155 {
156 }
157 }
158
159 wxMutexGuiLeave();
160 wxUsleep(10);
161 wxMutexGuiEnter();
162
163 return TRUE;
164 }
165
166 wxApp::wxApp()
167 {
168 wxTheApp = this;
169
170 m_topWindow = (wxWindow *) NULL;
171 m_exitOnFrameDelete = TRUE;
172
173 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
174
175 m_colorCube = (unsigned char*) NULL;
176 }
177
178 wxApp::~wxApp()
179 {
180 gtk_idle_remove( m_idleTag );
181
182 if (m_colorCube) free(m_colorCube);
183 }
184
185 bool wxApp::OnInitGui()
186 {
187 /* Nothing to do for 15, 16, 24, 32 bit displays */
188
189 GdkVisual *visual = gdk_visual_get_system();
190 if (visual->depth > 8) return TRUE;
191
192 /* this initiates the standard palette as defined by GdkImlib
193 in the GNOME libraries. it ensures that all GNOME applications
194 use the same 64 colormap entries on 8-bit displays so you
195 can use several rather graphics-heavy applications at the
196 same time.
197 NOTE: this doesn't really seem to work this way... */
198
199 /*
200 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
201
202 for (int i = 0; i < 64; i++)
203 {
204 GdkColor col;
205 col.red = g_palette[i*3 + 0] << 8;
206 col.green = g_palette[i*3 + 1] << 8;
207 col.blue = g_palette[i*3 + 2] << 8;
208 col.pixel = 0;
209
210 gdk_color_alloc( cmap, &col );
211 }
212
213 gtk_widget_set_default_colormap( cmap );
214 */
215
216 /* initialize color cube for 8-bit color reduction dithering */
217
218 GdkColormap *cmap = gtk_widget_get_default_colormap();
219
220 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
221
222 for (int r = 0; r < 32; r++)
223 {
224 for (int g = 0; g < 32; g++)
225 {
226 for (int b = 0; b < 32; b++)
227 {
228 int rr = (r << 3) | (r >> 2);
229 int gg = (g << 3) | (g >> 2);
230 int bb = (b << 3) | (b >> 2);
231
232 GdkColor *colors = cmap->colors;
233 int max = 3 * (65536);
234 int index = -1;
235
236 for (int i = 0; i < cmap->size; i++)
237 {
238 int rdiff = ((rr << 8) - colors[i].red);
239 int gdiff = ((gg << 8)- colors[i].green);
240 int bdiff = ((bb << 8)- colors[i].blue);
241 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
242 if (sum < max) { index = i; max = sum; }
243 }
244
245 m_colorCube[ (r*1024) + (g*32) + b ] = index;
246 }
247 }
248 }
249
250
251 return TRUE;
252 }
253
254 bool wxApp::ProcessIdle()
255 {
256 wxIdleEvent event;
257 event.SetEventObject( this );
258 ProcessEvent( event );
259
260 return event.MoreRequested();
261 }
262
263 void wxApp::OnIdle( wxIdleEvent &event )
264 {
265 static bool inOnIdle = FALSE;
266
267 /* Avoid recursion (via ProcessEvent default case) */
268 if (inOnIdle)
269 return;
270
271 inOnIdle = TRUE;
272
273 /* 'Garbage' collection of windows deleted with Close(). */
274 DeletePendingObjects();
275
276 /* flush the logged messages if any */
277 wxLog *log = wxLog::GetActiveTarget();
278 if (log != NULL && log->HasPendingMessages())
279 log->Flush();
280
281 /* Send OnIdle events to all windows */
282 bool needMore = SendIdleEvents();
283
284 if (needMore)
285 event.RequestMore(TRUE);
286
287 inOnIdle = FALSE;
288 }
289
290 bool wxApp::SendIdleEvents()
291 {
292 bool needMore = FALSE;
293
294 wxNode* node = wxTopLevelWindows.First();
295 while (node)
296 {
297 wxWindow* win = (wxWindow*) node->Data();
298 if (SendIdleEvents(win))
299 needMore = TRUE;
300 node = node->Next();
301 }
302 return needMore;
303 }
304
305 bool wxApp::SendIdleEvents( wxWindow* win )
306 {
307 bool needMore = FALSE;
308
309 wxIdleEvent event;
310 event.SetEventObject(win);
311
312 win->OnInternalIdle();
313
314 win->ProcessEvent(event);
315
316 if (event.MoreRequested())
317 needMore = TRUE;
318
319 wxNode* node = win->GetChildren().First();
320 while (node)
321 {
322 wxWindow* win = (wxWindow*) node->Data();
323 if (SendIdleEvents(win))
324 needMore = TRUE;
325
326 node = node->Next();
327 }
328 return needMore ;
329 }
330
331 int wxApp::MainLoop()
332 {
333 gtk_main();
334 return 0;
335 }
336
337 void wxApp::ExitMainLoop()
338 {
339 gtk_main_quit();
340 }
341
342 bool wxApp::Initialized()
343 {
344 return m_initialized;
345 }
346
347 bool wxApp::Pending()
348 {
349 return FALSE;
350 }
351
352 void wxApp::Dispatch()
353 {
354 }
355
356 void wxApp::DeletePendingObjects()
357 {
358 wxNode *node = wxPendingDelete.First();
359 while (node)
360 {
361 wxObject *obj = (wxObject *)node->Data();
362
363 delete obj;
364
365 if (wxPendingDelete.Member(obj))
366 delete node;
367
368 node = wxPendingDelete.First();
369 }
370 }
371
372 wxWindow *wxApp::GetTopWindow()
373 {
374 if (m_topWindow) return m_topWindow;
375 wxNode *node = wxTopLevelWindows.First();
376 if (!node) return (wxWindow *) NULL;
377 return (wxWindow*)node->Data();
378 }
379
380 void wxApp::SetTopWindow( wxWindow *win )
381 {
382 m_topWindow = win;
383 }
384
385 bool wxApp::Initialize()
386 {
387 wxBuffer = new char[BUFSIZ + 512];
388
389 wxClassInfo::InitializeClasses();
390
391 wxSystemSettings::Init();
392
393 /*
394 wxTheFontNameDirectory = new wxFontNameDirectory;
395 wxTheFontNameDirectory->Initialize();
396 */
397
398 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
399 wxTheColourDatabase->Initialize();
400
401 wxInitializeStockLists();
402 wxInitializeStockObjects();
403
404 #if wxUSE_WX_RESOURCES
405 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
406
407 wxInitializeResourceSystem();
408 #endif
409
410 wxImage::InitStandardHandlers();
411
412 /* no global cursor under X
413 g_globalCursor = new wxCursor; */
414
415 wxModule::RegisterModules();
416 if (!wxModule::InitializeModules()) return FALSE;
417
418 return TRUE;
419 }
420
421 void wxApp::CleanUp()
422 {
423 wxModule::CleanUpModules();
424
425 #if wxUSE_WX_RESOURCES
426 wxFlushResources();
427
428 if (wxTheResourceCache)
429 delete wxTheResourceCache;
430 wxTheResourceCache = (wxResourceCache*) NULL;
431
432 wxCleanUpResourceSystem();
433 #endif
434
435 if (wxTheColourDatabase)
436 delete wxTheColourDatabase;
437 wxTheColourDatabase = (wxColourDatabase*) NULL;
438
439 /*
440 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
441 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
442 */
443
444 wxDeleteStockObjects();
445
446 wxDeleteStockLists();
447
448 wxImage::CleanUpHandlers();
449
450 delete wxTheApp;
451 wxTheApp = (wxApp*) NULL;
452
453 wxSystemSettings::Done();
454
455 delete[] wxBuffer;
456
457 wxClassInfo::CleanUpClasses();
458
459 // check for memory leaks
460 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
461 if (wxDebugContext::CountObjectsLeft() > 0)
462 {
463 wxLogDebug("There were memory leaks.\n");
464 wxDebugContext::Dump();
465 wxDebugContext::PrintStatistics();
466 }
467 #endif
468
469 // do this as the very last thing because everything else can log messages
470 wxLog::DontCreateOnDemand();
471
472 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
473 if (oldLog)
474 delete oldLog;
475 }
476
477 wxLog *wxApp::CreateLogTarget()
478 {
479 return new wxLogGui;
480 }
481
482 //-----------------------------------------------------------------------------
483 // wxEntry
484 //-----------------------------------------------------------------------------
485
486 int wxEntry( int argc, char *argv[] )
487 {
488 gtk_set_locale();
489
490 gtk_init( &argc, &argv );
491
492 if (!wxApp::Initialize())
493 return -1;
494
495 if (!wxTheApp)
496 {
497 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
498 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
499
500 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
501
502 wxObject *test_app = app_ini();
503
504 wxTheApp = (wxApp*) test_app;
505 }
506
507 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
508
509 wxTheApp->argc = argc;
510 wxTheApp->argv = argv;
511
512 char name[200];
513 strcpy( name, argv[0] );
514 strcpy( name, wxFileNameFromPath(name) );
515 wxStripExtension( name );
516 wxTheApp->SetAppName( name );
517
518 if (!wxTheApp->OnInitGui())
519 return 0;
520
521 /* Here frames insert themselves automatically
522 * into wxTopLevelWindows by getting created
523 * in OnInit(). */
524
525 if (!wxTheApp->OnInit())
526 return 0;
527
528 wxTheApp->m_initialized = (wxTopLevelWindows.Number() > 0);
529
530 int retValue = 0;
531
532 if (wxTheApp->Initialized())
533 retValue = wxTheApp->OnRun();
534
535 wxWindow *topWindow = wxTheApp->GetTopWindow();
536 if (topWindow)
537 {
538 // Forcibly delete the window.
539 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
540 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
541 {
542 topWindow->Close( TRUE );
543 wxTheApp->DeletePendingObjects();
544 }
545 else
546 {
547 delete topWindow;
548 wxTheApp->SetTopWindow( (wxWindow*) NULL );
549 }
550 }
551
552 wxTheApp->OnExit();
553
554 // flush the logged messages if any
555 wxLog *log = wxLog::GetActiveTarget();
556 if (log != NULL && log->HasPendingMessages())
557 log->Flush();
558
559 // continuing to use user defined log target is unsafe from now on because
560 // some resources may be already unavailable, so replace it by something
561 // more safe
562 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
563 if ( oldlog )
564 delete oldlog;
565
566 wxApp::CleanUp();
567
568 return retValue;
569 }
570