1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/utilsgtk.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  16     #include "wx/string.h" 
  21 #include "wx/apptrait.h" 
  22 #include "wx/process.h" 
  23 #include "wx/sysopt.h" 
  25 #include "wx/unix/execute.h" 
  28 #include "wx/gtk/private/timer.h" 
  29 #include "wx/evtloop.h" 
  32 #ifdef GDK_WINDOWING_WIN32 
  33 #include <gdk/gdkwin32.h> 
  35 #ifdef GDK_WINDOWING_X11 
  40     #include "wx/gtk/assertdlg_gtk.h" 
  42         #include "wx/stackwalk.h" 
  43     #endif // wxUSE_STACKWALKER 
  44 #endif // wxDEBUG_LEVEL 
  49 #include <sys/types.h> 
  55     #include <X11/SM/SMlib.h> 
  57     #include "wx/unix/utilsx11.h" 
  60 #include "wx/gtk/private/gtk2-compat.h" 
  62 //----------------------------------------------------------------------------- 
  64 //----------------------------------------------------------------------------- 
  66 extern GtkWidget 
*wxGetRootWindow(); 
  68 //---------------------------------------------------------------------------- 
  70 //---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  78 // display characteristics 
  79 // ---------------------------------------------------------------------------- 
  81 #ifdef GDK_WINDOWING_X11 
  84     return GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(wxGetRootWindow())); 
  88 void wxDisplaySize( int *width
, int *height 
) 
  90     if (width
) *width 
= gdk_screen_width(); 
  91     if (height
) *height 
= gdk_screen_height(); 
  94 void wxDisplaySizeMM( int *width
, int *height 
) 
  96     if (width
) *width 
= gdk_screen_width_mm(); 
  97     if (height
) *height 
= gdk_screen_height_mm(); 
 100 void wxGetMousePosition( int* x
, int* y 
) 
 102     gdk_window_get_pointer(gtk_widget_get_root_window(wxGetRootWindow()), x
, y
, NULL
); 
 105 bool wxColourDisplay() 
 112     return gdk_visual_get_depth(gtk_widget_get_visual(wxGetRootWindow())); 
 115 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
) 
 117     return wxGenericFindWindowAtPoint(pt
); 
 122 WXDLLIMPEXP_CORE wxCharBuffer
 
 123 wxConvertToGTK(const wxString
& s
, wxFontEncoding enc
) 
 126     if ( enc 
== wxFONTENCODING_SYSTEM 
|| enc 
== wxFONTENCODING_DEFAULT 
) 
 128         wbuf 
= wxConvUI
->cMB2WC(s
); 
 130     else // another encoding, use generic conversion class 
 132         wbuf 
= wxCSConv(enc
).cMB2WC(s
.c_str()); 
 135     if ( !wbuf 
&& !s
.empty() ) 
 137         // conversion failed, but we still want to show something to the user 
 138         // even if it's going to be wrong it is better than nothing 
 140         // we choose ISO8859-1 here arbitrarily, it's just the most common 
 141         // encoding probably and, also importantly here, conversion from it 
 142         // never fails as it's done internally by wxCSConv 
 143         wbuf 
= wxCSConv(wxFONTENCODING_ISO8859_1
).cMB2WC(s
.c_str()); 
 146     return wxConvUTF8
.cWC2MB(wbuf
); 
 149 WXDLLIMPEXP_CORE wxCharBuffer
 
 150 wxConvertFromGTK(const wxString
& s
, wxFontEncoding enc
) 
 152     // this conversion should never fail as GTK+ always uses UTF-8 internally 
 153     // so there are no complications here 
 154     const wxWCharBuffer 
wbuf(wxConvUTF8
.cMB2WC(s
.c_str())); 
 155     if ( enc 
== wxFONTENCODING_SYSTEM 
) 
 156         return wxConvUI
->cWC2MB(wbuf
); 
 158     return wxCSConv(enc
).cWC2MB(wbuf
); 
 161 #endif // !wxUSE_UNICODE 
 163 // Returns NULL if version is certainly greater or equal than major.minor.micro 
 164 // Returns string describing the error if version is lower than 
 165 // major.minor.micro OR it cannot be determined and one should not rely on the 
 166 // availability of pango version major.minor.micro, nor the non-availability 
 167 const gchar 
