]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/app.cpp
With the exceptions of DnD, wxGTk now works with
[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 #if wxUSE_THREADS
50 extern wxList wxPendingEvents;
51 extern wxCriticalSection wxPendingEventsLocker;
52 #endif
53 extern wxResourceCache *wxTheResourceCache;
54
55 unsigned 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
127 extern void wxFlushResources(void);
128
129 //-----------------------------------------------------------------------------
130 // global functions
131 //-----------------------------------------------------------------------------
132
133 void wxExit()
134 {
135 gtk_main_quit();
136 }
137
138 bool 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 ( wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
144 node;
145 node = node->GetNext() )
146 {
147 wxWindow *win = 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
161 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
162
163 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
164 EVT_IDLE(wxApp::OnIdle)
165 END_EVENT_TABLE()
166
167 gint 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
183 wxApp::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
195 wxApp::~wxApp()
196 {
197 gtk_idle_remove( m_idleTag );
198
199 if (m_colorCube) free(m_colorCube);
200 }
201
202 bool 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
271 bool wxApp::ProcessIdle()
272 {
273 wxIdleEvent event;
274 event.SetEventObject( this );
275 ProcessEvent( event );
276
277 return event.MoreRequested();
278 }
279
280 void 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 #if wxUSE_THREADS
291 /* Resend in the main thread events which have been prepared in other
292 threads */
293 ProcessPendingEvents();
294 #endif
295
296 /* 'Garbage' collection of windows deleted with Close(). */
297 DeletePendingObjects();
298
299 /* flush the logged messages if any */
300 wxLog *log = wxLog::GetActiveTarget();
301 if (log != NULL && log->HasPendingMessages())
302 log->Flush();
303
304 /* Send OnIdle events to all windows */
305 bool needMore = SendIdleEvents();
306
307 if (needMore)
308 event.RequestMore(TRUE);
309
310 inOnIdle = FALSE;
311 }
312
313 bool wxApp::SendIdleEvents()
314 {
315 bool needMore = FALSE;
316
317 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
318 while (node)
319 {
320 wxWindow* win = node->GetData();
321 if (SendIdleEvents(win))
322 needMore = TRUE;
323 node = node->GetNext();
324 }
325
326 return needMore;
327 }
328
329 bool wxApp::SendIdleEvents( wxWindow* win )
330 {
331 bool needMore = FALSE;
332
333 wxIdleEvent event;
334 event.SetEventObject(win);
335
336 win->OnInternalIdle();
337
338 win->ProcessEvent(event);
339
340 if (event.MoreRequested())
341 needMore = TRUE;
342
343 wxNode* node = win->GetChildren().First();
344 while (node)
345 {
346 wxWindow* win = (wxWindow*) node->Data();
347 if (SendIdleEvents(win))
348 needMore = TRUE;
349
350 node = node->Next();
351 }
352 return needMore ;
353 }
354
355 int wxApp::MainLoop()
356 {
357 gtk_main();
358 return 0;
359 }
360
361 void wxApp::ExitMainLoop()
362 {
363 gtk_main_quit();
364 }
365
366 bool wxApp::Initialized()
367 {
368 return m_initialized;
369 }
370
371 bool wxApp::Pending()
372 {
373 return FALSE;
374 }
375
376 void wxApp::Dispatch()
377 {
378 }
379
380 #if wxUSE_THREADS
381 void 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();
391
392 delete node;
393
394 node = wxPendingEvents.First();
395 }
396 }
397 #endif
398
399 void wxApp::DeletePendingObjects()
400 {
401 wxNode *node = wxPendingDelete.First();
402 while (node)
403 {
404 wxObject *obj = (wxObject *)node->Data();
405
406 delete obj;
407
408 if (wxPendingDelete.Member(obj))
409 delete node;
410
411 node = wxPendingDelete.First();
412 }
413 }
414
415 wxWindow *wxApp::GetTopWindow()
416 {
417 if (m_topWindow)
418 return m_topWindow;
419 else if (wxTopLevelWindows.GetCount() > 0)
420 return wxTopLevelWindows.GetFirst()->GetData();
421 else
422 return NULL;
423 }
424
425 void wxApp::SetTopWindow( wxWindow *win )
426 {
427 m_topWindow = win;
428 }
429
430 bool wxApp::Initialize()
431 {
432 wxBuffer = new char[BUFSIZ + 512];
433
434 wxClassInfo::InitializeClasses();
435
436 wxSystemSettings::Init();
437
438 /*
439 wxTheFontNameDirectory = new wxFontNameDirectory;
440 wxTheFontNameDirectory->Initialize();
441 */
442
443 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
444 wxTheColourDatabase->Initialize();
445
446 wxInitializeStockLists();
447 wxInitializeStockObjects();
448
449 #if wxUSE_WX_RESOURCES
450 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
451
452 wxInitializeResourceSystem();
453 #endif
454
455 wxImage::InitStandardHandlers();
456
457 /* no global cursor under X
458 g_globalCursor = new wxCursor; */
459
460 wxModule::RegisterModules();
461 if (!wxModule::InitializeModules()) return FALSE;
462
463 return TRUE;
464 }
465
466 void wxApp::CleanUp()
467 {
468 wxModule::CleanUpModules();
469
470 #if wxUSE_WX_RESOURCES
471 wxFlushResources();
472
473 if (wxTheResourceCache)
474 delete wxTheResourceCache;
475 wxTheResourceCache = (wxResourceCache*) NULL;
476
477 wxCleanUpResourceSystem();
478 #endif
479
480 if (wxTheColourDatabase)
481 delete wxTheColourDatabase;
482 wxTheColourDatabase = (wxColourDatabase*) NULL;
483
484 /*
485 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
486 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
487 */
488
489 wxDeleteStockObjects();
490
491 wxDeleteStockLists();
492
493 wxImage::CleanUpHandlers();
494
495 delete wxTheApp;
496 wxTheApp = (wxApp*) NULL;
497
498 wxSystemSettings::Done();
499
500 delete[] wxBuffer;
501
502 wxClassInfo::CleanUpClasses();
503
504 // check for memory leaks
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
514 // do this as the very last thing because everything else can log messages
515 wxLog::DontCreateOnDemand();
516
517 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
518 if (oldLog)
519 delete oldLog;
520 }
521
522 wxLog *wxApp::CreateLogTarget()
523 {
524 return new wxLogGui;
525 }
526
527 //-----------------------------------------------------------------------------
528 // wxEntry
529 //-----------------------------------------------------------------------------
530
531 int wxEntry( int argc, char *argv[] )
532 {
533 gtk_set_locale();
534
535 gtk_init( &argc, &argv );
536
537 if (!wxApp::Initialize())
538 return -1;
539
540 if (!wxTheApp)
541 {
542 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
543 "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
544
545 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
546
547 wxObject *test_app = app_ini();
548
549 wxTheApp = (wxApp*) test_app;
550 }
551
552 wxCHECK_MSG( wxTheApp, -1, "wxWindows error: no application object" );
553
554 wxTheApp->argc = argc;
555 wxTheApp->argv = argv;
556
557 char name[200];
558 strcpy( name, argv[0] );
559 strcpy( name, wxFileNameFromPath(name) );
560 wxStripExtension( name );
561 wxTheApp->SetAppName( name );
562
563 if (!wxTheApp->OnInitGui())
564 return 0;
565
566 /* Here frames insert themselves automatically
567 * into wxTopLevelWindows by getting created
568 * in OnInit(). */
569
570 if (!wxTheApp->OnInit())
571 return 0;
572
573 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
574
575 int retValue = 0;
576
577 if (wxTheApp->Initialized())
578 retValue = wxTheApp->OnRun();
579
580 wxWindow *topWindow = wxTheApp->GetTopWindow();
581 if (topWindow)
582 {
583 // Forcibly delete the window.
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 }
595 }
596
597 wxTheApp->OnExit();
598
599 // flush the logged messages if any
600 wxLog *log = wxLog::GetActiveTarget();
601 if (log != NULL && log->HasPendingMessages())
602 log->Flush();
603
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
611 wxApp::CleanUp();
612
613 return retValue;
614 }
615