DH 2012-11-15 01:39:56 +02:00
parent de070bf485
commit a90b5cf37a
1998 changed files with 1034301 additions and 0 deletions

View file

@ -0,0 +1,83 @@
///////////////////////////////////////////////////////////////////////////////
// Name: src/unix/baseunix.cpp
// Purpose: misc stuff only used in console applications under Unix
// Author: Vadim Zeitlin
// Modified by:
// Created: 23.06.2003
// RCS-ID: $Id: baseunix.cpp 40599 2006-08-13 21:00:32Z VZ $
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/utils.h"
#endif //WX_PRECOMP
#include "wx/apptrait.h"
#include "wx/unix/execute.h"
// for waitpid()
#include <sys/types.h>
#include <sys/wait.h>
// ============================================================================
// wxConsoleAppTraits implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxExecute support
// ----------------------------------------------------------------------------
bool wxConsoleAppTraits::CreateEndProcessPipe(wxExecuteData& WXUNUSED(data))
{
// nothing to do, so always ok
return true;
}
bool
wxConsoleAppTraits::IsWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(data),
int WXUNUSED(fd))
{
// we don't have any pipe
return false;
}
void
wxConsoleAppTraits::DetachWriteFDOfEndProcessPipe(wxExecuteData& WXUNUSED(data))
{
// nothing to do
}
int
wxConsoleAppTraits::WaitForChild(wxExecuteData& execData)
{
wxASSERT_MSG( execData.flags & wxEXEC_SYNC,
wxT("async execution not supported yet") );
int exitcode = 0;
if ( waitpid(execData.pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
{
wxLogSysError(_("Waiting for subprocess termination failed"));
}
return exitcode;
}

View file

@ -0,0 +1,120 @@
#*****************************************************************************
# *
# Make file for VMS *
# Author : J.Jansen (joukj@hrem.nano.tudelft.nl) *
# Date : 13 February 2006 *
# *
#*****************************************************************************
.first
define wx [--.include.wx]
.ifdef __WXMOTIF__
CXX_DEFINE = /define=(__WXMOTIF__=1)/name=(as_is,short)\
/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXMOTIF__=1)/name=(as_is,short)
.else
.ifdef __WXGTK__
CXX_DEFINE = /define=(__WXGTK__=1)/float=ieee/name=(as_is,short)/ieee=denorm\
/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXGTK__=1)/float=ieee/name=(as_is,short)/ieee=denorm
.else
.ifdef __WXGTK2__
CXX_DEFINE = /define=(__WXGTK__=1,VMS_GTK2)/float=ieee/name=(as_is,short)/ieee=denorm\
/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXGTK__=1,VMS_GTK2)/float=ieee/name=(as_is,short)/ieee=denorm
.else
.ifdef __WXX11__
CXX_DEFINE = /define=(__WXX11__=1,__WXUNIVERSAL__==1)/float=ieee\
/name=(as_is,short)/assume=(nostdnew,noglobal_array_new)
CC_DEFINE = /define=(__WXX11__=1,__WXUNIVERSAL__==1)/float=ieee\
/name=(as_is,short)
.else
CXX_DEFINE =
CC_DEFINE =
.endif
.endif
.endif
.endif
.suffixes : .cpp
.cpp.obj :
cxx $(CXXFLAGS)$(CXX_DEFINE) $(MMS$TARGET_NAME).cpp
.c.obj :
cc $(CFLAGS)$(CC_DEFINE) $(MMS$TARGET_NAME).c
OBJECTS = baseunix.obj,\
dialup.obj,\
dir.obj,\
displayx11.obj,\
dlunix.obj,\
fontenum.obj,\
fontutil.obj,\
gsocket.obj,\
mimetype.obj,\
threadpsx.obj,\
utilsunx.obj,\
utilsx11.obj,\
joystick.obj,\
snglinst.obj,\
sound.obj,\
sound_sdl.obj,\
stdpaths.obj,\
taskbarx11.obj
SOURCES = baseunix.cpp,\
dialup.cpp,\
dir.cpp,\
displayx11.cpp,\
dlunix.cpp,\
fontenum.cpp,\
fontutil.cpp,\
gsocket.cpp,\
mimetype.cpp,\
threadpsx.cpp,\
utilsunx.cpp,\
utilsx11.cpp,\
joystick.cpp,\
snglinst.cpp,\
sound.cpp,\
sound_sdl.cpp,\
stdpaths.cpp,\
taskbarx11.cpp
all : $(SOURCES)
$(MMS)$(MMSQUALIFIERS) $(OBJECTS)
.ifdef __WXMOTIF__
library [--.lib]libwx_motif.olb $(OBJECTS)
.else
.ifdef __WXGTK__
library [--.lib]libwx_gtk.olb $(OBJECTS)
.else
.ifdef __WXGTK2__
library [--.lib]libwx_gtk2.olb $(OBJECTS)
.else
.ifdef __WXX11__
library [--.lib]libwx_x11_univ.olb $(OBJECTS)
.endif
.endif
.endif
.endif
baseunix.obj : baseunix.cpp
dialup.obj : dialup.cpp
dir.obj : dir.cpp
dlunix.obj : dlunix.cpp
fontenum.obj : fontenum.cpp
fontutil.obj : fontutil.cpp
gsocket.obj : gsocket.cpp
cxx $(CXXFLAGS)$(CXX_DEFINE)/nowarn gsocket.cpp
mimetype.obj : mimetype.cpp
threadpsx.obj : threadpsx.cpp
utilsunx.obj : utilsunx.cpp
utilsx11.obj : utilsx11.cpp
joystick.obj : joystick.cpp
snglinst.obj : snglinst.cpp
sound.obj : sound.cpp
sound_sdl.obj : sound_sdl.cpp
stdpaths.obj : stdpaths.cpp
taskbarx11.obj : taskbarx11.cpp
displayx11.obj : displayx11.cpp

View file

