]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/utilsgtk.cpp
72757f441ba6560126389d28288dad429e9ed7af
[wxWidgets.git] / src / gtk / utilsgtk.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/utilsgtk.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/utils.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/string.h"
17 #include "wx/intl.h"
18 #include "wx/log.h"
19 #endif
20
21 #include "wx/apptrait.h"
22
23 #include "wx/process.h"
24
25 #include "wx/unix/execute.h"
26
27 #ifdef __WXDEBUG__
28 #include "wx/gtk/assertdlg_gtk.h"
29 #if wxUSE_STACKWALKER
30 #include "wx/stackwalk.h"
31 #endif // wxUSE_STACKWALKER
32 #endif // __WXDEBUG__
33
34 #include <stdarg.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/wait.h> // for WNOHANG
39 #include <unistd.h>
40
41 #include "glib.h"
42 #include "gdk/gdk.h"
43 #include "gtk/gtk.h"
44 #include "gdk/gdkx.h"
45
46 #ifdef HAVE_X11_XKBLIB_H
47 /* under HP-UX and Solaris 2.6, at least, XKBlib.h defines structures with
48 * field named "explicit" - which is, of course, an error for a C++
49 * compiler. To be on the safe side, just redefine it everywhere. */
50 #define explicit __wx_explicit
51
52 #include "X11/XKBlib.h"
53
54 #undef explicit
55 #endif // HAVE_X11_XKBLIB_H
56
57
58 #if wxUSE_DETECT_SM
59 #include "X11/Xlib.h"
60 #include "X11/SM/SMlib.h"
61 #endif
62
63 //-----------------------------------------------------------------------------
64 // data
65 //-----------------------------------------------------------------------------
66
67 extern GtkWidget *wxGetRootWindow();
68
69 //----------------------------------------------------------------------------
70 // misc.
71 //----------------------------------------------------------------------------
72 #ifndef __EMX__
73 // on OS/2, we use the wxBell from wxBase library
74
75 void wxBell()
76 {
77 gdk_beep();
78 }
79 #endif
80
81 /* Don't synthesize KeyUp events holding down a key and producing
82 KeyDown events with autorepeat. */
83 #ifdef HAVE_X11_XKBLIB_H
84 bool wxSetDetectableAutoRepeat( bool flag )
85 {
86 Bool result;
87 XkbSetDetectableAutoRepeat( GDK_DISPLAY(), flag, &result );
88 return result; /* true if keyboard hardware supports this mode */
89 }
90 #else
91 bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
92 {
93 return false;
94 }
95 #endif
96
97 // Escapes string so that it is valid Pango markup XML string:
98 wxString wxEscapeStringForPangoMarkup(const wxString& str)
99 {
100 size_t len = str.length();
101 wxString out;
102 out.Alloc(len);
103 for (size_t i = 0; i < len; i++)
104 {
105 wxChar c = str[i];
106 switch (c)
107 {
108 case _T('&'):
109 out << _T("&amp;");
110 break;
111 case _T('<'):
112 out << _T("&lt;");
113 break;
114 case _T('>'):
115 out << _T("&gt;");
116 break;
117 case _T('\''):
118 out << _T("&apos;");
119 break;
120 case _T('"'):
121 out << _T("&quot;");
122 break;
123 default:
124 out << c;
125 break;
126 }
127 }
128 return out;
129 }
130
131
132 // ----------------------------------------------------------------------------
133 // display characterstics
134 // ----------------------------------------------------------------------------
135
136 void *wxGetDisplay()
137 {
138 return GDK_DISPLAY();
139 }
140
141 void wxDisplaySize( int *width, int *height )
142 {
143 if (width) *width = gdk_screen_width();
144 if (height) *height = gdk_screen_height();
145 }
146
147 void wxDisplaySizeMM( int *width, int *height )
148 {
149 if (width) *width = gdk_screen_width_mm();
150 if (height) *height = gdk_screen_height_mm();
151 }
152
153 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
154 {
155 // This is supposed to return desktop dimensions minus any window
156 // manager panels, menus, taskbars, etc. If there is a way to do that
157 // for this platform please fix this function, otherwise it defaults
158 // to the entire desktop.
159 if (x) *x = 0;
160 if (y) *y = 0;
161 wxDisplaySize(width, height);
162 }
163
164 void wxGetMousePosition( int* x, int* y )
165 {
166 gdk_window_get_pointer( (GdkWindow*) NULL, x, y, (GdkModifierType*) NULL );
167 }
168
169 bool wxColourDisplay()
170 {
171 return true;
172 }
173
174 int wxDisplayDepth()
175 {
176 return gdk_drawable_get_visual( wxGetRootWindow()->window )->depth;
177 }
178
179 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
180 {
181 return wxGenericFindWindowAtPoint(pt);
182 }
183
184 #if !wxUSE_UNICODE
185
186 wxCharBuffer wxConvertToGTK(const wxString& s, wxFontEncoding enc)
187 {
188 wxWCharBuffer wbuf;
189 if ( enc == wxFONTENCODING_SYSTEM || enc == wxFONTENCODING_DEFAULT )
190 {
191 wbuf = wxConvUI->cMB2WC(s);
192 }
193 else // another encoding, use generic conversion class
194 {
195 wbuf = wxCSConv(enc).cMB2WC(s);
196 }
197
198 if ( !wbuf && !s.empty() )
199 {
200 // conversion failed, but we still want to show something to the user
201 // even if it's going to be wrong it is better than nothing
202 //
203 // we choose ISO8859-1 here arbitrarily, it's just the most common
204 // encoding probably and, also importantly here, conversion from it
205 // never fails as it's done internally by wxCSConv
206 wbuf = wxCSConv(wxFONTENCODING_ISO8859_1).cMB2WC(s);
207 }
208
209 return wxConvUTF8.cWC2MB(wbuf);
210 }
211
212 #endif // !wxUSE_UNICODE
213
214 // ----------------------------------------------------------------------------
215 // subprocess routines
216 // ----------------------------------------------------------------------------
217
218 extern "C" {
219 static
220 void GTK_EndProcessDetector(gpointer data, gint source,
221 GdkInputCondition WXUNUSED(condition) )
222 {
223 wxEndProcessData *proc_data = (wxEndProcessData *)data;
224
225 // has the process really terminated? unfortunately GDK (or GLib) seem to
226 // generate G_IO_HUP notification even when it simply tries to read from a
227 // closed fd and hasn't terminated at all
228 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
229 int status = 0;
230 int rc = waitpid(pid, &status, WNOHANG);
231
232 if ( rc == 0 )
233 {
234 // no, it didn't exit yet, continue waiting
235 return;
236 }
237
238 // set exit code to -1 if something bad happened
239 proc_data->exitcode = rc != -1 && WIFEXITED(status) ? WEXITSTATUS(status)
240 : -1;
241
242 // child exited, end waiting
243 close(source);
244
245 // don't call us again!
246 gdk_input_remove(proc_data->tag);
247
248 wxHandleProcessTermination(proc_data);
249 }
250 }
251
252 int wxAddProcessCallback(wxEndProcessData *proc_data, int fd)
253 {
254 int tag = gdk_input_add(fd,
255 GDK_INPUT_READ,
256 GTK_EndProcessDetector,
257 (gpointer)proc_data);
258
259 return tag;
260 }
261
262
263
264 // ----------------------------------------------------------------------------
265 // wxPlatformInfo-related
266 // ----------------------------------------------------------------------------
267
268 wxPortId wxGUIAppTraits::GetToolkitVersion(int *verMaj, int *verMin) const
269 {
270 if ( verMaj )
271 *verMaj = gtk_major_version;
272 if ( verMin )
273 *verMin = gtk_minor_version;
274
275 return wxPORT_GTK;
276 }
277
278 #if wxUSE_DETECT_SM
279 static wxString GetSM()
280 {
281 class Dpy
282 {
283 public:
284 Dpy() { m_dpy = XOpenDisplay(NULL); }
285 ~Dpy() { if ( m_dpy ) XCloseDisplay(m_dpy); }
286
287 operator Display *() const { return m_dpy; }
288 private:
289 Display *m_dpy;
290 } dpy;
291
292 if ( !dpy )
293 return wxEmptyString;
294
295 char *client_id;
296 SmcConn smc_conn = SmcOpenConnection(NULL, NULL,
297 999, 999,
298 0 /* mask */, NULL /* callbacks */,
299 NULL, &client_id,
300 0, NULL);
301
302 if ( !smc_conn )
303 return wxEmptyString;
304
305 char *vendor = SmcVendor(smc_conn);
306 wxString ret = wxString::FromAscii( vendor );
307 free(vendor);
308
309 SmcCloseConnection(smc_conn, 0, NULL);
310 free(client_id);
311
312 return ret;
313 }
314 #endif // wxUSE_DETECT_SM
315
316
317 //-----------------------------------------------------------------------------
318 // wxGUIAppTraits
319 //-----------------------------------------------------------------------------
320
321 #ifdef __WXDEBUG__
322
323 #if wxUSE_STACKWALKER
324
325 // private helper class
326 class StackDump : public wxStackWalker
327 {
328 public:
329 StackDump(GtkAssertDialog *dlg) { m_dlg=dlg; }
330
331 protected:
332 virtual void OnStackFrame(const wxStackFrame& frame)
333 {
334 wxString fncname = frame.GetName();
335 wxString fncargs = fncname;
336
337 size_t n = fncname.find(wxT('('));
338 if (n != wxString::npos)
339 {
340 // remove arguments from function name
341 fncname.erase(n);
342
343 // remove function name and brackets from arguments
344 fncargs = fncargs.substr(n+1, fncargs.length()-n-2);
345 }
346 else
347 fncargs = wxEmptyString;
348
349 // append this stack frame's info in the dialog
350 if (!frame.GetFileName().empty() || !fncname.empty())
351 gtk_assert_dialog_append_stack_frame(m_dlg,
352 fncname.mb_str(),
353 fncargs.mb_str(),
354 frame.GetFileName().mb_str(),
355 frame.GetLine());
356 }
357
358 private:
359 GtkAssertDialog *m_dlg;
360 };
361
362 // the callback functions must be extern "C" to comply with GTK+ declarations
363 extern "C"
364 {
365 void get_stackframe_callback(StackDump *dump)
366 {
367 // skip over frames up to including wxOnAssert()
368 dump->ProcessFrames(3);
369 }
370 }
371
372 #endif // wxUSE_STACKWALKER
373
374 bool wxGUIAppTraits::ShowAssertDialog(const wxString& msg)
375 {
376 // under GTK2 we prefer to use a dialog widget written using directly GTK+;
377 // in fact we cannot use a dialog written using wxWidgets: it would need
378 // the wxWidgets idle processing to work correctly!
379 GtkWidget *dialog = gtk_assert_dialog_new();
380 gtk_assert_dialog_set_message(GTK_ASSERT_DIALOG(dialog), msg.mb_str());
381
382 #if wxUSE_STACKWALKER
383 // don't show more than maxLines or we could get a dialog too tall to be
384 // shown on screen: 20 should be ok everywhere as even with 15 pixel high
385 // characters it is still only 300 pixels...
386 static const int maxLines = 20;
387
388 // save current stack frame...
389 StackDump dump(GTK_ASSERT_DIALOG(dialog));
390 dump.SaveStack(maxLines);
391
392 // ...but process it only if the user needs it
393 gtk_assert_dialog_set_backtrace_callback(GTK_ASSERT_DIALOG(dialog),
394 (GtkAssertDialogStackFrameCallback)get_stackframe_callback,
395 &dump);
396 #endif // wxUSE_STACKWALKER
397
398 gint result = gtk_dialog_run(GTK_DIALOG (dialog));
399 bool returnCode = false;
400 switch (result)
401 {
402 case GTK_ASSERT_DIALOG_STOP:
403 wxTrap();
404 break;
405 case GTK_ASSERT_DIALOG_CONTINUE:
406 // nothing to do
407 break;
408 case GTK_ASSERT_DIALOG_CONTINUE_SUPPRESSING:
409 // no more asserts
410 returnCode = true;
411 break;
412
413 default:
414 wxFAIL_MSG( _T("unexpected return code from GtkAssertDialog") );
415 }
416
417 gtk_widget_destroy(dialog);
418 return returnCode;
419 }
420
421 #endif // __WXDEBUG__
422
423 wxString wxGUIAppTraits::GetDesktopEnvironment() const
424 {
425 #if wxUSE_DETECT_SM
426 const wxString SM = GetSM();
427
428 if (SM == wxT("GnomeSM"))
429 return wxT("GNOME");
430
431 if (SM == wxT("KDE"))
432 return wxT("KDE");
433 #endif // wxUSE_DETECT_SM
434
435 return wxEmptyString;
436 }
437
438
439