*wx_pango_version_check (int major
, int minor
, int micro
) 
 169     // NOTE: you don't need to use this macro to check for Pango features 
 170     //       added in pango-1.4 or earlier since GTK 2.4 (our minimum requirement 
 171     //       for GTK lib) required pango 1.4... 
 174     return pango_version_check(major
, minor
, micro
); 
 175 #elif defined(PANGO_VERSION_MAJOR) 
 176     if (!gtk_check_version (2,11,0)) 
 178         // GTK+ 2.11 requires Pango >= 1.15.3 and pango_version_check 
 179         // was added in Pango 1.15.2 thus we know for sure the pango lib we're 
 180         // using has the pango_version_check function: 
 181         return pango_version_check (major
, minor
, micro
); 
 184     return "can't check"; 
 185 #else // !PANGO_VERSION_MAJOR 
 190     return "too old headers"; 
 194 // ---------------------------------------------------------------------------- 
 195 // subprocess routines 
 196 // ---------------------------------------------------------------------------- 
 201 static gboolean 
EndProcessDetector(GIOChannel
* source
, GIOCondition
, void* data
) 
 203     wxEndProcessData 
* const 
 204         proc_data 
= static_cast<wxEndProcessData 
*>(data
); 
 206     // child exited, end waiting 
 207     close(g_io_channel_unix_get_fd(source
)); 
 209     wxHandleProcessTermination(proc_data
); 
 211     // don't call us again! 
 216 int wxGUIAppTraits::AddProcessCallback(wxEndProcessData 
*proc_data
, int fd
) 
 218     GIOChannel
* channel 
= g_io_channel_unix_new(fd
); 
 219     GIOCondition cond 
= GIOCondition(G_IO_IN 
| G_IO_HUP 
| G_IO_ERR
); 
 220     unsigned id 
= g_io_add_watch(channel
, cond
, EndProcessDetector
, proc_data
); 
 221     g_io_channel_unref(channel
); 
 227 // ---------------------------------------------------------------------------- 
 228 // wxPlatformInfo-related 
 229 // ---------------------------------------------------------------------------- 
 231 wxPortId 
wxGUIAppTraits::GetToolkitVersion(int *verMaj
, int *verMin
) const 
 234         *verMaj 
= gtk_major_version
; 
 236         *verMin 
= gtk_minor_version
; 
 243 wxTimerImpl 
*wxGUIAppTraits::CreateTimerImpl(wxTimer 
*timer
) 
 245     return new wxGTKTimerImpl(timer
); 
 248 #endif // wxUSE_TIMER 
 251 static wxString 
GetSM() 
 255         return wxEmptyString
; 
 259     SmcConn smc_conn 
= SmcOpenConnection(NULL
, NULL
, 
 261                                          0 /* mask */, NULL 
/* callbacks */, 
 263                                          WXSIZEOF(smerr
), smerr
); 
 267         wxLogDebug("Failed to connect to session manager: %s", smerr
); 
 268         return wxEmptyString
; 
 271     char *vendor 
= SmcVendor(smc_conn
); 
 272     wxString ret 
= wxString::FromAscii( vendor 
); 
 275     SmcCloseConnection(smc_conn
, 0, NULL
); 
 280 #endif // wxUSE_DETECT_SM 
 283 //----------------------------------------------------------------------------- 
 285 //----------------------------------------------------------------------------- 
 287 wxEventLoopBase 
*wxGUIAppTraits::CreateEventLoop() 
 289     return new wxEventLoop(); 
 293 #if wxUSE_INTL && defined(__UNIX__) 
 294 void wxGUIAppTraits::SetLocale() 
 297     setlocale(LC_ALL
, ""); 
 301     wxUpdateLocaleIsUtf8(); 
 307 #if wxDEBUG_LEVEL && wxUSE_STACKWALKER 
 309 // private helper class 
 310 class StackDump 
: public wxStackWalker
 
 313     StackDump(GtkAssertDialog 
*dlg
) { m_dlg
=dlg
; } 
 316     virtual void OnStackFrame(const wxStackFrame
& frame
) 
 318         wxString fncname 