@ -0,0 +1,828 @@
// -*- c++ -*- ////////////////////////////////////////////////////////////////
// Name: src/unix/dialup.cpp
// Purpose: Network related wxWidgets classes and functions
// Author: Karsten Ballüder
// Modified by:
// Created: 03.10.99
// RCS-ID: $Id: dialup.cpp 41020 2006-09-05 20:47:48Z VZ $
// Copyright: (c) Karsten Ballüder
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_DIALUP_MANAGER
#include "wx/dialup.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/event.h"
#include "wx/app.h"
#include "wx/utils.h"
#include "wx/timer.h"
#endif // !PCH
#include "wx/filefn.h"
#include "wx/ffile.h"
#include "wx/process.h"
#include "wx/wxchar.h"
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#define __STRICT_ANSI__
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED)
DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
// ----------------------------------------------------------------------------
// A class which groups functions dealing with connecting to the network from a
// workstation using dial-up access to the net. There is at most one instance
// of this class in the program accessed via GetDialUpManager().
// ----------------------------------------------------------------------------
/* TODO
*
* 1. more configurability for Unix: i.e. how to initiate the connection, how
* to check for online status, &c.
* 2. add a "long Dial(long connectionId = -1)" function which asks the user
* about which connection to dial (this may be done using native dialogs
* under NT, need generic dialogs for all others) and returns the identifier
* of the selected connection (it's opaque to the application) - it may be
* reused later to dial the same connection later (or use strings instead of
* longs may be?)
* 3. add an async version of dialing functions which notify the caller about
* the progress (or may be even start another thread to monitor it)
* 4. the static creation/accessor functions are not MT-safe - but is this
* really crucial? I think we may suppose they're always called from the
* main thread?
*/
class WXDLLEXPORT wxDialUpManagerImpl : public wxDialUpManager
{
public:
wxDialUpManagerImpl();
virtual ~wxDialUpManagerImpl();
/** Could the dialup manager be initialized correctly? If this function
returns false, no other functions will work neither, so it's a good idea
to call this function and check its result before calling any other
wxDialUpManager methods.
*/
virtual bool IsOk() const
{ return true; }
/** The simplest way to initiate a dial up: this function dials the given
ISP (exact meaning of the parameter depends on the platform), returns
true on success or false on failure and logs the appropriate error
message in the latter case.
@param nameOfISP optional paramater for dial program
@param username unused
@param password unused
*/
virtual bool Dial(const wxString& nameOfISP,
const wxString& WXUNUSED(username),
const wxString& WXUNUSED(password),
bool async);
// Hang up the currently active dial up connection.
virtual bool HangUp();
// returns true if the computer is connected to the network: under Windows,
// this just means that a RAS connection exists, under Unix we check that
// the "well-known host" (as specified by SetWellKnownHost) is reachable
virtual bool IsOnline() const
{
CheckStatus();
return m_IsOnline == Net_Connected;
}
// do we have a constant net connection?
virtual bool IsAlwaysOnline() const;
// returns true if (async) dialing is in progress
virtual bool IsDialing() const
{ return m_DialProcess != NULL; }
// cancel dialing the number initiated with Dial(async = true)
// NB: this won't result in DISCONNECTED event being sent
virtual bool CancelDialing();
size_t GetISPNames(class wxArrayString &) const
{ return 0; }
// sometimes the built-in logic for determining the online status may fail,
// so, in general, the user should be allowed to override it. This function
// allows to forcefully set the online status - whatever our internal
// algorithm may think about it.
virtual void SetOnlineStatus(bool isOnline = true)
{ m_IsOnline = isOnline ? Net_Connected : Net_No; }
// set misc wxDialUpManager options
// --------------------------------
// enable automatical checks for the connection status and sending of
// wxEVT_DIALUP_CONNECTED/wxEVT_DIALUP_DISCONNECTED events. The interval
// parameter is only for Unix where we do the check manually: under
// Windows, the notification about the change of connection status is
// instantenous.
//
// Returns false if couldn't set up automatic check for online status.
virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds);
// disable automatic check for connection status change - notice that the
// wxEVT_DIALUP_XXX events won't be sent any more neither.
virtual void DisableAutoCheckOnlineStatus();
// under Unix, the value of well-known host is used to check whether we're
// connected to the internet. It's unused under Windows, but this function
// is always safe to call. The default value is www.yahoo.com.
virtual void SetWellKnownHost(const wxString& hostname,
int portno = 80);
/** Sets the commands to start up the network and to hang up
again. Used by the Unix implementations only.
*/
virtual void SetConnectCommand(const wxString &command, const wxString &hupcmd)
{ m_ConnectCommand = command; m_HangUpCommand = hupcmd; }
//private: -- Sun CC 4.2 objects to using NetConnection enum as the return
// type if it is declared private
// the possible results of testing for Online() status
enum NetConnection
{
Net_Unknown = -1, // we couldn't learn anything
Net_No, // no network connection [currently]
Net_Connected // currently connected
};
// the possible net connection types
enum NetDeviceType
{
NetDevice_None = 0x0000, // no network devices (authoritative)
NetDevice_Unknown = 0x0001, // test doesn't work on this OS
NetDevice_Modem = 0x0002, // we have a modem
NetDevice_LAN = 0x0004 // a network card
};
private:
// the current status
NetConnection m_IsOnline;
// the connection we have with the network card
NetConnection m_connCard;
// Can we use ifconfig to list active devices?
int m_CanUseIfconfig;
// The path to ifconfig
wxString m_IfconfigPath;
// Can we use ping to find hosts?
int m_CanUsePing;
// The path to ping program
wxString m_PingPath;
// beacon host:
wxString m_BeaconHost;
// beacon host portnumber for connect:
int m_BeaconPort;
// command to connect to network
wxString m_ConnectCommand;
// command to hang up
wxString m_HangUpCommand;
// name of ISP
wxString m_ISPname;
// a timer for regular testing
class AutoCheckTimer *m_timer;
friend class AutoCheckTimer;
// a wxProcess for dialling in background
class wxDialProcess *m_DialProcess;
// pid of dial process
int m_DialPId;
friend class wxDialProcess;
// determine status
void CheckStatus(bool fromAsync = false) const;
// real status check
void CheckStatusInternal();
// check /proc/net (Linux only) for ppp/eth interfaces, returns the bit
// mask of NetDeviceType constants
int CheckProcNet();
// check output of ifconfig command for PPP/SLIP/PLIP devices, returns the
// bit mask of NetDeviceType constants
int CheckIfconfig();
// combines the 2 possible checks for determining the connection status
NetConnection CheckConnectAndPing();
// pings a host
NetConnection CheckPing();
// check by connecting to host on given port.
NetConnection CheckConnect();
};
class AutoCheckTimer : public wxTimer
{
public:
AutoCheckTimer(wxDialUpManagerImpl *dupman)
{
m_dupman = dupman;
}
virtual void Notify()
{
wxLogTrace(_T("dialup"), wxT("Checking dial up network status."));
m_dupman->CheckStatus();
}
public:
wxDialUpManagerImpl *m_dupman;
};
class wxDialProcess : public wxProcess
{
public:
wxDialProcess(wxDialUpManagerImpl *dupman)
{
m_DupMan = dupman;
}
void Disconnect() { m_DupMan = NULL; }
virtual void OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
{
if(m_DupMan)
{
m_DupMan->m_DialProcess = NULL;
m_DupMan->CheckStatus(true);
}
}
private:
wxDialUpManagerImpl *m_DupMan;
};
wxDialUpManagerImpl::wxDialUpManagerImpl()
{
m_IsOnline =
m_connCard = Net_Unknown;
m_DialProcess = NULL;
m_timer = NULL;
m_CanUseIfconfig = -1; // unknown
m_CanUsePing = -1; // unknown
m_BeaconHost = WXDIALUP_MANAGER_DEFAULT_BEACONHOST;
m_BeaconPort = 80;
#ifdef __SGI__
m_ConnectCommand = _T("/usr/etc/ppp");
#elif defined(__LINUX__)
// default values for Debian/GNU linux
m_ConnectCommand = _T("pon");
m_HangUpCommand = _T("poff");
#endif
wxChar * dial = wxGetenv(_T("WXDIALUP_DIALCMD"));
wxChar * hup = wxGetenv(_T("WXDIALUP_HUPCMD"));
SetConnectCommand(dial ? wxString(dial) : m_ConnectCommand,
hup ? wxString(hup) : m_HangUpCommand);
}
wxDialUpManagerImpl::~wxDialUpManagerImpl()
{
if(m_timer) delete m_timer;
if(m_DialProcess)
{
m_DialProcess->Disconnect();
m_DialProcess->Detach();
}
}
bool
wxDialUpManagerImpl::Dial(const wxString &isp,
const wxString & WXUNUSED(username),
const wxString & WXUNUSED(password),
bool async)
{
if(m_IsOnline == Net_Connected)
return false;
m_ISPname = isp;
wxString cmd;
if(m_ConnectCommand.Find(wxT("%s")))
cmd.Printf(m_ConnectCommand,m_ISPname.c_str());
else
cmd = m_ConnectCommand;
if ( async )
{
m_DialProcess = new wxDialProcess(this);
m_DialPId = (int)wxExecute(cmd, false, m_DialProcess);
if(m_DialPId == 0)
{
delete m_DialProcess;
m_DialProcess = NULL;
return false;
}
else
return true;
}
else
return wxExecute(cmd, /* sync */ true) == 0;
}
bool wxDialUpManagerImpl::HangUp()
{
if(m_IsOnline == Net_No)
return false;
if(IsDialing())
{
wxLogError(_("Already dialling ISP."));
return false;
}
wxString cmd;
if(m_HangUpCommand.Find(wxT("%s")))
cmd.Printf(m_HangUpCommand,m_ISPname.c_str(), m_DialProcess);
else
cmd = m_HangUpCommand;
return wxExecute(cmd, /* sync */ true) == 0;
}
bool wxDialUpManagerImpl::CancelDialing()
{
if(! IsDialing())
return false;
return kill(m_DialPId, SIGTERM) > 0;
}
bool wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds)
{
DisableAutoCheckOnlineStatus();
m_timer = new AutoCheckTimer(this);
bool rc = m_timer->Start(nSeconds*1000);
if(! rc)
{
delete m_timer;
m_timer = NULL;
}
return rc;
}
void wxDialUpManagerImpl::DisableAutoCheckOnlineStatus()
{
if(m_timer != NULL)
{
m_timer->Stop();
delete m_timer;
m_timer = NULL;
}
}
void wxDialUpManagerImpl::SetWellKnownHost(const wxString& hostname, int portno)
{
if(hostname.length() == 0)
{
m_BeaconHost = WXDIALUP_MANAGER_DEFAULT_BEACONHOST;
m_BeaconPort = 80;
return;
}
// does hostname contain a port number?
wxString port = hostname.After(wxT(':'));
if(port.length())
{
m_BeaconHost = hostname.Before(wxT(':'));
m_BeaconPort = wxAtoi(port);
}
else
{
m_BeaconHost = hostname;
m_BeaconPort = portno;
}
}
void wxDialUpManagerImpl::CheckStatus(bool fromAsync) const
{
// This function calls the CheckStatusInternal() helper function
// which is OS - specific and then sends the events.
NetConnection oldIsOnline = m_IsOnline;
( /* non-const */ (wxDialUpManagerImpl *)this)->CheckStatusInternal();
// now send the events as appropriate: i.e. if the status changed and
// if we're in defined state
if(m_IsOnline != oldIsOnline
&& m_IsOnline != Net_Unknown
&& oldIsOnline != Net_Unknown )
{
wxDialUpEvent event(m_IsOnline == Net_Connected, ! fromAsync);
(void)wxTheApp->ProcessEvent(event);
}
}
/*
We first try to find out if ppp interface is active. If it is, we assume
that we're online but don't have a permanent connection (this is false if a
networked machine uses modem to connect to somewhere else, but we can't do
anything in this case anyhow).
If no ppp interface is detected, we check for eth interface. If it is
found, we check that we can, indeed, connect to an Internet host. The logic
here is that connection check should be fast enough in this case and we
don't want to give false positives in a (common) case of a machine on a LAN
which is not connected to the outside.
If we didn't find either ppp or eth interfaces, we stop here and decide
that we're connected. However, if couldn't check for this, we try to ping a
remote host just in case.
NB1: Checking for the interface presence can be done in 2 ways
a) reading /proc/net/dev under Linux
b) spawning ifconfig under any OS
The first method is faster but only works under Linux.
NB2: pinging, actually, means that we first try to connect "manually" to
a port on remove machine and if it fails, we run ping.
*/
void wxDialUpManagerImpl::CheckStatusInternal()
{
m_IsOnline = Net_Unknown;
// first do quick checks to determine what kind of network devices do we
// have
int netDeviceType = CheckProcNet();
if ( netDeviceType == NetDevice_Unknown )
{
// nothing found, try ifconfig too
netDeviceType = CheckIfconfig();
}
switch ( netDeviceType )
{
case NetDevice_None:
// no network devices, no connection
m_IsOnline = Net_No;
break;
case NetDevice_LAN:
// we still do ping to confirm that we're connected but we only do
// it once and hope that the purpose of the network card (i.e.
// whether it used for connecting to the Internet or just to a
// LAN) won't change during the program lifetime
if ( m_connCard == Net_Unknown )
{
m_connCard = CheckConnectAndPing();
}
m_IsOnline = m_connCard;
break;
case NetDevice_Unknown:
// try to ping just in case
m_IsOnline = CheckConnectAndPing();
break;
case NetDevice_LAN + NetDevice_Modem:
case NetDevice_Modem:
// assume we're connected
m_IsOnline = Net_Connected;
break;
default:
wxFAIL_MSG(_T("Unexpected netDeviceType"));
}
}
bool wxDialUpManagerImpl::IsAlwaysOnline() const
{
wxDialUpManagerImpl *self = wxConstCast(this, wxDialUpManagerImpl);
int netDeviceType = self->CheckProcNet();
if ( netDeviceType == NetDevice_Unknown )
{
// nothing found, try ifconfig too
netDeviceType = self->CheckIfconfig();
}
if ( netDeviceType == NetDevice_Unknown )
{
// this is the only thing we can do unfortunately...
self->HangUp();
return IsOnline();
}
else
{
// we are only permanently online if we have a network card
return (netDeviceType & NetDevice_LAN) != 0;
}
}
wxDialUpManagerImpl::NetConnection wxDialUpManagerImpl::CheckConnectAndPing()
{
NetConnection conn;
// first try connecting - faster
conn = CheckConnect();
if ( conn == Net_Unknown )
{
// try pinging too
conn = CheckPing();
}
return conn;
}
wxDialUpManagerImpl::NetConnection wxDialUpManagerImpl::CheckConnect()
{
// second method: try to connect to a well known host:
// This can be used under Win 9x, too!
struct hostent *hp;
struct sockaddr_in serv_addr;
if((hp = gethostbyname(m_BeaconHost.mb_str())) == NULL)
return Net_No; // no DNS no net
serv_addr.sin_family = hp->h_addrtype;
memcpy(&serv_addr.sin_addr,hp->h_addr, hp->h_length);
serv_addr.sin_port = htons(m_BeaconPort);
int sockfd;
if( ( sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
{
return Net_Unknown; // no info
}
if( connect(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) >= 0)
{
close(sockfd);
return Net_Connected; // we can connect, so we have a network!
}
else // failed to connect
{
#ifdef ENETUNREACH
if(errno == ENETUNREACH)
return Net_No; // network is unreachable
else
#endif
return Net_Unknown; // connect failed, but don't know why
}
}
int
wxDialUpManagerImpl::CheckProcNet()
{
// assume that the test doesn't work
int netDevice = NetDevice_Unknown;
#ifdef __LINUX__
if (wxFileExists(_T("/proc/net/route")))
{
// cannot use wxFile::Length because file doesn't support seeking, so
// use stdio directly
FILE *f = fopen("/proc/net/route", "rt");
if (f != NULL)
{
// now we know that we will find all devices we may have
netDevice = NetDevice_None;
char output[256];
while (fgets(output, 256, f) != NULL)
{
if ( strstr(output, "eth") ) // network card
{
netDevice |= NetDevice_LAN;
}
else if (strstr(output,"ppp") // ppp
|| strstr(output,"sl") // slip
|| strstr(output,"pl")) // plip
{
netDevice |= NetDevice_Modem;
}
}
fclose(f);
}
}
#endif // __LINUX__
return netDevice;
}
int
wxDialUpManagerImpl::CheckIfconfig()
{
#ifdef __VMS
m_CanUseIfconfig = 0;
return -1;
#else
// assume that the test doesn't work
int netDevice = NetDevice_Unknown;
// first time check for ifconfig location
if ( m_CanUseIfconfig == -1 ) // unknown
{
static const wxChar *ifconfigLocations[] =
{
_T("/sbin"), // Linux, FreeBSD, Darwin
_T("/usr/sbin"), // SunOS, Solaris, AIX, HP-UX
_T("/usr/etc"), // IRIX
_T("/etc"), // AIX 5
};
for ( size_t n = 0; n < WXSIZEOF(ifconfigLocations); n++ )
{
wxString path(ifconfigLocations[n]);
path << _T("/ifconfig");
if ( wxFileExists(path) )
{
m_IfconfigPath = path;
break;
}
}
}
if ( m_CanUseIfconfig != 0 ) // unknown or yes
{
wxLogNull ln; // suppress all error messages
wxASSERT_MSG( m_IfconfigPath.length(),
_T("can't use ifconfig if it wasn't found") );
wxString tmpfile = wxGetTempFileName( wxT("_wxdialuptest") );
wxString cmd = wxT("/bin/sh -c \'");
cmd << m_IfconfigPath;
#if defined(__AIX__) || \
defined(__OSF__) || \
defined(__SOLARIS__) || defined (__SUNOS__)
// need to add -a flag
cmd << wxT(" -a");
#elif defined(__LINUX__) || defined(__SGI__)
// nothing to be added to ifconfig
#elif defined(__FREEBSD__) || defined(__DARWIN__)
// add -l flag
cmd << wxT(" -l");
#elif defined(__HPUX__)
// VZ: a wild guess (but without it, ifconfig fails completely)
cmd << wxT(" ppp0");
#else
#if defined(__GNUG__)
#warning "No ifconfig information for this OS."
#else
#pragma warning "No ifconfig information for this OS."
#endif
m_CanUseIfconfig = 0;
return -1;
#endif
cmd << wxT(" >") << tmpfile << wxT('\'');
/* I tried to add an option to wxExecute() to not close stdout,
so we could let ifconfig write directly to the tmpfile, but
this does not work. That should be faster, as it doesn´t call
the shell first. I have no idea why. :-( (KB) */
if ( wxExecute(cmd,true /* sync */) == 0 )
{
m_CanUseIfconfig = 1;
wxFFile file;
if( file.Open(tmpfile) )
{
wxString output;
if ( file.ReadAll(&output) )
{
// FIXME shouldn't we grep for "^ppp"? (VZ)
bool hasModem = false,
hasLAN = false;
#if defined(__SOLARIS__) || defined (__SUNOS__)
// dialup device under SunOS/Solaris
hasModem = strstr(output.fn_str(),"ipdptp") != (char *)NULL;
hasLAN = strstr(output.fn_str(), "hme") != (char *)NULL;
#elif defined(__LINUX__) || defined (__FREEBSD__)
hasModem = strstr(output.fn_str(),"ppp") // ppp
|| strstr(output.fn_str(),"sl") // slip
|| strstr(output.fn_str(),"pl"); // plip
hasLAN = strstr(output.fn_str(), "eth") != NULL;
#elif defined(__SGI__) // IRIX
hasModem = strstr(output.fn_str(), "ppp") != NULL; // PPP
#elif defined(__HPUX__)
// if could run ifconfig on interface, then it exists
hasModem = true;
#endif
netDevice = NetDevice_None;
if ( hasModem )
netDevice |= NetDevice_Modem;
if ( hasLAN )
netDevice |= NetDevice_LAN;
}
//else: error reading the file
}
//else: error opening the file
}
else // could not run ifconfig correctly
{
m_CanUseIfconfig = 0; // don´t try again
}
(void) wxRemoveFile(tmpfile);
}
return netDevice;
#endif
}
wxDialUpManagerImpl::NetConnection wxDialUpManagerImpl::CheckPing()
{
// First time check for ping location. We only use the variant
// which does not take arguments, a la GNU.
if(m_CanUsePing == -1) // unknown
{
#ifdef __VMS
if (wxFileExists( wxT("SYS$SYSTEM:TCPIP$PING.EXE") ))
m_PingPath = wxT("$SYS$SYSTEM:TCPIP$PING");
#elif defined(__AIX__)
m_PingPath = _T("/etc/ping");
#elif defined(__SGI__)
m_PingPath = _T("/usr/etc/ping");
#else
if (wxFileExists( wxT("/bin/ping") ))
m_PingPath = wxT("/bin/ping");
else if (wxFileExists( wxT("/usr/sbin/ping") ))
m_PingPath = wxT("/usr/sbin/ping");
#endif
if (!m_PingPath)
{
m_CanUsePing = 0;
}
}
if(! m_CanUsePing)
{
// we didn't find ping
return Net_Unknown;
}
wxLogNull ln; // suppress all error messages
wxASSERT(m_PingPath.length());
wxString cmd;
cmd << m_PingPath << wxT(' ');
#if defined(__SOLARIS__) || defined (__SUNOS__)
// nothing to add to ping command
#elif defined(__AIX__) || \
defined (__BSD__) || \
defined(__LINUX__) || \
defined(__OSF__) || \
defined(__SGI__) || \
defined(__VMS)
cmd << wxT("-c 1 "); // only ping once
#elif defined(__HPUX__)
cmd << wxT("64 1 "); // only ping once (need also specify the packet size)
#else
#if defined(__GNUG__)
#warning "No Ping information for this OS."
#else
#pragma warning "No Ping information for this OS."
#endif
m_CanUsePing = 0;
return Net_Unknown;
#endif
cmd << m_BeaconHost;
if(wxExecute(cmd, true /* sync */) == 0)
return Net_Connected;
else
return Net_No;
}
/* static */
wxDialUpManager *wxDialUpManager::Create()
{
return new wxDialUpManagerImpl;
}
#endif // wxUSE_DIALUP_MANAGER

334
wxWidgets/src/unix/dir.cpp Normal file
View file

@ -0,0 +1,334 @@
/////////////////////////////////////////////////////////////////////////////
// Name: unix/dir.cpp
// Purpose: wxDir implementation for Unix/POSIX systems
// Author: Vadim Zeitlin
// Modified by:
// Created: 08.12.99
// RCS-ID: $Id: dir.cpp 56867 2008-11-20 18:12:43Z VZ $
// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#endif // PCH
#include "wx/dir.h"
#include "wx/filefn.h" // for wxMatchWild
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
#define M_DIR ((wxDirData *)m_data)
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// this class stores everything we need to enumerate the files
class wxDirData
{
public:
wxDirData(const wxString& dirname);
~wxDirData();
bool IsOk() const { return m_dir != NULL; }
void SetFileSpec(const wxString& filespec) { m_filespec = filespec; }
void SetFlags(int flags) { m_flags = flags; }
void Rewind() { rewinddir(m_dir); }
bool Read(wxString *filename);
const wxString& GetName() const { return m_dirname; }
private:
DIR *m_dir;
wxString m_dirname;
wxString m_filespec;
int m_flags;
};
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxDirData
// ----------------------------------------------------------------------------
#if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
wxDirData::wxDirData(const wxString& dirname)
: m_dirname(dirname)
{
m_dir = NULL;
// throw away the trailing slashes
size_t n = m_dirname.length();
wxCHECK_RET( n, _T("empty dir name in wxDir") );
while ( n > 0 && m_dirname[--n] == '/' )
;
m_dirname.Truncate(n + 1);
// do open the dir
m_dir = opendir(m_dirname.fn_str());
}
wxDirData::~wxDirData()
{
if ( m_dir )
{
if ( closedir(m_dir) != 0 )
{
wxLogLastError(_T("closedir"));
}
}
}
bool wxDirData::Read(wxString *filename)
{
dirent *de = (dirent *)NULL; // just to silence compiler warnings
bool matches = false;
// speed up string concatenation in the loop a bit
wxString path = m_dirname;
path += _T('/');
path.reserve(path.length() + 255);
wxString de_d_name;
while ( !matches )
{
de = readdir(m_dir);
if ( !de )
return false;
#if wxUSE_UNICODE
de_d_name = wxConvFileName->cMB2WC( de->d_name );
#else
de_d_name = de->d_name;
#endif
// don't return "." and ".." unless asked for
if ( de->d_name[0] == '.' &&
((de->d_name[1] == '.' && de->d_name[2] == '\0') ||
(de->d_name[1] == '\0')) )
{
if ( !(m_flags & wxDIR_DOTDOT) )
continue;
// we found a valid match
break;
}
// check the type now
if ( !(m_flags & wxDIR_FILES) && !wxDir::Exists(path + de_d_name) )
{
// it's a file, but we don't want them
continue;
}
else if ( !(m_flags & wxDIR_DIRS) && wxDir::Exists(path + de_d_name) )
{
// it's a dir, and we don't want it
continue;
}
// finally, check the name
if ( m_filespec.empty() )
{
matches = m_flags & wxDIR_HIDDEN ? true : de->d_name[0] != '.';
}
else
{
// test against the pattern
matches = wxMatchWild(m_filespec, de_d_name,
!(m_flags & wxDIR_HIDDEN));
}
}
*filename = de_d_name;
return true;
}
#else // old VMS (TODO)
wxDirData::wxDirData(const wxString& WXUNUSED(dirname))
{
wxFAIL_MSG(_T("not implemented"));
}
wxDirData::~wxDirData()
{
}
bool wxDirData::Read(wxString * WXUNUSED(filename))
{
return false;
}
#endif // not or new VMS/old VMS
// ----------------------------------------------------------------------------
// wxDir helpers
// ----------------------------------------------------------------------------
/* static */
bool wxDir::Exists(const wxString& dir)
{
return wxDirExists(dir);
}
// ----------------------------------------------------------------------------
// wxDir construction/destruction
// ----------------------------------------------------------------------------
wxDir::wxDir(const wxString& dirname)
{
m_data = NULL;
(void)Open(dirname);
}
bool wxDir::Open(const wxString& dirname)
{
delete M_DIR;
m_data = new wxDirData(dirname);
if ( !M_DIR->IsOk() )
{
delete M_DIR;
m_data = NULL;
return false;
}
return true;
}
bool wxDir::IsOpened() const
{
return m_data != NULL;
}
wxString wxDir::GetName() const
{
wxString name;
if ( m_data )
{
name = M_DIR->GetName();
if ( !name.empty() && (name.Last() == _T('/')) )
{
// chop off the last (back)slash
name.Truncate(name.length() - 1);
}
}
return name;
}
wxDir::~wxDir()
{
delete M_DIR;
}
// ----------------------------------------------------------------------------
// wxDir enumerating
// ----------------------------------------------------------------------------
bool wxDir::GetFirst(wxString *filename,
const wxString& filespec,
int flags) const
{
wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
M_DIR->Rewind();
M_DIR->SetFileSpec(filespec);
M_DIR->SetFlags(flags);
return GetNext(filename);
}
bool wxDir::GetNext(wxString *filename) const
{
wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
wxCHECK_MSG( filename, false, _T("bad pointer in wxDir::GetNext()") );
return M_DIR->Read(filename);
}
bool wxDir::HasSubDirs(const wxString& spec)
{
wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
if ( spec.empty() )
{
// faster check for presence of any subdirectory: normally each subdir
// has a hard link to the parent directory and so, knowing that there
// are at least "." and "..", we have a subdirectory if and only if
// links number is > 2 - this is just a guess but it works fairly well
// in practice
//
// note that we may guess wrongly in one direction only: i.e. we may
// return true when there are no subdirectories but this is ok as the
// caller will learn it soon enough when it calls GetFirst(wxDIR)
// anyhow
wxStructStat stBuf;
if ( wxStat(M_DIR->GetName().c_str(), &stBuf) == 0 )
{
switch ( stBuf.st_nlink )
{
case 2:
// just "." and ".."
return false;
case 0:
case 1:
// weird filesystem, don't try to guess for it, use dumb
// method below
break;
default:
// assume we have subdirs - may turn out to be wrong if we
// have other hard links to this directory but it's not
// that bad as explained above
return true;
}
}
}
// just try to find first directory
wxString s;
return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN);
}

View file

@ -0,0 +1,426 @@
///////////////////////////////////////////////////////////////////////////
// Name: src/unix/displayx11.cpp
// Purpose: Unix/X11 implementation of wxDisplay class
// Author: Brian Victor, Vadim Zeitlin
// Modified by:
// Created: 12/05/02
// RCS-ID: $Id: displayx11.cpp 50143 2007-11-22 02:52:10Z PC $
// Copyright: (c) wxWidgets team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_DISPLAY
#include "wx/display.h"
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/gdicmn.h"
#include "wx/string.h"
#include "wx/utils.h"
#include "wx/intl.h"
#include "wx/log.h"
#endif /* WX_PRECOMP */
#include "wx/display_impl.h"
/* These must be included after the wx files. Otherwise the Data macro in
* Xlibint.h conflicts with a function declaration in wx/list.h. */
extern "C"
{
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/extensions/Xinerama.h>
#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
#include <X11/extensions/xf86vmode.h>
#endif
}
// ----------------------------------------------------------------------------
// helper class to automatically free XineramaQueryScreens() return value
// ----------------------------------------------------------------------------
class ScreensInfo
{
public:
ScreensInfo()
{
m_screens = XineramaQueryScreens((Display *)wxGetDisplay(), &m_num);
}
~ScreensInfo()
{
XFree(m_screens);
}
operator const XineramaScreenInfo *() const { return m_screens; }
unsigned GetCount() const { return wx_static_cast(unsigned, m_num); }
private:
XineramaScreenInfo *m_screens;
int m_num;
};
// ----------------------------------------------------------------------------
// display and display factory classes
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxDisplayImplX11 : public wxDisplayImpl
{
public:
wxDisplayImplX11(unsigned n, const XineramaScreenInfo& info)
: wxDisplayImpl(n),
m_rect(info.x_org, info.y_org, info.width, info.height)
{
}
virtual wxRect GetGeometry() const { return m_rect; }
virtual wxRect GetClientArea() const
{
// we intentionally don't cache the result here because the client
// display area may change (e.g. the user resized or hid a panel) and
// we don't currently react to its changes
return IsPrimary() ? wxGetClientDisplayRect() : m_rect;
}
virtual wxString GetName() const { return wxString(); }
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
virtual wxVideoMode GetCurrentMode() const;
virtual bool ChangeMode(const wxVideoMode& mode);
private:
wxRect m_rect;
int m_depth;
DECLARE_NO_COPY_CLASS(wxDisplayImplX11)
};
class wxDisplayFactoryX11 : public wxDisplayFactory
{
public:
wxDisplayFactoryX11() { }
virtual wxDisplayImpl *CreateDisplay(unsigned n);
virtual unsigned GetCount();
virtual int GetFromPoint(const wxPoint& pt);
protected:
DECLARE_NO_COPY_CLASS(wxDisplayFactoryX11)
};
// ============================================================================
// wxDisplayFactoryX11 implementation
// ============================================================================
unsigned wxDisplayFactoryX11::GetCount()
{
return ScreensInfo().GetCount();
}
int wxDisplayFactoryX11::GetFromPoint(const wxPoint& p)
{
ScreensInfo screens;
const unsigned numscreens(screens.GetCount());
for ( unsigned i = 0; i < numscreens; ++i )
{
const XineramaScreenInfo& s = screens[i];
if ( p.x >= s.x_org && p.x < s.x_org + s.width &&
p.y >= s.y_org && p.y < s.y_org + s.height )
{
return i;
}
}
return wxNOT_FOUND;
}
wxDisplayImpl *wxDisplayFactoryX11::CreateDisplay(unsigned n)
{
ScreensInfo screens;
return n < screens.GetCount() ? new wxDisplayImplX11(n, screens[n]) : NULL;
}
// ============================================================================
// wxDisplayImplX11 implementation
// ============================================================================
#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
//
// See (http://www.xfree86.org/4.2.0/XF86VidModeDeleteModeLine.3.html) for more
// info about xf86 video mode extensions
//
//free private data common to x (usually s3) servers
#define wxClearXVM(vm) if(vm.privsize) XFree(vm.c_private)
// Correct res rate from GLFW
#define wxCRR2(v,dc) (int) (((1000.0f * (float) dc) /*PIXELS PER SECOND */) / ((float) v.htotal * v.vtotal /*PIXELS PER FRAME*/) + 0.5f)
#define wxCRR(v) wxCRR2(v,v.dotclock)
#define wxCVM2(v, dc) wxVideoMode(v.hdisplay, v.vdisplay, DefaultDepth((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay())), wxCRR2(v,dc))
#define wxCVM(v) wxCVM2(v, v.dotclock)
wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& mode) const
{
//Convenience...
Display* pDisplay = (Display*) wxGetDisplay(); //default display
int nScreen = DefaultScreen(pDisplay); //default screen of (default) display...
//Some variables..
XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :))
int nNumModes; //Number of modes enumerated....
wxArrayVideoModes Modes; //modes to return...
if (XF86VidModeGetAllModeLines(pDisplay, nScreen, &nNumModes, &ppXModes) == TRUE)
{
for (int i = 0; i < nNumModes; ++i)
{
if (mode == wxDefaultVideoMode || //According to display.h All modes valid if dafault mode...
mode.Matches(wxCVM((*ppXModes[i]))) ) //...?
{
Modes.Add(wxCVM((*ppXModes[i])));
}
wxClearXVM((*ppXModes[i]));
// XFree(ppXModes[i]); //supposed to free?
}
XFree(ppXModes);
}
else //OOPS!
{
wxLogSysError(_("Failed to enumerate video modes"));
}
return Modes;
}
wxVideoMode wxDisplayImplX11::GetCurrentMode() const
{
XF86VidModeModeLine VM;
int nDotClock;
XF86VidModeGetModeLine((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
&nDotClock, &VM);
wxClearXVM(VM);
return wxCVM2(VM, nDotClock);
}
bool wxDisplayImplX11::ChangeMode(const wxVideoMode& mode)
{
XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :))
int nNumModes; //Number of modes enumerated....
if( !XF86VidModeGetAllModeLines((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()), &nNumModes, &ppXModes) )
{
wxLogSysError(_("Failed to change video mode"));
return false;
}
bool bRet = false;
if (mode == wxDefaultVideoMode)
{
bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
ppXModes[0]) == TRUE;
for (int i = 0; i < nNumModes; ++i)
{
wxClearXVM((*ppXModes[i]));
// XFree(ppXModes[i]); //supposed to free?
}
}
else
{
for (int i = 0; i < nNumModes; ++i)
{
if (!bRet &&
ppXModes[i]->hdisplay == mode.w &&
ppXModes[i]->vdisplay == mode.h &&
wxCRR((*ppXModes[i])) == mode.refresh)
{
//switch!
bRet = XF86VidModeSwitchToMode((Display*)wxGetDisplay(), DefaultScreen((Display*)wxGetDisplay()),
ppXModes[i]) == TRUE;
}
wxClearXVM((*ppXModes[i]));
// XFree(ppXModes[i]); //supposed to free?
}
}
XFree(ppXModes);
return bRet;
}
#else // !HAVE_X11_EXTENSIONS_XF86VMODE_H
wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& modeMatch) const
{
int count_return;
int* depths = XListDepths((Display*)wxGetDisplay(), 0, &count_return);
wxArrayVideoModes modes;
if ( depths )
{
for ( int x = 0; x < count_return; ++x )
{
wxVideoMode mode(m_rect.GetWidth(), m_rect.GetHeight(), depths[x]);
if ( mode.Matches(modeMatch) )
{
modes.Add(modeMatch);
}
}
XFree(depths);
}
return modes;
}
wxVideoMode wxDisplayImplX11::GetCurrentMode() const
{
// Not implemented
return wxVideoMode();
}
bool wxDisplayImplX11::ChangeMode(const wxVideoMode& WXUNUSED(mode))
{
// Not implemented
return false;
}
#endif // !HAVE_X11_EXTENSIONS_XF86VMODE_H
// ============================================================================
// wxDisplay::CreateFactory()
// ============================================================================
/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
{
if ( XineramaIsActive((Display*)wxGetDisplay()) )
{
return new wxDisplayFactoryX11;
}
return new wxDisplayFactorySingle;
}
#endif /* wxUSE_DISPLAY */
#if defined(__WXGTK__) || defined(__X__)
#include "wx/utils.h"
#include "wx/log.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
// TODO: make this a full-fledged class and move to a public header
class wxX11Ptr
{
public:
wxX11Ptr(void *ptr = NULL) : m_ptr(ptr) { }
~wxX11Ptr() { if ( m_ptr ) XFree(m_ptr); }
private:
void *m_ptr;
DECLARE_NO_COPY_CLASS(wxX11Ptr)
};
// NB: this function is implemented using X11 and not GDK calls as it's shared
// by wxGTK[12], wxX11 and wxMotif ports
void wxClientDisplayRect(int *x, int *y, int *width, int *height)
{
Display * const dpy = (Display *)wxGetDisplay();
wxCHECK_RET( dpy, _T("can't be called before initializing the GUI") );
const Atom atomWorkArea = XInternAtom(dpy, "_NET_WORKAREA", True);
if ( atomWorkArea )
{
long *workareas = NULL;
unsigned long numItems;
unsigned long bytesRemaining;
Atom actualType;
int format;
if ( XGetWindowProperty
(
dpy,
XDefaultRootWindow(dpy),
atomWorkArea,
0, // offset of data to retrieve
4, // number of items to retrieve
False, // don't delete property
XA_CARDINAL, // type of the items to get
&actualType,
&format,
&numItems,
&bytesRemaining,
(unsigned char **)&workareas
) == Success && workareas )
{
wxX11Ptr x11ptr(workareas); // ensure it will be freed
// check that we retrieved the property of the expected type and
// that we did get back 4 longs (32 is the format for long), as
// requested
if ( actualType != XA_CARDINAL ||
format != 32 ||
numItems != 4 )
{
wxLogDebug(_T("XGetWindowProperty(\"_NET_WORKAREA\") failed"));
return;
}
if ( x )
*x = workareas[0];
if ( y )
*y = workareas[1];
if ( width )
*width = workareas[2];
if ( height )
*height = workareas[3];
return;
}
}
// if we get here, _NET_WORKAREA is not supported so return the entire
// screen size as fall back
if (x)
*x = 0;
if (y)
*y = 0;
wxDisplaySize(width, height);
}
#else // !(wxGTK or X)
void wxClientDisplayRect(int *x, int *y, int *width, int *height)
{
if (x)
*x = 0;
if (y)
*y = 0;
wxDisplaySize(width, height);
}
#endif // wxGTK or X

