From: Stefan Csomor Date: Thu, 10 Aug 2000 04:43:04 +0000 (+0000) Subject: wxMac merge X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/ee6b1d97e741fda8d579fa21cbc89f0c91615cef?hp=6342bd1ab36c1957684c00d408d09fba65d33db6 wxMac merge git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@7999 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/mac/gsockmac.h b/include/wx/mac/gsockmac.h new file mode 100644 index 0000000000..4ffdc1266a --- /dev/null +++ b/include/wx/mac/gsockmac.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------------- + * Project: GSocket (Generic Socket) for WX + * Name: gsockunx.h + * Purpose: GSocket Macintosh header + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +#ifndef __GSOCK_UNX_H +#define __GSOCK_UNX_H + +#ifndef __GSOCKET_STANDALONE__ +#include "wx/setup.h" +#endif + +#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) + +#ifndef __GSOCKET_STANDALONE__ +#include "wx/gsocket.h" +#else +#include "gsocket.h" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef GSocket* GSocketPtr ; + +/* Definition of GSocket */ +struct _GSocket +{ + wxMacNotifierTableRef m_mac_events ; + EndpointRef m_endpoint; + GAddress *m_local; + GAddress *m_peer; + GSocketError m_error; + + int m_non_blocking; + int m_server; + int m_stream; + int m_oriented; + unsigned long m_timeout; + + /* Callbacks */ + GSocketEventFlags m_detected; + GSocketCallback m_cbacks[GSOCK_MAX_EVENT]; + char *m_data[GSOCK_MAX_EVENT]; + int m_takesEvents ; +}; + +/* Definition of GAddress */ + +struct _GAddress +{ + UInt32 m_host ; + UInt16 m_port ; + GAddressType m_family; + GSocketError m_error; +}; + +/* Input / Output */ + +GSocketError _GSocket_Input_Timeout(GSocket *socket); +GSocketError _GSocket_Output_Timeout(GSocket *socket); +int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size); +int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size); +int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size); +int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size); + +/* Callbacks */ + +void _GSocket_Enable_Events(GSocket *socket); +void _GSocket_Disable_Events(GSocket *socket); +void _GSocket_Internal_Proc(unsigned long e , void* data ) ; + +/* GAddress */ + +GSocketError _GAddress_translate_from(GAddress *address, + InetAddress *addr ); +GSocketError _GAddress_translate_to(GAddress *address, + InetAddress *addr); + +GSocketError _GAddress_Init_INET(GAddress *address); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ + +#endif /* __GSOCK_UNX_H */ diff --git a/include/wx/mac/macnotfy.h b/include/wx/mac/macnotfy.h new file mode 100644 index 0000000000..ae8a24e6de --- /dev/null +++ b/include/wx/mac/macnotfy.h @@ -0,0 +1,33 @@ +/* ------------------------------------------------------------------------- + * Project: Mac Notifier Support + * Name: macnotfy.h + * Author: Stefan CSomor + * Purpose: Mac Notifier include file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +#ifndef MAC_NOTIFYERS +#define MAC_NOTIFYERS + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef void (*wxMacNotificationProcPtr)(unsigned long event , void* data ) ; + +typedef void *wxMacNotifierTableRef ; +void wxMacCreateNotifierTable() ; +void wxMacDestroyNotifierTable() ; +wxMacNotifierTableRef wxMacGetNotifierTable() ; +void wxMacAddEvent( wxMacNotifierTableRef table , wxMacNotificationProcPtr handler , unsigned long event , void* data , short wakeUp ) ; +void wxMacWakeUp() ; +void wxMacProcessNotifierEvents() ; +void wxMacProcessNotifierAndPendingEvents() ; +void wxMacRemoveAllNotifiersForData( wxMacNotifierTableRef table , void* data ) ; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MAC_NOTIFYERS */ \ No newline at end of file diff --git a/src/mac/carbon/fontenum.cpp b/src/mac/carbon/fontenum.cpp new file mode 100644 index 0000000000..f296efd93c --- /dev/null +++ b/src/mac/carbon/fontenum.cpp @@ -0,0 +1,166 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: mac/fontenum.cpp +// Purpose: wxFontEnumerator class for MacOS +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "fontenum.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/font.h" +#endif + +#include "wx/fontenum.h" +#include "wx/fontmap.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxFontEnumeratorHelper +{ +public: + wxFontEnumeratorHelper(wxFontEnumerator *fontEnum); + + // control what exactly are we enumerating + bool SetEncoding(wxFontEncoding encoding); + void SetFixedOnly(bool fixedOnly) + { m_fixedOnly = fixedOnly; } + + // call to start enumeration + void DoEnumerate(); + +private: + // the object we forward calls to OnFont() to + wxFontEnumerator *m_fontEnum; + + // if != -1, enum only fonts which have this encoding + int m_charset; + + // if not empty, enum only the fonts with this facename + wxString m_facename; + + // if TRUE, enum only fixed fonts + bool m_fixedOnly; +}; +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFontEnumeratorHelper +// ---------------------------------------------------------------------------- + +wxFontEnumeratorHelper::wxFontEnumeratorHelper(wxFontEnumerator *fontEnum) +{ + m_fontEnum = fontEnum; + m_charset = -1; + m_fixedOnly = FALSE; +} + +bool wxFontEnumeratorHelper::SetEncoding(wxFontEncoding encoding) +{ + wxNativeEncodingInfo info; + if ( !wxGetNativeFontEncoding(encoding, &info) ) + { + if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) ) + { + // no such encodings at all + return FALSE; + } + } + m_charset = info.charset; + m_facename = info.facename; + + return TRUE; +} + +void wxFontEnumeratorHelper::DoEnumerate() +{ + MenuHandle menu ; + Str255 name ; + short lines ; + + menu = NewMenu( 32000 , "\pFont" ) ; + AppendResMenu( menu , 'FONT' ) ; + lines = CountMenuItems( menu ) ; + + for ( int i = 1 ; i < lines+1 ; i ++ ) + { + GetMenuItemText( menu , i , name ) ; + p2cstr( name ) ; + /* + + if ( m_fixedOnly ) + { + // check that it's a fixed pitch font (there is *no* error here, the + // flag name is misleading!) + if ( tm->tmPitchAndFamily & TMPF_FIXED_PITCH ) + { + // not a fixed pitch font + return TRUE; + } + } + + if ( m_charset != -1 ) + { + // check that we have the right encoding + if ( lf->lfCharSet != m_charset ) + { + return TRUE; + } + } + + */ + m_fontEnum->OnFacename( name ) ; + } + DisposeMenu( menu ) ; +} + +// ---------------------------------------------------------------------------- +// wxFontEnumerator +// ---------------------------------------------------------------------------- + +bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding, + bool fixedWidthOnly) +{ + wxFontEnumeratorHelper fe(this); + if ( fe.SetEncoding(encoding) ) + { + fe.SetFixedOnly(fixedWidthOnly); + + fe.DoEnumerate(); + } + // else: no such fonts, unknown encoding + + return TRUE; +} + +bool wxFontEnumerator::EnumerateEncodings(const wxString& family) +{ + wxFAIL_MSG(wxT("TODO")); + + return TRUE; +} diff --git a/src/mac/carbon/gsocket.c b/src/mac/carbon/gsocket.c new file mode 100644 index 0000000000..5b36717505 --- /dev/null +++ b/src/mac/carbon/gsocket.c @@ -0,0 +1,1593 @@ +/* ------------------------------------------------------------------------- + * Project: GSocket (Generic Socket) for WX + * Name: gsocket.c + * Authors: Guilhem Lavaux, + * Guillermo Rodriguez Garcia (maintainer) + * Stefan CSomor + * Purpose: GSocket main mac file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +/* + * PLEASE don't put C++ comments here - this is a C source file. + */ + +#ifndef __GSOCKET_STANDALONE__ +#include "wx/setup.h" +#endif + +#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) + +#include +#include +#include +#include +#include +#include +#include +#include +#define OTUNIXERRORS 1 +#include +#include +#include +#if TARGET_CARBON + #define OTAssert( str , cond ) /* does not exists in Carbon */ +#endif +#include + +/* + * INADDR_BROADCAST is identical to INADDR_NONE which is not defined + * on all unices. INADDR_BROADCAST should be fine to indicate an error. + */ +#ifndef INADDR_BROADCAST +#define INADDR_BROADCAST 0xFFFFFFFFUL +#endif +#ifndef INADDR_NONE +#define INADDR_NONE INADDR_BROADCAST +#endif +#ifndef INADDR_ANY +#define INADDR_ANY 0x0UL +#endif +#ifndef __GSOCKET_STANDALONE__ + +#include "wx/mac/macnotfy.h" +#include "wx/mac/gsockmac.h" +#include "wx/gsocket.h" + +#else + +#include "gsockmac.h" +#include "gsocket.h" + +#endif /* __GSOCKET_STANDALONE__ */ + +void wxCYield() ; +#ifdef __WXDEBUG__ +#define qDebug 1 +#define qDebug2 1 +extern pascal void OTDebugStr(const char* str); +#endif +#include +InetSvcRef gInetSvcRef = 0 ; + + +OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode); + +/* Input: ep - endpointref on which to negotiate the option + enableReuseIPMode - desired option setting - true/false + Return: kOTNoError indicates that the option was successfully negotiated + OSStatus is an error if < 0, otherwise, the status field is + returned and is > 0. + + IMPORTANT NOTE: The endpoint is assumed to be in synchronous more, otherwise + this code will not function as desired +*/ + + +OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode) + +{ + UInt8 buf[kOTFourByteOptionSize]; // define buffer for fourByte Option size + TOption* opt; // option ptr to make items easier to access + TOptMgmt req; + TOptMgmt ret; + OSStatus err; + + if (!OTIsSynchronous(ep)) + { + return (-1); + } + opt = (TOption*)buf; // set option ptr to buffer + req.opt.buf = buf; + req.opt.len = sizeof(buf); + req.flags = T_NEGOTIATE; // negotiate for option + + ret.opt.buf = buf; + ret.opt.maxlen = kOTFourByteOptionSize; + + opt->level = INET_IP; // dealing with an IP Level function + opt->name = IP_REUSEADDR; + opt->len = kOTFourByteOptionSize; + opt->status = 0; + *(UInt32*)opt->value = enableReuseIPMode; // set the desired option level, true or false + + err = OTOptionManagement(ep, &req, &ret); + + // if no error then return the option status value + if (err == kOTNoError) + { + if (opt->status != T_SUCCESS) + err = opt->status; + else + err = kOTNoError; + } + + return err; +} + + +pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult, void *cookie) ; +pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult result, void *cookie) +{ + int wakeUp = true ; + GSocket* sock = (GSocket*) s ; + + if ( event == kOTSyncIdleEvent ) + { + YieldToAnyThread() ; + return ; + } + + if ( s ) + { + wxMacAddEvent( sock->m_mac_events , _GSocket_Internal_Proc , event , s , wakeUp ) ; + } + + return; +} + +static void SetDefaultEndpointModes(EndpointRef ep , void *data ) + // This routine sets the supplied endpoint into the default + // mode used in this application. The specifics are: + // blocking, synchronous, and using synch idle events with + // the standard YieldingNotifier. +{ + OSStatus junk = kOTNoError ; + OTAssert ("SetDefaultEndpointModes:invalid ref", ep != kOTInvalidEndpointRef ) ; + junk = OTSetAsynchronous(ep); + OTAssert("SetDefaultEndpointModes: Could not set asynchronous", junk == noErr); +/* + junk = OTSetBlocking(ep); + OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); + junk = OTSetSynchronous(ep); + OTAssert("SetDefaultEndpointModes: Could not set synchronous", junk == noErr); + junk = OTSetBlocking(ep); + OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); +*/ + junk = OTInstallNotifier(ep, OTInetEventHandler, data); + OTAssert("SetDefaultEndpointModes: Could not install notifier", junk == noErr); +/* + junk = OTUseSyncIdleEvents(ep, true); + OTAssert("SetDefaultEndpointModes: Could not use sync idle events", junk == noErr); +*/ +} + +/* Global initialisers */ + +int GSocket_Init() +{ + OSStatus err ; +#if TARGET_CARBON + InitOpenTransportInContext( kInitOTForApplicationMask , NULL ) ; +#else + InitOpenTransport() ; +#endif + gInetSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &err); + if ( gInetSvcRef == NULL || err != kOTNoError ) + { + OTAssert("Could not open Inet Services", err == noErr); + return FALSE ; + } + return TRUE; +} + +void GSocket_Cleanup() +{ + if ( gInetSvcRef != NULL ) + OTCloseProvider( gInetSvcRef ); +#if TARGET_CARBON + CloseOpenTransportInContext( NULL ) ; +#else + CloseOpenTransport() ; +#endif +} + +/* Constructors / Destructors for GSocket */ + +GSocket *GSocket_new() +{ + int i; + GSocket *socket; + + socket = (GSocket *)malloc(sizeof(GSocket)); + + if (socket == NULL) + return NULL; + + socket->m_endpoint = NULL ; + for (i=0;im_cbacks[i] = NULL; + } + socket->m_detected = 0; + socket->m_local = NULL; + socket->m_peer = NULL; + socket->m_error = GSOCK_NOERROR; + socket->m_server = FALSE; + socket->m_stream = TRUE; + socket->m_non_blocking = FALSE; + socket->m_timeout = 10*60*1000; + /* 10 minutes * 60 sec * 1000 millisec */ + socket->m_takesEvents = TRUE ; + socket->m_mac_events = wxMacGetNotifierTable() ; + return socket; +} + +void GSocket_destroy(GSocket *socket) +{ + assert(socket != NULL); + + /* Check that the socket is really shutdowned */ + if (socket->m_endpoint != kOTInvalidEndpointRef) + GSocket_Shutdown(socket); + + + /* Destroy private addresses */ + if (socket->m_local) + GAddress_destroy(socket->m_local); + + if (socket->m_peer) + GAddress_destroy(socket->m_peer); + + /* Destroy the socket itself */ + free(socket); +} + +/* GSocket_Shutdown: + * Disallow further read/write operations on this socket, close + * the fd and disable all callbacks. + */ +void GSocket_Shutdown(GSocket *socket) +{ + OSStatus err ; + int evt; + + assert(socket != NULL); + + /* If socket has been created, shutdown it */ + if (socket->m_endpoint != kOTInvalidEndpointRef ) + { + err = OTSndOrderlyDisconnect( socket->m_endpoint ) ; + if ( err != kOTNoError ) + { + + } + err = OTRcvOrderlyDisconnect( socket->m_endpoint ) ; + err = OTUnbind( socket->m_endpoint ) ; + err = OTCloseProvider( socket->m_endpoint ) ; + socket->m_endpoint = kOTInvalidEndpointRef ; + } + + /* Disable GUI callbacks */ + for (evt = 0; evt < GSOCK_MAX_EVENT; evt++) + socket->m_cbacks[evt] = NULL; + + socket->m_detected = 0; + _GSocket_Disable_Events(socket); + wxMacRemoveAllNotifiersForData( wxMacGetNotifierTable() , socket ) ; +} + + +/* Address handling */ + +/* GSocket_SetLocal: + * GSocket_GetLocal: + * GSocket_SetPeer: + * GSocket_GetPeer: + * Set or get the local or peer address for this socket. The 'set' + * functions return GSOCK_NOERROR on success, an error code otherwise. + * The 'get' functions return a pointer to a GAddress object on success, + * or NULL otherwise, in which case they set the error code of the + * corresponding GSocket. + * + * Error codes: + * GSOCK_INVSOCK - the socket is not valid. + * GSOCK_INVADDR - the address is not valid. + */ +GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address) +{ + assert(socket != NULL); + + /* the socket must be initialized, or it must be a server */ + if ((socket->m_endpoint != kOTInvalidEndpointRef && !socket->m_server)) + { + socket->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + socket->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (socket->m_local) + GAddress_destroy(socket->m_local); + + socket->m_local = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address) +{ + assert(socket != NULL); + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + socket->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (socket->m_peer) + GAddress_destroy(socket->m_peer); + + socket->m_peer = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GAddress *GSocket_GetLocal(GSocket *socket) +{ + GAddress *address = NULL ; + InetAddress addr; + GSocketError err; + InetAddress loc ; + + assert(socket != NULL); + + /* try to get it from the m_local var first */ + if (socket->m_local) + return GAddress_copy(socket->m_local); + + /* else, if the socket is initialized, try getsockname */ + if (socket->m_endpoint == kOTInvalidEndpointRef) + { + socket->m_error = GSOCK_INVSOCK; + return NULL; + } + + +/* we do not support multihoming with this code at the moment + OTGetProtAddress will have to be used then - but we don't have a handy + method to use right now +*/ + { + InetInterfaceInfo info; + OTInetGetInterfaceInfo(&info, kDefaultInetInterface); + loc.fHost = info.fAddress ; + loc.fPort = 0 ; + loc.fAddressType = AF_INET ; + } + + /* got a valid address from getsockname, create a GAddress object */ + address = GAddress_new(); + if (address == NULL) + { + socket->m_error = GSOCK_MEMERR; + return NULL; + } + + err = _GAddress_translate_from(address, &loc); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(address); + socket->m_error = err; + return NULL; + } + + return address; +} + +GAddress *GSocket_GetPeer(GSocket *socket) +{ + assert(socket != NULL); + + /* try to get it from the m_peer var */ + if (socket->m_peer) + return GAddress_copy(socket->m_peer); + + return NULL; +} + +/* Server specific parts */ + +/* GSocket_SetServer: + * Sets up this socket as a server. The local address must have been + * set with GSocket_SetLocal() before GSocket_SetServer() is called. + * Returns GSOCK_NOERROR on success, one of the following otherwise: + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use. + * GSOCK_INVADDR - the local address has not been set. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_SetServer(GSocket *sck) +{ + int type; + int arg = 1; + + assert(sck != NULL); + + /* must not be in use */ + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* the local addr must have been set */ + if (!sck->m_local) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Initialize all fields */ + sck->m_stream = TRUE; + sck->m_server = TRUE; + sck->m_oriented = TRUE; + +// TODO +#if 0 + /* Create the socket */ + sck->m_endpoint = socket(sck->m_local->m_realfamily, SOCK_STREAM, 0); + socket_set_ref( sck->m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) sck ) ; + if (sck->m_endpoint == kOTInvalidEndpointRef) + { + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + + ioctl(sck->m_endpoint, FIONBIO, &arg); + _GSocket_Enable_Events(sck); + + /* Bind to the local address, + * retrieve the actual address bound, + * and listen up to 5 connections. + */ + if ((bind(sck->m_endpoint, sck->m_local->m_addr, sck->m_local->m_len) != 0) || + (getsockname(sck->m_endpoint, + sck->m_local->m_addr, + (SOCKLEN_T *) &sck->m_local->m_len) != 0) || + (listen(sck->m_endpoint, 5) != 0)) + { + close(sck->m_endpoint); + sck->m_endpoint = -1; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +#endif + return GSOCK_NOERROR; +} + +/* GSocket_WaitConnection: + * Waits for an incoming client connection. Returns a pointer to + * a GSocket object, or NULL if there was an error, in which case + * the last error field will be updated for the calling GSocket. + * + * Error codes (set in the calling GSocket) + * GSOCK_INVSOCK - the socket is not valid or not a server. + * GSOCK_TIMEDOUT - timeout, no incoming connections. + * GSOCK_WOULDBLOCK - the call would block and the socket is nonblocking. + * GSOCK_MEMERR - couldn't allocate memory. + * GSOCK_IOERR - low-level error. + */ +GSocket *GSocket_WaitConnection(GSocket *socket) +{ + GSocket *connection = NULL ; + GSocketError err; + + int arg = 1; + + assert(socket != NULL); + + /* Reenable CONNECTION events */ + socket->m_detected &= ~GSOCK_CONNECTION_FLAG; + + /* If the socket has already been created, we exit immediately */ + if (socket->m_endpoint == kOTInvalidEndpointRef || !socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return NULL; + } + + /* Create a GSocket object for the new connection */ + connection = GSocket_new(); + + if (!connection) + { + socket->m_error = GSOCK_MEMERR; + return NULL; + } + + /* Wait for a connection (with timeout) */ + if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) + { + GSocket_destroy(connection); + /* socket->m_error set by _GSocket_Input_Timeout */ + return NULL; + } + +// TODO +#if 0 + connection->m_endpoint = accept(socket->m_endpoint, &from, (SOCKLEN_T *) &fromlen); +#endif + + if (connection->m_endpoint == kOTInvalidEndpointRef ) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + + GSocket_destroy(connection); + return NULL; + } + + /* Initialize all fields */ + connection->m_server = FALSE; + connection->m_stream = TRUE; + connection->m_oriented = TRUE; + + /* Setup the peer address field */ + connection->m_peer = GAddress_new(); + if (!connection->m_peer) + { + GSocket_destroy(connection); + socket->m_error = GSOCK_MEMERR; + return NULL; + } + // TODO + #if 0 + err = _GAddress_translate_from(connection->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(connection->m_peer); + GSocket_destroy(connection); + socket->m_error = err; + return NULL; + } + + ioctl(connection->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(connection); + + return connection; +} + +/* Datagram sockets */ + +/* GSocket_SetNonOriented: + * Sets up this socket as a non-connection oriented (datagram) socket. + * Before using this function, the local address must have been set + * with GSocket_SetLocal(), or the call will fail. Returns GSOCK_NOERROR + * on success, or one of the following otherwise. + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use. + * GSOCK_INVADDR - the local address has not been set. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_SetNonOriented(GSocket *sck) +{ + int arg = 1; + + assert(sck != NULL); + + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + if (!sck->m_local) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Initialize all fields */ + sck->m_stream = FALSE; + sck->m_server = FALSE; + sck->m_oriented = FALSE; + + /* Create the socket */ + +// TODO +#if 0 + sck->m_endpoint = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0); + socket_set_ref( sck->m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) sck ) ; +#endif + if (sck->m_endpoint == kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + +// TODO +#if 0 + ioctl(sck->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(sck); + + /* Bind to the local address, + * and retrieve the actual address bound. + */ +// TODO +#if 0 + if ((bind(sck->m_endpoint, sck->m_local->m_addr, sck->m_local->m_len) != 0) || + (getsockname(sck->m_endpoint, + sck->m_local->m_addr, + (SOCKLEN_T *) &sck->m_local->m_len) != 0)) + { + close(sck->m_endpoint); + sck->m_endpoint = -1; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +#endif + return GSOCK_NOERROR; +} + +/* Client specific parts */ + +/* GSocket_Connect: + * For stream (connection oriented) sockets, GSocket_Connect() tries + * to establish a client connection to a server using the peer address + * as established with GSocket_SetPeer(). Returns GSOCK_NOERROR if the + * connection has been succesfully established, or one of the error + * codes listed below. Note that for nonblocking sockets, a return + * value of GSOCK_WOULDBLOCK doesn't mean a failure. The connection + * request can be completed later; you should use GSocket_Select() + * to poll for GSOCK_CONNECTION | GSOCK_LOST, or wait for the + * corresponding asynchronous events. + * + * For datagram (non connection oriented) sockets, GSocket_Connect() + * just sets the peer address established with GSocket_SetPeer() as + * default destination. + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use or not valid. + * GSOCK_INVADDR - the peer address has not been established. + * GSOCK_TIMEDOUT - timeout, the connection failed. + * GSOCK_WOULDBLOCK - connection in progress (nonblocking sockets only) + * GSOCK_MEMERR - couldn't allocate memory. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) +{ + int ret; + int arg = 1; + InetAddress addr ; + TEndpointInfo info; + OTFlags flags = 0; + OSStatus err = kOTNoError; + TCall peer ; + + assert(sck != NULL); + + /* Enable CONNECTION events (needed for nonblocking connections) */ + sck->m_detected &= ~GSOCK_CONNECTION_FLAG; + + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + if (!sck->m_peer) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Streamed or dgram socket? */ + sck->m_stream = (stream == GSOCK_STREAMED); + sck->m_oriented = TRUE; + sck->m_server = FALSE; + + /* Create the socket */ +#if TARGET_CARBON + sck->m_endpoint = + OTOpenEndpointInContext( OTCreateConfiguration( kTCPName) , 0 , &info , &err , NULL ) ; +#else + sck->m_endpoint = + OTOpenEndpoint( OTCreateConfiguration( kTCPName) , 0 , &info , &err ) ; +#endif + if ( sck->m_endpoint == kOTInvalidEndpointRef || err != kOTNoError ) + { + sck->m_endpoint = kOTInvalidEndpointRef ; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + err = OTBind( sck->m_endpoint , nil , nil ) ; + if ( err != kOTNoError ) + { + return GSOCK_IOERR; + } + SetDefaultEndpointModes( sck->m_endpoint , sck ) ; +// TODO +#if 0 + ioctl(sck->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(sck); + + _GAddress_translate_to( sck->m_peer , &addr ) ; + memset( &peer , 0 , sizeof( TCall ) ) ; + peer.addr.len = sizeof( InetAddress ) ; + peer.addr.buf = (unsigned char*) &addr ; + err = OTConnect( sck->m_endpoint , &peer , nil ) ; + if ( err != noErr ) + { + /* If connect failed with EINPROGRESS and the GSocket object + * is in blocking mode, we select() for the specified timeout + * checking for writability to see if the connection request + * completes. + */ + + if ((err == kOTNoDataErr ) && (!sck->m_non_blocking)) + { + if (_GSocket_Output_Timeout(sck) == GSOCK_TIMEDOUT) + { + OTSndOrderlyDisconnect( sck->m_endpoint ) ; + sck->m_endpoint = kOTInvalidEndpointRef ; + /* sck->m_error is set in _GSocket_Output_Timeout */ + return GSOCK_TIMEDOUT; + } + else + { +/* + int error; + SOCKLEN_T len = sizeof(error); + + getsockopt(sck->m_endpoint, SOL_SOCKET, SO_ERROR, (void*) &error, &len); + + if (!error) +*/ + return GSOCK_NOERROR; + } + } + + /* If connect failed with EINPROGRESS and the GSocket object + * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK + * (and return GSOCK_WOULDBLOCK) but we don't close the socket; + * this way if the connection completes, a GSOCK_CONNECTION + * event will be generated, if enabled. + */ + if ((err == kOTNoDataErr) && (sck->m_non_blocking)) + { + sck->m_error = GSOCK_WOULDBLOCK; + return GSOCK_WOULDBLOCK; + } + + /* If connect failed with an error other than EINPROGRESS, + * then the call to GSocket_Connect has failed. + */ + OTSndOrderlyDisconnect( sck->m_endpoint ) ; + + sck->m_endpoint = kOTInvalidEndpointRef ; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +// OTInetEventHandler(sck, T_CONNECT , kOTNoError , NULL ) ; + return GSOCK_NOERROR; +} + +/* Generic IO */ + +/* Like recv(), send(), ... */ +int GSocket_Read(GSocket *socket, char *buffer, int size) +{ + int ret = 0 ; + + assert(socket != NULL); + + /* Reenable INPUT events */ + socket->m_detected &= ~GSOCK_INPUT_FLAG; + + if (socket->m_endpoint == kOTInvalidEndpointRef || socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return -1; + } + + /* If the socket is blocking, wait for data (with a timeout) */ + if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) + return -1; + + /* Read the data */ + if (socket->m_stream) + ret = _GSocket_Recv_Stream(socket, buffer, size); + else + ret = _GSocket_Recv_Dgram(socket, buffer, size); + + if (ret == -1) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + } + + return ret; +} + +int GSocket_Write(GSocket *socket, const char *buffer, int size) +{ + int ret; + + assert(socket != NULL); + + if (socket->m_endpoint == kOTInvalidEndpointRef || socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return -1; + } + + /* If the socket is blocking, wait for writability (with a timeout) */ + if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT) + return -1; + + /* Write the data */ + if (socket->m_stream) + ret = _GSocket_Send_Stream(socket, buffer, size); + else + ret = _GSocket_Send_Dgram(socket, buffer, size); + + if (ret == -1) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + + /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect + * in MSW). Once the first OUTPUT event is received, users can assume + * that the socket is writable until a read operation fails. Only then + * will further OUTPUT events be posted. + */ + socket->m_detected &= ~GSOCK_OUTPUT_FLAG; + return -1; + } + + return ret; +} + +/* GSocket_Select: + * Polls the socket to determine its status. This function will + * check for the events specified in the 'flags' parameter, and + * it will return a mask indicating which operations can be + * performed. This function won't block, regardless of the + * mode (blocking | nonblocking) of the socket. + */ +GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags) +{ + OTResult state ; + assert(socket != NULL); + wxMacProcessNotifierEvents() ; + /* + state = OTGetEndpointState(socket->m_endpoint); + + if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( socket->m_detected & GSOCK_INPUT_FLAG ) ) + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( socket->m_detected & GSOCK_OUTPUT_FLAG ) ) + { + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_detected |=GSOCK_OUTPUT_FLAG ; + (socket->m_cbacks[GSOCK_OUTPUT])(socket, GSOCK_OUTPUT, socket->m_data[GSOCK_OUTPUT]); + } + } + */ + return ( flags & socket->m_detected ) ; +} + +/* Flags */ + +/* GSocket_SetNonBlocking: + * Sets the socket to non-blocking mode. All IO calls will return + * immediately. + */ +void GSocket_SetNonBlocking(GSocket *socket, int non_block) +{ + assert(socket != NULL); + + socket->m_non_blocking = non_block; +} + +/* GSocket_SetTimeout: + * Sets the timeout for blocking calls. Time is expressed in + * milliseconds. + */ +void GSocket_SetTimeout(GSocket *socket, unsigned long millisec) +{ + assert(socket != NULL); + + socket->m_timeout = millisec; +} + +/* GSocket_GetError: + * Returns the last error occured for this socket. Note that successful + * operations do not clear this back to GSOCK_NOERROR, so use it only + * after an error. + */ +GSocketError GSocket_GetError(GSocket *socket) +{ + assert(socket != NULL); + + return socket->m_error; +} + +/* Callbacks */ + +/* GSOCK_INPUT: + * There is data to be read in the input buffer. If, after a read + * operation, there is still data available, the callback function will + * be called again. + * GSOCK_OUTPUT: + * The socket is available for writing. That is, the next write call + * won't block. This event is generated only once, when the connection is + * first established, and then only if a call failed with GSOCK_WOULDBLOCK, + * when the output buffer empties again. This means that the app should + * assume that it can write since the first OUTPUT event, and no more + * OUTPUT events will be generated unless an error occurs. + * GSOCK_CONNECTION: + * Connection succesfully established, for client sockets, or incoming + * client connection, for server sockets. Wait for this event (also watch + * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. + * GSOCK_LOST: + * The connection is lost (or a connection request failed); this could + * be due to a failure, or due to the peer closing it gracefully. + */ + +/* GSocket_SetCallback: + * Enables the callbacks specified by 'flags'. Note that 'flags' + * may be a combination of flags OR'ed toghether, so the same + * callback function can be made to accept different events. + * The callback function must have the following prototype: + * + * void function(GSocket *socket, GSocketEvent event, char *cdata) + */ +void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags, + GSocketCallback callback, char *cdata) +{ + int count; + + assert(socket != NULL); + + for (count = 0; count < GSOCK_MAX_EVENT; count++) + { + if ((flags & (1 << count)) != 0) + { + socket->m_cbacks[count] = callback; + socket->m_data[count] = cdata; + } + } +} + +/* GSocket_UnsetCallback: + * Disables all callbacks specified by 'flags', which may be a + * combination of flags OR'ed toghether. + */ +void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags) +{ + int count; + + assert(socket != NULL); + + for (count = 0; count < GSOCK_MAX_EVENT; count++) + { + if ((flags & (1 << count)) != 0) + { + socket->m_cbacks[count] = NULL; + socket->m_data[count] = NULL; + } + } +} + + +#define CALL_CALLBACK(socket, event) { \ + _GSocket_Disable(socket, event); \ + if (socket->m_cbacks[event]) \ + socket->m_cbacks[event](socket, event, socket->m_data[event]); \ +} + +int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size) +{ + OTFlags flags ; + OTResult res ; + + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + res = OTRcv( socket->m_endpoint , buffer , size , &flags ) ; + if ( res < 0 ) + { + return -1 ; + } + + // we simulate another read event if there are still bytes + if ( socket->m_takesEvents ) + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + return res ; +} + +int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) +{ +// TODO + int ret = -1; +#if 0 + struct sockaddr from; + SOCKLEN_T fromlen = sizeof(from); + GSocketError err; + + fromlen = sizeof(from); + + ret = recvfrom(socket->m_endpoint, buffer, size, 0, &from, (SOCKLEN_T *) &fromlen); + + if (ret == -1) + return -1; + + /* Translate a system address into a GSocket address */ + if (!socket->m_peer) + { + socket->m_peer = GAddress_new(); + if (!socket->m_peer) + { + socket->m_error = GSOCK_MEMERR; + return -1; + } + } + err = _GAddress_translate_from(socket->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(socket->m_peer); + socket->m_peer = NULL; + socket->m_error = err; + return -1; + } +#endif + return ret; +} + +int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size) +{ + OTFlags flags = 0 ; + OTResult res ; + + res = OTSnd( socket->m_endpoint , (void*) buffer , size , flags ) ; + return res ; +} + +int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) +{ + int ret = -1 ; +// TODO +#if 0 + struct sockaddr *addr; + int len ; + GSocketError err; + + if (!socket->m_peer) + { + socket->m_error = GSOCK_INVADDR; + return -1; + } + + err = _GAddress_translate_to(socket->m_peer, &addr, &len); + if (err != GSOCK_NOERROR) + { + socket->m_error = err; + return -1; + } + + ret = sendto(socket->m_endpoint, buffer, size, 0, addr, len); + + /* Frees memory allocated from _GAddress_translate_to */ + free(addr); +#endif + return ret; +} + + +/* + * ------------------------------------------------------------------------- + * GAddress + * ------------------------------------------------------------------------- + */ + +/* CHECK_ADDRESS verifies that the current family is either GSOCK_NOFAMILY + * or GSOCK_*family*, and if it is GSOCK_NOFAMILY, it initalizes address + * to be a GSOCK_*family*. In other cases, it returns GSOCK_INVADDR. + */ +#define CHECK_ADDRESS(address, family, retval) \ +{ \ + if (address->m_family == GSOCK_NOFAMILY) \ + if (_GAddress_Init_##family(address) != GSOCK_NOERROR) \ + return address->m_error; \ + if (address->m_family != GSOCK_##family) \ + { \ + address->m_error = GSOCK_INVADDR; \ + return retval; \ + } \ +} + +GAddress *GAddress_new() +{ + GAddress *address; + + if ((address = (GAddress *) malloc(sizeof(GAddress))) == NULL) + return NULL; + + address->m_family = GSOCK_NOFAMILY; + address->m_host = INADDR_NONE ; + address->m_port = 0 ; + + return address; +} + +GAddress *GAddress_copy(GAddress *address) +{ + GAddress *addr2; + + assert(address != NULL); + + if ((addr2 = (GAddress *) malloc(sizeof(GAddress))) == NULL) + return NULL; + + memcpy(addr2, address, sizeof(GAddress)); + return addr2; +} + +void GAddress_destroy(GAddress *address) +{ + assert(address != NULL); + + free(address); +} + +void GAddress_SetFamily(GAddress *address, GAddressType type) +{ + assert(address != NULL); + + address->m_family = type; +} + +GAddressType GAddress_GetFamily(GAddress *address) +{ + assert(address != NULL); + + return address->m_family; +} + +GSocketError _GAddress_translate_from(GAddress *address, + InetAddress *addr) +{ + switch (addr->fAddressType) + { + case AF_INET: + address->m_family = GSOCK_INET; + break; +#ifdef AF_INET6 + case AF_INET6: + address->m_family = GSOCK_INET6; + break; +#endif + default: + { + address->m_error = GSOCK_INVOP; + return GSOCK_INVOP; + } + } + address->m_host = addr->fHost ; + address->m_port = addr->fPort ; + return GSOCK_NOERROR; +} + +GSocketError _GAddress_translate_to(GAddress *address, + InetAddress *addr) +{ + memset(addr, 0 , sizeof(struct InetAddress)); + OTInitInetAddress( addr , address->m_port , address->m_host ) ; + return GSOCK_NOERROR; +} + +/* + * ------------------------------------------------------------------------- + * Internet address family + * ------------------------------------------------------------------------- + */ + +GSocketError _GAddress_Init_INET(GAddress *address) +{ + address->m_family = GSOCK_INET; + address->m_host = kOTAnyInetAddress ; + + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname) +{ + InetHostInfo hinfo ; + OSStatus ret ; + + assert(address != NULL); + + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + ret = OTInetStringToAddress( gInetSvcRef , (char*) hostname , &hinfo ) ; + if ( ret != kOTNoError ) + { + address->m_host = INADDR_NONE ; + address->m_error = GSOCK_NOHOST; + return GSOCK_NOHOST; + } + address->m_host = hinfo.addrs[0] ; + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_SetAnyAddress(GAddress *address) +{ + return GAddress_INET_SetHostAddress(address, INADDR_ANY); +} + +GSocketError GAddress_INET_SetHostAddress(GAddress *address, + unsigned long hostaddr) +{ + struct in_addr *addr; + + assert(address != NULL); + + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + address->m_host = hostaddr ; + + return GSOCK_NOERROR; +} + +struct service_entry +{ + char * name ; + unsigned short port ; + char * protocol ; +} ; +typedef struct service_entry service_entry ; + +service_entry gServices[] = +{ + { "http" , 80 , "tcp" } +} ; + +GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, + const char *protocol) +{ + InetAddress *addr; + int i ; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + if (!port) + { + address->m_error = GSOCK_INVPORT; + return GSOCK_INVPORT; + } + for ( i = 0 ; i < sizeof( gServices) / sizeof( service_entry ) ; ++i ) + { + if ( strcmp( port , gServices[i].name ) == 0 ) + { + if ( protocol == NULL || strcmp( protocol , gServices[i].protocol ) ) + { + address->m_port = gServices[i].port ; + return GSOCK_NOERROR; + } + } + } + + if (isdigit(port[0])) + { + address->m_port = atoi(port); + return GSOCK_NOERROR; + } + + address->m_error = GSOCK_INVPORT; + return GSOCK_INVPORT; +} + +GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) +{ + InetAddress *addr; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + address->m_port = port ; + + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t sbuf) +{ + InetDomainName name ; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + OTInetAddressToName( gInetSvcRef , address->m_host , &name ) ; + strncpy( hostname , name , sbuf ) ; + return GSOCK_NOERROR; +} + +unsigned long GAddress_INET_GetHostAddress(GAddress *address) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); + + return address->m_host; +} + +unsigned short GAddress_INET_GetPort(GAddress *address) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); + + return address->m_port; +} + +void _GSocket_Enable_Events(GSocket *socket) +{ + if ( socket->m_takesEvents ) + return ; + + { + OTResult state ; + socket->m_takesEvents = TRUE ; + state = OTGetEndpointState(socket->m_endpoint); + + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + { + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_detected |=GSOCK_OUTPUT_FLAG ; + (socket->m_cbacks[GSOCK_OUTPUT])(socket, GSOCK_OUTPUT, socket->m_data[GSOCK_OUTPUT]); + } + } + } +} + +void _GSocket_Disable_Events(GSocket *socket) +{ + socket->m_takesEvents = FALSE ; +} + +/* _GSocket_Input_Timeout: + * For blocking sockets, wait until data is available or + * until timeout ellapses. + */ +GSocketError _GSocket_Input_Timeout(GSocket *socket) +{ + if ( !socket->m_non_blocking ) + { + UnsignedWide now , start ; + short formerTakesEvents = socket->m_takesEvents ; + Microseconds(&start); + now = start ; + socket->m_takesEvents = FALSE ; + + while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < socket->m_timeout * 1000.0 ) + { + OTResult state ; + size_t sz = 0 ; + state = OTGetEndpointState(socket->m_endpoint); + + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_takesEvents = formerTakesEvents ; + return GSOCK_NOERROR; + } + Microseconds(&now); + } + socket->m_takesEvents = formerTakesEvents ; + socket->m_error = GSOCK_TIMEDOUT; + return GSOCK_TIMEDOUT; + } + return GSOCK_NOERROR; +} + +/* _GSocket_Output_Timeout: + * For blocking sockets, wait until data can be sent without + * blocking or until timeout ellapses. + */ +GSocketError _GSocket_Output_Timeout(GSocket *socket) +{ + if ( !socket->m_non_blocking ) + { + UnsignedWide now , start ; + short formerTakesEvents = socket->m_takesEvents ; + Microseconds(&start); + now = start ; + socket->m_takesEvents = FALSE ; + + while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < socket->m_timeout * 1000.0 ) + { + OTResult state ; + state = OTGetEndpointState(socket->m_endpoint); + + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_takesEvents = formerTakesEvents ; + return GSOCK_NOERROR; + } + Microseconds(&now); + } + socket->m_takesEvents = formerTakesEvents ; + socket->m_error = GSOCK_TIMEDOUT; + return GSOCK_TIMEDOUT; + } + return GSOCK_NOERROR; +} + +/* GSOCK_INPUT: + * There is data to be read in the input buffer. If, after a read + * operation, there is still data available, the callback function will + * be called again. + * GSOCK_OUTPUT: + * The socket is available for writing. That is, the next write call + * won't block. This event is generated only once, when the connection is + * first established, and then only if a call failed with GSOCK_WOULDBLOCK, + * when the output buffer empties again. This means that the app should + * assume that it can write since the first OUTPUT event, and no more + * OUTPUT events will be generated unless an error occurs. + * GSOCK_CONNECTION: + * Connection succesfully established, for client sockets, or incoming + * client connection, for server sockets. Wait for this event (also watch + * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. + * GSOCK_LOST: + * The connection is lost (or a connection request failed); this could + * be due to a failure, or due to the peer closing it gracefully. + */ + +void _GSocket_Internal_Proc(unsigned long e , void* d ) +{ + + GSocket * socket = (GSocket*) d ; + OTEventCode ev = (OTEventCode) e ; + GSocketEvent event; + GSocketEvent event2; + GSocketCallback cback; + char *data; + GSocketCallback cback2; + char *data2; + + if ( !socket ) + return ; + event = GSOCK_MAX_EVENT ; + event2 = GSOCK_MAX_EVENT ; + cback = NULL; + data = NULL; + cback2 = NULL; + data2 = NULL; + + /* Check that the socket still exists (it has not been + * destroyed) and for safety, check that the m_endpoint field + * is what we expect it to be. + */ + if ((socket != NULL) && (socket->m_takesEvents)) + { + switch (ev) + { + case T_LISTEN : + event = GSOCK_CONNECTION ; + break ; + case T_CONNECT : + event = GSOCK_CONNECTION ; + event2 = GSOCK_OUTPUT ; + { + TCall retCall; + + retCall.addr.buf = NULL; + retCall.addr.maxlen = 0; + retCall.opt.buf = NULL; + retCall.opt.maxlen = 0; + retCall.udata.buf = NULL; + retCall.udata.maxlen= 0; + OTRcvConnect( socket->m_endpoint , &retCall ) ; + } + break ; + case T_DISCONNECT : + event = GSOCK_LOST ; + break ; + case T_GODATA : + case T_GOEXDATA : + event = GSOCK_OUTPUT ; + break ; + case T_DATA : + event = GSOCK_INPUT ; + break ; + case T_EXDATA : + event = GSOCK_INPUT ; + break ; + } + if (event != GSOCK_MAX_EVENT) + { + cback = socket->m_cbacks[event]; + data = socket->m_data[event]; + + if (event == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event); + } + if (event2 != GSOCK_MAX_EVENT) + { + cback2 = socket->m_cbacks[event2]; + data2 = socket->m_data[event2]; + + if (event2 == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event2); + } + } + + /* OK, we can now leave the critical section because we have + * already obtained the callback address (we make no further + * accesses to socket->whatever). However, the app should + * be prepared to handle events from a socket that has just + * been closed! + */ + + if (cback != NULL) + (cback)(socket, event, data); + if (cback2 != NULL) + (cback2)(socket, event2, data2); + +} + +#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ diff --git a/src/mac/carbon/macnotfy.cpp b/src/mac/carbon/macnotfy.cpp new file mode 100644 index 0000000000..3546eeb7f2 --- /dev/null +++ b/src/mac/carbon/macnotfy.cpp @@ -0,0 +1,137 @@ +/* ------------------------------------------------------------------------- + * Project: Mac Notifier Support + * Name: macnotfy.c + * Author: Stefan CSomor + * Purpose: Mac Notifier main file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +#include "wx/mac/macnotfy.h" + +const short kMaxEvents = 1000 ; + +struct wxMacNotificationEvents +{ + short top ; + short bottom ; + + wxMacNotificationProcPtr proc[kMaxEvents] ; + unsigned long events[kMaxEvents] ; + void* data[kMaxEvents] ; +} ; + +typedef struct wxMacNotificationEvents wxMacNotificationEvents ; +wxMacNotificationEvents gMacNotificationEvents ; + +ProcessSerialNumber gSocketProcess ; + +void wxMacWakeUp() +{ + ProcessSerialNumber psn ; + Boolean isSame ; + psn.highLongOfPSN = 0 ; + psn.lowLongOfPSN = kCurrentProcess ; + SameProcess( &gSocketProcess , &psn , &isSame ) ; + if ( isSame ) + { + PostEvent( nullEvent , 0 ) ; + } + else + { + WakeUpProcess( &gSocketProcess ) ; + } +} + +void wxMacCreateNotifierTable() +{ + GetCurrentProcess(&gSocketProcess); + gMacNotificationEvents.top = 0 ; + gMacNotificationEvents.bottom = 0 ; + for ( int i = 0 ; i < kMaxEvents ; ++i ) + { + gMacNotificationEvents.proc[i] = NULL ; + gMacNotificationEvents.events[i] = NULL ; + gMacNotificationEvents.data[i] = NULL ; + } +} + +void wxMacDestroyNotifierTable() +{ + wxASSERT( gMacNotificationEvents.top == gMacNotificationEvents.bottom ) ; +} + +wxMacNotifierTableRef wxMacGetNotifierTable() +{ + return (wxMacNotifierTableRef) &gMacNotificationEvents ; +} + +void wxMacAddEvent( + wxMacNotifierTableRef table , + wxMacNotificationProcPtr handler , + unsigned long event , + void* data , + short wakeUp ) +{ + wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ; + /* this should be protected eventually */ + short index = e->top++ ; + + if ( e->top == kMaxEvents ) + e->top = 0 ; + + e->proc[index] = handler ; + e->events[index] = event ; + e->data[index] = data ; + if ( wakeUp ) + wxMacWakeUp() ; +} + +bool gInProcessing = false ; + +void wxMacRemoveAllNotifiersForData( wxMacNotifierTableRef table , void* data ) +{ + wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ; + /* this should be protected eventually */ + short index = e->bottom ; + + while ( e->top != index ) + { + if ( index == kMaxEvents ) + index = 0 ; + if ( e->data[index] == data ) + e->data[index] = NULL ; + index++ ; + } +} + +void wxMacProcessNotifierEvents() +{ +// if ( gInProcessing ) +// return ; + + gInProcessing = true ; + while ( gMacNotificationEvents.top != gMacNotificationEvents.bottom ) + { + // consume event at bottom + short index = gMacNotificationEvents.bottom++ ; + if ( gMacNotificationEvents.bottom == kMaxEvents ) + gMacNotificationEvents.bottom = 0 ; + void* data = gMacNotificationEvents.data[index] ; + unsigned long event = gMacNotificationEvents.events[index] ; + wxMacNotificationProcPtr handler = gMacNotificationEvents.proc[index] ; + + gMacNotificationEvents.data[index] = NULL ; + gMacNotificationEvents.events[index] = NULL ; + gMacNotificationEvents.proc[index] = NULL ; + + handler( event , data ) ; + } + gInProcessing = false ; +} + +void wxMacProcessNotifierAndPendingEvents() +{ + wxMacProcessNotifierEvents() ; + wxTheApp->ProcessPendingEvents() ; +} diff --git a/src/mac/carbon/notebmac.cpp b/src/mac/carbon/notebmac.cpp new file mode 100644 index 0000000000..ab97b53540 --- /dev/null +++ b/src/mac/carbon/notebmac.cpp @@ -0,0 +1,413 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: notebook.cpp +// Purpose: implementation of wxNotebook +// Author: AUTHOR +// Modified by: +// Created: ??/??/98 +// RCS-ID: $Id$ +// Copyright: (c) AUTHOR +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- +#ifdef __GNUG__ +#pragma implementation "notebook.h" +#endif + +#include +#include +#include +#include +#include +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount())) + +const short kwxMacTabLeftMargin = 16 ; +const short kwxMacTabTopMargin = 30 ; +const short kwxMacTabRightMargin = 16 ; +const short kwxMacTabBottomMargin = 16 ; + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +#if !USE_SHARED_LIBRARIES +BEGIN_EVENT_TABLE(wxNotebook, wxControl) + EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange) + + EVT_SIZE(wxNotebook::OnSize) + EVT_SET_FOCUS(wxNotebook::OnSetFocus) + EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent) +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxNotebook construction +// ---------------------------------------------------------------------------- + +// common part of all ctors +void wxNotebook::Init() +{ + m_pImageList = NULL; + m_nSelection = -1; +} + +// default for dynamic class +wxNotebook::wxNotebook() +{ + Init(); +} + +// the same arguments as for wxControl +wxNotebook::wxNotebook(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + Create(parent, id, pos, size, style, name); +} + +// Create() function +bool wxNotebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , "" , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ; + + m_macControl = UMANewControl( parent->GetMacRootWindow() , &bounds , title , true , 0 , 0 , 1, + kControlTabSmallProc , (long) this ) ; + + MacPostControlCreate() ; + return TRUE ; +} + +// dtor +wxNotebook::~wxNotebook() +{ + m_macControl = NULL ; +} + +// ---------------------------------------------------------------------------- +// wxNotebook accessors +// ---------------------------------------------------------------------------- +int wxNotebook::GetPageCount() const +{ + return m_aPages.Count(); +} + +int wxNotebook::GetRowCount() const +{ + return 1; +} + +int wxNotebook::SetSelection(int nPage) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + ChangePage(m_nSelection, nPage); + SetControlValue( m_macControl , m_nSelection + 1 ) ; +// Boolean enabled = true ; + +// SetControlData( m_macControl, m_nSelection + 1, kControlTabEnabledFlagTag, sizeof( Boolean ), (Ptr)&enabled ); + return m_nSelection; +} + +void wxNotebook::AdvanceSelection(bool bForward) +{ + int nSel = GetSelection(); + int nMax = GetPageCount() - 1; + if ( bForward ) + SetSelection(nSel == nMax ? 0 : nSel + 1); + else + SetSelection(nSel == 0 ? nMax : nSel - 1); +} + +bool wxNotebook::SetPageText(int nPage, const wxString& strText) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return FALSE; +} + +wxString wxNotebook::GetPageText(int nPage) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return wxString(""); +} + +int wxNotebook::GetPageImage(int nPage) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return 0; +} + +bool wxNotebook::SetPageImage(int nPage, int nImage) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return FALSE; +} + +void wxNotebook::SetImageList(wxImageList* imageList) +{ + m_pImageList = imageList; + // TODO +} + +// ---------------------------------------------------------------------------- +// wxNotebook operations +// ---------------------------------------------------------------------------- + +// remove one page from the notebook +bool wxNotebook::DeletePage(int nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), FALSE ); + + // TODO: delete native widget page + + delete m_aPages[nPage]; + m_aPages.Remove(nPage); + + return TRUE; +} + +// remove one page from the notebook, without deleting the window +bool wxNotebook::RemovePage(int nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), FALSE ); + + m_aPages.Remove(nPage); + + return TRUE; +} + +// remove all pages +bool wxNotebook::DeleteAllPages() +{ + // TODO: delete native widget pages + + int nPageCount = GetPageCount(); + int nPage; + for ( nPage = 0; nPage < nPageCount; nPage++ ) + delete m_aPages[nPage]; + + m_aPages.Clear(); + + return TRUE; +} + +// add a page to the notebook +bool wxNotebook::AddPage(wxNotebookPage *pPage, + const wxString& strText, + bool bSelect, + int imageId) +{ + return InsertPage(GetPageCount(), pPage, strText, bSelect, imageId); +} + +// same as AddPage() but does it at given position +bool wxNotebook::InsertPage(int nPage, + wxNotebookPage *pPage, + const wxString& strText, + bool bSelect, + int imageId) +{ + wxASSERT( pPage != NULL ); + wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), FALSE ); + + ControlTabInfoRec tie ; + Boolean enabled = true ; + if ( nPage + 1 > GetControlMaximum( m_macControl ) ) + { + SetControlMaximum( m_macControl , nPage + 1 ) ; + } + + tie.version = 0 ; + tie.iconSuiteID = 0 ; + strcpy( (char*) tie.name , strText ) ; + c2pstr( (char*) tie.name ) ; + SetControlData( m_macControl, nPage + 1, kControlTabInfoTag , sizeof( ControlTabInfoRec) , (char*) &tie ) ; + SetControlData( m_macControl, m_nSelection + 1, kControlTabEnabledFlagTag, sizeof( Boolean ), (Ptr)&enabled ); + + // save the pointer to the page + m_aPages.Insert(pPage, nPage); + + // some page must be selected: either this one or the first one if there is + // still no selection + if ( bSelect ) + m_nSelection = nPage; + else if ( m_nSelection == -1 ) + m_nSelection = 0; + + // don't show pages by default (we'll need to adjust their size first) + pPage->Show( FALSE ) ; + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxNotebook callbacks +// ---------------------------------------------------------------------------- + +// @@@ OnSize() is used for setting the font when it's called for the first +// time because doing it in ::Create() doesn't work (for unknown reasons) +void wxNotebook::OnSize(wxSizeEvent& event) +{ + static bool s_bFirstTime = TRUE; + if ( s_bFirstTime ) { + // TODO: any first-time-size processing. + s_bFirstTime = FALSE; + } + + // TODO: all this may or may not be necessary for your platform + + // emulate page change (it's esp. important to do it first time because + // otherwise our page would stay invisible) + int nSel = m_nSelection; + m_nSelection = -1; + SetSelection(nSel); + + // fit the notebook page to the tab control's display area + int w, h; + GetSize(&w, &h); + + unsigned int nCount = m_aPages.Count(); + for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) { + wxNotebookPage *pPage = m_aPages[nPage]; + pPage->SetSize(kwxMacTabLeftMargin, kwxMacTabTopMargin, w - kwxMacTabLeftMargin - kwxMacTabRightMargin, + h - kwxMacTabTopMargin - kwxMacTabBottomMargin ); +// pPage->SetSize(0, 0, w, h); + if ( pPage->GetAutoLayout() ) + pPage->Layout(); + } + + // Processing continues to next OnSize + event.Skip(); +} + +void wxNotebook::OnSelChange(wxNotebookEvent& event) +{ + // is it our tab control? + if ( event.GetEventObject() == this ) + ChangePage(event.GetOldSelection(), event.GetSelection()); + + // we want to give others a chance to process this message as well + event.Skip(); +} + +void wxNotebook::OnSetFocus(wxFocusEvent& event) +{ + // set focus to the currently selected page if any + if ( m_nSelection != -1 ) + m_aPages[m_nSelection]->SetFocus(); + + event.Skip(); +} + +void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event) +{ + if ( event.IsWindowChange() ) { + // change pages + AdvanceSelection(event.GetDirection()); + } + else { + // pass to the parent + if ( GetParent() ) { + event.SetCurrentFocus(this); + GetParent()->ProcessEvent(event); + } + } +} + +// ---------------------------------------------------------------------------- +// wxNotebook base class virtuals +// ---------------------------------------------------------------------------- + +// override these 2 functions to do nothing: everything is done in OnSize + +void wxNotebook::SetConstraintSizes(bool /* recurse */) +{ + // don't set the sizes of the pages - their correct size is not yet known + wxControl::SetConstraintSizes(FALSE); +} + +bool wxNotebook::DoPhase(int /* nPhase */) +{ + return TRUE; +} + +void wxNotebook::Command(wxCommandEvent& event) +{ + wxFAIL_MSG("wxNotebook::Command not implemented"); +} + +// ---------------------------------------------------------------------------- +// wxNotebook helper functions +// ---------------------------------------------------------------------------- + +// hide the currently active panel and show the new one +void wxNotebook::ChangePage(int nOldSel, int nSel) +{ + // it's not an error (the message may be generated by the tab control itself) + // and it may happen - just do nothing + if ( nSel == nOldSel ) + { + wxNotebookPage *pPage = m_aPages[nSel]; + pPage->Show(FALSE); + pPage->Show(TRUE); + pPage->SetFocus(); + return; + } + + if ( nOldSel != -1 ) { + m_aPages[nOldSel]->Show(FALSE); + } + + wxNotebookPage *pPage = m_aPages[nSel]; + pPage->Show(TRUE); + pPage->SetFocus(); + + m_nSelection = nSel; +} + +void wxNotebook::MacHandleControlClick( ControlHandle control , SInt16 controlpart ) +{ + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_windowId , ::GetControlValue(m_macControl) - 1, m_nSelection); + event.SetEventObject(this); + + ProcessEvent(event); +} + diff --git a/src/mac/carbon/statbrma.cpp b/src/mac/carbon/statbrma.cpp new file mode 100644 index 0000000000..d3c0e102dd --- /dev/null +++ b/src/mac/carbon/statbrma.cpp @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: statbar.cpp +// Purpose: native implementation of wxStatusBar (optional) +// Author: AUTHOR +// Modified by: +// Created: ??/??/98 +// RCS-ID: $Id$ +// Copyright: (c) 1998 AUTHOR +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "statusbr.h" +#endif + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/mac/statusbr.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxStatusBarMac, wxStatusBarGeneric); + +BEGIN_EVENT_TABLE(wxStatusBarMac, wxStatusBarGeneric) + EVT_PAINT(wxStatusBarMac::OnPaint) +END_EVENT_TABLE() +#endif //USE_SHARED_LIBRARY + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStatusBarXX class +// ---------------------------------------------------------------------------- + +wxStatusBarMac::wxStatusBarMac() +{ + SetParent(NULL); +} + +wxStatusBarMac::~wxStatusBarMac() +{ +} + +bool wxStatusBarMac::Create(wxWindow *parent, wxWindowID id, + long style , + const wxString& name) +{ + return wxStatusBarGeneric::Create( parent , id , style , name ) ; +} + +void wxStatusBarMac::DrawFieldText(wxDC& dc, int i) +{ + int leftMargin = 2; + + wxRect rect; + GetFieldRect(i, rect); + + wxString text(GetStatusText(i)); + + long x, y; + + dc.GetTextExtent(text, &x, &y); + + int xpos = rect.x + leftMargin + 1 ; + int ypos = 2 ; + + dc.SetClippingRegion(rect.x, 0, rect.width, m_height); + + dc.DrawText(text, xpos, ypos); + + dc.DestroyClippingRegion(); +} + +void wxStatusBarMac::DrawField(wxDC& dc, int i) +{ + DrawFieldText(dc, i); +} + +void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + wxPen black( wxBLACK , 1 , wxSOLID ) ; + wxPen white( wxWHITE , 1 , wxSOLID ) ; + + dc.SetPen(black); + dc.DrawLine(0, 0 , + m_width , 0); + dc.SetPen(white); + dc.DrawLine(0, 1 , + m_width , 1); + + + int i; + if ( GetFont().Ok() ) + dc.SetFont(GetFont()); + dc.SetBackgroundMode(wxTRANSPARENT); + + for ( i = 0; i < m_nFields; i ++ ) + DrawField(dc, i); + +# ifdef __WXMSW__ + dc.SetFont(wxNullFont); +# endif // MSW +} \ No newline at end of file diff --git a/src/mac/carbon/statlmac.cpp b/src/mac/carbon/statlmac.cpp new file mode 100644 index 0000000000..52f3d40733 --- /dev/null +++ b/src/mac/carbon/statlmac.cpp @@ -0,0 +1,61 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: generic/statline.cpp +// Purpose: a generic wxStaticLine class +// Author: Vadim Zeitlin +// Created: 28.06.99 +// Version: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "statline.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/statline.h" +#include "wx/statbox.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStaticLine, wxControl) + +// ---------------------------------------------------------------------------- +// wxStaticLine +// ---------------------------------------------------------------------------- + +bool wxStaticLine::Create( wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxString &name) +{ + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; + + // ok, this is ugly but it's better than nothing: use a thin static box to + // emulate static line + + wxSize sizeReal = AdjustSize(size); + +// m_statbox = new wxStaticBox(parent, id, wxT(""), pos, sizeReal, style, name); + + return TRUE; +} diff --git a/src/mac/carbon/tooltip.cpp b/src/mac/carbon/tooltip.cpp new file mode 100644 index 0000000000..583bd9b892 --- /dev/null +++ b/src/mac/carbon/tooltip.cpp @@ -0,0 +1,334 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: tooltip.cpp +// Purpose: wxToolTip implementation +// Author: Robert Roebling +// Id: $Id$ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "tooltip.h" +#endif + +#include "wx/setup.h" + +#if wxUSE_TOOLTIPS + +#include "wx/window.h" +#include "wx/tooltip.h" +#include "wx/geometry.h" +#include "wx/mac/aga.h" +#include "wx/mac/uma.h" + +//----------------------------------------------------------------------------- +// global data +//----------------------------------------------------------------------------- + +class wxMacToolTip +{ + public : + wxMacToolTip( ) ; + ~wxMacToolTip() ; + + void Setup( WindowRef window , wxString text , wxPoint localPosition ) ; + long GetMark() { return m_mark ; } + void Draw() ; + void Clear() ; + bool IsShown() { return m_shown ; } + private : + + wxString m_label ; + wxPoint m_position ; + Rect m_rect ; + WindowRef m_window ; + PicHandle m_backpict ; + bool m_shown ; + long m_mark ; +} ; + +class wxMacToolTipTimer : wxTimer +{ +public: + wxMacToolTipTimer(wxMacToolTip* tip, int iMilliseconds) ; + + void Notify() + { + if ( m_mark == m_tip->GetMark() ) + m_tip->Draw() ; + + delete this; + } + +protected: + wxMacToolTip* m_tip; + long m_mark ; +}; + +//----------------------------------------------------------------------------- +// wxToolTip +//----------------------------------------------------------------------------- +static long s_ToolTipDelay = 500 ; +static bool s_ShowToolTips = true ; +static wxMacToolTip s_ToolTip ; +static wxWindow* s_LastWindowEntered = NULL ; +static wxRect2DInt s_ToolTipArea ; +static WindowRef s_ToolTipWindowRef = NULL ; +wxToolTip::wxToolTip( const wxString &tip ) +{ + m_text = tip; + m_window = (wxWindow*) NULL; +} + +wxToolTip::~wxToolTip() +{ +} + +void wxToolTip::SetTip( const wxString &tip ) +{ + m_text = tip; + + if ( m_window ) + { + /* + // update it immediately + wxToolInfo ti(GetHwndOf(m_window)); + ti.lpszText = (wxChar *)m_text.c_str(); + + (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, 0, &ti); + */ + } +} + +void wxToolTip::SetWindow( wxWindow *win ) +{ + m_window = win; +} + +void wxToolTip::Enable( bool flag ) +{ + if ( s_ShowToolTips != flag ) + { + s_ShowToolTips = flag ; + if ( s_ShowToolTips ) + { + } + else + { + s_ToolTip.Clear() ; + } + } +} + +void wxToolTip::SetDelay( long msecs ) +{ + s_ToolTipDelay = msecs ; +} + +void wxToolTip::RelayEvent( wxWindow *win , wxMouseEvent &event ) +{ + if ( s_ShowToolTips ) + { + if ( event.GetEventType() == wxEVT_LEAVE_WINDOW ) + { + s_ToolTip.Clear() ; + } + else if (event.GetEventType() == wxEVT_ENTER_WINDOW || event.GetEventType() == wxEVT_MOTION ) + { + wxPoint2DInt where( event.m_x , event.m_y ) ; + if ( s_LastWindowEntered == win && s_ToolTipArea.Contains( where ) ) + { + } + else + { + s_ToolTip.Clear() ; + s_ToolTipArea = wxRect2DInt( event.m_x - 2 , event.m_y - 2 , 4 , 4 ) ; + s_LastWindowEntered = win ; + + WindowRef window = win->GetMacRootWindow() ; + int x = event.m_x ; + int y = event.m_y ; + wxPoint local( x , y ) ; + win->MacClientToRootWindow( &x, &y ) ; + wxPoint windowlocal( x , y ) ; + s_ToolTip.Setup( window , win->MacGetToolTipString( local ) , windowlocal ) ; + } + } + } +} + +void wxToolTip::RemoveToolTips() +{ + s_ToolTip.Clear() ; +} +// --- mac specific + +wxMacToolTipTimer::wxMacToolTipTimer( wxMacToolTip *tip , int msec ) +{ + m_tip = tip; + m_mark = tip->GetMark() ; + Start(msec, true); +} + +wxMacToolTip::wxMacToolTip() +{ + m_window = NULL ; + m_backpict = NULL ; + m_mark = 0 ; + m_shown = false ; +} + +void wxMacToolTip::Setup( WindowRef window , wxString text , wxPoint localPosition ) +{ + m_mark++ ; + Clear() ; + m_position = localPosition ; + m_label = wxMacMakeMacStringFromPC( text ) ; + m_window = window ; + s_ToolTipWindowRef = window ; + m_backpict = NULL ; + new wxMacToolTipTimer( this , s_ToolTipDelay ) ; +} + +wxMacToolTip::~wxMacToolTip() +{ + if ( m_backpict ) + Clear() ; +} + +const short kTipBorder = 2 ; +const short kTipOffset = 5 ; + +void wxMacToolTip::Draw() +{ + if ( m_label.Length() == 0 ) + return ; + + if ( m_window == s_ToolTipWindowRef ) + { + #if TARGET_CARBON + AGAPortHelper help( GetWindowPort( m_window ) ); + #else + AGAPortHelper help( ( m_window ) ); + #endif + m_shown = true ; + + SetOrigin( 0 , 0 ) ; + TextFont( kFontIDGeneva ) ; + TextSize( 9 ) ; + TextFace( 0 ) ; + FontInfo fontInfo; + ::GetFontInfo(&fontInfo); + short lineh = fontInfo.ascent + fontInfo.descent + fontInfo.leading; + short height = 0 ; + // short width = TextWidth( m_label , 0 ,m_label.Length() ) ; + + int i = 0 ; + int length = m_label.Length() ; + int width = 0 ; + int thiswidth = 0 ; + int laststop = 0 ; + const char *text = m_label ; + while( i < length ) + { + if( text[i] == 13 || text[i] == 10) + { + thiswidth = ::TextWidth( text , laststop , i - laststop ) ; + if ( thiswidth > width ) + width = thiswidth ; + + height += lineh ; + laststop = i+1 ; + } + i++ ; + } + if ( i - laststop > 0 ) + { + thiswidth = ::TextWidth( text , laststop , i - laststop ) ; + if ( thiswidth > width ) + width = thiswidth ; + height += lineh ; + } + + + m_rect.left = m_position.x + kTipOffset; + m_rect.top = m_position.y + kTipOffset; + m_rect.right = m_rect.left + width + 2 * kTipBorder; + m_rect.bottom = m_rect.top + height + 2 * kTipBorder; + ClipRect( &m_rect ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + m_backpict = OpenPicture(&m_rect); + + CopyBits(GetPortBitMapForCopyBits(GetWindowPort(m_window)), + GetPortBitMapForCopyBits(GetWindowPort(m_window)), + &m_rect, + &m_rect, + srcCopy, + NULL); + + ClosePicture(); + RGBColor yellow = { 0xFFFF , 0xFFFF , (153<<8)+153 } ; + RGBBackColor( &yellow ) ; + EraseRect( &m_rect ) ; + FrameRect( &m_rect ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder); + + i = 0 ; + laststop = 0 ; + height = 0 ; + while( i < length ) + { + if( text[i] == 13 || text[i] == 10) + { + ::DrawText( text , laststop , i - laststop ) ; + height += lineh ; + ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder + height ); + laststop = i+1 ; + } + i++ ; + } + + ::DrawText( text , laststop , i - laststop ) ; + ::TextMode( srcOr ) ; + + // DrawText( m_label , 0 , m_label.Length() ) ; + } +} + +void wxToolTip::NotifyWindowDelete( WindowRef win ) +{ + if ( win == s_ToolTipWindowRef ) + { + s_ToolTipWindowRef = NULL ; + } +} + +void wxMacToolTip::Clear() +{ + m_mark++ ; + if ( !m_shown ) + return ; + + if ( m_window == s_ToolTipWindowRef && m_backpict ) + { + #if TARGET_CARBON + AGAPortHelper help( GetWindowPort(m_window) ) ; + #else + AGAPortHelper help( (m_window) ) ; + #endif + m_shown = false ; + + SetOrigin( 0 , 0 ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + DrawPicture(m_backpict, &m_rect); + KillPicture(m_backpict); + m_backpict = NULL ; + } +} + +#endif + diff --git a/src/mac/cdef/extcdef.mcp b/src/mac/cdef/extcdef.mcp index ecd61b8d7f..be38f065b4 100644 Binary files a/src/mac/cdef/extcdef.mcp and b/src/mac/cdef/extcdef.mcp differ diff --git a/src/mac/fontenum.cpp b/src/mac/fontenum.cpp new file mode 100644 index 0000000000..f296efd93c --- /dev/null +++ b/src/mac/fontenum.cpp @@ -0,0 +1,166 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: mac/fontenum.cpp +// Purpose: wxFontEnumerator class for MacOS +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "fontenum.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/font.h" +#endif + +#include "wx/fontenum.h" +#include "wx/fontmap.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxFontEnumeratorHelper +{ +public: + wxFontEnumeratorHelper(wxFontEnumerator *fontEnum); + + // control what exactly are we enumerating + bool SetEncoding(wxFontEncoding encoding); + void SetFixedOnly(bool fixedOnly) + { m_fixedOnly = fixedOnly; } + + // call to start enumeration + void DoEnumerate(); + +private: + // the object we forward calls to OnFont() to + wxFontEnumerator *m_fontEnum; + + // if != -1, enum only fonts which have this encoding + int m_charset; + + // if not empty, enum only the fonts with this facename + wxString m_facename; + + // if TRUE, enum only fixed fonts + bool m_fixedOnly; +}; +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFontEnumeratorHelper +// ---------------------------------------------------------------------------- + +wxFontEnumeratorHelper::wxFontEnumeratorHelper(wxFontEnumerator *fontEnum) +{ + m_fontEnum = fontEnum; + m_charset = -1; + m_fixedOnly = FALSE; +} + +bool wxFontEnumeratorHelper::SetEncoding(wxFontEncoding encoding) +{ + wxNativeEncodingInfo info; + if ( !wxGetNativeFontEncoding(encoding, &info) ) + { + if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) ) + { + // no such encodings at all + return FALSE; + } + } + m_charset = info.charset; + m_facename = info.facename; + + return TRUE; +} + +void wxFontEnumeratorHelper::DoEnumerate() +{ + MenuHandle menu ; + Str255 name ; + short lines ; + + menu = NewMenu( 32000 , "\pFont" ) ; + AppendResMenu( menu , 'FONT' ) ; + lines = CountMenuItems( menu ) ; + + for ( int i = 1 ; i < lines+1 ; i ++ ) + { + GetMenuItemText( menu , i , name ) ; + p2cstr( name ) ; + /* + + if ( m_fixedOnly ) + { + // check that it's a fixed pitch font (there is *no* error here, the + // flag name is misleading!) + if ( tm->tmPitchAndFamily & TMPF_FIXED_PITCH ) + { + // not a fixed pitch font + return TRUE; + } + } + + if ( m_charset != -1 ) + { + // check that we have the right encoding + if ( lf->lfCharSet != m_charset ) + { + return TRUE; + } + } + + */ + m_fontEnum->OnFacename( name ) ; + } + DisposeMenu( menu ) ; +} + +// ---------------------------------------------------------------------------- +// wxFontEnumerator +// ---------------------------------------------------------------------------- + +bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding, + bool fixedWidthOnly) +{ + wxFontEnumeratorHelper fe(this); + if ( fe.SetEncoding(encoding) ) + { + fe.SetFixedOnly(fixedWidthOnly); + + fe.DoEnumerate(); + } + // else: no such fonts, unknown encoding + + return TRUE; +} + +bool wxFontEnumerator::EnumerateEncodings(const wxString& family) +{ + wxFAIL_MSG(wxT("TODO")); + + return TRUE; +} diff --git a/src/mac/gsocket.c b/src/mac/gsocket.c new file mode 100644 index 0000000000..5b36717505 --- /dev/null +++ b/src/mac/gsocket.c @@ -0,0 +1,1593 @@ +/* ------------------------------------------------------------------------- + * Project: GSocket (Generic Socket) for WX + * Name: gsocket.c + * Authors: Guilhem Lavaux, + * Guillermo Rodriguez Garcia (maintainer) + * Stefan CSomor + * Purpose: GSocket main mac file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +/* + * PLEASE don't put C++ comments here - this is a C source file. + */ + +#ifndef __GSOCKET_STANDALONE__ +#include "wx/setup.h" +#endif + +#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) + +#include +#include +#include +#include +#include +#include +#include +#include +#define OTUNIXERRORS 1 +#include +#include +#include +#if TARGET_CARBON + #define OTAssert( str , cond ) /* does not exists in Carbon */ +#endif +#include + +/* + * INADDR_BROADCAST is identical to INADDR_NONE which is not defined + * on all unices. INADDR_BROADCAST should be fine to indicate an error. + */ +#ifndef INADDR_BROADCAST +#define INADDR_BROADCAST 0xFFFFFFFFUL +#endif +#ifndef INADDR_NONE +#define INADDR_NONE INADDR_BROADCAST +#endif +#ifndef INADDR_ANY +#define INADDR_ANY 0x0UL +#endif +#ifndef __GSOCKET_STANDALONE__ + +#include "wx/mac/macnotfy.h" +#include "wx/mac/gsockmac.h" +#include "wx/gsocket.h" + +#else + +#include "gsockmac.h" +#include "gsocket.h" + +#endif /* __GSOCKET_STANDALONE__ */ + +void wxCYield() ; +#ifdef __WXDEBUG__ +#define qDebug 1 +#define qDebug2 1 +extern pascal void OTDebugStr(const char* str); +#endif +#include +InetSvcRef gInetSvcRef = 0 ; + + +OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode); + +/* Input: ep - endpointref on which to negotiate the option + enableReuseIPMode - desired option setting - true/false + Return: kOTNoError indicates that the option was successfully negotiated + OSStatus is an error if < 0, otherwise, the status field is + returned and is > 0. + + IMPORTANT NOTE: The endpoint is assumed to be in synchronous more, otherwise + this code will not function as desired +*/ + + +OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode) + +{ + UInt8 buf[kOTFourByteOptionSize]; // define buffer for fourByte Option size + TOption* opt; // option ptr to make items easier to access + TOptMgmt req; + TOptMgmt ret; + OSStatus err; + + if (!OTIsSynchronous(ep)) + { + return (-1); + } + opt = (TOption*)buf; // set option ptr to buffer + req.opt.buf = buf; + req.opt.len = sizeof(buf); + req.flags = T_NEGOTIATE; // negotiate for option + + ret.opt.buf = buf; + ret.opt.maxlen = kOTFourByteOptionSize; + + opt->level = INET_IP; // dealing with an IP Level function + opt->name = IP_REUSEADDR; + opt->len = kOTFourByteOptionSize; + opt->status = 0; + *(UInt32*)opt->value = enableReuseIPMode; // set the desired option level, true or false + + err = OTOptionManagement(ep, &req, &ret); + + // if no error then return the option status value + if (err == kOTNoError) + { + if (opt->status != T_SUCCESS) + err = opt->status; + else + err = kOTNoError; + } + + return err; +} + + +pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult, void *cookie) ; +pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult result, void *cookie) +{ + int wakeUp = true ; + GSocket* sock = (GSocket*) s ; + + if ( event == kOTSyncIdleEvent ) + { + YieldToAnyThread() ; + return ; + } + + if ( s ) + { + wxMacAddEvent( sock->m_mac_events , _GSocket_Internal_Proc , event , s , wakeUp ) ; + } + + return; +} + +static void SetDefaultEndpointModes(EndpointRef ep , void *data ) + // This routine sets the supplied endpoint into the default + // mode used in this application. The specifics are: + // blocking, synchronous, and using synch idle events with + // the standard YieldingNotifier. +{ + OSStatus junk = kOTNoError ; + OTAssert ("SetDefaultEndpointModes:invalid ref", ep != kOTInvalidEndpointRef ) ; + junk = OTSetAsynchronous(ep); + OTAssert("SetDefaultEndpointModes: Could not set asynchronous", junk == noErr); +/* + junk = OTSetBlocking(ep); + OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); + junk = OTSetSynchronous(ep); + OTAssert("SetDefaultEndpointModes: Could not set synchronous", junk == noErr); + junk = OTSetBlocking(ep); + OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); +*/ + junk = OTInstallNotifier(ep, OTInetEventHandler, data); + OTAssert("SetDefaultEndpointModes: Could not install notifier", junk == noErr); +/* + junk = OTUseSyncIdleEvents(ep, true); + OTAssert("SetDefaultEndpointModes: Could not use sync idle events", junk == noErr); +*/ +} + +/* Global initialisers */ + +int GSocket_Init() +{ + OSStatus err ; +#if TARGET_CARBON + InitOpenTransportInContext( kInitOTForApplicationMask , NULL ) ; +#else + InitOpenTransport() ; +#endif + gInetSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &err); + if ( gInetSvcRef == NULL || err != kOTNoError ) + { + OTAssert("Could not open Inet Services", err == noErr); + return FALSE ; + } + return TRUE; +} + +void GSocket_Cleanup() +{ + if ( gInetSvcRef != NULL ) + OTCloseProvider( gInetSvcRef ); +#if TARGET_CARBON + CloseOpenTransportInContext( NULL ) ; +#else + CloseOpenTransport() ; +#endif +} + +/* Constructors / Destructors for GSocket */ + +GSocket *GSocket_new() +{ + int i; + GSocket *socket; + + socket = (GSocket *)malloc(sizeof(GSocket)); + + if (socket == NULL) + return NULL; + + socket->m_endpoint = NULL ; + for (i=0;im_cbacks[i] = NULL; + } + socket->m_detected = 0; + socket->m_local = NULL; + socket->m_peer = NULL; + socket->m_error = GSOCK_NOERROR; + socket->m_server = FALSE; + socket->m_stream = TRUE; + socket->m_non_blocking = FALSE; + socket->m_timeout = 10*60*1000; + /* 10 minutes * 60 sec * 1000 millisec */ + socket->m_takesEvents = TRUE ; + socket->m_mac_events = wxMacGetNotifierTable() ; + return socket; +} + +void GSocket_destroy(GSocket *socket) +{ + assert(socket != NULL); + + /* Check that the socket is really shutdowned */ + if (socket->m_endpoint != kOTInvalidEndpointRef) + GSocket_Shutdown(socket); + + + /* Destroy private addresses */ + if (socket->m_local) + GAddress_destroy(socket->m_local); + + if (socket->m_peer) + GAddress_destroy(socket->m_peer); + + /* Destroy the socket itself */ + free(socket); +} + +/* GSocket_Shutdown: + * Disallow further read/write operations on this socket, close + * the fd and disable all callbacks. + */ +void GSocket_Shutdown(GSocket *socket) +{ + OSStatus err ; + int evt; + + assert(socket != NULL); + + /* If socket has been created, shutdown it */ + if (socket->m_endpoint != kOTInvalidEndpointRef ) + { + err = OTSndOrderlyDisconnect( socket->m_endpoint ) ; + if ( err != kOTNoError ) + { + + } + err = OTRcvOrderlyDisconnect( socket->m_endpoint ) ; + err = OTUnbind( socket->m_endpoint ) ; + err = OTCloseProvider( socket->m_endpoint ) ; + socket->m_endpoint = kOTInvalidEndpointRef ; + } + + /* Disable GUI callbacks */ + for (evt = 0; evt < GSOCK_MAX_EVENT; evt++) + socket->m_cbacks[evt] = NULL; + + socket->m_detected = 0; + _GSocket_Disable_Events(socket); + wxMacRemoveAllNotifiersForData( wxMacGetNotifierTable() , socket ) ; +} + + +/* Address handling */ + +/* GSocket_SetLocal: + * GSocket_GetLocal: + * GSocket_SetPeer: + * GSocket_GetPeer: + * Set or get the local or peer address for this socket. The 'set' + * functions return GSOCK_NOERROR on success, an error code otherwise. + * The 'get' functions return a pointer to a GAddress object on success, + * or NULL otherwise, in which case they set the error code of the + * corresponding GSocket. + * + * Error codes: + * GSOCK_INVSOCK - the socket is not valid. + * GSOCK_INVADDR - the address is not valid. + */ +GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address) +{ + assert(socket != NULL); + + /* the socket must be initialized, or it must be a server */ + if ((socket->m_endpoint != kOTInvalidEndpointRef && !socket->m_server)) + { + socket->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + socket->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (socket->m_local) + GAddress_destroy(socket->m_local); + + socket->m_local = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address) +{ + assert(socket != NULL); + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + socket->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (socket->m_peer) + GAddress_destroy(socket->m_peer); + + socket->m_peer = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GAddress *GSocket_GetLocal(GSocket *socket) +{ + GAddress *address = NULL ; + InetAddress addr; + GSocketError err; + InetAddress loc ; + + assert(socket != NULL); + + /* try to get it from the m_local var first */ + if (socket->m_local) + return GAddress_copy(socket->m_local); + + /* else, if the socket is initialized, try getsockname */ + if (socket->m_endpoint == kOTInvalidEndpointRef) + { + socket->m_error = GSOCK_INVSOCK; + return NULL; + } + + +/* we do not support multihoming with this code at the moment + OTGetProtAddress will have to be used then - but we don't have a handy + method to use right now +*/ + { + InetInterfaceInfo info; + OTInetGetInterfaceInfo(&info, kDefaultInetInterface); + loc.fHost = info.fAddress ; + loc.fPort = 0 ; + loc.fAddressType = AF_INET ; + } + + /* got a valid address from getsockname, create a GAddress object */ + address = GAddress_new(); + if (address == NULL) + { + socket->m_error = GSOCK_MEMERR; + return NULL; + } + + err = _GAddress_translate_from(address, &loc); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(address); + socket->m_error = err; + return NULL; + } + + return address; +} + +GAddress *GSocket_GetPeer(GSocket *socket) +{ + assert(socket != NULL); + + /* try to get it from the m_peer var */ + if (socket->m_peer) + return GAddress_copy(socket->m_peer); + + return NULL; +} + +/* Server specific parts */ + +/* GSocket_SetServer: + * Sets up this socket as a server. The local address must have been + * set with GSocket_SetLocal() before GSocket_SetServer() is called. + * Returns GSOCK_NOERROR on success, one of the following otherwise: + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use. + * GSOCK_INVADDR - the local address has not been set. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_SetServer(GSocket *sck) +{ + int type; + int arg = 1; + + assert(sck != NULL); + + /* must not be in use */ + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* the local addr must have been set */ + if (!sck->m_local) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Initialize all fields */ + sck->m_stream = TRUE; + sck->m_server = TRUE; + sck->m_oriented = TRUE; + +// TODO +#if 0 + /* Create the socket */ + sck->m_endpoint = socket(sck->m_local->m_realfamily, SOCK_STREAM, 0); + socket_set_ref( sck->m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) sck ) ; + if (sck->m_endpoint == kOTInvalidEndpointRef) + { + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + + ioctl(sck->m_endpoint, FIONBIO, &arg); + _GSocket_Enable_Events(sck); + + /* Bind to the local address, + * retrieve the actual address bound, + * and listen up to 5 connections. + */ + if ((bind(sck->m_endpoint, sck->m_local->m_addr, sck->m_local->m_len) != 0) || + (getsockname(sck->m_endpoint, + sck->m_local->m_addr, + (SOCKLEN_T *) &sck->m_local->m_len) != 0) || + (listen(sck->m_endpoint, 5) != 0)) + { + close(sck->m_endpoint); + sck->m_endpoint = -1; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +#endif + return GSOCK_NOERROR; +} + +/* GSocket_WaitConnection: + * Waits for an incoming client connection. Returns a pointer to + * a GSocket object, or NULL if there was an error, in which case + * the last error field will be updated for the calling GSocket. + * + * Error codes (set in the calling GSocket) + * GSOCK_INVSOCK - the socket is not valid or not a server. + * GSOCK_TIMEDOUT - timeout, no incoming connections. + * GSOCK_WOULDBLOCK - the call would block and the socket is nonblocking. + * GSOCK_MEMERR - couldn't allocate memory. + * GSOCK_IOERR - low-level error. + */ +GSocket *GSocket_WaitConnection(GSocket *socket) +{ + GSocket *connection = NULL ; + GSocketError err; + + int arg = 1; + + assert(socket != NULL); + + /* Reenable CONNECTION events */ + socket->m_detected &= ~GSOCK_CONNECTION_FLAG; + + /* If the socket has already been created, we exit immediately */ + if (socket->m_endpoint == kOTInvalidEndpointRef || !socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return NULL; + } + + /* Create a GSocket object for the new connection */ + connection = GSocket_new(); + + if (!connection) + { + socket->m_error = GSOCK_MEMERR; + return NULL; + } + + /* Wait for a connection (with timeout) */ + if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) + { + GSocket_destroy(connection); + /* socket->m_error set by _GSocket_Input_Timeout */ + return NULL; + } + +// TODO +#if 0 + connection->m_endpoint = accept(socket->m_endpoint, &from, (SOCKLEN_T *) &fromlen); +#endif + + if (connection->m_endpoint == kOTInvalidEndpointRef ) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + + GSocket_destroy(connection); + return NULL; + } + + /* Initialize all fields */ + connection->m_server = FALSE; + connection->m_stream = TRUE; + connection->m_oriented = TRUE; + + /* Setup the peer address field */ + connection->m_peer = GAddress_new(); + if (!connection->m_peer) + { + GSocket_destroy(connection); + socket->m_error = GSOCK_MEMERR; + return NULL; + } + // TODO + #if 0 + err = _GAddress_translate_from(connection->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(connection->m_peer); + GSocket_destroy(connection); + socket->m_error = err; + return NULL; + } + + ioctl(connection->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(connection); + + return connection; +} + +/* Datagram sockets */ + +/* GSocket_SetNonOriented: + * Sets up this socket as a non-connection oriented (datagram) socket. + * Before using this function, the local address must have been set + * with GSocket_SetLocal(), or the call will fail. Returns GSOCK_NOERROR + * on success, or one of the following otherwise. + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use. + * GSOCK_INVADDR - the local address has not been set. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_SetNonOriented(GSocket *sck) +{ + int arg = 1; + + assert(sck != NULL); + + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + if (!sck->m_local) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Initialize all fields */ + sck->m_stream = FALSE; + sck->m_server = FALSE; + sck->m_oriented = FALSE; + + /* Create the socket */ + +// TODO +#if 0 + sck->m_endpoint = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0); + socket_set_ref( sck->m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) sck ) ; +#endif + if (sck->m_endpoint == kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + +// TODO +#if 0 + ioctl(sck->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(sck); + + /* Bind to the local address, + * and retrieve the actual address bound. + */ +// TODO +#if 0 + if ((bind(sck->m_endpoint, sck->m_local->m_addr, sck->m_local->m_len) != 0) || + (getsockname(sck->m_endpoint, + sck->m_local->m_addr, + (SOCKLEN_T *) &sck->m_local->m_len) != 0)) + { + close(sck->m_endpoint); + sck->m_endpoint = -1; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +#endif + return GSOCK_NOERROR; +} + +/* Client specific parts */ + +/* GSocket_Connect: + * For stream (connection oriented) sockets, GSocket_Connect() tries + * to establish a client connection to a server using the peer address + * as established with GSocket_SetPeer(). Returns GSOCK_NOERROR if the + * connection has been succesfully established, or one of the error + * codes listed below. Note that for nonblocking sockets, a return + * value of GSOCK_WOULDBLOCK doesn't mean a failure. The connection + * request can be completed later; you should use GSocket_Select() + * to poll for GSOCK_CONNECTION | GSOCK_LOST, or wait for the + * corresponding asynchronous events. + * + * For datagram (non connection oriented) sockets, GSocket_Connect() + * just sets the peer address established with GSocket_SetPeer() as + * default destination. + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use or not valid. + * GSOCK_INVADDR - the peer address has not been established. + * GSOCK_TIMEDOUT - timeout, the connection failed. + * GSOCK_WOULDBLOCK - connection in progress (nonblocking sockets only) + * GSOCK_MEMERR - couldn't allocate memory. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) +{ + int ret; + int arg = 1; + InetAddress addr ; + TEndpointInfo info; + OTFlags flags = 0; + OSStatus err = kOTNoError; + TCall peer ; + + assert(sck != NULL); + + /* Enable CONNECTION events (needed for nonblocking connections) */ + sck->m_detected &= ~GSOCK_CONNECTION_FLAG; + + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + if (!sck->m_peer) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Streamed or dgram socket? */ + sck->m_stream = (stream == GSOCK_STREAMED); + sck->m_oriented = TRUE; + sck->m_server = FALSE; + + /* Create the socket */ +#if TARGET_CARBON + sck->m_endpoint = + OTOpenEndpointInContext( OTCreateConfiguration( kTCPName) , 0 , &info , &err , NULL ) ; +#else + sck->m_endpoint = + OTOpenEndpoint( OTCreateConfiguration( kTCPName) , 0 , &info , &err ) ; +#endif + if ( sck->m_endpoint == kOTInvalidEndpointRef || err != kOTNoError ) + { + sck->m_endpoint = kOTInvalidEndpointRef ; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + err = OTBind( sck->m_endpoint , nil , nil ) ; + if ( err != kOTNoError ) + { + return GSOCK_IOERR; + } + SetDefaultEndpointModes( sck->m_endpoint , sck ) ; +// TODO +#if 0 + ioctl(sck->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(sck); + + _GAddress_translate_to( sck->m_peer , &addr ) ; + memset( &peer , 0 , sizeof( TCall ) ) ; + peer.addr.len = sizeof( InetAddress ) ; + peer.addr.buf = (unsigned char*) &addr ; + err = OTConnect( sck->m_endpoint , &peer , nil ) ; + if ( err != noErr ) + { + /* If connect failed with EINPROGRESS and the GSocket object + * is in blocking mode, we select() for the specified timeout + * checking for writability to see if the connection request + * completes. + */ + + if ((err == kOTNoDataErr ) && (!sck->m_non_blocking)) + { + if (_GSocket_Output_Timeout(sck) == GSOCK_TIMEDOUT) + { + OTSndOrderlyDisconnect( sck->m_endpoint ) ; + sck->m_endpoint = kOTInvalidEndpointRef ; + /* sck->m_error is set in _GSocket_Output_Timeout */ + return GSOCK_TIMEDOUT; + } + else + { +/* + int error; + SOCKLEN_T len = sizeof(error); + + getsockopt(sck->m_endpoint, SOL_SOCKET, SO_ERROR, (void*) &error, &len); + + if (!error) +*/ + return GSOCK_NOERROR; + } + } + + /* If connect failed with EINPROGRESS and the GSocket object + * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK + * (and return GSOCK_WOULDBLOCK) but we don't close the socket; + * this way if the connection completes, a GSOCK_CONNECTION + * event will be generated, if enabled. + */ + if ((err == kOTNoDataErr) && (sck->m_non_blocking)) + { + sck->m_error = GSOCK_WOULDBLOCK; + return GSOCK_WOULDBLOCK; + } + + /* If connect failed with an error other than EINPROGRESS, + * then the call to GSocket_Connect has failed. + */ + OTSndOrderlyDisconnect( sck->m_endpoint ) ; + + sck->m_endpoint = kOTInvalidEndpointRef ; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +// OTInetEventHandler(sck, T_CONNECT , kOTNoError , NULL ) ; + return GSOCK_NOERROR; +} + +/* Generic IO */ + +/* Like recv(), send(), ... */ +int GSocket_Read(GSocket *socket, char *buffer, int size) +{ + int ret = 0 ; + + assert(socket != NULL); + + /* Reenable INPUT events */ + socket->m_detected &= ~GSOCK_INPUT_FLAG; + + if (socket->m_endpoint == kOTInvalidEndpointRef || socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return -1; + } + + /* If the socket is blocking, wait for data (with a timeout) */ + if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) + return -1; + + /* Read the data */ + if (socket->m_stream) + ret = _GSocket_Recv_Stream(socket, buffer, size); + else + ret = _GSocket_Recv_Dgram(socket, buffer, size); + + if (ret == -1) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + } + + return ret; +} + +int GSocket_Write(GSocket *socket, const char *buffer, int size) +{ + int ret; + + assert(socket != NULL); + + if (socket->m_endpoint == kOTInvalidEndpointRef || socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return -1; + } + + /* If the socket is blocking, wait for writability (with a timeout) */ + if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT) + return -1; + + /* Write the data */ + if (socket->m_stream) + ret = _GSocket_Send_Stream(socket, buffer, size); + else + ret = _GSocket_Send_Dgram(socket, buffer, size); + + if (ret == -1) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + + /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect + * in MSW). Once the first OUTPUT event is received, users can assume + * that the socket is writable until a read operation fails. Only then + * will further OUTPUT events be posted. + */ + socket->m_detected &= ~GSOCK_OUTPUT_FLAG; + return -1; + } + + return ret; +} + +/* GSocket_Select: + * Polls the socket to determine its status. This function will + * check for the events specified in the 'flags' parameter, and + * it will return a mask indicating which operations can be + * performed. This function won't block, regardless of the + * mode (blocking | nonblocking) of the socket. + */ +GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags) +{ + OTResult state ; + assert(socket != NULL); + wxMacProcessNotifierEvents() ; + /* + state = OTGetEndpointState(socket->m_endpoint); + + if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( socket->m_detected & GSOCK_INPUT_FLAG ) ) + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( socket->m_detected & GSOCK_OUTPUT_FLAG ) ) + { + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_detected |=GSOCK_OUTPUT_FLAG ; + (socket->m_cbacks[GSOCK_OUTPUT])(socket, GSOCK_OUTPUT, socket->m_data[GSOCK_OUTPUT]); + } + } + */ + return ( flags & socket->m_detected ) ; +} + +/* Flags */ + +/* GSocket_SetNonBlocking: + * Sets the socket to non-blocking mode. All IO calls will return + * immediately. + */ +void GSocket_SetNonBlocking(GSocket *socket, int non_block) +{ + assert(socket != NULL); + + socket->m_non_blocking = non_block; +} + +/* GSocket_SetTimeout: + * Sets the timeout for blocking calls. Time is expressed in + * milliseconds. + */ +void GSocket_SetTimeout(GSocket *socket, unsigned long millisec) +{ + assert(socket != NULL); + + socket->m_timeout = millisec; +} + +/* GSocket_GetError: + * Returns the last error occured for this socket. Note that successful + * operations do not clear this back to GSOCK_NOERROR, so use it only + * after an error. + */ +GSocketError GSocket_GetError(GSocket *socket) +{ + assert(socket != NULL); + + return socket->m_error; +} + +/* Callbacks */ + +/* GSOCK_INPUT: + * There is data to be read in the input buffer. If, after a read + * operation, there is still data available, the callback function will + * be called again. + * GSOCK_OUTPUT: + * The socket is available for writing. That is, the next write call + * won't block. This event is generated only once, when the connection is + * first established, and then only if a call failed with GSOCK_WOULDBLOCK, + * when the output buffer empties again. This means that the app should + * assume that it can write since the first OUTPUT event, and no more + * OUTPUT events will be generated unless an error occurs. + * GSOCK_CONNECTION: + * Connection succesfully established, for client sockets, or incoming + * client connection, for server sockets. Wait for this event (also watch + * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. + * GSOCK_LOST: + * The connection is lost (or a connection request failed); this could + * be due to a failure, or due to the peer closing it gracefully. + */ + +/* GSocket_SetCallback: + * Enables the callbacks specified by 'flags'. Note that 'flags' + * may be a combination of flags OR'ed toghether, so the same + * callback function can be made to accept different events. + * The callback function must have the following prototype: + * + * void function(GSocket *socket, GSocketEvent event, char *cdata) + */ +void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags, + GSocketCallback callback, char *cdata) +{ + int count; + + assert(socket != NULL); + + for (count = 0; count < GSOCK_MAX_EVENT; count++) + { + if ((flags & (1 << count)) != 0) + { + socket->m_cbacks[count] = callback; + socket->m_data[count] = cdata; + } + } +} + +/* GSocket_UnsetCallback: + * Disables all callbacks specified by 'flags', which may be a + * combination of flags OR'ed toghether. + */ +void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags) +{ + int count; + + assert(socket != NULL); + + for (count = 0; count < GSOCK_MAX_EVENT; count++) + { + if ((flags & (1 << count)) != 0) + { + socket->m_cbacks[count] = NULL; + socket->m_data[count] = NULL; + } + } +} + + +#define CALL_CALLBACK(socket, event) { \ + _GSocket_Disable(socket, event); \ + if (socket->m_cbacks[event]) \ + socket->m_cbacks[event](socket, event, socket->m_data[event]); \ +} + +int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size) +{ + OTFlags flags ; + OTResult res ; + + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + res = OTRcv( socket->m_endpoint , buffer , size , &flags ) ; + if ( res < 0 ) + { + return -1 ; + } + + // we simulate another read event if there are still bytes + if ( socket->m_takesEvents ) + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + return res ; +} + +int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) +{ +// TODO + int ret = -1; +#if 0 + struct sockaddr from; + SOCKLEN_T fromlen = sizeof(from); + GSocketError err; + + fromlen = sizeof(from); + + ret = recvfrom(socket->m_endpoint, buffer, size, 0, &from, (SOCKLEN_T *) &fromlen); + + if (ret == -1) + return -1; + + /* Translate a system address into a GSocket address */ + if (!socket->m_peer) + { + socket->m_peer = GAddress_new(); + if (!socket->m_peer) + { + socket->m_error = GSOCK_MEMERR; + return -1; + } + } + err = _GAddress_translate_from(socket->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(socket->m_peer); + socket->m_peer = NULL; + socket->m_error = err; + return -1; + } +#endif + return ret; +} + +int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size) +{ + OTFlags flags = 0 ; + OTResult res ; + + res = OTSnd( socket->m_endpoint , (void*) buffer , size , flags ) ; + return res ; +} + +int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) +{ + int ret = -1 ; +// TODO +#if 0 + struct sockaddr *addr; + int len ; + GSocketError err; + + if (!socket->m_peer) + { + socket->m_error = GSOCK_INVADDR; + return -1; + } + + err = _GAddress_translate_to(socket->m_peer, &addr, &len); + if (err != GSOCK_NOERROR) + { + socket->m_error = err; + return -1; + } + + ret = sendto(socket->m_endpoint, buffer, size, 0, addr, len); + + /* Frees memory allocated from _GAddress_translate_to */ + free(addr); +#endif + return ret; +} + + +/* + * ------------------------------------------------------------------------- + * GAddress + * ------------------------------------------------------------------------- + */ + +/* CHECK_ADDRESS verifies that the current family is either GSOCK_NOFAMILY + * or GSOCK_*family*, and if it is GSOCK_NOFAMILY, it initalizes address + * to be a GSOCK_*family*. In other cases, it returns GSOCK_INVADDR. + */ +#define CHECK_ADDRESS(address, family, retval) \ +{ \ + if (address->m_family == GSOCK_NOFAMILY) \ + if (_GAddress_Init_##family(address) != GSOCK_NOERROR) \ + return address->m_error; \ + if (address->m_family != GSOCK_##family) \ + { \ + address->m_error = GSOCK_INVADDR; \ + return retval; \ + } \ +} + +GAddress *GAddress_new() +{ + GAddress *address; + + if ((address = (GAddress *) malloc(sizeof(GAddress))) == NULL) + return NULL; + + address->m_family = GSOCK_NOFAMILY; + address->m_host = INADDR_NONE ; + address->m_port = 0 ; + + return address; +} + +GAddress *GAddress_copy(GAddress *address) +{ + GAddress *addr2; + + assert(address != NULL); + + if ((addr2 = (GAddress *) malloc(sizeof(GAddress))) == NULL) + return NULL; + + memcpy(addr2, address, sizeof(GAddress)); + return addr2; +} + +void GAddress_destroy(GAddress *address) +{ + assert(address != NULL); + + free(address); +} + +void GAddress_SetFamily(GAddress *address, GAddressType type) +{ + assert(address != NULL); + + address->m_family = type; +} + +GAddressType GAddress_GetFamily(GAddress *address) +{ + assert(address != NULL); + + return address->m_family; +} + +GSocketError _GAddress_translate_from(GAddress *address, + InetAddress *addr) +{ + switch (addr->fAddressType) + { + case AF_INET: + address->m_family = GSOCK_INET; + break; +#ifdef AF_INET6 + case AF_INET6: + address->m_family = GSOCK_INET6; + break; +#endif + default: + { + address->m_error = GSOCK_INVOP; + return GSOCK_INVOP; + } + } + address->m_host = addr->fHost ; + address->m_port = addr->fPort ; + return GSOCK_NOERROR; +} + +GSocketError _GAddress_translate_to(GAddress *address, + InetAddress *addr) +{ + memset(addr, 0 , sizeof(struct InetAddress)); + OTInitInetAddress( addr , address->m_port , address->m_host ) ; + return GSOCK_NOERROR; +} + +/* + * ------------------------------------------------------------------------- + * Internet address family + * ------------------------------------------------------------------------- + */ + +GSocketError _GAddress_Init_INET(GAddress *address) +{ + address->m_family = GSOCK_INET; + address->m_host = kOTAnyInetAddress ; + + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname) +{ + InetHostInfo hinfo ; + OSStatus ret ; + + assert(address != NULL); + + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + ret = OTInetStringToAddress( gInetSvcRef , (char*) hostname , &hinfo ) ; + if ( ret != kOTNoError ) + { + address->m_host = INADDR_NONE ; + address->m_error = GSOCK_NOHOST; + return GSOCK_NOHOST; + } + address->m_host = hinfo.addrs[0] ; + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_SetAnyAddress(GAddress *address) +{ + return GAddress_INET_SetHostAddress(address, INADDR_ANY); +} + +GSocketError GAddress_INET_SetHostAddress(GAddress *address, + unsigned long hostaddr) +{ + struct in_addr *addr; + + assert(address != NULL); + + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + address->m_host = hostaddr ; + + return GSOCK_NOERROR; +} + +struct service_entry +{ + char * name ; + unsigned short port ; + char * protocol ; +} ; +typedef struct service_entry service_entry ; + +service_entry gServices[] = +{ + { "http" , 80 , "tcp" } +} ; + +GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, + const char *protocol) +{ + InetAddress *addr; + int i ; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + if (!port) + { + address->m_error = GSOCK_INVPORT; + return GSOCK_INVPORT; + } + for ( i = 0 ; i < sizeof( gServices) / sizeof( service_entry ) ; ++i ) + { + if ( strcmp( port , gServices[i].name ) == 0 ) + { + if ( protocol == NULL || strcmp( protocol , gServices[i].protocol ) ) + { + address->m_port = gServices[i].port ; + return GSOCK_NOERROR; + } + } + } + + if (isdigit(port[0])) + { + address->m_port = atoi(port); + return GSOCK_NOERROR; + } + + address->m_error = GSOCK_INVPORT; + return GSOCK_INVPORT; +} + +GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) +{ + InetAddress *addr; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + address->m_port = port ; + + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t sbuf) +{ + InetDomainName name ; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + OTInetAddressToName( gInetSvcRef , address->m_host , &name ) ; + strncpy( hostname , name , sbuf ) ; + return GSOCK_NOERROR; +} + +unsigned long GAddress_INET_GetHostAddress(GAddress *address) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); + + return address->m_host; +} + +unsigned short GAddress_INET_GetPort(GAddress *address) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); + + return address->m_port; +} + +void _GSocket_Enable_Events(GSocket *socket) +{ + if ( socket->m_takesEvents ) + return ; + + { + OTResult state ; + socket->m_takesEvents = TRUE ; + state = OTGetEndpointState(socket->m_endpoint); + + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + { + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_detected |=GSOCK_OUTPUT_FLAG ; + (socket->m_cbacks[GSOCK_OUTPUT])(socket, GSOCK_OUTPUT, socket->m_data[GSOCK_OUTPUT]); + } + } + } +} + +void _GSocket_Disable_Events(GSocket *socket) +{ + socket->m_takesEvents = FALSE ; +} + +/* _GSocket_Input_Timeout: + * For blocking sockets, wait until data is available or + * until timeout ellapses. + */ +GSocketError _GSocket_Input_Timeout(GSocket *socket) +{ + if ( !socket->m_non_blocking ) + { + UnsignedWide now , start ; + short formerTakesEvents = socket->m_takesEvents ; + Microseconds(&start); + now = start ; + socket->m_takesEvents = FALSE ; + + while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < socket->m_timeout * 1000.0 ) + { + OTResult state ; + size_t sz = 0 ; + state = OTGetEndpointState(socket->m_endpoint); + + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_takesEvents = formerTakesEvents ; + return GSOCK_NOERROR; + } + Microseconds(&now); + } + socket->m_takesEvents = formerTakesEvents ; + socket->m_error = GSOCK_TIMEDOUT; + return GSOCK_TIMEDOUT; + } + return GSOCK_NOERROR; +} + +/* _GSocket_Output_Timeout: + * For blocking sockets, wait until data can be sent without + * blocking or until timeout ellapses. + */ +GSocketError _GSocket_Output_Timeout(GSocket *socket) +{ + if ( !socket->m_non_blocking ) + { + UnsignedWide now , start ; + short formerTakesEvents = socket->m_takesEvents ; + Microseconds(&start); + now = start ; + socket->m_takesEvents = FALSE ; + + while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < socket->m_timeout * 1000.0 ) + { + OTResult state ; + state = OTGetEndpointState(socket->m_endpoint); + + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_takesEvents = formerTakesEvents ; + return GSOCK_NOERROR; + } + Microseconds(&now); + } + socket->m_takesEvents = formerTakesEvents ; + socket->m_error = GSOCK_TIMEDOUT; + return GSOCK_TIMEDOUT; + } + return GSOCK_NOERROR; +} + +/* GSOCK_INPUT: + * There is data to be read in the input buffer. If, after a read + * operation, there is still data available, the callback function will + * be called again. + * GSOCK_OUTPUT: + * The socket is available for writing. That is, the next write call + * won't block. This event is generated only once, when the connection is + * first established, and then only if a call failed with GSOCK_WOULDBLOCK, + * when the output buffer empties again. This means that the app should + * assume that it can write since the first OUTPUT event, and no more + * OUTPUT events will be generated unless an error occurs. + * GSOCK_CONNECTION: + * Connection succesfully established, for client sockets, or incoming + * client connection, for server sockets. Wait for this event (also watch + * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. + * GSOCK_LOST: + * The connection is lost (or a connection request failed); this could + * be due to a failure, or due to the peer closing it gracefully. + */ + +void _GSocket_Internal_Proc(unsigned long e , void* d ) +{ + + GSocket * socket = (GSocket*) d ; + OTEventCode ev = (OTEventCode) e ; + GSocketEvent event; + GSocketEvent event2; + GSocketCallback cback; + char *data; + GSocketCallback cback2; + char *data2; + + if ( !socket ) + return ; + event = GSOCK_MAX_EVENT ; + event2 = GSOCK_MAX_EVENT ; + cback = NULL; + data = NULL; + cback2 = NULL; + data2 = NULL; + + /* Check that the socket still exists (it has not been + * destroyed) and for safety, check that the m_endpoint field + * is what we expect it to be. + */ + if ((socket != NULL) && (socket->m_takesEvents)) + { + switch (ev) + { + case T_LISTEN : + event = GSOCK_CONNECTION ; + break ; + case T_CONNECT : + event = GSOCK_CONNECTION ; + event2 = GSOCK_OUTPUT ; + { + TCall retCall; + + retCall.addr.buf = NULL; + retCall.addr.maxlen = 0; + retCall.opt.buf = NULL; + retCall.opt.maxlen = 0; + retCall.udata.buf = NULL; + retCall.udata.maxlen= 0; + OTRcvConnect( socket->m_endpoint , &retCall ) ; + } + break ; + case T_DISCONNECT : + event = GSOCK_LOST ; + break ; + case T_GODATA : + case T_GOEXDATA : + event = GSOCK_OUTPUT ; + break ; + case T_DATA : + event = GSOCK_INPUT ; + break ; + case T_EXDATA : + event = GSOCK_INPUT ; + break ; + } + if (event != GSOCK_MAX_EVENT) + { + cback = socket->m_cbacks[event]; + data = socket->m_data[event]; + + if (event == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event); + } + if (event2 != GSOCK_MAX_EVENT) + { + cback2 = socket->m_cbacks[event2]; + data2 = socket->m_data[event2]; + + if (event2 == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event2); + } + } + + /* OK, we can now leave the critical section because we have + * already obtained the callback address (we make no further + * accesses to socket->whatever). However, the app should + * be prepared to handle events from a socket that has just + * been closed! + */ + + if (cback != NULL) + (cback)(socket, event, data); + if (cback2 != NULL) + (cback2)(socket, event2, data2); + +} + +#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ diff --git a/src/mac/ldef/extldef.mcp b/src/mac/ldef/extldef.mcp index 12bf6effdd..b8973350a8 100644 Binary files a/src/mac/ldef/extldef.mcp and b/src/mac/ldef/extldef.mcp differ diff --git a/src/mac/macnotfy.cpp b/src/mac/macnotfy.cpp new file mode 100644 index 0000000000..3546eeb7f2 --- /dev/null +++ b/src/mac/macnotfy.cpp @@ -0,0 +1,137 @@ +/* ------------------------------------------------------------------------- + * Project: Mac Notifier Support + * Name: macnotfy.c + * Author: Stefan CSomor + * Purpose: Mac Notifier main file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +#include "wx/mac/macnotfy.h" + +const short kMaxEvents = 1000 ; + +struct wxMacNotificationEvents +{ + short top ; + short bottom ; + + wxMacNotificationProcPtr proc[kMaxEvents] ; + unsigned long events[kMaxEvents] ; + void* data[kMaxEvents] ; +} ; + +typedef struct wxMacNotificationEvents wxMacNotificationEvents ; +wxMacNotificationEvents gMacNotificationEvents ; + +ProcessSerialNumber gSocketProcess ; + +void wxMacWakeUp() +{ + ProcessSerialNumber psn ; + Boolean isSame ; + psn.highLongOfPSN = 0 ; + psn.lowLongOfPSN = kCurrentProcess ; + SameProcess( &gSocketProcess , &psn , &isSame ) ; + if ( isSame ) + { + PostEvent( nullEvent , 0 ) ; + } + else + { + WakeUpProcess( &gSocketProcess ) ; + } +} + +void wxMacCreateNotifierTable() +{ + GetCurrentProcess(&gSocketProcess); + gMacNotificationEvents.top = 0 ; + gMacNotificationEvents.bottom = 0 ; + for ( int i = 0 ; i < kMaxEvents ; ++i ) + { + gMacNotificationEvents.proc[i] = NULL ; + gMacNotificationEvents.events[i] = NULL ; + gMacNotificationEvents.data[i] = NULL ; + } +} + +void wxMacDestroyNotifierTable() +{ + wxASSERT( gMacNotificationEvents.top == gMacNotificationEvents.bottom ) ; +} + +wxMacNotifierTableRef wxMacGetNotifierTable() +{ + return (wxMacNotifierTableRef) &gMacNotificationEvents ; +} + +void wxMacAddEvent( + wxMacNotifierTableRef table , + wxMacNotificationProcPtr handler , + unsigned long event , + void* data , + short wakeUp ) +{ + wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ; + /* this should be protected eventually */ + short index = e->top++ ; + + if ( e->top == kMaxEvents ) + e->top = 0 ; + + e->proc[index] = handler ; + e->events[index] = event ; + e->data[index] = data ; + if ( wakeUp ) + wxMacWakeUp() ; +} + +bool gInProcessing = false ; + +void wxMacRemoveAllNotifiersForData( wxMacNotifierTableRef table , void* data ) +{ + wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ; + /* this should be protected eventually */ + short index = e->bottom ; + + while ( e->top != index ) + { + if ( index == kMaxEvents ) + index = 0 ; + if ( e->data[index] == data ) + e->data[index] = NULL ; + index++ ; + } +} + +void wxMacProcessNotifierEvents() +{ +// if ( gInProcessing ) +// return ; + + gInProcessing = true ; + while ( gMacNotificationEvents.top != gMacNotificationEvents.bottom ) + { + // consume event at bottom + short index = gMacNotificationEvents.bottom++ ; + if ( gMacNotificationEvents.bottom == kMaxEvents ) + gMacNotificationEvents.bottom = 0 ; + void* data = gMacNotificationEvents.data[index] ; + unsigned long event = gMacNotificationEvents.events[index] ; + wxMacNotificationProcPtr handler = gMacNotificationEvents.proc[index] ; + + gMacNotificationEvents.data[index] = NULL ; + gMacNotificationEvents.events[index] = NULL ; + gMacNotificationEvents.proc[index] = NULL ; + + handler( event , data ) ; + } + gInProcessing = false ; +} + +void wxMacProcessNotifierAndPendingEvents() +{ + wxMacProcessNotifierEvents() ; + wxTheApp->ProcessPendingEvents() ; +} diff --git a/src/mac/notebmac.cpp b/src/mac/notebmac.cpp new file mode 100644 index 0000000000..ab97b53540 --- /dev/null +++ b/src/mac/notebmac.cpp @@ -0,0 +1,413 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: notebook.cpp +// Purpose: implementation of wxNotebook +// Author: AUTHOR +// Modified by: +// Created: ??/??/98 +// RCS-ID: $Id$ +// Copyright: (c) AUTHOR +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- +#ifdef __GNUG__ +#pragma implementation "notebook.h" +#endif + +#include +#include +#include +#include +#include +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount())) + +const short kwxMacTabLeftMargin = 16 ; +const short kwxMacTabTopMargin = 30 ; +const short kwxMacTabRightMargin = 16 ; +const short kwxMacTabBottomMargin = 16 ; + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +#if !USE_SHARED_LIBRARIES +BEGIN_EVENT_TABLE(wxNotebook, wxControl) + EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange) + + EVT_SIZE(wxNotebook::OnSize) + EVT_SET_FOCUS(wxNotebook::OnSetFocus) + EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent) +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxNotebook construction +// ---------------------------------------------------------------------------- + +// common part of all ctors +void wxNotebook::Init() +{ + m_pImageList = NULL; + m_nSelection = -1; +} + +// default for dynamic class +wxNotebook::wxNotebook() +{ + Init(); +} + +// the same arguments as for wxControl +wxNotebook::wxNotebook(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + Create(parent, id, pos, size, style, name); +} + +// Create() function +bool wxNotebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , "" , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ; + + m_macControl = UMANewControl( parent->GetMacRootWindow() , &bounds , title , true , 0 , 0 , 1, + kControlTabSmallProc , (long) this ) ; + + MacPostControlCreate() ; + return TRUE ; +} + +// dtor +wxNotebook::~wxNotebook() +{ + m_macControl = NULL ; +} + +// ---------------------------------------------------------------------------- +// wxNotebook accessors +// ---------------------------------------------------------------------------- +int wxNotebook::GetPageCount() const +{ + return m_aPages.Count(); +} + +int wxNotebook::GetRowCount() const +{ + return 1; +} + +int wxNotebook::SetSelection(int nPage) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + ChangePage(m_nSelection, nPage); + SetControlValue( m_macControl , m_nSelection + 1 ) ; +// Boolean enabled = true ; + +// SetControlData( m_macControl, m_nSelection + 1, kControlTabEnabledFlagTag, sizeof( Boolean ), (Ptr)&enabled ); + return m_nSelection; +} + +void wxNotebook::AdvanceSelection(bool bForward) +{ + int nSel = GetSelection(); + int nMax = GetPageCount() - 1; + if ( bForward ) + SetSelection(nSel == nMax ? 0 : nSel + 1); + else + SetSelection(nSel == 0 ? nMax : nSel - 1); +} + +bool wxNotebook::SetPageText(int nPage, const wxString& strText) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return FALSE; +} + +wxString wxNotebook::GetPageText(int nPage) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return wxString(""); +} + +int wxNotebook::GetPageImage(int nPage) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return 0; +} + +bool wxNotebook::SetPageImage(int nPage, int nImage) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return FALSE; +} + +void wxNotebook::SetImageList(wxImageList* imageList) +{ + m_pImageList = imageList; + // TODO +} + +// ---------------------------------------------------------------------------- +// wxNotebook operations +// ---------------------------------------------------------------------------- + +// remove one page from the notebook +bool wxNotebook::DeletePage(int nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), FALSE ); + + // TODO: delete native widget page + + delete m_aPages[nPage]; + m_aPages.Remove(nPage); + + return TRUE; +} + +// remove one page from the notebook, without deleting the window +bool wxNotebook::RemovePage(int nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), FALSE ); + + m_aPages.Remove(nPage); + + return TRUE; +} + +// remove all pages +bool wxNotebook::DeleteAllPages() +{ + // TODO: delete native widget pages + + int nPageCount = GetPageCount(); + int nPage; + for ( nPage = 0; nPage < nPageCount; nPage++ ) + delete m_aPages[nPage]; + + m_aPages.Clear(); + + return TRUE; +} + +// add a page to the notebook +bool wxNotebook::AddPage(wxNotebookPage *pPage, + const wxString& strText, + bool bSelect, + int imageId) +{ + return InsertPage(GetPageCount(), pPage, strText, bSelect, imageId); +} + +// same as AddPage() but does it at given position +bool wxNotebook::InsertPage(int nPage, + wxNotebookPage *pPage, + const wxString& strText, + bool bSelect, + int imageId) +{ + wxASSERT( pPage != NULL ); + wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), FALSE ); + + ControlTabInfoRec tie ; + Boolean enabled = true ; + if ( nPage + 1 > GetControlMaximum( m_macControl ) ) + { + SetControlMaximum( m_macControl , nPage + 1 ) ; + } + + tie.version = 0 ; + tie.iconSuiteID = 0 ; + strcpy( (char*) tie.name , strText ) ; + c2pstr( (char*) tie.name ) ; + SetControlData( m_macControl, nPage + 1, kControlTabInfoTag , sizeof( ControlTabInfoRec) , (char*) &tie ) ; + SetControlData( m_macControl, m_nSelection + 1, kControlTabEnabledFlagTag, sizeof( Boolean ), (Ptr)&enabled ); + + // save the pointer to the page + m_aPages.Insert(pPage, nPage); + + // some page must be selected: either this one or the first one if there is + // still no selection + if ( bSelect ) + m_nSelection = nPage; + else if ( m_nSelection == -1 ) + m_nSelection = 0; + + // don't show pages by default (we'll need to adjust their size first) + pPage->Show( FALSE ) ; + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxNotebook callbacks +// ---------------------------------------------------------------------------- + +// @@@ OnSize() is used for setting the font when it's called for the first +// time because doing it in ::Create() doesn't work (for unknown reasons) +void wxNotebook::OnSize(wxSizeEvent& event) +{ + static bool s_bFirstTime = TRUE; + if ( s_bFirstTime ) { + // TODO: any first-time-size processing. + s_bFirstTime = FALSE; + } + + // TODO: all this may or may not be necessary for your platform + + // emulate page change (it's esp. important to do it first time because + // otherwise our page would stay invisible) + int nSel = m_nSelection; + m_nSelection = -1; + SetSelection(nSel); + + // fit the notebook page to the tab control's display area + int w, h; + GetSize(&w, &h); + + unsigned int nCount = m_aPages.Count(); + for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) { + wxNotebookPage *pPage = m_aPages[nPage]; + pPage->SetSize(kwxMacTabLeftMargin, kwxMacTabTopMargin, w - kwxMacTabLeftMargin - kwxMacTabRightMargin, + h - kwxMacTabTopMargin - kwxMacTabBottomMargin ); +// pPage->SetSize(0, 0, w, h); + if ( pPage->GetAutoLayout() ) + pPage->Layout(); + } + + // Processing continues to next OnSize + event.Skip(); +} + +void wxNotebook::OnSelChange(wxNotebookEvent& event) +{ + // is it our tab control? + if ( event.GetEventObject() == this ) + ChangePage(event.GetOldSelection(), event.GetSelection()); + + // we want to give others a chance to process this message as well + event.Skip(); +} + +void wxNotebook::OnSetFocus(wxFocusEvent& event) +{ + // set focus to the currently selected page if any + if ( m_nSelection != -1 ) + m_aPages[m_nSelection]->SetFocus(); + + event.Skip(); +} + +void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event) +{ + if ( event.IsWindowChange() ) { + // change pages + AdvanceSelection(event.GetDirection()); + } + else { + // pass to the parent + if ( GetParent() ) { + event.SetCurrentFocus(this); + GetParent()->ProcessEvent(event); + } + } +} + +// ---------------------------------------------------------------------------- +// wxNotebook base class virtuals +// ---------------------------------------------------------------------------- + +// override these 2 functions to do nothing: everything is done in OnSize + +void wxNotebook::SetConstraintSizes(bool /* recurse */) +{ + // don't set the sizes of the pages - their correct size is not yet known + wxControl::SetConstraintSizes(FALSE); +} + +bool wxNotebook::DoPhase(int /* nPhase */) +{ + return TRUE; +} + +void wxNotebook::Command(wxCommandEvent& event) +{ + wxFAIL_MSG("wxNotebook::Command not implemented"); +} + +// ---------------------------------------------------------------------------- +// wxNotebook helper functions +// ---------------------------------------------------------------------------- + +// hide the currently active panel and show the new one +void wxNotebook::ChangePage(int nOldSel, int nSel) +{ + // it's not an error (the message may be generated by the tab control itself) + // and it may happen - just do nothing + if ( nSel == nOldSel ) + { + wxNotebookPage *pPage = m_aPages[nSel]; + pPage->Show(FALSE); + pPage->Show(TRUE); + pPage->SetFocus(); + return; + } + + if ( nOldSel != -1 ) { + m_aPages[nOldSel]->Show(FALSE); + } + + wxNotebookPage *pPage = m_aPages[nSel]; + pPage->Show(TRUE); + pPage->SetFocus(); + + m_nSelection = nSel; +} + +void wxNotebook::MacHandleControlClick( ControlHandle control , SInt16 controlpart ) +{ + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_windowId , ::GetControlValue(m_macControl) - 1, m_nSelection); + event.SetEventObject(this); + + ProcessEvent(event); +} + diff --git a/src/mac/statbrma.cpp b/src/mac/statbrma.cpp new file mode 100644 index 0000000000..d3c0e102dd --- /dev/null +++ b/src/mac/statbrma.cpp @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: statbar.cpp +// Purpose: native implementation of wxStatusBar (optional) +// Author: AUTHOR +// Modified by: +// Created: ??/??/98 +// RCS-ID: $Id$ +// Copyright: (c) 1998 AUTHOR +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "statusbr.h" +#endif + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/mac/statusbr.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxStatusBarMac, wxStatusBarGeneric); + +BEGIN_EVENT_TABLE(wxStatusBarMac, wxStatusBarGeneric) + EVT_PAINT(wxStatusBarMac::OnPaint) +END_EVENT_TABLE() +#endif //USE_SHARED_LIBRARY + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStatusBarXX class +// ---------------------------------------------------------------------------- + +wxStatusBarMac::wxStatusBarMac() +{ + SetParent(NULL); +} + +wxStatusBarMac::~wxStatusBarMac() +{ +} + +bool wxStatusBarMac::Create(wxWindow *parent, wxWindowID id, + long style , + const wxString& name) +{ + return wxStatusBarGeneric::Create( parent , id , style , name ) ; +} + +void wxStatusBarMac::DrawFieldText(wxDC& dc, int i) +{ + int leftMargin = 2; + + wxRect rect; + GetFieldRect(i, rect); + + wxString text(GetStatusText(i)); + + long x, y; + + dc.GetTextExtent(text, &x, &y); + + int xpos = rect.x + leftMargin + 1 ; + int ypos = 2 ; + + dc.SetClippingRegion(rect.x, 0, rect.width, m_height); + + dc.DrawText(text, xpos, ypos); + + dc.DestroyClippingRegion(); +} + +void wxStatusBarMac::DrawField(wxDC& dc, int i) +{ + DrawFieldText(dc, i); +} + +void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + wxPen black( wxBLACK , 1 , wxSOLID ) ; + wxPen white( wxWHITE , 1 , wxSOLID ) ; + + dc.SetPen(black); + dc.DrawLine(0, 0 , + m_width , 0); + dc.SetPen(white); + dc.DrawLine(0, 1 , + m_width , 1); + + + int i; + if ( GetFont().Ok() ) + dc.SetFont(GetFont()); + dc.SetBackgroundMode(wxTRANSPARENT); + + for ( i = 0; i < m_nFields; i ++ ) + DrawField(dc, i); + +# ifdef __WXMSW__ + dc.SetFont(wxNullFont); +# endif // MSW +} \ No newline at end of file diff --git a/src/mac/statlmac.cpp b/src/mac/statlmac.cpp new file mode 100644 index 0000000000..52f3d40733 --- /dev/null +++ b/src/mac/statlmac.cpp @@ -0,0 +1,61 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: generic/statline.cpp +// Purpose: a generic wxStaticLine class +// Author: Vadim Zeitlin +// Created: 28.06.99 +// Version: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "statline.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/statline.h" +#include "wx/statbox.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStaticLine, wxControl) + +// ---------------------------------------------------------------------------- +// wxStaticLine +// ---------------------------------------------------------------------------- + +bool wxStaticLine::Create( wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxString &name) +{ + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; + + // ok, this is ugly but it's better than nothing: use a thin static box to + // emulate static line + + wxSize sizeReal = AdjustSize(size); + +// m_statbox = new wxStaticBox(parent, id, wxT(""), pos, sizeReal, style, name); + + return TRUE; +} diff --git a/src/mac/tooltip.cpp b/src/mac/tooltip.cpp new file mode 100644 index 0000000000..583bd9b892 --- /dev/null +++ b/src/mac/tooltip.cpp @@ -0,0 +1,334 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: tooltip.cpp +// Purpose: wxToolTip implementation +// Author: Robert Roebling +// Id: $Id$ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "tooltip.h" +#endif + +#include "wx/setup.h" + +#if wxUSE_TOOLTIPS + +#include "wx/window.h" +#include "wx/tooltip.h" +#include "wx/geometry.h" +#include "wx/mac/aga.h" +#include "wx/mac/uma.h" + +//----------------------------------------------------------------------------- +// global data +//----------------------------------------------------------------------------- + +class wxMacToolTip +{ + public : + wxMacToolTip( ) ; + ~wxMacToolTip() ; + + void Setup( WindowRef window , wxString text , wxPoint localPosition ) ; + long GetMark() { return m_mark ; } + void Draw() ; + void Clear() ; + bool IsShown() { return m_shown ; } + private : + + wxString m_label ; + wxPoint m_position ; + Rect m_rect ; + WindowRef m_window ; + PicHandle m_backpict ; + bool m_shown ; + long m_mark ; +} ; + +class wxMacToolTipTimer : wxTimer +{ +public: + wxMacToolTipTimer(wxMacToolTip* tip, int iMilliseconds) ; + + void Notify() + { + if ( m_mark == m_tip->GetMark() ) + m_tip->Draw() ; + + delete this; + } + +protected: + wxMacToolTip* m_tip; + long m_mark ; +}; + +//----------------------------------------------------------------------------- +// wxToolTip +//----------------------------------------------------------------------------- +static long s_ToolTipDelay = 500 ; +static bool s_ShowToolTips = true ; +static wxMacToolTip s_ToolTip ; +static wxWindow* s_LastWindowEntered = NULL ; +static wxRect2DInt s_ToolTipArea ; +static WindowRef s_ToolTipWindowRef = NULL ; +wxToolTip::wxToolTip( const wxString &tip ) +{ + m_text = tip; + m_window = (wxWindow*) NULL; +} + +wxToolTip::~wxToolTip() +{ +} + +void wxToolTip::SetTip( const wxString &tip ) +{ + m_text = tip; + + if ( m_window ) + { + /* + // update it immediately + wxToolInfo ti(GetHwndOf(m_window)); + ti.lpszText = (wxChar *)m_text.c_str(); + + (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, 0, &ti); + */ + } +} + +void wxToolTip::SetWindow( wxWindow *win ) +{ + m_window = win; +} + +void wxToolTip::Enable( bool flag ) +{ + if ( s_ShowToolTips != flag ) + { + s_ShowToolTips = flag ; + if ( s_ShowToolTips ) + { + } + else + { + s_ToolTip.Clear() ; + } + } +} + +void wxToolTip::SetDelay( long msecs ) +{ + s_ToolTipDelay = msecs ; +} + +void wxToolTip::RelayEvent( wxWindow *win , wxMouseEvent &event ) +{ + if ( s_ShowToolTips ) + { + if ( event.GetEventType() == wxEVT_LEAVE_WINDOW ) + { + s_ToolTip.Clear() ; + } + else if (event.GetEventType() == wxEVT_ENTER_WINDOW || event.GetEventType() == wxEVT_MOTION ) + { + wxPoint2DInt where( event.m_x , event.m_y ) ; + if ( s_LastWindowEntered == win && s_ToolTipArea.Contains( where ) ) + { + } + else + { + s_ToolTip.Clear() ; + s_ToolTipArea = wxRect2DInt( event.m_x - 2 , event.m_y - 2 , 4 , 4 ) ; + s_LastWindowEntered = win ; + + WindowRef window = win->GetMacRootWindow() ; + int x = event.m_x ; + int y = event.m_y ; + wxPoint local( x , y ) ; + win->MacClientToRootWindow( &x, &y ) ; + wxPoint windowlocal( x , y ) ; + s_ToolTip.Setup( window , win->MacGetToolTipString( local ) , windowlocal ) ; + } + } + } +} + +void wxToolTip::RemoveToolTips() +{ + s_ToolTip.Clear() ; +} +// --- mac specific + +wxMacToolTipTimer::wxMacToolTipTimer( wxMacToolTip *tip , int msec ) +{ + m_tip = tip; + m_mark = tip->GetMark() ; + Start(msec, true); +} + +wxMacToolTip::wxMacToolTip() +{ + m_window = NULL ; + m_backpict = NULL ; + m_mark = 0 ; + m_shown = false ; +} + +void wxMacToolTip::Setup( WindowRef window , wxString text , wxPoint localPosition ) +{ + m_mark++ ; + Clear() ; + m_position = localPosition ; + m_label = wxMacMakeMacStringFromPC( text ) ; + m_window = window ; + s_ToolTipWindowRef = window ; + m_backpict = NULL ; + new wxMacToolTipTimer( this , s_ToolTipDelay ) ; +} + +wxMacToolTip::~wxMacToolTip() +{ + if ( m_backpict ) + Clear() ; +} + +const short kTipBorder = 2 ; +const short kTipOffset = 5 ; + +void wxMacToolTip::Draw() +{ + if ( m_label.Length() == 0 ) + return ; + + if ( m_window == s_ToolTipWindowRef ) + { + #if TARGET_CARBON + AGAPortHelper help( GetWindowPort( m_window ) ); + #else + AGAPortHelper help( ( m_window ) ); + #endif + m_shown = true ; + + SetOrigin( 0 , 0 ) ; + TextFont( kFontIDGeneva ) ; + TextSize( 9 ) ; + TextFace( 0 ) ; + FontInfo fontInfo; + ::GetFontInfo(&fontInfo); + short lineh = fontInfo.ascent + fontInfo.descent + fontInfo.leading; + short height = 0 ; + // short width = TextWidth( m_label , 0 ,m_label.Length() ) ; + + int i = 0 ; + int length = m_label.Length() ; + int width = 0 ; + int thiswidth = 0 ; + int laststop = 0 ; + const char *text = m_label ; + while( i < length ) + { + if( text[i] == 13 || text[i] == 10) + { + thiswidth = ::TextWidth( text , laststop , i - laststop ) ; + if ( thiswidth > width ) + width = thiswidth ; + + height += lineh ; + laststop = i+1 ; + } + i++ ; + } + if ( i - laststop > 0 ) + { + thiswidth = ::TextWidth( text , laststop , i - laststop ) ; + if ( thiswidth > width ) + width = thiswidth ; + height += lineh ; + } + + + m_rect.left = m_position.x + kTipOffset; + m_rect.top = m_position.y + kTipOffset; + m_rect.right = m_rect.left + width + 2 * kTipBorder; + m_rect.bottom = m_rect.top + height + 2 * kTipBorder; + ClipRect( &m_rect ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + m_backpict = OpenPicture(&m_rect); + + CopyBits(GetPortBitMapForCopyBits(GetWindowPort(m_window)), + GetPortBitMapForCopyBits(GetWindowPort(m_window)), + &m_rect, + &m_rect, + srcCopy, + NULL); + + ClosePicture(); + RGBColor yellow = { 0xFFFF , 0xFFFF , (153<<8)+153 } ; + RGBBackColor( &yellow ) ; + EraseRect( &m_rect ) ; + FrameRect( &m_rect ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder); + + i = 0 ; + laststop = 0 ; + height = 0 ; + while( i < length ) + { + if( text[i] == 13 || text[i] == 10) + { + ::DrawText( text , laststop , i - laststop ) ; + height += lineh ; + ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder + height ); + laststop = i+1 ; + } + i++ ; + } + + ::DrawText( text , laststop , i - laststop ) ; + ::TextMode( srcOr ) ; + + // DrawText( m_label , 0 , m_label.Length() ) ; + } +} + +void wxToolTip::NotifyWindowDelete( WindowRef win ) +{ + if ( win == s_ToolTipWindowRef ) + { + s_ToolTipWindowRef = NULL ; + } +} + +void wxMacToolTip::Clear() +{ + m_mark++ ; + if ( !m_shown ) + return ; + + if ( m_window == s_ToolTipWindowRef && m_backpict ) + { + #if TARGET_CARBON + AGAPortHelper help( GetWindowPort(m_window) ) ; + #else + AGAPortHelper help( (m_window) ) ; + #endif + m_shown = false ; + + SetOrigin( 0 , 0 ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + DrawPicture(m_backpict, &m_rect); + KillPicture(m_backpict); + m_backpict = NULL ; + } +} + +#endif +