= frame
.GetName(); 
 320         // append this stack frame's info in the dialog 
 321         if (!frame
.GetFileName().empty() || !fncname
.empty()) 
 322             gtk_assert_dialog_append_stack_frame(m_dlg
, 
 324                                                 frame
.GetFileName().mb_str(), 
 329     GtkAssertDialog 
*m_dlg
; 
 332 static void get_stackframe_callback(void* p
) 
 334     StackDump
* dump 
= static_cast<StackDump
*>(p
); 
 335     // skip over frames up to including wxOnAssert() 
 336     dump
->ProcessFrames(3); 
 339 #endif // wxDEBUG_LEVEL && wxUSE_STACKWALKER 
 341 bool wxGUIAppTraits::ShowAssertDialog(const wxString
& msg
) 
 344     // we can't show the dialog from another thread 
 345     if ( wxIsMainThread() ) 
 347         // under GTK2 we prefer to use a dialog widget written using directly 
 348         // in GTK+ as use a dialog written using wxWidgets would need the 
 349         // wxWidgets idle processing to work correctly which might not be the 
 350         // case when assert happens 
 351         GtkWidget 
*dialog 
= gtk_assert_dialog_new(); 
 352         gtk_assert_dialog_set_message(GTK_ASSERT_DIALOG(dialog
), msg
.mb_str()); 
 354 #if wxUSE_STACKWALKER 
 355         // save the current stack ow... 
 356         StackDump 
dump(GTK_ASSERT_DIALOG(dialog
)); 
 357         dump
.SaveStack(100); // showing more than 100 frames is not very useful 
 359         // ...but process it only if the user needs it 
 360         gtk_assert_dialog_set_backtrace_callback
 
 362             GTK_ASSERT_DIALOG(dialog
), 
 363             get_stackframe_callback
, 
 366 #endif // wxUSE_STACKWALKER 
 368         gint result 
= gtk_dialog_run(GTK_DIALOG (dialog
)); 
 369         bool returnCode 
= false; 
 372             case GTK_ASSERT_DIALOG_STOP
: 
 375             case GTK_ASSERT_DIALOG_CONTINUE
: 
 378             case GTK_ASSERT_DIALOG_CONTINUE_SUPPRESSING
: 
 384                 wxFAIL_MSG( wxT("unexpected return code from GtkAssertDialog") ); 
 387         gtk_widget_destroy(dialog
); 
 390 #endif // wxDEBUG_LEVEL 
 392     return wxAppTraitsBase::ShowAssertDialog(msg
); 
 397 #if defined(__UNIX__) || defined(__OS2__) 
 399 wxString 
wxGUIAppTraits::GetDesktopEnvironment() const 
 401     wxString de 
= wxSystemOptions::GetOption(wxT("gtk.desktop")); 
 405         static const wxString s_SM 
= GetSM(); 
 407         if (s_SM 
== wxT("GnomeSM")) 
 409         else if (s_SM 
== wxT("KDE")) 
 412 #endif // wxUSE_DETECT_SM 
 417 #endif // __UNIX__ || __OS2__ 
 419 // see the hack below in wxCmdLineParser::GetUsageString(). 
 420 // TODO: replace this hack with a g_option_group_get_entries() 
 421 //       call as soon as such function exists; 
 422 //       see http://bugzilla.gnome.org/show_bug.cgi?id=431021 for the relative 
 428   gchar           
*help_description
; 
 430   GDestroyNotify   destroy_notify
; 
 433   GTranslateFunc   translate_func
; 
 434   GDestroyNotify   translate_notify
; 
 435   gpointer     translate_data
; 
 437   GOptionEntry    
*entries
; 
 440   GOptionParseFunc pre_parse_func
; 
 441   GOptionParseFunc post_parse_func
; 
 442   GOptionErrorFunc error_func
; 
 445 wxString 
wxGetNameFromGtkOptionEntry(const GOptionEntry 
*opt
) 
 450         ret 
<< wxT("-") << opt
->short_name
; 
 455         ret 
<< wxT("--") << opt
->long_name
; 
 457         if (opt
->arg_description
) 
 458             ret 
<< wxT("=") << opt
->arg_description
; 
 461     return wxT("  ") + ret
; 
 467 wxGUIAppTraits::GetStandardCmdLineOptions(wxArrayString
& names
, 
 468                                           wxArrayString
& desc
) const 
 472     // check whether GLib version is greater than 2.6 but also lower than 2.33 
 473     // because, as we use the undocumented _GOptionGroup struct, we don't want 
 474     // to run this code with future versions which might change it (2.32 is the 
 475     // latest one at the time of this writing) 
 476     if (glib_check_version(2,33,0)) 
 478         usage 
<< _("The following standard GTK+ options are also supported:\n"); 
 480         // passing true here means that the function can open the default 
 481         // display while parsing (not really used here anyhow) 
 482         GOptionGroup 
*gtkOpts 
= gtk_get_option_group(true); 
 484         // WARNING: here we access the internals of GOptionGroup: 
 485         GOptionEntry 
*entries 
= ((_GOptionGroup
*)gtkOpts
)->entries
; 
 486         unsigned int n_entries 
= ((_GOptionGroup
*)gtkOpts
)->n_entries
; 
 487         wxArrayString namesOptions
, descOptions
; 
 489         for ( size_t n 
= 0; n 
< n_entries
; n
++ ) 
 491             if ( entries
[n
].flags 
& G_OPTION_FLAG_HIDDEN 
) 
 494             names
.push_back(wxGetNameFromGtkOptionEntry(&entries
[n
])); 
 496             const gchar 
* const entryDesc 
= entries
[n
].description
; 
 497             desc
.push_back(wxString(entryDesc
)); 
 500         g_option_group_free (gtkOpts
);