View file

@ -0,0 +1,461 @@
/////////////////////////////////////////////////////////////////////////////
// Name: unix/dlunix.cpp
// Purpose: Unix-specific part of wxDynamicLibrary and related classes
// Author: Vadim Zeitlin
// Modified by:
// Created: 2005-01-16 (extracted from common/dynlib.cpp)
// RCS-ID: $Id: dlunix.cpp 51903 2008-02-19 01:13:48Z DE $
// Copyright: (c) 2000-2005 Vadim Zeitlin <vadim@wxwindows.org>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_DYNLIB_CLASS
#include "wx/dynlib.h"
#include "wx/ffile.h"
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#endif
#ifdef HAVE_DLOPEN
#include <dlfcn.h>
#endif
#ifdef __DARWIN__
#include <AvailabilityMacros.h>
#endif
// if some flags are not supported, just ignore them
#ifndef RTLD_LAZY
#define RTLD_LAZY 0
#endif
#ifndef RTLD_NOW
#define RTLD_NOW 0
#endif
#ifndef RTLD_GLOBAL
#define RTLD_GLOBAL 0
#endif
#if defined(HAVE_DLOPEN) || defined(__DARWIN__)
#define USE_POSIX_DL_FUNCS
#elif !defined(HAVE_SHL_LOAD)
#error "Don't know how to load dynamic libraries on this platform!"
#endif
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// standard shared libraries extensions for different Unix versions
#if defined(__HPUX__)
const wxChar *wxDynamicLibrary::ms_dllext = _T(".sl");
#elif defined(__DARWIN__)
const wxChar *wxDynamicLibrary::ms_dllext = _T(".bundle");
#else
const wxChar *wxDynamicLibrary::ms_dllext = _T(".so");
#endif
// ============================================================================
// wxDynamicLibrary implementation
// ============================================================================
// ----------------------------------------------------------------------------
// dlxxx() emulation for Darwin
// Only useful if the OS X version could be < 10.3 at runtime
// ----------------------------------------------------------------------------
#if defined(__DARWIN__) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3)
// ---------------------------------------------------------------------------
// For Darwin/Mac OS X
// supply the sun style dlopen functions in terms of Darwin NS*
// ---------------------------------------------------------------------------
/* Porting notes:
* The dlopen port is a port from dl_next.xs by Anno Siegel.
* dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
* The method used here is just to supply the sun style dlopen etc.
* functions in terms of Darwin NS*.
*/
#include <stdio.h>
#include <mach-o/dyld.h>
static char dl_last_error[1024];
static const char *wx_darwin_dlerror()
{
return dl_last_error;
}
static void *wx_darwin_dlopen(const char *path, int WXUNUSED(mode) /* mode is ignored */)
{
NSObjectFileImage ofile;
NSModule handle = NULL;
unsigned dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
if ( dyld_result != NSObjectFileImageSuccess )
{
handle = NULL;
static const char *errorStrings[] =
{
"%d: Object Image Load Failure",
"%d: Object Image Load Success",
"%d: Not an recognisable object file",
"%d: No valid architecture",
"%d: Object image has an invalid format",
"%d: Invalid access (permissions?)",
"%d: Unknown error code from NSCreateObjectFileImageFromFile"
};
const int index = dyld_result < WXSIZEOF(errorStrings)
? dyld_result
: WXSIZEOF(errorStrings) - 1;
// this call to sprintf() is safe as strings above are fixed at
// compile-time and are shorter than WXSIZEOF(dl_last_error)
sprintf(dl_last_error, errorStrings[index], dyld_result);
}
else
{
handle = NSLinkModule
(
ofile,
path,
NSLINKMODULE_OPTION_BINDNOW |
NSLINKMODULE_OPTION_RETURN_ON_ERROR
);
if ( !handle )
{
NSLinkEditErrors err;
int code;
const char *filename;
const char *errmsg;
NSLinkEditError(&err, &code, &filename, &errmsg);
strncpy(dl_last_error, errmsg, WXSIZEOF(dl_last_error)-1);
dl_last_error[WXSIZEOF(dl_last_error)-1] = '\0';
}
}
return handle;
}
static int wx_darwin_dlclose(void *handle)
{
NSUnLinkModule((NSModule)handle, NSUNLINKMODULE_OPTION_NONE);
return 0;
}
static void *wx_darwin_dlsym(void *handle, const char *symbol)
{
// as on many other systems, C symbols have prepended underscores under
// Darwin but unlike the normal dlopen(), NSLookupSymbolInModule() is not
// aware of this
wxCharBuffer buf(strlen(symbol) + 1);
char *p = buf.data();
p[0] = '_';
strcpy(p + 1, symbol);
NSSymbol nsSymbol = NSLookupSymbolInModule((NSModule)handle, p );
return nsSymbol ? NSAddressOfSymbol(nsSymbol) : NULL;
}
// Add the weak linking attribute to dlopen's declaration
extern void * dlopen(const char * __path, int __mode) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
// For all of these methods we test dlopen since all of the dl functions we use were added
// to OS X at the same time. This also ensures we don't dlopen with the real function then
// dlclose with the internal implementation.
static inline void *wx_dlopen(const char *__path, int __mode)
{
#ifdef HAVE_DLOPEN
if(&dlopen != NULL)
return dlopen(__path, __mode);
else
#endif
return wx_darwin_dlopen(__path, __mode);
}
static inline int wx_dlclose(void *__handle)
{
#ifdef HAVE_DLOPEN
if(&dlopen != NULL)
return dlclose(__handle);
else
#endif
return wx_darwin_dlclose(__handle);
}
static inline const char *wx_dlerror()
{
#ifdef HAVE_DLOPEN
if(&dlopen != NULL)
return dlerror();
else
#endif
return wx_darwin_dlerror();
}
static inline void *wx_dlsym(void *__handle, const char *__symbol)
{
#ifdef HAVE_DLOPEN
if(&dlopen != NULL)
return dlsym(__handle, __symbol);
else
#endif
return wx_darwin_dlsym(__handle, __symbol);
}
#else // __DARWIN__/!__DARWIN__
// Use preprocessor definitions for non-Darwin or OS X >= 10.3
#define wx_dlopen(__path,__mode) dlopen(__path,__mode)
#define wx_dlclose(__handle) dlclose(__handle)
#define wx_dlerror() dlerror()
#define wx_dlsym(__handle,__symbol) dlsym(__handle,__symbol)
#endif // defined(__DARWIN__)
// ----------------------------------------------------------------------------
// loading/unloading DLLs
// ----------------------------------------------------------------------------
wxDllType wxDynamicLibrary::GetProgramHandle()
{
#ifdef USE_POSIX_DL_FUNCS
return wx_dlopen(0, RTLD_LAZY);
#else
return PROG_HANDLE;
#endif
}
/* static */
wxDllType wxDynamicLibrary::RawLoad(const wxString& libname, int flags)
{
wxASSERT_MSG( !(flags & wxDL_NOW) || !(flags & wxDL_LAZY),
_T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
#ifdef USE_POSIX_DL_FUNCS
// we need to use either RTLD_NOW or RTLD_LAZY because if we call dlopen()
// with flags == 0 recent versions of glibc just fail the call, so use
// RTLD_NOW even if wxDL_NOW was not specified
int rtldFlags = flags & wxDL_LAZY ? RTLD_LAZY : RTLD_NOW;
if ( flags & wxDL_GLOBAL )
rtldFlags |= RTLD_GLOBAL;
return wx_dlopen(libname.fn_str(), rtldFlags);
#else // !USE_POSIX_DL_FUNCS
int shlFlags = 0;
if ( flags & wxDL_LAZY )
{
shlFlags |= BIND_DEFERRED;
}
else if ( flags & wxDL_NOW )
{
shlFlags |= BIND_IMMEDIATE;
}
return shl_load(libname.fn_str(), shlFlags, 0);
#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
}
/* static */
void wxDynamicLibrary::Unload(wxDllType handle)
{
#ifdef wxHAVE_DYNLIB_ERROR
int rc =
#endif
#ifdef USE_POSIX_DL_FUNCS
wx_dlclose(handle);
#else // !USE_POSIX_DL_FUNCS
shl_unload(handle);
#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
#if defined(USE_POSIX_DL_FUNCS) && defined(wxHAVE_DYNLIB_ERROR)
if ( rc != 0 )
Error();
#endif
}
/* static */
void *wxDynamicLibrary::RawGetSymbol(wxDllType handle, const wxString& name)
{
void *symbol;
#ifdef USE_POSIX_DL_FUNCS
symbol = wx_dlsym(handle, name.fn_str());
#else // !USE_POSIX_DL_FUNCS
// note that shl_findsym modifies the handle argument to indicate where the
// symbol was found, but it's ok to modify the local handle copy here
if ( shl_findsym(&handle, name.fn_str(), TYPE_UNDEFINED, &symbol) != 0 )
symbol = 0;
#endif // USE_POSIX_DL_FUNCS/!USE_POSIX_DL_FUNCS
return symbol;
}
// ----------------------------------------------------------------------------
// error handling
// ----------------------------------------------------------------------------
#ifdef wxHAVE_DYNLIB_ERROR
/* static */
void wxDynamicLibrary::Error()
{
#if wxUSE_UNICODE
wxWCharBuffer buffer = wxConvLocal.cMB2WC( wx_dlerror() );
const wxChar *err = buffer;
#else
const wxChar *err = wx_dlerror();
#endif
wxLogError(wxT("%s"), err ? err : _("Unknown dynamic library error"));
}
#endif // wxHAVE_DYNLIB_ERROR
// ----------------------------------------------------------------------------
// listing loaded modules
// ----------------------------------------------------------------------------
// wxDynamicLibraryDetails declares this class as its friend, so put the code
// initializing new details objects here
class wxDynamicLibraryDetailsCreator
{
public:
// create a new wxDynamicLibraryDetails from the given data
static wxDynamicLibraryDetails *
New(void *start, void *end, const wxString& path)
{
wxDynamicLibraryDetails *details = new wxDynamicLibraryDetails;
details->m_path = path;
details->m_name = path.AfterLast(_T('/'));
details->m_address = start;
details->m_length = (char *)end - (char *)start;
// try to extract the library version from its name
const size_t posExt = path.rfind(_T(".so"));
if ( posExt != wxString::npos )
{
if ( path.c_str()[posExt + 3] == _T('.') )
{
// assume "libfoo.so.x.y.z" case
details->m_version.assign(path, posExt + 4, wxString::npos);
}
else
{
size_t posDash = path.find_last_of(_T('-'), posExt);
if ( posDash != wxString::npos )
{
// assume "libbar-x.y.z.so" case
posDash++;
details->m_version.assign(path, posDash, posExt - posDash);
}
}
}
return details;
}
};
/* static */
wxDynamicLibraryDetailsArray wxDynamicLibrary::ListLoaded()
{
wxDynamicLibraryDetailsArray dlls;
#ifdef __LINUX__
// examine /proc/self/maps to find out what is loaded in our address space
wxFFile file(_T("/proc/self/maps"));
if ( file.IsOpened() )
{
// details of the module currently being parsed
wxString pathCur;
void *startCur = NULL,
*endCur = NULL;
char path[1024];
char buf[1024];
while ( fgets(buf, WXSIZEOF(buf), file.fp()) )
{
// format is: "start-end perm offset maj:min inode path", see proc(5)
void *start,
*end;
switch ( sscanf(buf, "%p-%p %*4s %*p %*02x:%*02x %*d %1024s\n",
&start, &end, path) )
{
case 2:
// there may be no path column
path[0] = '\0';
break;
case 3:
// nothing to do, read everything we wanted
break;
default:
// chop '\n'
buf[strlen(buf) - 1] = '\0';
wxLogDebug(_T("Failed to parse line \"%s\" in /proc/self/maps."),
buf);
continue;
}
wxASSERT_MSG( start >= endCur,
_T("overlapping regions in /proc/self/maps?") );
wxString pathNew = wxString::FromAscii(path);
if ( pathCur.empty() )
{
// new module start
pathCur = pathNew;
startCur = start;
endCur = end;
}
else if ( pathCur == pathNew && endCur == end )
{
// continuation of the same module in the address space
endCur = end;
}
else // end of the current module
{
dlls.Add(wxDynamicLibraryDetailsCreator::New(startCur,
endCur,
pathCur));
pathCur.clear();
}
}
}
#endif // __LINUX__
return dlls;
}
#endif // wxUSE_DYNLIB_CLASS

View file

@ -0,0 +1,362 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/unix/fontenum.cpp
// Purpose: wxFontEnumerator class for X11/GDK
// Author: Vadim Zeitlin
// Modified by:
// Created: 01.10.99
// RCS-ID: $Id: fontenum.cpp 43727 2006-12-01 10:14:28Z VS $
// Copyright: (c) Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/fontenum.h"
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/string.h"
#include "wx/app.h"
#include "wx/utils.h"
#endif
#include "wx/regex.h"
#include "wx/fontmap.h"
#include "wx/fontutil.h"
#include "wx/encinfo.h"
// ----------------------------------------------------------------------------
// Pango
// ----------------------------------------------------------------------------
#if wxUSE_PANGO
#include "pango/pango.h"
#ifdef __WXGTK20__
#include "gtk/gtk.h"
extern GtkWidget *wxGetRootWindow();
#endif // __WXGTK20__
extern "C" int wxCMPFUNC_CONV
wxCompareFamilies (const void *a, const void *b)
{
const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
return g_utf8_collate (a_name, b_name);
}
bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding,
bool fixedWidthOnly)
{
if ( encoding != wxFONTENCODING_SYSTEM && encoding != wxFONTENCODING_UTF8 )
{
// Pango supports only UTF-8 encoding (and system means any, so we
// accept it too)
return false;
}
#if defined(__WXGTK20__) || !defined(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE)
if ( fixedWidthOnly
#if defined(__WXGTK24__)
&& (gtk_check_version(2,4,0) != NULL)
#endif
)
{
OnFacename( wxT("monospace") );
}
else // !fixedWidthOnly
#endif // __WXGTK20__ || !HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE
{
PangoFontFamily **families = NULL;
gint n_families = 0;
pango_context_list_families (
#ifdef __WXGTK20__
gtk_widget_get_pango_context( wxGetRootWindow() ),
#else
wxTheApp->GetPangoContext(),
#endif
&families, &n_families );
qsort (families, n_families, sizeof (PangoFontFamily *), wxCompareFamilies);
for (int i=0; i<n_families; i++)
{
#if defined(__WXGTK24__) || defined(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE)
if (!fixedWidthOnly || (
#ifdef __WXGTK24__
!gtk_check_version(2,4,0) &&
#endif
pango_font_family_is_monospace(families[i])
) )
#endif
{
const gchar *name = pango_font_family_get_name(families[i]);
OnFacename(wxString(name, wxConvUTF8));
}
}
g_free(families);
}
return true;
}
bool wxFontEnumerator::EnumerateEncodings(const wxString& facename)
{
return EnumerateEncodingsUTF8(facename);
}
#else // !wxUSE_PANGO
#ifdef __VMS__ // Xlib.h for VMS is not (yet) compatible with C++
// The resulting warnings are switched off here
#pragma message disable nosimpint
#endif
#include <X11/Xlib.h>
#ifdef __VMS__
#pragma message enable nosimpint
#endif
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// create the list of all fonts with the given spacing and encoding
static char **CreateFontList(wxChar spacing, wxFontEncoding encoding,
int *nFonts);
// extract all font families from the given font list and call our
// OnFacename() for each of them
static bool ProcessFamiliesFromFontList(wxFontEnumerator *This,
char **fonts,
int nFonts);
// ----------------------------------------------------------------------------
// private types
// ----------------------------------------------------------------------------
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// helpers
// ----------------------------------------------------------------------------
#if !wxUSE_NANOX
static char **CreateFontList(wxChar spacing,
wxFontEncoding encoding,
int *nFonts)
{
wxNativeEncodingInfo info;
wxGetNativeFontEncoding(encoding, &info);
#if wxUSE_FONTMAP
if ( !wxTestFontEncoding(info) )
{
// ask font mapper for a replacement
(void)wxFontMapper::Get()->GetAltForEncoding(encoding, &info);
}
#endif // wxUSE_FONTMAP
wxString pattern;
pattern.Printf(wxT("-*-*-*-*-*-*-*-*-*-*-%c-*-%s-%s"),
spacing,
info.xregistry.c_str(),
info.xencoding.c_str());
// get the list of all fonts
return XListFonts((Display *)wxGetDisplay(), pattern.mb_str(), 32767, nFonts);
}
static bool ProcessFamiliesFromFontList(wxFontEnumerator *This,
char **fonts,
int nFonts)
{
#if wxUSE_REGEX
wxRegEx re(wxT("^(-[^-]*){14}$"), wxRE_NOSUB);
#endif // wxUSE_REGEX
// extract the list of (unique) font families
wxSortedArrayString families;
for ( int n = 0; n < nFonts; n++ )
{
char *font = fonts[n];
#if wxUSE_REGEX
if ( !re.Matches(font) )
#else // !wxUSE_REGEX
if ( !wxString(font).Matches(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*")) )
#endif // wxUSE_REGEX/!wxUSE_REGEX
{
// it's not a full font name (probably an alias)
continue;
}
// coverity[returned_null]
char *dash = strchr(font + 1, '-');
char *family = dash + 1;
dash = strchr(family, '-');
*dash = '\0'; // !NULL because Matches() above succeeded
wxString fam(family);
if ( families.Index(fam) == wxNOT_FOUND )
{
if ( !This->OnFacename(fam) )
{
// stop enumerating
return false;
}
families.Add(fam);
}
//else: already seen
}
return true;
}
#endif
// wxUSE_NANOX
// ----------------------------------------------------------------------------
// wxFontEnumerator
// ----------------------------------------------------------------------------
bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding,
bool fixedWidthOnly)
{
#if wxUSE_NANOX
return false;
#else
int nFonts;
char **fonts;
if ( fixedWidthOnly )
{
bool cont = true;
fonts = CreateFontList(wxT('m'), encoding, &nFonts);
if ( fonts )
{
cont = ProcessFamiliesFromFontList(this, fonts, nFonts);
XFreeFontNames(fonts);
}
if ( !cont )
{
return true;
}
fonts = CreateFontList(wxT('c'), encoding, &nFonts);
if ( !fonts )
{
return true;
}
}
else
{
fonts = CreateFontList(wxT('*'), encoding, &nFonts);
if ( !fonts )
{
// it's ok if there are no fonts in given encoding - but it's not
// ok if there are no fonts at all
wxASSERT_MSG(encoding != wxFONTENCODING_SYSTEM,
wxT("No fonts at all on this system?"));
return false;
}
}
(void)ProcessFamiliesFromFontList(this, fonts, nFonts);
XFreeFontNames(fonts);
return true;
#endif
// wxUSE_NANOX
}
bool wxFontEnumerator::EnumerateEncodings(const wxString& family)
{
#if wxUSE_NANOX
return false;
#else
wxString pattern;
pattern.Printf(wxT("-*-%s-*-*-*-*-*-*-*-*-*-*-*-*"),
family.empty() ? wxT("*") : family.c_str());
// get the list of all fonts
int nFonts;
char **fonts = XListFonts((Display *)wxGetDisplay(), pattern.mb_str(),
32767, &nFonts);
if ( !fonts )
{
// unknown family?
return false;
}
// extract the list of (unique) encodings
wxSortedArrayString encodings;
for ( int n = 0; n < nFonts; n++ )
{
char *font = fonts[n];
if ( !wxString(font).Matches(wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*")) )
{
// it's not a full font name (probably an alias)
continue;
}
// extract the family
char *dash = strchr(font + 1, '-');
char *familyFont = dash + 1;
dash = strchr(familyFont, '-');
*dash = '\0'; // !NULL because Matches() above succeeded
if ( !family.empty() && (family != familyFont) )
{
// family doesn't match
continue;
}
// now extract the registry/encoding
char *p = dash + 1; // just after the dash after family
dash = strrchr(p, '-');
wxString registry(dash + 1);
*dash = '\0';
dash = strrchr(p, '-');
wxString encoding(dash + 1);
encoding << wxT('-') << registry;
if ( encodings.Index(encoding) == wxNOT_FOUND )
{
if ( !OnFontEncoding(familyFont, encoding) )
{
break;
}
encodings.Add(encoding);
}
//else: already had this one
}
XFreeFontNames(fonts);
return true;
#endif
// wxUSE_NANOX
}
#endif // !wxUSE_PANGO

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,496 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/unix/joystick.cpp
// Purpose: wxJoystick class
// Author: Ported to Linux by Guilhem Lavaux
// Modified by:
// Created: 05/23/98
// RCS-ID: $Id: joystick.cpp 40530 2006-08-09 11:18:24Z MW $
// Copyright: (c) Guilhem Lavaux
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_JOYSTICK
#include "wx/joystick.h"
#ifndef WX_PRECOMP
#include "wx/event.h"
#include "wx/window.h"
#endif //WX_PRECOMP
#include <linux/joystick.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include "wx/unix/private.h"
enum {
wxJS_AXIS_X = 0,
wxJS_AXIS_Y,
wxJS_AXIS_Z,
wxJS_AXIS_RUDDER,
wxJS_AXIS_U,
wxJS_AXIS_V,
wxJS_AXIS_MAX = 32767,
wxJS_AXIS_MIN = -32767
};
IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
////////////////////////////////////////////////////////////////////////////
// Background thread for reading the joystick device
////////////////////////////////////////////////////////////////////////////
class wxJoystickThread : public wxThread
{
public:
wxJoystickThread(int device, int joystick);
void* Entry();
private:
int m_device;
int m_joystick;
wxPoint m_lastposition;
int m_axe[15];
int m_buttons;
wxWindow* m_catchwin;
int m_polling;
friend class wxJoystick;
};
wxJoystickThread::wxJoystickThread(int device, int joystick)
: m_device(device),
m_joystick(joystick),
m_lastposition(wxDefaultPosition),
m_buttons(0),
m_catchwin(NULL),
m_polling(0)
{
for (int i=0; i<15; i++)
m_axe[i] = 0;
}
void* wxJoystickThread::Entry()
{
struct js_event j_evt;
fd_set read_fds;
struct timeval time_out = {0, 0};
wxFD_ZERO(&read_fds);
while (true)
{
if (TestDestroy())
break;
// We use select when either polling or 'blocking' as even in the
// blocking case we need to check TestDestroy periodically
if (m_polling)
time_out.tv_usec = m_polling * 1000;
else
time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
wxFD_SET(m_device, &read_fds);
select(m_device+1, &read_fds, NULL, NULL, &time_out);
if (wxFD_ISSET(m_device, &read_fds))
{
memset(&j_evt, 0, sizeof(j_evt));
read(m_device, &j_evt, sizeof(j_evt));
//printf("time: %d\t value: %d\t type: %d\t number: %d\n",
// j_evt.time, j_evt.value, j_evt.type, j_evt.number);
wxJoystickEvent jwx_event;
if (j_evt.type & JS_EVENT_AXIS)
{
m_axe[j_evt.number] = j_evt.value;
switch (j_evt.number)
{
case wxJS_AXIS_X:
m_lastposition.x = j_evt.value;
jwx_event.SetEventType(wxEVT_JOY_MOVE);
break;
case wxJS_AXIS_Y:
m_lastposition.y = j_evt.value;
jwx_event.SetEventType(wxEVT_JOY_MOVE);
break;
case wxJS_AXIS_Z:
jwx_event.SetEventType(wxEVT_JOY_ZMOVE);
break;
default:
jwx_event.SetEventType(wxEVT_JOY_MOVE);
// TODO: There should be a way to indicate that the event
// is for some other axes.
break;
}
}
if (j_evt.type & JS_EVENT_BUTTON)
{
if (j_evt.value)
{
m_buttons |= (1 << j_evt.number);
jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN);
}
else
{
m_buttons &= ~(1 << j_evt.number);
jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP);
}
jwx_event.SetButtonChange(j_evt.number);
jwx_event.SetTimestamp(j_evt.time);
jwx_event.SetJoystick(m_joystick);
jwx_event.SetButtonState(m_buttons);
jwx_event.SetPosition(m_lastposition);
jwx_event.SetZPosition(m_axe[3]);
jwx_event.SetEventObject(m_catchwin);
if (m_catchwin)
m_catchwin->AddPendingEvent(jwx_event);
}
}
}
close(m_device);
return NULL;
}
////////////////////////////////////////////////////////////////////////////
wxJoystick::wxJoystick(int joystick)
: m_device(-1),
m_joystick(joystick),
m_thread(NULL)
{
wxString dev_name;
// old /dev structure
dev_name.Printf( wxT("/dev/js%d"), joystick);
m_device = open(dev_name.fn_str(), O_RDONLY);
// new /dev structure with "input" subdirectory
if (m_device == -1)
{
dev_name.Printf( wxT("/dev/input/js%d"), joystick);
m_device = open(dev_name.fn_str(), O_RDONLY);
}
if (m_device != -1)
{
m_thread = new wxJoystickThread(m_device, m_joystick);
m_thread->Create();
m_thread->Run();
}
}
wxJoystick::~wxJoystick()
{
ReleaseCapture();
if (m_thread)
m_thread->Delete(); // It's detached so it will delete itself
m_device = -1;
}
////////////////////////////////////////////////////////////////////////////
// State
////////////////////////////////////////////////////////////////////////////
wxPoint wxJoystick::GetPosition() const
{
wxPoint pos(wxDefaultPosition);
if (m_thread) pos = m_thread->m_lastposition;
return pos;
}
int wxJoystick::GetZPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_Z];
return 0;
}
int wxJoystick::GetButtonState() const
{
if (m_thread)
return m_thread->m_buttons;
return 0;
}
int wxJoystick::GetPOVPosition() const
{
return -1;
}
int wxJoystick::GetPOVCTSPosition() const
{
return -1;
}
int wxJoystick::GetRudderPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_RUDDER];
return 0;
}
int wxJoystick::GetUPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_U];
return 0;
}
int wxJoystick::GetVPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_V];
return 0;
}
int wxJoystick::GetMovementThreshold() const
{
return 0;
}
void wxJoystick::SetMovementThreshold(int threshold)
{
}
////////////////////////////////////////////////////////////////////////////
// Capabilities
////////////////////////////////////////////////////////////////////////////
bool wxJoystick::IsOk() const
{
return (m_device != -1);
}
int wxJoystick::GetNumberJoysticks()
{
wxString dev_name;
int fd, j;
for (j=0; j<4; j++) {
dev_name.Printf(wxT("/dev/js%d"), j);
fd = open(dev_name.fn_str(), O_RDONLY);
if (fd == -1)
break;
close(fd);
}
if (j == 0) {
for (j=0; j<4; j++) {
dev_name.Printf(wxT("/dev/input/js%d"), j);
fd = open(dev_name.fn_str(), O_RDONLY);
if (fd == -1)
return j;
close(fd);
}
}
return j;
}
int wxJoystick::GetManufacturerId() const
{
return 0;
}
int wxJoystick::GetProductId() const
{
return 0;
}
wxString wxJoystick::GetProductName() const
{
char name[128];
if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
strcpy(name, "Unknown");
return wxString(name, wxConvLibc);
}
int wxJoystick::GetXMin() const
{
return wxJS_AXIS_MIN;
}
int wxJoystick::GetYMin() const
{
return wxJS_AXIS_MIN;
}
int wxJoystick::GetZMin() const
{
return wxJS_AXIS_MIN;
}
int wxJoystick::GetXMax() const
{
return wxJS_AXIS_MAX;
}
int wxJoystick::GetYMax() const
{
return wxJS_AXIS_MAX;
}
int wxJoystick::GetZMax() const
{
return wxJS_AXIS_MAX;
}
int wxJoystick::GetNumberButtons() const
{
char nb=0;
if (m_device != -1)
ioctl(m_device, JSIOCGBUTTONS, &nb);
return nb;
}
int wxJoystick::GetNumberAxes() const
{
char nb=0;
if (m_device != -1)
ioctl(m_device, JSIOCGAXES, &nb);
return nb;
}
int wxJoystick::GetMaxButtons() const
{
return 15; // internal
}
int wxJoystick::GetMaxAxes() const
{
return 15; // internal
}
int wxJoystick::GetPollingMin() const
{
return 10;
}
int wxJoystick::GetPollingMax() const
{
return 1000;
}
int wxJoystick::GetRudderMin() const
{
return wxJS_AXIS_MIN;
}
int wxJoystick::GetRudderMax() const
{
return wxJS_AXIS_MAX;
}
int wxJoystick::GetUMin() const
{
return wxJS_AXIS_MIN;
}
int wxJoystick::GetUMax() const
{
return wxJS_AXIS_MAX;
}
int wxJoystick::GetVMin() const
{
return wxJS_AXIS_MIN;
}
int wxJoystick::GetVMax() const
{
return wxJS_AXIS_MAX;
}
bool wxJoystick::HasRudder() const
{
return GetNumberAxes() >= wxJS_AXIS_RUDDER;
}
bool wxJoystick::HasZ() const
{
return GetNumberAxes() >= wxJS_AXIS_Z;
}
bool wxJoystick::HasU() const
{
return GetNumberAxes() >= wxJS_AXIS_U;
}
bool wxJoystick::HasV() const
{
return GetNumberAxes() >= wxJS_AXIS_V;
}
bool wxJoystick::HasPOV() const
{
return false;
}
bool wxJoystick::HasPOV4Dir() const
{
return false;
}
bool wxJoystick::HasPOVCTS() const
{
return false;
}
////////////////////////////////////////////////////////////////////////////
// Operations
////////////////////////////////////////////////////////////////////////////
bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
{
if (m_thread)
{
m_thread->m_catchwin = win;
m_thread->m_polling = pollingFreq;
return true;
}
return false;
}
bool wxJoystick::ReleaseCapture()
{
if (m_thread)
{
m_thread->m_catchwin = NULL;
m_thread->m_polling = 0;
return true;
}
return false;
}
#endif // wxUSE_JOYSTICK

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,398 @@
///////////////////////////////////////////////////////////////////////////////
// Name: src/unix/snglinst.cpp
// Purpose: implements wxSingleInstanceChecker class for Unix using
// lock files with fcntl(2) or flock(2)
// Author: Vadim Zeitlin
// Modified by:
// Created: 09.06.01
// RCS-ID: $Id: snglinst.cpp 55833 2008-09-24 13:47:41Z VZ $
// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_SNGLINST_CHECKER
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/utils.h" // wxGetHomeDir()
#endif //WX_PRECOMP
#include "wx/file.h"
#include "wx/snglinst.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> // for S_I[RW]USR
#include <signal.h> // for kill()
#include <errno.h>
#ifdef HAVE_FCNTL
#include <fcntl.h>
#elif defined(HAVE_FLOCK)
#include <sys/file.h>
#else
// normally, wxUSE_SNGLINST_CHECKER must have been reset by configure
#error "wxSingleInstanceChecker can't be compiled on this platform"
#endif // fcntl()/flock()
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// argument of wxLockFile()
enum LockOperation
{
LOCK,
UNLOCK
};
// return value of CreateLockFile()
enum LockResult
{
LOCK_ERROR = -1,
LOCK_EXISTS,
LOCK_CREATED
};
// ----------------------------------------------------------------------------
// private functions: (exclusively) lock/unlock the file
// ----------------------------------------------------------------------------
#ifdef HAVE_FCNTL
static int wxLockFile(int fd, LockOperation lock)
{
// init the flock parameter struct
struct flock fl;
fl.l_type = lock == LOCK ? F_WRLCK : F_UNLCK;
// lock the entire file
fl.l_start =
fl.l_len =
fl.l_whence = 0;
// is this needed?
fl.l_pid = getpid();
return fcntl(fd, F_SETLK, &fl);
}
#else // HAVE_FLOCK
static int wxLockFile(int fd, LockOperation lock)
{
return flock(fd, lock == LOCK ? LOCK_EX | LOCK_NB : LOCK_UN);
}
#endif // fcntl()/flock()
// ----------------------------------------------------------------------------
// wxSingleInstanceCheckerImpl: the real implementation class
// ----------------------------------------------------------------------------
class wxSingleInstanceCheckerImpl
{
public:
wxSingleInstanceCheckerImpl()
{
m_fdLock = -1;
m_pidLocker = 0;
}
bool Create(const wxString& name);
pid_t GetLockerPID() const { return m_pidLocker; }
~wxSingleInstanceCheckerImpl() { Unlock(); }
private:
// try to create and lock the file
LockResult CreateLockFile();
// unlock and remove the lock file
void Unlock();
// the descriptor of our lock file, -1 if none
int m_fdLock;
// pid of the process owning the lock file
pid_t m_pidLocker;
// the name of the lock file
wxString m_nameLock;
};
// ============================================================================
// wxSingleInstanceCheckerImpl implementation
// ============================================================================
LockResult wxSingleInstanceCheckerImpl::CreateLockFile()
{
// try to open the file
m_fdLock = open(m_nameLock.fn_str(),
O_WRONLY | O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR);
if ( m_fdLock != -1 )
{
// try to lock it
if ( wxLockFile(m_fdLock, LOCK) == 0 )
{
// fine, we have the exclusive lock to the file, write our PID
// into it
m_pidLocker = getpid();
// use char here, not wxChar!
char buf[256]; // enough for any PID size
int len = sprintf(buf, "%d", (int)m_pidLocker) + 1;
if ( write(m_fdLock, buf, len) != len )
{
wxLogSysError(_("Failed to write to lock file '%s'"),
m_nameLock.c_str());
Unlock();
return LOCK_ERROR;
}
fsync(m_fdLock);
// change file's permission so that only this user can access it:
if ( chmod(m_nameLock.fn_str(), S_IRUSR | S_IWUSR) != 0 )
{
wxLogSysError(_("Failed to set permissions on lock file '%s'"),
m_nameLock.c_str());
Unlock();
return LOCK_ERROR;
}
return LOCK_CREATED;
}
else // failure: see what exactly happened
{
close(m_fdLock);
m_fdLock = -1;
if ( errno != EACCES && errno != EAGAIN )
{
wxLogSysError(_("Failed to lock the lock file '%s'"),
m_nameLock.c_str());
unlink(m_nameLock.fn_str());
return LOCK_ERROR;
}
//else: couldn't lock because the lock is held by another process:
// this might have happened because of a race condition:
// maybe another instance opened and locked the file between
// our calls to open() and flock(), so don't give an error
}
}
// we didn't create and lock the file
return LOCK_EXISTS;
}
bool wxSingleInstanceCheckerImpl::Create(const wxString& name)
{
m_nameLock = name;
switch ( CreateLockFile() )
{
case LOCK_EXISTS:
// there is a lock file, check below if it is still valid
break;
case LOCK_CREATED:
// nothing more to do
return true;
case LOCK_ERROR:
// oops...
return false;
}
// Check if the file is owned by current user and has 0600 permissions.
// If it doesn't, it's a fake file, possibly meant as a DoS attack, and
// so we refuse to touch it:
wxStructStat stats;
if ( wxStat(name, &stats) != 0 )
{
wxLogSysError(_("Failed to inspect the lock file '%s'"), name.c_str());
return false;
}
if ( stats.st_uid != getuid() )
{
wxLogError(_("Lock file '%s' has incorrect owner."), name.c_str());
return false;
}
if ( stats.st_mode != (S_IFREG | S_IRUSR | S_IWUSR) )
{
wxLogError(_("Lock file '%s' has incorrect permissions."), name.c_str());
return false;
}
// try to open the file for reading and get the PID of the process
// which has it
wxFile file(name, wxFile::read);
if ( !file.IsOpened() )
{
// well, this is really weird - file doesn't exist and we can't
// create it
//
// normally, this just means that we don't have write access to
// the directory where we try to create it, so return failure,
// even it might also be a rare case of a race condition when
// another process managed to open and lock the file and terminate
// (erasing it) before we got here, but this should happen so
// rarely in practice that we don't care
wxLogError(_("Failed to access lock file."));
return false;
}
char buf[256];
ssize_t count = file.Read(buf, WXSIZEOF(buf));
if ( count == wxInvalidOffset )
{
wxLogError(_("Failed to read PID from lock file."));
}
else
{
if ( sscanf(buf, "%d", (int *)&m_pidLocker) == 1 )
{
if ( kill(m_pidLocker, 0) != 0 )
{
if ( unlink(name.fn_str()) != 0 )
{
wxLogError(_("Failed to remove stale lock file '%s'."),
name.c_str());
// return true in this case for now...
}
else
{
wxLogMessage(_("Deleted stale lock file '%s'."),
name.c_str());
// retry now
(void)CreateLockFile();
}
}
//else: the other process is running
}
else
{
wxLogWarning(_("Invalid lock file '%s'."), name.c_str());
}
}
// return true if we could get the PID of the process owning the lock file
// (whether it is still running or not), FALSE otherwise as it is
// unexpected
return m_pidLocker != 0;
}
void wxSingleInstanceCheckerImpl::Unlock()
{
if ( m_fdLock != -1 )
{
if ( unlink(m_nameLock.fn_str()) != 0 )
{
wxLogSysError(_("Failed to remove lock file '%s'"),
m_nameLock.c_str());
}
if ( wxLockFile(m_fdLock, UNLOCK) != 0 )
{
wxLogSysError(_("Failed to unlock lock file '%s'"),
m_nameLock.c_str());
}
if ( close(m_fdLock) != 0 )
{
wxLogSysError(_("Failed to close lock file '%s'"),
m_nameLock.c_str());
}
}
m_pidLocker = 0;
}
// ============================================================================
// wxSingleInstanceChecker implementation
// ============================================================================
bool wxSingleInstanceChecker::Create(const wxString& name,
const wxString& path)
{
wxASSERT_MSG( !m_impl,
_T("calling wxSingleInstanceChecker::Create() twice?") );
// must have the file name to create a lock file
wxASSERT_MSG( !name.empty(), _T("lock file name can't be empty") );
m_impl = new wxSingleInstanceCheckerImpl;
wxString fullname = path;
if ( fullname.empty() )
{
fullname = wxGetHomeDir();
}
if ( fullname.Last() != _T('/') )
{
fullname += _T('/');
}
fullname << name;
return m_impl->Create(fullname);
}
bool wxSingleInstanceChecker::IsAnotherRunning() const
{
wxCHECK_MSG( m_impl, false, _T("must call Create() first") );
const pid_t lockerPid = m_impl->GetLockerPID();
if ( !lockerPid )
{
// we failed to open the lock file, return false as we're definitely
// not sure that another our process is running and so it's better not
// to prevent this one from starting up
return false;
}
// if another instance is running, it must own the lock file - otherwise
// we have it and the locker PID is ours one
return lockerPid != getpid();
}
wxSingleInstanceChecker::~wxSingleInstanceChecker()
{
delete m_impl;
}
#endif // wxUSE_SNGLINST_CHECKER

