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