add support for GDK_SCROLL_SMOOTH mouse wheel event, introduced in GTK+ 3.4
[wxWidgets.git] / src / motif / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #include "wx/app.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/hash.h"
18 #include "wx/intl.h"
19 #include "wx/log.h"
20 #include "wx/utils.h"
21 #include "wx/memory.h"
22 #include "wx/font.h"
23 #endif
24
25 #include "wx/evtloop.h"
26
27 #if wxUSE_THREADS
28 #include "wx/thread.h"
29 #endif
30
31 #ifdef __VMS__
32 #pragma message disable nosimpint
33 #endif
34 #include <Xm/Xm.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/Xresource.h>
38 #include <X11/Xatom.h>
39 #ifdef __VMS__
40 #pragma message enable nosimpint
41 #endif
42
43 #include "wx/motif/private.h"
44
45 #include <string.h>
46
47 struct wxPerDisplayData
48 {
49 wxPerDisplayData()
50 {
51 m_visualInfo = NULL;
52 m_topLevelWidget = NULL;
53 m_topLevelRealizedWidget = NULL;
54 }
55
56 wxXVisualInfo* m_visualInfo;
57 Widget m_topLevelWidget, m_topLevelRealizedWidget;
58 };
59
60 static void wxTLWidgetDestroyCallback(Widget w, XtPointer clientData,
61 XtPointer ptr);
62 static WXWidget wxCreateTopLevelWidget( WXDisplay* display );
63
64 extern bool wxAddIdleCallback();
65
66 wxHashTable *wxWidgetHashTable = NULL;
67
68 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
69
70 extern "C"
71 {
72 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
73 }
74
75 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
76
77 extern "C"
78 {
79
80 static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
81 {
82 // just forward to the default handler for now
83 return gs_pfnXErrorHandler(dpy, xevent);
84 }
85
86 }
87
88 bool wxApp::Initialize(int& argc_, wxChar **argv_)
89 {
90 #if wxUSE_INTL
91 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
92 #endif
93
94 if ( !wxAppBase::Initialize(argc_, argv_) )
95 return false;
96
97 wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
98
99 #ifdef __HPUX__
100 // under HP-UX creating XmFontSet fails when the system locale is C and
101 // we're using a remote DISPLAY, presumably because HP-UX uses its own
102 // names for C and ISO locales (roman8 and iso8859n respectively) and so
103 // its Motif libraries have troubles with non-HP X server
104 //
105 // whatever the reason, the fact is that without this hack any wxMotif
106 // program crashes on startup because it can't create any font (HP programs
107 // still work but they do spit out messages about failing to create font
108 // sets and failing back on "fixed" font too)
109 //
110 // notice that calling setlocale() here is not enough because X(m) init
111 // functions call setlocale() later so we really have to change environment
112 bool fixAll = false; // tweak LC_ALL (or just LC_CTYPE)?
113 const char *loc = getenv("LC_CTYPE");
114 if ( !loc )
115 {
116 loc = getenv("LC_ALL");
117 if ( loc )
118 fixAll = true;
119 }
120
121 if ( !loc ||
122 (loc[0] == 'C' && loc[1] == '\0') ||
123 strcmp(loc, "POSIX") == 0 )
124 {
125 // we're using C locale, "fix" it
126 wxLogDebug(wxT("HP-UX fontset hack: forcing locale to en_US.iso88591"));
127 putenv(fixAll ? "LC_ALL=en_US.iso88591" : "LC_CTYPE=en_US.iso88591");
128 }
129 #endif // __HPUX__
130
131 XtSetLanguageProc(NULL, NULL, NULL);
132 XtToolkitInitialize() ;
133 wxTheApp->m_appContext = (WXAppContext) XtCreateApplicationContext();
134
135 static char *fallbackResources[] = {
136 // better defaults for CDE under Irix
137 //
138 // TODO: do something similar for the other systems, the hardcoded defaults
139 // below are ugly
140 #ifdef __SGI__
141 wxMOTIF_STR("*sgiMode: True"),
142 wxMOTIF_STR("*useSchemes: all"),
143 #else // !__SGI__
144 #if !wxMOTIF_USE_RENDER_TABLE
145 wxMOTIF_STR("*.fontList: -*-helvetica-medium-r-normal-*-*-120-*-*-*-*-*-*"),
146 #else
147 wxMOTIF_STR("*wxDefaultRendition.fontName: -*-helvetica-medium-r-normal-*-*-120-*-*-*-*-*-*"),
148 wxMOTIF_STR("*wxDefaultRendition.fontType: FONT_IS_FONTSET"),
149 wxMOTIF_STR("*.renderTable: wxDefaultRendition"),
150 #endif
151 wxMOTIF_STR("*listBox.background: white"),
152 wxMOTIF_STR("*text.background: white"),
153 wxMOTIF_STR("*comboBox.Text.background: white"),
154 wxMOTIF_STR("*comboBox.List.background: white"),
155 #endif // __SGI__/!__SGI__
156 NULL
157 };
158 XtAppSetFallbackResources((XtAppContext) wxTheApp->m_appContext, fallbackResources);
159
160 // we shouldn't pass empty application/class name as it results in
161 // immediate crash inside XOpenIM() (if XIM is used) under IRIX
162 wxString appname = wxTheApp->GetAppName();
163 if ( appname.empty() )
164 appname = wxT("wxapp");
165 wxString clsname = wxTheApp->GetClassName();
166 if ( clsname.empty() )
167 clsname = wxT("wx");
168
169 // FIXME-UTF8: This code is taken from wxGTK and duplicated here. This
170 // is just a temporary fix to make wxX11 compile in Unicode
171 // build, the real fix is to change Initialize()'s signature
172 // to use char* on Unix.
173 #if wxUSE_UNICODE
174 // XtOpenDisplay() wants char*, not wchar_t*, so convert
175 int i;
176 char **argvX11 = new char *[argc + 1];
177 for ( i = 0; i < argc; i++ )
178 {
179 argvX11[i] = strdup(wxConvLibc.cWX2MB(argv_[i]));
180 }
181
182 argvX11[argc] = NULL;
183
184 int argcX11 = argc;
185
186 Display *dpy = XtOpenDisplay((XtAppContext) wxTheApp->m_appContext,
187 (String)NULL,
188 appname.c_str(),
189 clsname.c_str(),
190 NULL, 0, // no options
191 # if XtSpecificationRelease < 5
192 (Cardinal*) &argcX11,
193 # else
194 &argcX11,
195 # endif
196 argvX11);
197
198 if ( argcX11 != argc )
199 {
200 // we have to drop the parameters which were consumed by X11+
201 for ( i = 0; i < argcX11; i++ )
202 {
203 while ( strcmp(wxConvLibc.cWX2MB(argv_[i]), argvX11[i]) != 0 )
204 {
205 memmove(argv_ + i, argv_ + i + 1, (argc - i)*sizeof(*argv_));
206 }
207 }
208
209 argc = argcX11;
210
211 // update internal arg[cv] as X11 may have removed processed options:
212 argc = argc_;
213 argv = argv_;
214 }
215 //else: XtOpenDisplay() didn't modify our parameters
216
217 // free our copy
218 for ( i = 0; i < argcX11; i++ )
219 {
220 free(argvX11[i]);
221 }
222
223 delete [] argvX11;
224
225 #else // ANSI
226
227 Display *dpy = XtOpenDisplay((XtAppContext) wxTheApp->m_appContext,
228 (String)NULL,
229 appname.c_str(),
230 clsname.c_str(),
231 NULL, 0, // no options
232 # if XtSpecificationRelease < 5
233 (Cardinal*) &argc,
234 # else
235 &argc,
236 # endif
237 argv);
238
239 #endif // Unicode/ANSI
240
241 if (!dpy) {
242 // if you don't log to stderr, nothing will be shown...
243 delete wxLog::SetActiveTarget(new wxLogStderr);
244 wxString className(wxTheApp->GetClassName());
245 wxLogError(_("wxWidgets could not open display for '%s': exiting."),
246 className.c_str());
247 exit(-1);
248 }
249 m_initialDisplay = (WXDisplay*) dpy;
250
251 // install the X error handler
252 gs_pfnXErrorHandler = XSetErrorHandler(wxXErrorHandler);
253
254 // Add general resize proc
255 XtActionsRec rec;
256 rec.string = wxMOTIF_STR("resize");
257 rec.proc = (XtActionProc)wxWidgetResizeProc;
258 XtAppAddActions((XtAppContext) wxTheApp->m_appContext, &rec, 1);
259
260 GetMainColormap(dpy);
261
262 wxAddIdleCallback();
263
264 return true;
265 }
266
267 void wxApp::CleanUp()
268 {
269 wxAppBase::CleanUp();
270
271 wxDELETE(wxWidgetHashTable);
272
273 delete m_mainLoop;
274
275 for( wxPerDisplayDataMap::iterator it = m_perDisplayData->begin(),
276 end = m_perDisplayData->end();
277 it != end; ++it )
278 {
279 delete it->second->m_visualInfo;
280 // On Solaris 10 calling XtDestroyWidget on the top level widget
281 // dumps core if the locale is set to something other than "C"
282 #ifndef __SUN__
283 XtDestroyWidget( it->second->m_topLevelWidget );
284 #endif
285 delete it->second;
286 }
287 }
288
289 void wxApp::Exit()
290 {
291 wxApp::CleanUp();
292
293 wxAppConsole::Exit();
294 }
295
296 // ============================================================================
297 // wxApp
298 // ============================================================================
299
300 wxApp::wxApp()
301 {
302 m_mainLoop = new wxEventLoop;
303 m_mainColormap = (WXColormap) NULL;
304 m_appContext = (WXAppContext) NULL;
305 m_initialDisplay = (WXDisplay*) 0;
306 m_perDisplayData = new wxPerDisplayDataMap;
307 }
308
309 wxApp::~wxApp()
310 {
311 delete m_perDisplayData;
312 }
313
314 int wxApp::MainLoop()
315 {
316 /*
317 * Sit around forever waiting to process X-events. Property Change
318 * event are handled special, because they have to refer to
319 * the root window rather than to a widget. therefore we can't
320 * use an Xt-eventhandler.
321 */
322
323 XSelectInput(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()),
324 XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())),
325 PropertyChangeMask);
326
327 m_mainLoop->Run();
328
329 return 0;
330 }
331
332 // This should be redefined in a derived class for
333 // handling property change events for XAtom IPC.
334 void wxApp::HandlePropertyChange(WXEvent *event)
335 {
336 // by default do nothing special
337 XtDispatchEvent((XEvent*) event); /* let Motif do the work */
338 }
339
340 WXColormap wxApp::GetMainColormap(WXDisplay* display)
341 {
342 if (!display) /* Must be called first with non-NULL display */
343 return m_mainColormap;
344
345 int defaultScreen = DefaultScreen((Display*) display);
346 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
347
348 Colormap c = DefaultColormapOfScreen(screen);
349
350 if (!m_mainColormap)
351 m_mainColormap = (WXColormap) c;
352
353 return (WXColormap) c;
354 }
355
356 static inline wxPerDisplayData& GetOrCreatePerDisplayData
357 ( wxPerDisplayDataMap& m, WXDisplay* display )
358 {
359 wxPerDisplayDataMap::iterator it = m.find( display );
360 if( it != m.end() && it->second != NULL )
361 return *(it->second);
362
363 wxPerDisplayData* nData = new wxPerDisplayData();
364 m[display] = nData;
365
366 return *nData;
367 }
368
369 wxXVisualInfo* wxApp::GetVisualInfo( WXDisplay* display )
370 {
371 wxPerDisplayData& data = GetOrCreatePerDisplayData( *m_perDisplayData,
372 display );
373 if( data.m_visualInfo )
374 return data.m_visualInfo;
375
376 wxXVisualInfo* vi = new wxXVisualInfo;
377 wxFillXVisualInfo( vi, (Display*)display );
378
379 data.m_visualInfo = vi;
380
381 return vi;
382 }
383
384 static void wxTLWidgetDestroyCallback(Widget w, XtPointer WXUNUSED(clientData),
385 XtPointer WXUNUSED(ptr))
386 {
387 if( wxTheApp )
388 {
389 wxTheApp->SetTopLevelWidget( (WXDisplay*)XtDisplay(w),
390 (WXWidget)NULL );
391 wxTheApp->SetTopLevelRealizedWidget( (WXDisplay*)XtDisplay(w),
392 (WXWidget)NULL );
393 }
394 }
395
396 WXWidget wxCreateTopLevelWidget( WXDisplay* display )
397 {
398 Widget tlw = XtAppCreateShell( (String)NULL,
399 wxTheApp->GetClassName().c_str(),
400 applicationShellWidgetClass,
401 (Display*)display,
402 NULL, 0 );
403 XtVaSetValues( tlw,
404 XmNoverrideRedirect, True,
405 NULL );
406
407 XtAddCallback( tlw, XmNdestroyCallback,
408 (XtCallbackProc)wxTLWidgetDestroyCallback,
409 (XtPointer)NULL );
410
411 return (WXWidget)tlw;
412 }
413
414 WXWidget wxCreateTopLevelRealizedWidget( WXDisplay* WXUNUSED(display) )
415 {
416 Widget rTlw = XtVaCreateWidget( "dummy_widget", topLevelShellWidgetClass,
417 (Widget)wxTheApp->GetTopLevelWidget(),
418 NULL );
419 XtSetMappedWhenManaged( rTlw, False );
420 XtRealizeWidget( rTlw );
421
422 return (WXWidget)rTlw;
423 }
424
425 WXWidget wxApp::GetTopLevelWidget()
426 {
427 WXDisplay* display = wxGetDisplay();
428 wxPerDisplayData& data = GetOrCreatePerDisplayData( *m_perDisplayData,
429 display );
430 if( data.m_topLevelWidget )
431 return (WXWidget)data.m_topLevelWidget;
432
433 WXWidget tlw = wxCreateTopLevelWidget( display );
434 SetTopLevelWidget( display, tlw );
435
436 return tlw;
437 }
438
439 WXWidget wxApp::GetTopLevelRealizedWidget()
440 {
441 WXDisplay* display = wxGetDisplay();
442 wxPerDisplayDataMap::iterator it = m_perDisplayData->find( display );
443
444 if( it != m_perDisplayData->end() && it->second->m_topLevelRealizedWidget )
445 return (WXWidget)it->second->m_topLevelRealizedWidget;
446
447 WXWidget rTlw = wxCreateTopLevelRealizedWidget( display );
448 SetTopLevelRealizedWidget( display, rTlw );
449
450 return rTlw;
451 }
452
453 void wxApp::SetTopLevelWidget(WXDisplay* display, WXWidget widget)
454 {
455 GetOrCreatePerDisplayData( *m_perDisplayData, display )
456 .m_topLevelWidget = (Widget)widget;
457 }
458
459 void wxApp::SetTopLevelRealizedWidget(WXDisplay* display, WXWidget widget)
460 {
461 GetOrCreatePerDisplayData( *m_perDisplayData, display )
462 .m_topLevelRealizedWidget = (Widget)widget;
463 }
464
465
466 // ----------------------------------------------------------------------------
467 // accessors for C modules
468 // ----------------------------------------------------------------------------
469
470 extern "C" XtAppContext wxGetAppContext()
471 {
472 return (XtAppContext)wxTheApp->GetAppContext();
473 }