View file

@ -0,0 +1,722 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/unix/sound.cpp
// Purpose: wxSound
// Author: Marcel Rasche, Vaclav Slavik
// Modified by:
// Created: 25/10/98
// RCS-ID: $Id: sound.cpp 41020 2006-09-05 20:47:48Z VZ $
// Copyright: (c) Julian Smart, Open Source Applications Foundation
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if defined(__BORLANDC__)
#pragma hdrstop
#endif
#if wxUSE_SOUND
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#endif
#ifndef WX_PRECOMP
#include "wx/event.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/module.h"
#endif
#include "wx/thread.h"
#include "wx/file.h"
#include "wx/sound.h"
#include "wx/dynlib.h"
#if wxUSE_THREADS
// mutex for all wxSound's synchronization
static wxMutex gs_soundMutex;
#endif
// ----------------------------------------------------------------------------
// wxSoundData
// ----------------------------------------------------------------------------
void wxSoundData::IncRef()
{
#if wxUSE_THREADS
wxMutexLocker locker(gs_soundMutex);
#endif
m_refCnt++;
}
void wxSoundData::DecRef()
{
#if wxUSE_THREADS
wxMutexLocker locker(gs_soundMutex);
#endif
if (--m_refCnt == 0)
delete this;
}
wxSoundData::~wxSoundData()
{
delete[] m_dataWithHeader;
}
// ----------------------------------------------------------------------------
// wxSoundBackendNull, used in absence of audio API or card
// ----------------------------------------------------------------------------
class wxSoundBackendNull : public wxSoundBackend
{
public:
wxString GetName() const { return _("No sound"); }
int GetPriority() const { return 0; }
bool IsAvailable() const { return true; }
bool HasNativeAsyncPlayback() const { return true; }
bool Play(wxSoundData *WXUNUSED(data), unsigned WXUNUSED(flags),
volatile wxSoundPlaybackStatus *WXUNUSED(status))
{ return true; }
void Stop() {}
bool IsPlaying() const { return false; }
};
// ----------------------------------------------------------------------------
// wxSoundBackendOSS, for Linux
// ----------------------------------------------------------------------------
#ifdef HAVE_SYS_SOUNDCARD_H
#ifndef AUDIODEV
#define AUDIODEV "/dev/dsp" // Default path for audio device
#endif
class wxSoundBackendOSS : public wxSoundBackend
{
public:
wxString GetName() const { return _T("Open Sound System"); }
int GetPriority() const { return 10; }
bool IsAvailable() const;
bool HasNativeAsyncPlayback() const { return false; }
bool Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status);
void Stop() {}
bool IsPlaying() const { return false; }
private:
int OpenDSP(const wxSoundData *data);
bool InitDSP(int dev, const wxSoundData *data);
int m_DSPblkSize; // Size of the DSP buffer
bool m_needConversion;
};
bool wxSoundBackendOSS::IsAvailable() const
{
int fd;
fd = open(AUDIODEV, O_WRONLY | O_NONBLOCK);
if (fd < 0)
return false;
close(fd);
return true;
}
bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status)
{
int dev = OpenDSP(data);
if (dev < 0)
return false;
ioctl(dev, SNDCTL_DSP_SYNC, 0);
do
{
bool play = true;
int i;
unsigned l = 0;
size_t datasize = data->m_dataBytes;
do
{
if (status->m_stopRequested)
{
wxLogTrace(_T("sound"), _T("playback stopped"));
close(dev);
return true;
}
i= (int)((l + m_DSPblkSize) < datasize ?
m_DSPblkSize : (datasize - l));
if (write(dev, &data->m_data[l], i) != i)
{
play = false;
}
l += i;
} while (play && l < datasize);
} while (flags & wxSOUND_LOOP);
close(dev);
return true;
}
int wxSoundBackendOSS::OpenDSP(const wxSoundData *data)
{
int dev = -1;
if ((dev = open(AUDIODEV, O_WRONLY, 0)) <0)
return -1;
if (!InitDSP(dev, data) || m_needConversion)
{
close(dev);
return -1;
}
return dev;
}
bool wxSoundBackendOSS::InitDSP(int dev, const wxSoundData *data)
{
unsigned tmp;
// Reset the dsp
if (ioctl(dev, SNDCTL_DSP_RESET, 0) < 0)
{
wxLogTrace(_T("sound"), _T("unable to reset dsp"));
return false;
}
m_needConversion = false;
tmp = data->m_bitsPerSample;
if (ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SAMPLESIZE)"));
return false;
}
if (tmp != data->m_bitsPerSample)
{
wxLogTrace(_T("sound"),
_T("Unable to set DSP sample size to %d (wants %d)"),
data->m_bitsPerSample, tmp);
m_needConversion = true;
}
unsigned stereo = data->m_channels == 1 ? 0 : 1;
tmp = stereo;
if (ioctl(dev, SNDCTL_DSP_STEREO, &tmp) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_STEREO)"));
return false;
}
if (tmp != stereo)
{
wxLogTrace(_T("sound"), _T("Unable to set DSP to %s."), stereo? _T("stereo"):_T("mono"));
m_needConversion = true;
}
tmp = data->m_samplingRate;
if (ioctl(dev, SNDCTL_DSP_SPEED, &tmp) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SPEED)"));
return false;
}
if (tmp != data->m_samplingRate)
{
// If the rate the sound card is using is not within 1% of what the
// data specified then override the data setting. The only reason not
// to always override this is because of clock-rounding
// problems. Sound cards will sometimes use things like 44101 when you
// ask for 44100. No need overriding this and having strange output
// file rates for something that we can't hear anyways.
if (data->m_samplingRate - tmp > (tmp * .01) ||
tmp - data->m_samplingRate > (tmp * .01)) {
wxLogTrace(_T("sound"),
_T("Unable to set DSP sampling rate to %d (wants %d)"),
data->m_samplingRate, tmp);
m_needConversion = true;
}
}
// Do this last because some drivers can adjust the buffer sized based on
// the sampling rate, etc.
if (ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &m_DSPblkSize) < 0)
{
wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_GETBLKSIZE)"));
return false;
}
return true;
}
#endif // HAVE_SYS_SOUNDCARD_H
// ----------------------------------------------------------------------------
// wxSoundSyncOnlyAdaptor
// ----------------------------------------------------------------------------
#if wxUSE_THREADS
class wxSoundSyncOnlyAdaptor;
// this class manages asynchronous playback of audio if the backend doesn't
// support it natively (e.g. OSS backend)
class wxSoundAsyncPlaybackThread : public wxThread
{
public:
wxSoundAsyncPlaybackThread(wxSoundSyncOnlyAdaptor *adaptor,
wxSoundData *data, unsigned flags)
: wxThread(), m_adapt(adaptor), m_data(data), m_flags(flags) {}
virtual ExitCode Entry();
protected:
wxSoundSyncOnlyAdaptor *m_adapt;
wxSoundData *m_data;
unsigned m_flags;
};
#endif // wxUSE_THREADS
// This class turns wxSoundBackend that doesn't support asynchronous playback
// into one that does
class wxSoundSyncOnlyAdaptor : public wxSoundBackend
{
public:
wxSoundSyncOnlyAdaptor(wxSoundBackend *backend)
: m_backend(backend), m_playing(false) {}
virtual ~wxSoundSyncOnlyAdaptor()
{
delete m_backend;
}
wxString GetName() const
{
return m_backend->GetName();
}
int GetPriority() const
{
return m_backend->GetPriority();
}
bool IsAvailable() const
{
return m_backend->IsAvailable();
}
bool HasNativeAsyncPlayback() const
{
return true;
}
bool Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status);
void Stop();
bool IsPlaying() const;
private:
friend class wxSoundAsyncPlaybackThread;
wxSoundBackend *m_backend;
bool m_playing;
#if wxUSE_THREADS
// player thread holds this mutex and releases it after it finishes
// playing, so that the main thread knows when it can play sound
wxMutex m_mutexRightToPlay;
wxSoundPlaybackStatus m_status;
#endif
};
#if wxUSE_THREADS
wxThread::ExitCode wxSoundAsyncPlaybackThread::Entry()
{
m_adapt->m_backend->Play(m_data, m_flags & ~wxSOUND_ASYNC,
&m_adapt->m_status);
m_data->DecRef();
m_adapt->m_playing = false;
m_adapt->m_mutexRightToPlay.Unlock();
wxLogTrace(_T("sound"), _T("terminated async playback thread"));
return 0;
}
#endif
bool wxSoundSyncOnlyAdaptor::Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status)
{
Stop();
if (flags & wxSOUND_ASYNC)
{
#if wxUSE_THREADS
m_mutexRightToPlay.Lock();
m_status.m_playing = true;
m_status.m_stopRequested = false;
data->IncRef();
wxThread *th = new wxSoundAsyncPlaybackThread(this, data, flags);
th->Create();
th->Run();
wxLogTrace(_T("sound"), _T("launched async playback thread"));
return true;
#else
wxLogError(_("Unable to play sound asynchronously."));
return false;
#endif
}
else
{
#if wxUSE_THREADS
m_mutexRightToPlay.Lock();
#endif
bool rv = m_backend->Play(data, flags, status);
#if wxUSE_THREADS
m_mutexRightToPlay.Unlock();
#endif
return rv;
}
}
void wxSoundSyncOnlyAdaptor::Stop()
{
wxLogTrace(_T("sound"), _T("asking audio to stop"));
#if wxUSE_THREADS
// tell the player thread (if running) to stop playback ASAP:
m_status.m_stopRequested = true;
// acquire the mutex to be sure no sound is being played, then
// release it because we don't need it for anything (the effect of this
// is that calling thread will wait until playback thread reacts to
// our request to interrupt playback):
m_mutexRightToPlay.Lock();
m_mutexRightToPlay.Unlock();
wxLogTrace(_T("sound"), _T("audio was stopped"));
#endif
}
bool wxSoundSyncOnlyAdaptor::IsPlaying() const
{
#if wxUSE_THREADS
return m_status.m_playing;
#else
return false;
#endif
}
// ----------------------------------------------------------------------------
// wxSound
// ----------------------------------------------------------------------------
wxSoundBackend *wxSound::ms_backend = NULL;
// FIXME - temporary, until we have plugins architecture
#if wxUSE_LIBSDL
#if wxUSE_PLUGINS
wxDynamicLibrary *wxSound::ms_backendSDL = NULL;
#else
extern "C" wxSoundBackend *wxCreateSoundBackendSDL();
#endif
#endif
wxSound::wxSound() : m_data(NULL)
{
}
wxSound::wxSound(const wxString& sFileName, bool isResource) : m_data(NULL)
{
Create(sFileName, isResource);
}
wxSound::wxSound(int size, const wxByte* data) : m_data(NULL)
{
Create(size, data);
}
wxSound::~wxSound()
{
Free();
}
bool wxSound::Create(const wxString& fileName,
bool WXUNUSED_UNLESS_DEBUG(isResource))
{
wxASSERT_MSG( !isResource,
_T("Loading sound from resources is only supported on Windows") );
Free();
wxFile fileWave;
if (!fileWave.Open(fileName, wxFile::read))
{
return false;
}
wxFileOffset lenOrig = fileWave.Length();
if ( lenOrig == wxInvalidOffset )
return false;
size_t len = wx_truncate_cast(size_t, lenOrig);
wxUint8 *data = new wxUint8[len];
if ( fileWave.Read(data, len) != lenOrig )
{
delete [] data;
wxLogError(_("Couldn't load sound data from '%s'."), fileName.c_str());
return false;
}
if (!LoadWAV(data, len, false))
{
delete [] data;
wxLogError(_("Sound file '%s' is in unsupported format."),
fileName.c_str());
return false;
}
return true;
}
bool wxSound::Create(int size, const wxByte* data)
{
wxASSERT( data != NULL );
Free();
if (!LoadWAV(data, size, true))
{
wxLogError(_("Sound data are in unsupported format."));
return false;
}
return true;
}
/*static*/ void wxSound::EnsureBackend()
{
if (!ms_backend)
{
// FIXME -- make this fully dynamic when plugins architecture is in
// place
#if wxUSE_LIBSDL
//if (!ms_backend)
{
#if !wxUSE_PLUGINS
ms_backend = wxCreateSoundBackendSDL();
#else
wxString dllname;
dllname.Printf(_T("%s/%s"),
wxDynamicLibrary::GetPluginsDirectory().c_str(),
wxDynamicLibrary::CanonicalizePluginName(
_T("sound_sdl"), wxDL_PLUGIN_BASE).c_str());
wxLogTrace(_T("sound"),
_T("trying to load SDL plugin from '%s'..."),
dllname.c_str());
wxLogNull null;
ms_backendSDL = new wxDynamicLibrary(dllname, wxDL_NOW);
if (!ms_backendSDL->IsLoaded())
{
wxDELETE(ms_backendSDL);
}
else
{
typedef wxSoundBackend *(*wxCreateSoundBackend_t)();
wxDYNLIB_FUNCTION(wxCreateSoundBackend_t,
wxCreateSoundBackendSDL, *ms_backendSDL);
if (pfnwxCreateSoundBackendSDL)
{
ms_backend = (*pfnwxCreateSoundBackendSDL)();
}
}
#endif
if (ms_backend && !ms_backend->IsAvailable())
{
wxDELETE(ms_backend);
}
}
#endif
#ifdef HAVE_SYS_SOUNDCARD_H
if (!ms_backend)
{
ms_backend = new wxSoundBackendOSS();
if (!ms_backend->IsAvailable())
{
wxDELETE(ms_backend);
}
}
#endif
if (!ms_backend)
ms_backend = new wxSoundBackendNull();
if (!ms_backend->HasNativeAsyncPlayback())
ms_backend = new wxSoundSyncOnlyAdaptor(ms_backend);
wxLogTrace(_T("sound"),
_T("using backend '%s'"), ms_backend->GetName().c_str());
}
}
/*static*/ void wxSound::UnloadBackend()
{
if (ms_backend)
{
wxLogTrace(_T("sound"), _T("unloading backend"));
Stop();
delete ms_backend;
ms_backend = NULL;
#if wxUSE_LIBSDL && wxUSE_PLUGINS
delete ms_backendSDL;
#endif
}
}
bool wxSound::DoPlay(unsigned flags) const
{
wxCHECK_MSG( IsOk(), false, _T("Attempt to play invalid wave data") );
EnsureBackend();
wxSoundPlaybackStatus status;
status.m_playing = true;
status.m_stopRequested = false;
return ms_backend->Play(m_data, flags, &status);
}
/*static*/ void wxSound::Stop()
{
if (ms_backend)
ms_backend->Stop();
}
/*static*/ bool wxSound::IsPlaying()
{
if (ms_backend)
return ms_backend->IsPlaying();
else
return false;
}
void wxSound::Free()
{
if (m_data)
m_data->DecRef();
}
typedef struct
{
wxUint32 uiSize;
wxUint16 uiFormatTag;
wxUint16 uiChannels;
wxUint32 ulSamplesPerSec;
wxUint32 ulAvgBytesPerSec;
wxUint16 uiBlockAlign;
wxUint16 uiBitsPerSample;
} WAVEFORMAT;
#define WAVE_FORMAT_PCM 1
#define WAVE_INDEX 8
#define FMT_INDEX 12
bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
{
// the simplest wave file header consists of 44 bytes:
//
// 0 "RIFF"
// 4 file size - 8
// 8 "WAVE"
//
// 12 "fmt "
// 16 chunk size |
// 20 format tag |
// 22 number of channels |
// 24 sample rate | WAVEFORMAT
// 28 average bytes per second |
// 32 bytes per frame |
// 34 bits per sample |
//
// 36 "data"
// 40 number of data bytes
// 44 (wave signal) data
//
// so check that we have at least as much
if ( length < 44 )
return false;
WAVEFORMAT waveformat;
memcpy(&waveformat, &data[FMT_INDEX + 4], sizeof(WAVEFORMAT));
waveformat.uiSize = wxUINT32_SWAP_ON_BE(waveformat.uiSize);
waveformat.uiFormatTag = wxUINT16_SWAP_ON_BE(waveformat.uiFormatTag);
waveformat.uiChannels = wxUINT16_SWAP_ON_BE(waveformat.uiChannels);
waveformat.ulSamplesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulSamplesPerSec);
waveformat.ulAvgBytesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulAvgBytesPerSec);
waveformat.uiBlockAlign = wxUINT16_SWAP_ON_BE(waveformat.uiBlockAlign);
waveformat.uiBitsPerSample = wxUINT16_SWAP_ON_BE(waveformat.uiBitsPerSample);
// get the sound data size
wxUint32 ul;
memcpy(&ul, &data[FMT_INDEX + waveformat.uiSize + 12], 4);
ul = wxUINT32_SWAP_ON_BE(ul);
if ( length < ul + FMT_INDEX + waveformat.uiSize + 16 )
return false;
if (memcmp(data, "RIFF", 4) != 0)
return false;
if (memcmp(&data[WAVE_INDEX], "WAVE", 4) != 0)
return false;
if (memcmp(&data[FMT_INDEX], "fmt ", 4) != 0)
return false;
if (memcmp(&data[FMT_INDEX + waveformat.uiSize + 8], "data", 4) != 0)
return false;
if (waveformat.uiFormatTag != WAVE_FORMAT_PCM)
return false;
if (waveformat.ulSamplesPerSec !=
waveformat.ulAvgBytesPerSec / waveformat.uiBlockAlign)
return false;
m_data = new wxSoundData;
m_data->m_channels = waveformat.uiChannels;
m_data->m_samplingRate = waveformat.ulSamplesPerSec;
m_data->m_bitsPerSample = waveformat.uiBitsPerSample;
m_data->m_samples = ul / (m_data->m_channels * m_data->m_bitsPerSample / 8);
m_data->m_dataBytes = ul;
if (copyData)
{
m_data->m_dataWithHeader = new wxUint8[length];
memcpy(m_data->m_dataWithHeader, data, length);
}
else
m_data->m_dataWithHeader = (wxUint8*)data;
m_data->m_data =
(&m_data->m_dataWithHeader[FMT_INDEX + waveformat.uiSize + 8]);
return true;
}
// ----------------------------------------------------------------------------
// wxSoundCleanupModule
// ----------------------------------------------------------------------------
class wxSoundCleanupModule: public wxModule
{
public:
bool OnInit() { return true; }
void OnExit() { wxSound::UnloadBackend(); }
DECLARE_DYNAMIC_CLASS(wxSoundCleanupModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxSoundCleanupModule, wxModule)
#endif

View file

@ -0,0 +1,335 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/unix/sound_sdl.cpp
// Purpose: wxSound backend using SDL
// Author: Vaclav Slavik
// Modified by:
// Created: 2004/01/31
// RCS-ID: $Id: sound_sdl.cpp 40943 2006-08-31 19:31:43Z ABX $
// Copyright: (c) 2004, Open Source Applications Foundation
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if defined(__BORLANDC__)
#pragma hdrstop
#endif
#if wxUSE_SOUND && wxUSE_LIBSDL
#include <SDL.h>
#ifndef WX_PRECOMP
#include "wx/event.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/utils.h"
#include "wx/module.h"
#endif
#include "wx/thread.h"
#include "wx/sound.h"
// ----------------------------------------------------------------------------
// wxSoundBackendSDL, for Unix with libSDL
// ----------------------------------------------------------------------------
class wxSoundBackendSDLNotification : public wxEvent
{
public:
DECLARE_DYNAMIC_CLASS(wxSoundBackendSDLNotification)
wxSoundBackendSDLNotification();
wxEvent *Clone() const { return new wxSoundBackendSDLNotification(*this); }
};
typedef void (wxEvtHandler::*wxSoundBackendSDLNotificationFunction)
(wxSoundBackendSDLNotification&);
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_LOCAL_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, -1)
END_DECLARE_EVENT_TYPES()
#define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \
DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \
-1, \
-1, \
(wxObjectEventFunction) wxStaticCastEvent( wxSoundBackendSDLNotificationFunction, & func ), \
(wxObject *) NULL ),
IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification, wxEvtHandler)
DEFINE_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION)
wxSoundBackendSDLNotification::wxSoundBackendSDLNotification()
{
SetEventType(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION);
}
class wxSoundBackendSDLEvtHandler;
class wxSoundBackendSDL : public wxSoundBackend
{
public:
wxSoundBackendSDL()
: m_initialized(false), m_playing(false), m_audioOpen(false),
m_data(NULL), m_evtHandler(NULL) {}
virtual ~wxSoundBackendSDL();
wxString GetName() const { return _T("Simple DirectMedia Layer"); }
int GetPriority() const { return 9; }
bool IsAvailable() const;
bool HasNativeAsyncPlayback() const { return true; }
bool Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *status);
void FillAudioBuffer(Uint8 *stream, int len);
void FinishedPlayback();
void Stop();
bool IsPlaying() const { return m_playing; }
private:
bool OpenAudio();
void CloseAudio();
bool m_initialized;
bool m_playing, m_audioOpen;
// playback information:
wxSoundData *m_data;
unsigned m_pos;
SDL_AudioSpec m_spec;
bool m_loop;
wxSoundBackendSDLEvtHandler *m_evtHandler;
};
class wxSoundBackendSDLEvtHandler : public wxEvtHandler
{
public:
wxSoundBackendSDLEvtHandler(wxSoundBackendSDL *bk) : m_backend(bk) {}
private:
void OnNotify(wxSoundBackendSDLNotification& WXUNUSED(event))
{
wxLogTrace(_T("sound"),
_T("received playback status change notification"));
m_backend->FinishedPlayback();
}
wxSoundBackendSDL *m_backend;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(wxSoundBackendSDLEvtHandler, wxEvtHandler)
EVT_SOUND_BACKEND_SDL_NOTIFICATON(wxSoundBackendSDLEvtHandler::OnNotify)
END_EVENT_TABLE()
wxSoundBackendSDL::~wxSoundBackendSDL()
{
Stop();
CloseAudio();
delete m_evtHandler;
}
bool wxSoundBackendSDL::IsAvailable() const
{
if (m_initialized)
return true;
if (SDL_WasInit(SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
{
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) == -1)
return false;
}
wxConstCast(this, wxSoundBackendSDL)->m_initialized = true;
wxLogTrace(_T("sound"), _T("initialized SDL audio subsystem"));
return true;
}
extern "C" void wx_sdl_audio_callback(void *userdata, Uint8 *stream, int len)
{
wxSoundBackendSDL *bk = (wxSoundBackendSDL*)userdata;
bk->FillAudioBuffer(stream, len);
}
void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
{
if (m_playing)
{
// finished playing the sample
if (m_pos == m_data->m_dataBytes)
{
m_playing = false;
wxSoundBackendSDLNotification event;
m_evtHandler->AddPendingEvent(event);
}
// still something to play
else
{
unsigned size = ((len + m_pos) < m_data->m_dataBytes) ?
len :
(m_data->m_dataBytes - m_pos);
memcpy(stream, m_data->m_data + m_pos, size);
m_pos += size;
len -= size;
stream += size;
}
}
// the sample doesn't play, fill the buffer with silence and wait for
// the main thread to shut the playback down:
if (len > 0)
{
if (m_loop)
{
m_pos = 0;
FillAudioBuffer(stream, len);
return;
}
else
{
memset(stream, m_spec.silence, len);
}
}
}
void wxSoundBackendSDL::FinishedPlayback()
{
if (!m_playing)
Stop();
}
bool wxSoundBackendSDL::OpenAudio()
{
if (!m_audioOpen)
{
if (!m_evtHandler)
m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
m_spec.silence = 0;
m_spec.samples = 4096;
m_spec.size = 0;
m_spec.callback = wx_sdl_audio_callback;
m_spec.userdata = (void*)this;
wxLogTrace(_T("sound"), _T("opening SDL audio..."));
if (SDL_OpenAudio(&m_spec, NULL) >= 0)
{
#if wxUSE_LOG_DEBUG
char driver[256];
SDL_AudioDriverName(driver, 256);
wxLogTrace(_T("sound"), _T("opened audio, driver '%s'"),
wxString(driver, wxConvLocal).c_str());
#endif
m_audioOpen = true;
return true;
}
else
{
wxString err(SDL_GetError(), wxConvLocal);
wxLogError(_("Couldn't open audio: %s"), err.c_str());
return false;
}
}
return true;
}
void wxSoundBackendSDL::CloseAudio()
{
if (m_audioOpen)
{
SDL_CloseAudio();
wxLogTrace(_T("sound"), _T("closed audio"));
m_audioOpen = false;
}
}
bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
volatile wxSoundPlaybackStatus *WXUNUSED(status))
{
Stop();
int format;
if (data->m_bitsPerSample == 8)
format = AUDIO_U8;
else if (data->m_bitsPerSample == 16)
format = AUDIO_S16LSB;
else
return false;
bool needsOpen = true;
if (m_audioOpen)
{
if (format == m_spec.format &&
m_spec.freq == (int)data->m_samplingRate &&
m_spec.channels == data->m_channels)
{
needsOpen = false;
}
else
{
CloseAudio();
}
}
if (needsOpen)
{
m_spec.format = format;
m_spec.freq = data->m_samplingRate;
m_spec.channels = data->m_channels;
if (!OpenAudio())
return false;
}
SDL_LockAudio();
wxLogTrace(_T("sound"), _T("playing new sound"));
m_playing = true;
m_pos = 0;
m_loop = (flags & wxSOUND_LOOP);
m_data = data;
data->IncRef();
SDL_UnlockAudio();
SDL_PauseAudio(0);
// wait until playback finishes if called in sync mode:
if (!(flags & wxSOUND_ASYNC))
{
wxLogTrace(_T("sound"), _T("waiting for sample to finish"));
while (m_playing && m_data == data)
{
#if wxUSE_THREADS
// give the playback thread a chance to add event to pending
// events queue, release GUI lock temporarily:
if (wxThread::IsMain())
wxMutexGuiLeave();
#endif
wxMilliSleep(10);
#if wxUSE_THREADS
if (wxThread::IsMain())
wxMutexGuiEnter();
#endif
}
wxLogTrace(_T("sound"), _T("sample finished"));
}
return true;
}
void wxSoundBackendSDL::Stop()
{
SDL_LockAudio();
SDL_PauseAudio(1);
m_playing = false;
if (m_data)
{
m_data->DecRef();
m_data = NULL;
}
SDL_UnlockAudio();
}
extern "C" wxSoundBackend *wxCreateSoundBackendSDL()
{
return new wxSoundBackendSDL();
}
#endif // wxUSE_SOUND && wxUSE_LIBSDL

