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