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