View file

@ -0,0 +1,309 @@
/////////////////////////////////////////////////////////////////////////////
// Name: msw/stackwalk.cpp
// Purpose: wxStackWalker implementation for Unix/glibc
// Author: Vadim Zeitlin
// Modified by:
// Created: 2005-01-18
// RCS-ID: $Id: stackwalk.cpp 43965 2006-12-13 13:04:44Z VZ $
// Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_STACKWALKER
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/app.h"
#include "wx/log.h"
#include "wx/utils.h"
#endif
#include "wx/stackwalk.h"
#include "wx/stdpaths.h"
#include <execinfo.h>
#ifdef HAVE_CXA_DEMANGLE
#include <cxxabi.h>
#endif // HAVE_CXA_DEMANGLE
// ----------------------------------------------------------------------------
// tiny helper wrapper around popen/pclose()
// ----------------------------------------------------------------------------
class wxStdioPipe
{
public:
// ctor parameters are passed to popen()
wxStdioPipe(const char *command, const char *type)
{
m_fp = popen(command, type);
}
// conversion to stdio FILE
operator FILE *() const { return m_fp; }
// dtor closes the pipe
~wxStdioPipe()
{
if ( m_fp )
pclose(m_fp);
}
private:
FILE *m_fp;
DECLARE_NO_COPY_CLASS(wxStdioPipe)
};
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxStackFrame
// ----------------------------------------------------------------------------
void wxStackFrame::OnGetName()
{
if ( !m_name.empty() )
return;
// we already tried addr2line in wxStackWalker::InitFrames: it always
// gives us demangled names (even if __cxa_demangle is not available) when
// the function is part of the ELF (when it's in a shared object addr2line
// will give "??") and because it seems less error-prone.
// when it works, backtrace_symbols() sometimes returns incorrect results
// format is: "module(funcname+offset) [address]" but the part in
// parentheses can be not present
wxString syminfo = wxString::FromAscii(m_syminfo);
const size_t posOpen = syminfo.find(_T('('));
if ( posOpen != wxString::npos )
{
const size_t posPlus = syminfo.find(_T('+'), posOpen + 1);
if ( posPlus != wxString::npos )
{
const size_t posClose = syminfo.find(_T(')'), posPlus + 1);
if ( posClose != wxString::npos )
{
if ( m_name.empty() )
{
m_name.assign(syminfo, posOpen + 1, posPlus - posOpen - 1);
#ifdef HAVE_CXA_DEMANGLE
int rc = -1;
char *cppfunc = __cxxabiv1::__cxa_demangle
(
m_name.mb_str(),
NULL, // output buffer (none, alloc it)
NULL, // [out] len of output buffer
&rc
);
if ( rc == 0 )
m_name = wxString::FromAscii(cppfunc);
free(cppfunc);
#endif // HAVE_CXA_DEMANGLE
}
unsigned long ofs;
if ( wxString(syminfo, posPlus + 1, posClose - posPlus - 1).
ToULong(&ofs, 0) )
m_offset = ofs;
}
}
m_module.assign(syminfo, posOpen);
}
else // not in "module(funcname+offset)" format
{
m_module = syminfo;
}
}
// ----------------------------------------------------------------------------
// wxStackWalker
// ----------------------------------------------------------------------------
// that many frames should be enough for everyone
#define MAX_FRAMES 200
// we need a char buffer big enough to contain a call to addr2line with
// up to MAX_FRAMES addresses !
// NB: %p specifier will print the pointer in hexadecimal form
// and thus will require 2 chars for each byte + 3 for the
// " 0x" prefix
#define CHARS_PER_FRAME (sizeof(void*) * 2 + 3)
// BUFSIZE will be 2250 for 32 bit machines
#define BUFSIZE (50 + MAX_FRAMES*CHARS_PER_FRAME)
// static data
void *wxStackWalker::ms_addresses[MAX_FRAMES];
char **wxStackWalker::ms_symbols = NULL;
int wxStackWalker::m_depth = 0;
wxString wxStackWalker::ms_exepath;
static char g_buf[BUFSIZE];
void wxStackWalker::SaveStack(size_t maxDepth)
{
// read all frames required
maxDepth = wxMin(WXSIZEOF(ms_addresses)/sizeof(void*), maxDepth);
m_depth = backtrace(ms_addresses, maxDepth*sizeof(void*));
if ( !m_depth )
return;
ms_symbols = backtrace_symbols(ms_addresses, m_depth);
}
void wxStackWalker::ProcessFrames(size_t skip)
{
wxStackFrame frames[MAX_FRAMES];
if (!ms_symbols || !m_depth)
return;
// we have 3 more "intermediate" frames which the calling code doesn't know
// about, account for them
skip += 3;
// call addr2line only once since this call may be very slow
// (it has to load in memory the entire EXE of this app which may be quite
// big, especially if it contains debug info and is compiled statically!)
int towalk = InitFrames(frames, m_depth - skip, &ms_addresses[skip], &ms_symbols[skip]);
// now do user-defined operations on each frame
for ( int n = 0; n < towalk - (int)skip; n++ )
OnStackFrame(frames[n]);
}
void wxStackWalker::FreeStack()
{
// ms_symbols has been allocated by backtrace_symbols() and it's the responsibility
// of the caller, i.e. us, to free that pointer
if (ms_symbols)
free( ms_symbols );
ms_symbols = NULL;
m_depth = 0;
}
int wxStackWalker::InitFrames(wxStackFrame *arr, size_t n, void **addresses, char **syminfo)
{
// we need to launch addr2line tool to get this information and we need to
// have the program name for this
wxString exepath = wxStackWalker::GetExePath();
if ( exepath.empty() )
{
exepath = wxStandardPaths::Get().GetExecutablePath();
if ( exepath.empty() )
{
wxLogDebug(wxT("Cannot parse stack frame because the executable ")
wxT("path could not be detected"));
return 0;
}
}
// build the (long) command line for executing addr2line in an optimized way
// (e.g. use always chars, even in Unicode build: popen() always takes chars)
int len = snprintf(g_buf, BUFSIZE, "addr2line -C -f -e \"%s\"", (const char*) exepath.mb_str());
len = (len <= 0) ? strlen(g_buf) : len; // in case snprintf() is broken
for (size_t i=0; i<n; i++)
{
snprintf(&g_buf[len], BUFSIZE - len, " %p", addresses[i]);
len = strlen(g_buf);
}
//wxLogDebug(wxT("piping the command '%s'"), g_buf); // for debug only
wxStdioPipe fp(g_buf, "r");
if ( !fp )
return 0;
// parse addr2line output (should be exactly 2 lines for each address)
// reusing the g_buf used for building the command line above
wxString name, filename;
unsigned long line = 0,
curr = 0;
for ( size_t i = 0; i < n; i++ )
{
// 1st line has function name
if ( fgets(g_buf, WXSIZEOF(g_buf), fp) )
{
name = wxString::FromAscii(g_buf);
name.RemoveLast(); // trailing newline
if ( name == _T("??") )
name.clear();
}
else
{
wxLogDebug(_T("cannot read addr2line output for stack frame #%lu"),
(unsigned long)i);
return false;
}
// 2nd one -- the file/line info
if ( fgets(g_buf, WXSIZEOF(g_buf), fp) )
{
filename = wxString::FromAscii(g_buf);
filename.RemoveLast();
const size_t posColon = filename.find(_T(':'));
if ( posColon != wxString::npos )
{
// parse line number (it's ok if it fails, this will just leave
// line at its current, invalid, 0 value)
wxString(filename, posColon + 1, wxString::npos).ToULong(&line);
// remove line number from 'filename'
filename.erase(posColon);
if ( filename == _T("??") )
filename.clear();
}
else
{
wxLogDebug(_T("Unexpected addr2line format: \"%s\" - ")
_T("the semicolon is missing"),
filename.c_str());
}
}
// now we've got enough info to initialize curr-th stack frame
// (at worst, only addresses[i] and syminfo[i] have been initialized,
// but wxStackFrame::OnGetName may still be able to get function name):
arr[curr++].Set(name, filename, syminfo[i], i, line, addresses[i]);
}
return curr;
}
void wxStackWalker::Walk(size_t skip, size_t maxDepth)
{
// read all frames required
SaveStack(maxDepth);
// process them
ProcessFrames(skip);
// cleanup
FreeStack();
}
#endif // wxUSE_STACKWALKER

View file

@ -0,0 +1,220 @@
///////////////////////////////////////////////////////////////////////////////
// Name: unix/stdpaths.cpp
// Purpose: wxStandardPaths implementation for Unix & OpenVMS systems
// Author: Vadim Zeitlin
// Modified by:
// Created: 2004-10-19
// RCS-ID: $Id: stdpaths.cpp 43443 2006-11-16 13:31:40Z JJ $
// Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org>
// License: wxWindows license
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_STDPATHS
#include "wx/stdpaths.h"
#ifndef WX_PRECOMP
#include "wx/utils.h"
#endif //WX_PRECOMP
#include "wx/filename.h"
#if defined( __LINUX__ ) || defined( __VMS )
#include <unistd.h>
#endif
// ============================================================================
// common VMS/Unix part of wxStandardPaths implementation
// ============================================================================
void wxStandardPaths::SetInstallPrefix(const wxString& prefix)
{
m_prefix = prefix;
}
wxString wxStandardPaths::GetUserConfigDir() const
{
return wxFileName::GetHomeDir();
}
// ============================================================================
// wxStandardPaths implementation for VMS
// ============================================================================
#ifdef __VMS
wxString wxStandardPaths::GetInstallPrefix() const
{
if ( m_prefix.empty() )
{
wx_const_cast(wxStandardPaths *, this)->m_prefix = wxT("/sys$system");
}
return m_prefix;
}
wxString wxStandardPaths::GetConfigDir() const
{
return _T("/sys$manager");
}
wxString wxStandardPaths::GetDataDir() const
{
return AppendAppName(GetInstallPrefix() + _T("/sys$share"));
}
wxString wxStandardPaths::GetLocalDataDir() const
{
return AppendAppName(_T("/sys$manager"));
}
wxString wxStandardPaths::GetUserDataDir() const
{
return wxFileName::GetHomeDir();
}
wxString wxStandardPaths::GetPluginsDir() const
{
return wxString(); // TODO: this is wrong, it should return something
}
wxString
wxStandardPaths::GetLocalizedResourcesDir(const wxChar *lang,
ResourceCat category) const
{
return wxStandardPathsBase::GetLocalizedResourcesDir(lang, category);
}
wxString wxStandardPaths::GetExecutablePath() const
{
return wxStandardPathsBase::GetExecutablePath();
}
#else // !__VMS
// ============================================================================
// wxStandardPaths implementation for Unix
// ============================================================================
wxString wxStandardPaths::GetExecutablePath() const
{
#ifdef __LINUX__
wxString exeStr;
char buf[4096];
int result = readlink("/proc/self/exe", buf, WXSIZEOF(buf) - sizeof(char));
if ( result != -1 )
{
buf[result] = '\0'; // readlink() doesn't NUL-terminate the buffer
// if the /proc/self/exe symlink has been dropped by the kernel for
// some reason, then readlink() could also return success but
// "(deleted)" as link destination...
if ( strcmp(buf, "(deleted)") != 0 )
exeStr = wxString(buf, wxConvLibc);
}
if ( exeStr.empty() )
{
// UPX-specific hack: when using UPX on linux, the kernel will drop the
// /proc/self/exe link; in this case we try to look for a special
// environment variable called " " which is created by UPX to save
// /proc/self/exe contents. See
// http://sf.net/tracker/?func=detail&atid=309863&aid=1565357&group_id=9863
// for more information about this issue.
wxGetEnv(wxT(" "), &exeStr);
}
if ( !exeStr.empty() )
return exeStr;
#endif // __LINUX__
return wxStandardPathsBase::GetExecutablePath();
}
void wxStandardPaths::DetectPrefix()
{
// we can try to infer the prefix from the location of the executable
wxString exeStr = GetExecutablePath();
if ( !exeStr.empty() )
{
// consider that we're in the last "bin" subdirectory of our prefix
size_t pos = exeStr.rfind(wxT("/bin/"));
if ( pos != wxString::npos )
m_prefix.assign(exeStr, 0, pos);
}
if ( m_prefix.empty() )
{
m_prefix = wxT("/usr/local");
}
}
wxString wxStandardPaths::GetInstallPrefix() const
{
if ( m_prefix.empty() )
{
wxStandardPaths *pathPtr = wx_const_cast(wxStandardPaths *, this);
pathPtr->DetectPrefix();
}
return m_prefix;
}
// ----------------------------------------------------------------------------
// public functions
// ----------------------------------------------------------------------------
wxString wxStandardPaths::GetConfigDir() const
{
return _T("/etc");
}
wxString wxStandardPaths::GetDataDir() const
{
return AppendAppName(GetInstallPrefix() + _T("/share"));
}
wxString wxStandardPaths::GetLocalDataDir() const
{
return AppendAppName(_T("/etc"));
}
wxString wxStandardPaths::GetUserDataDir() const
{
return AppendAppName(wxFileName::GetHomeDir() + _T("/."));
}
wxString wxStandardPaths::GetPluginsDir() const
{
return AppendAppName(GetInstallPrefix() + _T("/lib"));
}
wxString
wxStandardPaths::GetLocalizedResourcesDir(const wxChar *lang,
ResourceCat category) const
{
if ( category != ResourceCat_Messages )
return wxStandardPathsBase::GetLocalizedResourcesDir(lang, category);
return GetInstallPrefix() + _T("/share/locale/") + lang + _T("/LC_MESSAGES");
}
#endif // __VMS/!__VMS
#endif // wxUSE_STDPATHS

View file

@ -0,0 +1,346 @@
/////////////////////////////////////////////////////////////////////////
// File: src/unix/taskbarx11.cpp
// Purpose: wxTaskBarIcon class for common Unix desktops
// Author: Vaclav Slavik
// Modified by:
// Created: 04/04/2003
// RCS-ID: $Id: taskbarx11.cpp 53582 2008-05-12 23:54:34Z RD $
// Copyright: (c) Vaclav Slavik, 2003
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////
// NB: This implementation does *not* work with every X11 window manager.
// Currently only GNOME 1.2 and KDE 1,2,3 methods are implemented here.
// Freedesktop.org's System Tray specification is implemented in
// src/gtk/taskbar.cpp and used from here under wxGTK.
//
// Thanks to Ian Campbell, author of XMMS Status Docklet, for publishing
// KDE and GNOME 1.2 methods.
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef wxHAS_TASK_BAR_ICON
#include "wx/taskbar.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/frame.h"
#include "wx/dcclient.h"
#include "wx/statbmp.h"
#include "wx/sizer.h"
#include "wx/bitmap.h"
#include "wx/image.h"
#endif
#ifdef __VMS
#pragma message disable nosimpint
#endif
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#ifdef __VMS
#pragma message enable nosimpint
#endif
// ----------------------------------------------------------------------------
// base class that implements toolkit-specific method:
// ----------------------------------------------------------------------------
#ifdef __WXGTK20__
#include <gtk/gtk.h>
#if GTK_CHECK_VERSION(2,1,0)
#include "wx/gtk/taskbarpriv.h"
#define TASKBAR_ICON_AREA_BASE_INCLUDED
#endif
#endif
#ifndef TASKBAR_ICON_AREA_BASE_INCLUDED
class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxFrame
{
public:
wxTaskBarIconAreaBase()
: wxFrame(NULL, wxID_ANY, _T("systray icon"),
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR |
wxSIMPLE_BORDER | wxFRAME_SHAPED) {}
bool IsProtocolSupported() const { return false; }
};
#endif
// ----------------------------------------------------------------------------
// toolkit dependent methods to set properties on helper window:
// ----------------------------------------------------------------------------
#if defined(__WXGTK__)
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#define GetDisplay() GDK_DISPLAY()
#define GetXWindow(wxwin) GDK_WINDOW_XWINDOW((wxwin)->m_widget->window)
#elif defined(__WXX11__) || defined(__WXMOTIF__)
#include "wx/x11/privx.h"
#define GetDisplay() ((Display*)wxGlobalDisplay())
#define GetXWindow(wxwin) ((Window)(wxwin)->GetHandle())
#else
#error "You must define X11 accessors for this port!"
#endif
// ----------------------------------------------------------------------------
// wxTaskBarIconArea is the real window that shows the icon:
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_ADV wxTaskBarIconArea : public wxTaskBarIconAreaBase
{
public:
wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp);
void SetTrayIcon(const wxBitmap& bmp);
bool IsOk() { return true; }
protected:
void SetLegacyWMProperties();
void OnSizeChange(wxSizeEvent& event);
void OnPaint(wxPaintEvent& evt);
void OnMouseEvent(wxMouseEvent& event);
void OnMenuEvent(wxCommandEvent& event);
wxTaskBarIcon *m_icon;
wxPoint m_pos;
wxBitmap m_bmp;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(wxTaskBarIconArea, wxTaskBarIconAreaBase)
EVT_SIZE(wxTaskBarIconArea::OnSizeChange)
EVT_MOUSE_EVENTS(wxTaskBarIconArea::OnMouseEvent)
EVT_MENU(wxID_ANY, wxTaskBarIconArea::OnMenuEvent)
EVT_PAINT(wxTaskBarIconArea::OnPaint)
END_EVENT_TABLE()
wxTaskBarIconArea::wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp)
: wxTaskBarIconAreaBase(), m_icon(icon), m_pos(0,0)
{
#if defined(__WXGTK20__) && defined(TASKBAR_ICON_AREA_BASE_INCLUDED)
m_invokingWindow = icon;
#endif
// Set initial size to bitmap size (tray manager may and often will
// change it):
SetClientSize(wxSize(bmp.GetWidth(), bmp.GetHeight()));
SetTrayIcon(bmp);
if (!IsProtocolSupported())
{
wxLogTrace(_T("systray"),
_T("using legacy KDE1,2 and GNOME 1.2 methods"));
SetLegacyWMProperties();
}
}
void wxTaskBarIconArea::SetTrayIcon(const wxBitmap& bmp)
{
m_bmp = bmp;
// determine suitable bitmap size:
wxSize winsize(GetClientSize());
wxSize bmpsize(m_bmp.GetWidth(), m_bmp.GetHeight());
wxSize iconsize(wxMin(winsize.x, bmpsize.x), wxMin(winsize.y, bmpsize.y));
// rescale the bitmap to fit into the tray icon window:
if (bmpsize != iconsize)
{
wxImage img = m_bmp.ConvertToImage();
img.Rescale(iconsize.x, iconsize.y);
m_bmp = wxBitmap(img);
}
wxRegion region;
region.Union(m_bmp);
// if the bitmap is smaller than the window, offset it:
if (winsize != iconsize)
{
m_pos.x = (winsize.x - iconsize.x) / 2;
m_pos.y = (winsize.y - iconsize.y) / 2;
region.Offset(m_pos.x, m_pos.y);
}
// set frame's shape to correct value and redraw:
SetShape(region);
Refresh();
}
void wxTaskBarIconArea::SetLegacyWMProperties()
{
#ifdef __WXGTK__
gtk_widget_realize(m_widget);
#endif
long data[1];
// KDE 2 & KDE 3:
Atom _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR =
XInternAtom(GetDisplay(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
data[0] = 0;
XChangeProperty(GetDisplay(), GetXWindow(this),
_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
XA_WINDOW, 32,
PropModeReplace, (unsigned char*)data, 1);
// GNOME 1.2 & KDE 1:
Atom KWM_DOCKWINDOW =
XInternAtom(GetDisplay(), "KWM_DOCKWINDOW", False);
data[0] = 1;
XChangeProperty(GetDisplay(), GetXWindow(this),
KWM_DOCKWINDOW,
KWM_DOCKWINDOW, 32,
PropModeReplace, (unsigned char*)data, 1);
}
void wxTaskBarIconArea::OnSizeChange(wxSizeEvent& WXUNUSED(event))
{
wxLogTrace(_T("systray"), _T("icon size changed to %i x %i"),
GetSize().x, GetSize().y);
// rescale or reposition the icon as needed:
wxBitmap bmp(m_bmp);
SetTrayIcon(bmp);
}
void wxTaskBarIconArea::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc(this);
dc.DrawBitmap(m_bmp, m_pos.x, m_pos.y, true);
}
void wxTaskBarIconArea::OnMouseEvent(wxMouseEvent& event)
{
wxEventType type = 0;
wxEventType mtype = event.GetEventType();
if (mtype == wxEVT_LEFT_DOWN)
type = wxEVT_TASKBAR_LEFT_DOWN;
else if (mtype == wxEVT_LEFT_UP)
type = wxEVT_TASKBAR_LEFT_UP;
else if (mtype == wxEVT_LEFT_DCLICK)
type = wxEVT_TASKBAR_LEFT_DCLICK;
else if (mtype == wxEVT_RIGHT_DOWN)
type = wxEVT_TASKBAR_RIGHT_DOWN;
else if (mtype == wxEVT_RIGHT_UP)
type = wxEVT_TASKBAR_RIGHT_UP;
else if (mtype == wxEVT_RIGHT_DCLICK)
type = wxEVT_TASKBAR_RIGHT_DCLICK;
else if (mtype == wxEVT_MOTION)
type = wxEVT_TASKBAR_MOVE;
else
return;
wxTaskBarIconEvent e(type, m_icon);
m_icon->ProcessEvent(e);
}
void wxTaskBarIconArea::OnMenuEvent(wxCommandEvent& event)
{
m_icon->ProcessEvent(event);
}
// ----------------------------------------------------------------------------
// wxTaskBarIcon class:
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
wxTaskBarIcon::wxTaskBarIcon() : m_iconWnd(NULL)
{
}
wxTaskBarIcon::~wxTaskBarIcon()
{
if (m_iconWnd)
{
m_iconWnd->Disconnect(wxEVT_DESTROY, (wxObjectEventFunction)NULL,
(wxObject*)NULL, this);
RemoveIcon();
}
}
bool wxTaskBarIcon::IsOk() const
{
return true;
}
bool wxTaskBarIcon::IsIconInstalled() const
{
return m_iconWnd != NULL;
}
// Destroy event from wxTaskBarIconArea
void wxTaskBarIcon::OnDestroy(wxWindowDestroyEvent&)
{
// prevent crash if wxTaskBarIconArea is destroyed by something else,
// for example if panel/kicker is killed
m_iconWnd = NULL;
}
bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
{
wxBitmap bmp;
bmp.CopyFromIcon(icon);
if (!m_iconWnd)
{
m_iconWnd = new wxTaskBarIconArea(this, bmp);
if (m_iconWnd->IsOk())
{
m_iconWnd->Connect(wxEVT_DESTROY,
wxWindowDestroyEventHandler(wxTaskBarIcon::OnDestroy),
NULL, this);
m_iconWnd->Show();
}
else
{
m_iconWnd->Destroy();
m_iconWnd = NULL;
return false;
}
}
else
{
m_iconWnd->SetTrayIcon(bmp);
}
#if wxUSE_TOOLTIPS
if (!tooltip.empty())
m_iconWnd->SetToolTip(tooltip);
else
m_iconWnd->SetToolTip(NULL);
#else
wxUnusedVar(tooltip);
#endif
return true;
}
bool wxTaskBarIcon::RemoveIcon()
{
if (!m_iconWnd)
return false;
m_iconWnd->Destroy();
m_iconWnd = NULL;
return true;
}
bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
{
if (!m_iconWnd)
return false;
m_iconWnd->PopupMenu(menu);
return true;
}
#endif // wxHAS_TASK_BAR_ICON

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,847 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/unix/utilsx11.cpp
// Purpose: Miscellaneous X11 functions
// Author: Mattia Barbon, Vaclav Slavik, Robert Roebling
// Modified by:
// Created: 25.03.02
// RCS-ID: $Id: utilsx11.cpp 44895 2007-03-18 17:49:06Z VZ $
// Copyright: (c) wxWidgets team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__)
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/unix/utilsx11.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/app.h"
#include "wx/icon.h"
#include "wx/image.h"
#endif
#include "wx/iconbndl.h"
#ifdef __VMS
#pragma message disable nosimpint
#endif
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#ifdef __VMS
#pragma message enable nosimpint
#endif
#ifdef __WXGTK__
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#endif
// Various X11 Atoms used in this file:
static Atom _NET_WM_ICON = 0;
static Atom _NET_WM_STATE = 0;
static Atom _NET_WM_STATE_FULLSCREEN = 0;
static Atom _NET_WM_STATE_STAYS_ON_TOP = 0;
static Atom _NET_WM_WINDOW_TYPE = 0;
static Atom _NET_WM_WINDOW_TYPE_NORMAL = 0;
static Atom _KDE_NET_WM_WINDOW_TYPE_OVERRIDE = 0;
static Atom _WIN_LAYER = 0;
static Atom KWIN_RUNNING = 0;
#ifndef __WXGTK20__
static Atom _NET_SUPPORTING_WM_CHECK = 0;
static Atom _NET_SUPPORTED = 0;
#endif
#define wxMAKE_ATOM(name, display) \
if (name == 0) name = XInternAtom((display), #name, False)
// X11 Window is an int type, so use the macro to suppress warnings when
// converting to it
#define WindowCast(w) (Window)(wxPtrToUInt(w))
// Is the window mapped?
static bool IsMapped(Display *display, Window window)
{
XWindowAttributes attr;
XGetWindowAttributes(display, window, &attr);
return (attr.map_state != IsUnmapped);
}
// Suspends X11 errors. Used when we expect errors but they are not fatal
// for us.
extern "C"
{
typedef int (*wxX11ErrorHandler)(Display *, XErrorEvent *);
static int wxX11ErrorsSuspender_handler(Display*, XErrorEvent*) { return 0; }
}
class wxX11ErrorsSuspender
{
public:
wxX11ErrorsSuspender(Display *d) : m_display(d)
{
m_old = XSetErrorHandler(wxX11ErrorsSuspender_handler);
}
~wxX11ErrorsSuspender()
{
XFlush(m_display);
XSetErrorHandler(m_old);
}
private:
Display *m_display;
wxX11ErrorHandler m_old;
};
// ----------------------------------------------------------------------------
// Setting icons for window manager:
// ----------------------------------------------------------------------------
void wxSetIconsX11( WXDisplay* display, WXWindow window,
const wxIconBundle& ib )
{
#if !wxUSE_NANOX
size_t size = 0;
size_t i, max = ib.m_icons.GetCount();
for( i = 0; i < max; ++i )
if( ib.m_icons[i].Ok() )
size += 2 + ib.m_icons[i].GetWidth() * ib.m_icons[i].GetHeight();
wxMAKE_ATOM(_NET_WM_ICON, (Display*)display);
if( size > 0 )
{
// The code below is correct for 64-bit machines also.
// wxUint32* data = new wxUint32[size];
// wxUint32* ptr = data;
unsigned long* data = new unsigned long[size];
unsigned long* ptr = data;
for( i = 0; i < max; ++i )
{
const wxImage image = ib.m_icons[i].ConvertToImage();
int width = image.GetWidth(), height = image.GetHeight();
unsigned char* imageData = image.GetData();
unsigned char* imageDataEnd = imageData + ( width * height * 3 );
bool hasMask = image.HasMask();
unsigned char rMask, gMask, bMask;
unsigned char r, g, b, a;
if( hasMask )
{
rMask = image.GetMaskRed();
gMask = image.GetMaskGreen();
bMask = image.GetMaskBlue();
}
else // no mask, but still init the variables to avoid warnings
{
rMask =
gMask =
bMask = 0;
}
*ptr++ = width;
*ptr++ = height;
while( imageData < imageDataEnd ) {
r = imageData[0];
g = imageData[1];
b = imageData[2];
if( hasMask && r == rMask && g == gMask && b == bMask )
a = 0;
else
a = 255;
*ptr++ = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
imageData += 3;
}
}
XChangeProperty( (Display*)display,
WindowCast(window),
_NET_WM_ICON,
XA_CARDINAL, 32,
PropModeReplace,
(unsigned char*)data, size );
delete[] data;
}
else
{
XDeleteProperty( (Display*)display,
WindowCast(window),
_NET_WM_ICON );
}
#endif // !wxUSE_NANOX
}
// ----------------------------------------------------------------------------
// Fullscreen mode:
// ----------------------------------------------------------------------------
// NB: Setting fullscreen mode under X11 is a complicated matter. There was
// no standard way of doing it until recently. ICCCM doesn't know the
// concept of fullscreen windows and the only way to make a window
// fullscreen is to remove decorations, resize it to cover entire screen
// and set WIN_LAYER_ABOVE_DOCK.
//
// This doesn't always work, though. Specifically, at least kwin from
// KDE 3 ignores the hint. The only way to make kwin accept our request
// is to emulate the way Qt does it. That is, unmap the window, set
// _NET_WM_WINDOW_TYPE to _KDE_NET_WM_WINDOW_TYPE_OVERRIDE (KDE extension),
// add _NET_WM_STATE_STAYS_ON_TOP (ditto) to _NET_WM_STATE and map
// the window again.
//
// Version 1.2 of Window Manager Specification (aka wm-spec aka
// Extended Window Manager Hints) introduced _NET_WM_STATE_FULLSCREEN
// window state which provides cleanest and simplest possible way of
// making a window fullscreen. WM-spec is a de-facto standard adopted
// by GNOME and KDE folks, but _NET_WM_STATE_FULLSCREEN isn't yet widely
// supported. As of January 2003, only GNOME 2's default WM Metacity
// implements, KDE will support it from version 3.2. At toolkits level,
// GTK+ >= 2.1.2 uses it as the only method of making windows fullscreen
// (that's why wxGTK will *not* switch to using gtk_window_fullscreen
// unless it has better compatibility with older WMs).
//
//
// This is what wxWidgets does in wxSetFullScreenStateX11:
// 1) if _NET_WM_STATE_FULLSCREEN is supported, use it
// 2) otherwise try WM-specific hacks (KDE, IceWM)
// 3) use _WIN_LAYER and hope that the WM will recognize it
// The code was tested with:
// twm, IceWM, WindowMaker, Metacity, kwin, sawfish, lesstif-mwm
#define WIN_LAYER_NORMAL 4
#define WIN_LAYER_ABOVE_DOCK 10
static void wxWinHintsSetLayer(Display *display, Window rootWnd,
Window window, int layer)
{
wxX11ErrorsSuspender noerrors(display);
XEvent xev;
wxMAKE_ATOM( _WIN_LAYER, display );
if (IsMapped(display, window))
{
xev.type = ClientMessage;
xev.xclient.type = ClientMessage;
xev.xclient.window = window;
xev.xclient.message_type = _WIN_LAYER;
xev.xclient.format = 32;
xev.xclient.data.l[0] = (long)layer;
xev.xclient.data.l[1] = CurrentTime;
XSendEvent(display, rootWnd, False,
SubstructureNotifyMask, (XEvent*) &xev);
}
else
{
long data[1];
data[0] = layer;
XChangeProperty(display, window,
_WIN_LAYER, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)data, 1);
}
}
#ifdef __WXGTK20__
static bool wxQueryWMspecSupport(Display* WXUNUSED(display),
Window WXUNUSED(rootWnd),
Atom (feature))
{
GdkAtom gatom = gdk_x11_xatom_to_atom(feature);
return gdk_net_wm_supports(gatom);
}
#else
static bool wxQueryWMspecSupport(Display *display, Window rootWnd, Atom feature)
{
wxMAKE_ATOM(_NET_SUPPORTING_WM_CHECK, display);
wxMAKE_ATOM(_NET_SUPPORTED, display);
// FIXME: We may want to cache these checks. Note that we can't simply
// remember the results in global variable because the WM may go
// away and be replaced by another one! One possible approach
// would be invalidate the case every 15 seconds or so. Since this
// code is currently only used by wxTopLevelWindow::ShowFullScreen,
// it is not important that it is not optimized.
//
// If the WM supports ICCCM (i.e. the root window has
// _NET_SUPPORTING_WM_CHECK property that points to a WM-owned
// window), we could watch for DestroyNotify event on the window
// and invalidate our cache when the windows goes away (= WM
// is replaced by another one). This is what GTK+ 2 does.
// Let's do it only if it is needed, it requires changes to
// the event loop.
Atom type;
Window *wins;
Atom *atoms;
int format;
unsigned long after;
unsigned long nwins, natoms;
// Is the WM ICCCM supporting?
XGetWindowProperty(display, rootWnd,
_NET_SUPPORTING_WM_CHECK, 0, LONG_MAX,
False, XA_WINDOW, &type, &format, &nwins,
&after, (unsigned char **)&wins);
if ( type != XA_WINDOW || nwins <= 0 || wins[0] == None )
return false;
XFree(wins);
// Query for supported features:
XGetWindowProperty(display, rootWnd,
_NET_SUPPORTED, 0, LONG_MAX,
False, XA_ATOM, &type, &format, &natoms,
&after, (unsigned char **)&atoms);
if ( type != XA_ATOM || atoms == NULL )
return false;
// Lookup the feature we want:
for (unsigned i = 0; i < natoms; i++)
{
if ( atoms[i] == feature )
{
XFree(atoms);
return true;
}
}
XFree(atoms);
return false;
}
#endif
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
static void wxWMspecSetState(Display *display, Window rootWnd,
Window window, int operation, Atom state)
{
wxMAKE_ATOM(_NET_WM_STATE, display);
if ( IsMapped(display, window) )
{
XEvent xev;
xev.type = ClientMessage;
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.display = display;
xev.xclient.window = window;
xev.xclient.message_type = _NET_WM_STATE;
xev.xclient.format = 32;
xev.xclient.data.l[0] = operation;
xev.xclient.data.l[1] = state;
xev.xclient.data.l[2] = None;
XSendEvent(display, rootWnd,
False,
SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
}
// FIXME - must modify _NET_WM_STATE property list if the window
// wasn't mapped!
}
static void wxWMspecSetFullscreen(Display *display, Window rootWnd,
Window window, bool fullscreen)
{
wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN, display);
wxWMspecSetState(display, rootWnd,
window,
fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
_NET_WM_STATE_FULLSCREEN);
}
// Is the user running KDE's kwin window manager? At least kwin from KDE 3
// sets KWIN_RUNNING property on the root window.
static bool wxKwinRunning(Display *display, Window rootWnd)
{
wxMAKE_ATOM(KWIN_RUNNING, display);
long *data;
Atom type;
int format;
unsigned long nitems, after;
if (XGetWindowProperty(display, rootWnd,
KWIN_RUNNING, 0, 1, False, KWIN_RUNNING,
&type, &format, &nitems, &after,
(unsigned char**)&data) != Success)
{
return false;
}
bool retval = (type == KWIN_RUNNING &&
nitems == 1 && data && data[0] == 1);
XFree(data);
return retval;
}
// KDE's kwin is Qt-centric so much than no normal method of fullscreen
// mode will work with it. We have to carefully emulate the Qt way.
static void wxSetKDEFullscreen(Display *display, Window rootWnd,
Window w, bool fullscreen, wxRect *origRect)
{
long data[2];
unsigned lng;
wxMAKE_ATOM(_NET_WM_WINDOW_TYPE, display);
wxMAKE_ATOM(_NET_WM_WINDOW_TYPE_NORMAL, display);
wxMAKE_ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE, display);
wxMAKE_ATOM(_NET_WM_STATE_STAYS_ON_TOP, display);
if (fullscreen)
{
data[0] = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE;
data[1] = _NET_WM_WINDOW_TYPE_NORMAL;
lng = 2;
}
else
{
data[0] = _NET_WM_WINDOW_TYPE_NORMAL;
data[1] = None;
lng = 1;
}
// it is necessary to unmap the window, otherwise kwin will ignore us:
XSync(display, False);
bool wasMapped = IsMapped(display, w);
if (wasMapped)
{
XUnmapWindow(display, w);
XSync(display, False);
}
XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
PropModeReplace, (unsigned char *) &data[0], lng);
XSync(display, False);
if (wasMapped)
{
XMapRaised(display, w);
XSync(display, False);
}
wxWMspecSetState(display, rootWnd, w,
fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
_NET_WM_STATE_STAYS_ON_TOP);
XSync(display, False);
if (!fullscreen)
{
// NB: like many other WMs, kwin ignores the first request for a window
// position change after the window was mapped. This additional
// move+resize event will ensure that the window is restored in
// exactly the same position as before it was made fullscreen
// (because wxTopLevelWindow::ShowFullScreen will call SetSize, thus
// setting the position for the second time).
XMoveResizeWindow(display, w,
origRect->x, origRect->y,
origRect->width, origRect->height);
XSync(display, False);
}
}
wxX11FullScreenMethod wxGetFullScreenMethodX11(WXDisplay* display,
WXWindow rootWindow)
{
Window root = WindowCast(rootWindow);
Display *disp = (Display*)display;
// if WM supports _NET_WM_STATE_FULLSCREEN from wm-spec 1.2, use it:
wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN, disp);
if (wxQueryWMspecSupport(disp, root, _NET_WM_STATE_FULLSCREEN))
{
wxLogTrace(_T("fullscreen"),
_T("detected _NET_WM_STATE_FULLSCREEN support"));
return wxX11_FS_WMSPEC;
}
// if the user is running KDE's kwin WM, use a legacy hack because
// kwin doesn't understand any other method:
if (wxKwinRunning(disp, root))
{
wxLogTrace(_T("fullscreen"), _T("detected kwin"));
return wxX11_FS_KDE;
}
// finally, fall back to ICCCM heuristic method:
wxLogTrace(_T("fullscreen"), _T("unknown WM, using _WIN_LAYER"));
return wxX11_FS_GENERIC;
}
void wxSetFullScreenStateX11(WXDisplay* display, WXWindow rootWindow,
WXWindow window, bool show,
wxRect *origRect,
wxX11FullScreenMethod method)
{
// NB: please see the comment under "Fullscreen mode:" title above
// for implications of changing this code.
Window wnd = WindowCast(window);
Window root = WindowCast(rootWindow);
Display *disp = (Display*)display;
if (method == wxX11_FS_AUTODETECT)
method = wxGetFullScreenMethodX11(display, rootWindow);
switch (method)
{
case wxX11_FS_WMSPEC:
wxWMspecSetFullscreen(disp, root, wnd, show);
break;
case wxX11_FS_KDE:
wxSetKDEFullscreen(disp, root, wnd, show, origRect);
break;
default:
wxWinHintsSetLayer(disp, root, wnd,
show ? WIN_LAYER_ABOVE_DOCK : WIN_LAYER_NORMAL);
break;
}
}
// ----------------------------------------------------------------------------
// keycode translations
// ----------------------------------------------------------------------------
#include <X11/keysym.h>
// FIXME what about tables??
int wxCharCodeXToWX(KeySym keySym)
{
int id;
switch (keySym)
{
case XK_Shift_L:
case XK_Shift_R:
id = WXK_SHIFT; break;
case XK_Control_L:
case XK_Control_R:
id = WXK_CONTROL; break;
case XK_Meta_L:
case XK_Meta_R:
id = WXK_ALT; break;
case XK_Caps_Lock:
id = WXK_CAPITAL; break;
case XK_BackSpace:
id = WXK_BACK; break;
case XK_Delete:
id = WXK_DELETE; break;
case XK_Clear:
id = WXK_CLEAR; break;
case XK_Tab:
id = WXK_TAB; break;
case XK_numbersign:
id = '#'; break;
case XK_Return:
id = WXK_RETURN; break;
case XK_Escape:
id = WXK_ESCAPE; break;
case XK_Pause:
case XK_Break:
id = WXK_PAUSE; break;
case XK_Num_Lock:
id = WXK_NUMLOCK; break;
case XK_Scroll_Lock:
id = WXK_SCROLL; break;
case XK_Home:
id = WXK_HOME; break;
case XK_End:
id = WXK_END; break;
case XK_Left:
id = WXK_LEFT; break;
case XK_Right:
id = WXK_RIGHT; break;
case XK_Up:
id = WXK_UP; break;
case XK_Down:
id = WXK_DOWN; break;
case XK_Next:
id = WXK_PAGEDOWN; break;
case XK_Prior:
id = WXK_PAGEUP; break;
case XK_Menu:
id = WXK_MENU; break;
case XK_Select:
id = WXK_SELECT; break;
case XK_Cancel:
id = WXK_CANCEL; break;
case XK_Print:
id = WXK_PRINT; break;
case XK_Execute:
id = WXK_EXECUTE; break;
case XK_Insert:
id = WXK_INSERT; break;
case XK_Help:
id = WXK_HELP; break;
case XK_KP_Multiply:
id = WXK_NUMPAD_MULTIPLY; break;
case XK_KP_Add:
id = WXK_NUMPAD_ADD; break;
case XK_KP_Subtract:
id = WXK_NUMPAD_SUBTRACT; break;
case XK_KP_Divide:
id = WXK_NUMPAD_DIVIDE; break;
case XK_KP_Decimal:
id = WXK_NUMPAD_DECIMAL; break;
case XK_KP_Equal:
id = WXK_NUMPAD_EQUAL; break;
case XK_KP_Space:
id = WXK_NUMPAD_SPACE; break;
case XK_KP_Tab:
id = WXK_NUMPAD_TAB; break;
case XK_KP_Enter:
id = WXK_NUMPAD_ENTER; break;
case XK_KP_0:
id = WXK_NUMPAD0; break;
case XK_KP_1:
id = WXK_NUMPAD1; break;
case XK_KP_2:
id = WXK_NUMPAD2; break;
case XK_KP_3:
id = WXK_NUMPAD3; break;
case XK_KP_4:
id = WXK_NUMPAD4; break;
case XK_KP_5:
id = WXK_NUMPAD5; break;
case XK_KP_6:
id = WXK_NUMPAD6; break;
case XK_KP_7:
id = WXK_NUMPAD7; break;
case XK_KP_8:
id = WXK_NUMPAD8; break;
case XK_KP_9:
id = WXK_NUMPAD9; break;
case XK_KP_Insert:
id = WXK_NUMPAD_INSERT; break;
case XK_KP_End:
id = WXK_NUMPAD_END; break;
case XK_KP_Down:
id = WXK_NUMPAD_DOWN; break;
case XK_KP_Page_Down:
id = WXK_NUMPAD_PAGEDOWN; break;
case XK_KP_Left:
id = WXK_NUMPAD_LEFT; break;
case XK_KP_Right:
id = WXK_NUMPAD_RIGHT; break;
case XK_KP_Home:
id = WXK_NUMPAD_HOME; break;
case XK_KP_Up:
id = WXK_NUMPAD_UP; break;
case XK_KP_Page_Up:
id = WXK_NUMPAD_PAGEUP; break;
case XK_F1:
id = WXK_F1; break;
case XK_F2:
id = WXK_F2; break;
case XK_F3:
id = WXK_F3; break;
case XK_F4:
id = WXK_F4; break;
case XK_F5:
id = WXK_F5; break;
case XK_F6:
id = WXK_F6; break;
case XK_F7:
id = WXK_F7; break;
case XK_F8:
id = WXK_F8; break;
case XK_F9:
id = WXK_F9; break;
case XK_F10:
id = WXK_F10; break;
case XK_F11:
id = WXK_F11; break;
case XK_F12:
id = WXK_F12; break;
case XK_F13:
id = WXK_F13; break;
case XK_F14:
id = WXK_F14; break;
case XK_F15:
id = WXK_F15; break;
case XK_F16:
id = WXK_F16; break;
case XK_F17:
id = WXK_F17; break;
case XK_F18:
id = WXK_F18; break;
case XK_F19:
id = WXK_F19; break;
case XK_F20:
id = WXK_F20; break;
case XK_F21:
id = WXK_F21; break;
case XK_F22:
id = WXK_F22; break;
case XK_F23:
id = WXK_F23; break;
case XK_F24:
id = WXK_F24; break;
default:
id = (keySym <= 255) ? (int)keySym : -1;
}
return id;
}
KeySym wxCharCodeWXToX(int id)
{
KeySym keySym;
switch (id)
{
case WXK_CANCEL: keySym = XK_Cancel; break;
case WXK_BACK: keySym = XK_BackSpace; break;
case WXK_TAB: keySym = XK_Tab; break;
case WXK_CLEAR: keySym = XK_Clear; break;
case WXK_RETURN: keySym = XK_Return; break;
case WXK_SHIFT: keySym = XK_Shift_L; break;
case WXK_CONTROL: keySym = XK_Control_L; break;
case WXK_ALT: keySym = XK_Meta_L; break;
case WXK_CAPITAL: keySym = XK_Caps_Lock; break;
case WXK_MENU : keySym = XK_Menu; break;
case WXK_PAUSE: keySym = XK_Pause; break;
case WXK_ESCAPE: keySym = XK_Escape; break;
case WXK_SPACE: keySym = ' '; break;
case WXK_PAGEUP: keySym = XK_Prior; break;
case WXK_PAGEDOWN: keySym = XK_Next; break;
case WXK_END: keySym = XK_End; break;
case WXK_HOME : keySym = XK_Home; break;
case WXK_LEFT : keySym = XK_Left; break;
case WXK_UP: keySym = XK_Up; break;
case WXK_RIGHT: keySym = XK_Right; break;
case WXK_DOWN : keySym = XK_Down; break;
case WXK_SELECT: keySym = XK_Select; break;
case WXK_PRINT: keySym = XK_Print; break;
case WXK_EXECUTE: keySym = XK_Execute; break;
case WXK_INSERT: keySym = XK_Insert; break;
case WXK_DELETE: keySym = XK_Delete; break;
case WXK_HELP : keySym = XK_Help; break;
case WXK_NUMPAD0: keySym = XK_KP_0; break; case WXK_NUMPAD_INSERT: keySym = XK_KP_Insert; break;
case WXK_NUMPAD1: keySym = XK_KP_1; break; case WXK_NUMPAD_END: keySym = XK_KP_End; break;
case WXK_NUMPAD2: keySym = XK_KP_2; break; case WXK_NUMPAD_DOWN: keySym = XK_KP_Down; break;
case WXK_NUMPAD3: keySym = XK_KP_3; break; case WXK_NUMPAD_PAGEDOWN: keySym = XK_KP_Page_Down; break;
case WXK_NUMPAD4: keySym = XK_KP_4; break; case WXK_NUMPAD_LEFT: keySym = XK_KP_Left; break;
case WXK_NUMPAD5: keySym = XK_KP_5; break;
case WXK_NUMPAD6: keySym = XK_KP_6; break; case WXK_NUMPAD_RIGHT: keySym = XK_KP_Right; break;
case WXK_NUMPAD7: keySym = XK_KP_7; break; case WXK_NUMPAD_HOME: keySym = XK_KP_Home; break;
case WXK_NUMPAD8: keySym = XK_KP_8; break; case WXK_NUMPAD_UP: keySym = XK_KP_Up; break;
case WXK_NUMPAD9: keySym = XK_KP_9; break; case WXK_NUMPAD_PAGEUP: keySym = XK_KP_Page_Up; break;
case WXK_NUMPAD_DECIMAL: keySym = XK_KP_Decimal; break; case WXK_NUMPAD_DELETE: keySym = XK_KP_Delete; break;
case WXK_NUMPAD_MULTIPLY: keySym = XK_KP_Multiply; break;
case WXK_NUMPAD_ADD: keySym = XK_KP_Add; break;
case WXK_NUMPAD_SUBTRACT: keySym = XK_KP_Subtract; break;
case WXK_NUMPAD_DIVIDE: keySym = XK_KP_Divide; break;
case WXK_NUMPAD_ENTER: keySym = XK_KP_Enter; break;
case WXK_NUMPAD_SEPARATOR: keySym = XK_KP_Separator; break;
case WXK_F1: keySym = XK_F1; break;
case WXK_F2: keySym = XK_F2; break;
case WXK_F3: keySym = XK_F3; break;
case WXK_F4: keySym = XK_F4; break;
case WXK_F5: keySym = XK_F5; break;
case WXK_F6: keySym = XK_F6; break;
case WXK_F7: keySym = XK_F7; break;
case WXK_F8: keySym = XK_F8; break;
case WXK_F9: keySym = XK_F9; break;
case WXK_F10: keySym = XK_F10; break;
case WXK_F11: keySym = XK_F11; break;
case WXK_F12: keySym = XK_F12; break;
case WXK_F13: keySym = XK_F13; break;
case WXK_F14: keySym = XK_F14; break;
case WXK_F15: keySym = XK_F15; break;
case WXK_F16: keySym = XK_F16; break;
case WXK_F17: keySym = XK_F17; break;
case WXK_F18: keySym = XK_F18; break;
case WXK_F19: keySym = XK_F19; break;
case WXK_F20: keySym = XK_F20; break;
case WXK_F21: keySym = XK_F21; break;
case WXK_F22: keySym = XK_F22; break;
case WXK_F23: keySym = XK_F23; break;
case WXK_F24: keySym = XK_F24; break;
case WXK_NUMLOCK: keySym = XK_Num_Lock; break;
case WXK_SCROLL: keySym = XK_Scroll_Lock; break;
default: keySym = id <= 255 ? (KeySym)id : 0;
}
return keySym;
}
// ----------------------------------------------------------------------------
// check current state of a key
// ----------------------------------------------------------------------------
bool wxGetKeyState(wxKeyCode key)
{
wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
Display *pDisplay = (Display*) wxGetDisplay();
int iKey = wxCharCodeWXToX(key);
int iKeyMask = 0;
Window wDummy1, wDummy2;
int iDummy3, iDummy4, iDummy5, iDummy6;
unsigned int iMask;
KeyCode keyCode = XKeysymToKeycode(pDisplay,iKey);
if (keyCode == NoSymbol)
return false;
if ( IsModifierKey(iKey) ) // If iKey is a modifier key, use a different method
{
XModifierKeymap *map = XGetModifierMapping(pDisplay);
wxCHECK_MSG( map, false, _T("failed to get X11 modifiers map") );
for (int i = 0; i < 8; ++i)
{
if ( map->modifiermap[map->max_keypermod * i] == keyCode)
{
iKeyMask = 1 << i;
}
}
XQueryPointer(pDisplay, DefaultRootWindow(pDisplay), &wDummy1, &wDummy2,
&iDummy3, &iDummy4, &iDummy5, &iDummy6, &iMask );
XFreeModifiermap(map);
return (iMask & iKeyMask) != 0;
}
// From the XLib manual:
// The XQueryKeymap() function returns a bit vector for the logical state of the keyboard,
// where each bit set to 1 indicates that the corresponding key is currently pressed down.
// The vector is represented as 32 bytes. Byte N (from 0) contains the bits for keys 8N to 8N + 7
// with the least-significant bit in the byte representing key 8N.
char key_vector[32];
XQueryKeymap(pDisplay, key_vector);
return key_vector[keyCode >> 3] & (1 << (keyCode & 7));
}
#endif // __WXX11__ || __WXGTK__ || __WXMOTIF__