From ee6b1d97e741fda8d579fa21cbc89f0c91615cef Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 10 Aug 2000 04:43:04 +0000 Subject: [PATCH] wxMac merge git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@7999 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/mac/gsockmac.h | 93 ++ include/wx/mac/macnotfy.h | 33 + src/mac/carbon/fontenum.cpp | 166 ++++ src/mac/carbon/gsocket.c | 1593 +++++++++++++++++++++++++++++++++++ src/mac/carbon/macnotfy.cpp | 137 +++ src/mac/carbon/notebmac.cpp | 413 +++++++++ src/mac/carbon/statbrma.cpp | 108 +++ src/mac/carbon/statlmac.cpp | 61 ++ src/mac/carbon/tooltip.cpp | 334 ++++++++ src/mac/cdef/extcdef.mcp | Bin 100937 -> 100791 bytes src/mac/fontenum.cpp | 166 ++++ src/mac/gsocket.c | 1593 +++++++++++++++++++++++++++++++++++ src/mac/ldef/extldef.mcp | Bin 102079 -> 100471 bytes src/mac/macnotfy.cpp | 137 +++ src/mac/notebmac.cpp | 413 +++++++++ src/mac/statbrma.cpp | 108 +++ src/mac/statlmac.cpp | 61 ++ src/mac/tooltip.cpp | 334 ++++++++ 18 files changed, 5750 insertions(+) create mode 100644 include/wx/mac/gsockmac.h create mode 100644 include/wx/mac/macnotfy.h create mode 100644 src/mac/carbon/fontenum.cpp create mode 100644 src/mac/carbon/gsocket.c create mode 100644 src/mac/carbon/macnotfy.cpp create mode 100644 src/mac/carbon/notebmac.cpp create mode 100644 src/mac/carbon/statbrma.cpp create mode 100644 src/mac/carbon/statlmac.cpp create mode 100644 src/mac/carbon/tooltip.cpp create mode 100644 src/mac/fontenum.cpp create mode 100644 src/mac/gsocket.c create mode 100644 src/mac/macnotfy.cpp create mode 100644 src/mac/notebmac.cpp create mode 100644 src/mac/statbrma.cpp create mode 100644 src/mac/statlmac.cpp create mode 100644 src/mac/tooltip.cpp 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 ecd61b8d7f44b0aa3d11c0a09a3cccf77c9147f9..be38f065b4b6a95288179caf8f70f1988f5633cf 100644 GIT binary patch delta 2597 zcmZ{k4Nz4@6vy}6$GwmAg*+wlllu?C7!;UF(TbwWpL#j!66G)#D_NbbSX^L4EmP`7%@BsV$VYOXdxA&XB zhVM~H^Oi(XxMCv`dQH~S#*7uZ^HLD@b$BX6$a9zaM=Mw)z40|apPs@?CinC$(F;cRwQsq- zwySIBT!1@dE>5g+*sb6}RHfUGPNgx!Wd>ewYBsx|jZ>2JC0Vt4YI}@7!4c_6md7xrukAIyWs&>2Y zlfD_kM&NC^p+shEZQ3OBaI;4Ly)tj}P`c$Xev79w`cJJf#t}C?qMyCuZ|1d;s!!_N ztGiuJ-+hj1cNoR_)YGhP-{tVmOQcZCf1fpQN&v^vIfgz&z~N@s-IC}Bg%Va9>|Gf} zTOE3?OKz5_>anfw7%lO12_DQg&bVnJP6_fTig(mR%23U*MSX1Dhgj0#J(x@@HR;B2 zGVgS1HZ%4{gW|2vq@;)S-fa<>-caQcab##>nze<%nyzR7d%|f z@(w1kY@hQI^bBbg;>CGFD7>HQYzN5nVd084a%yN?*aS>1^QbE5S!^z=HjdWN?zn6R z=Hcwlu6xj@vb|!X5ZYAc*LQ$D$9&NhV{}Q;78DBGyiHC_PN08H%jLUm^ULpTO6-{ zYLhe+vfd>V zyTy9}qI?x6AbBvMgvV>o%r%t znmH-iiW<@;xZV{Z*BBI=&P7V_QdH{ zoqX9Kqe4Vz*-GEXWp(pFIj^)d=p(KwoG9KbA0ULRkl7JUo4!HeV98!a$<9Xft=<<6kbt6D4<<+|9p(9PuXabJxPWd`no3Ar> z>ySu!V}3ma&3YdbE7zVt9*H-3QSwqq&RH$+DD>?XmoZqWaPe#CJD8^vB-enpuoC)P z7T1lR>uI=+W_)J!SxqrY-gzTc%EESI0c2cp2VQ`aT2cJ*kt_swUvB@K_x%E7AM*tv J#<#1f;xFwRY+L{U delta 2544 zcmYk72~d?)6vyvL=q7fp39(uK&dEbC@P9dpaLU^xF=7P+?U{@ zpN3_&K`v$UIlZ*SnaoUW(sFB*nIK1BGl}MwIGFT5?|wvg=DYXY-#K?V=iYNamr&1E ztG1k?qC&=)nK9m%@s*W~uR8vjZI|DezxMpfa(gga474VER1)#cfpIEhUTytAW+9Pv zGORj#dYDeDbnrfvX<4Gczm6-qEx_tknQ%h%vU}^l+q#*>9(#cZ4SFD^26xw21!wWf zG;eV=#Ltr2bdRwmQTm@DwF<@sFAgyYM@A=CQ3OBBT_rI*fNKG9e4e=5XSV2Jw}|YB zFmWf_M{JGQ<-@TsXPgz~>;3G#0z1SXOTCfM+Il8LzhB?Ndqlz$m>9*&Bab@P^UUGa z)~4Pb6OlWzs|5g#h66n1`s(-gGEUzuxdCinN!%NB7?HdZm9IaJ?UI>W~^opw2#+YooA$CRf| zavcff7T)IX^9db=qts7db5Z3Yxint1uJsecG6E?Goqa`ZeJq7wIo$RY!Hv+SooYz?O+WI=PRuab_8MFIn7aTkV%lYbQ?sTPnio;sIgTJKvKlU*} z8zYJft+ce}J(-Uc%b$GVg8v&-{lJ|m7T4xzmvc=!g=XMWMA2GYlAFi8zNfRDKow&d4piTH zxbos{$hfyuGM;G#P97Z_p`a5Z_48LkP9rU2g)?yF<$Ox08z9|-S;P?SypyK{JJB`N z!&X4fkm^NwTGU$pQEX`y`XO>VAN~V5Q|e1`snkr#?;QY}F8OLN&0Nl-oflun<+Mos zvd^K*lKP+5V>{jDHeXl+HcRsIAhb4V-(-h8TXK6(v_8__KLv8OXngp$i<{(Y}!avGUQ%06oth^F^=XiZsv;Jkg-uJw<(h6q=QdihP;F*V^4;{ z!63P@Ok$-T%$g^nt&>NjL@h&SsZ=!FL>nz9+C>o|9ZK`x?N>Pe2*7d=W{rVp!=(MU ze?X@Di_$mU#u_d&`f4@dBf zJW-B51Y0M0ADlY!#B-0;Nfe0n9tCsHMr%0tFbZ;ohjaTIXpKbq;Va10$K3XvsEtHv zjfA{`FgWFgyx;1`-jFvE2LBk9ktY|nkXM_eqVK0@Wuhnt`$OJraEh>zC^Zd`w-~$y z6UjtTE_MOiDtW&v|0Rm*pjTs?Uk@FeFM zbd8Wdm=Ae3>0xjKwG6o$`53ZB82lD$Bjnp@Q+o)5)49t;QBKpdw3jgB@rzLziBk3s z$Xk++q6pU&mpJh+P-;Ixhjs_s(F0M-L{TbcLf%IhJi9$nD(oO{OP)Yaf=m?E)EP1@ z0(-}osEx}y7!NwzPnhup3cbAaYQWcQ1Y_?KhoTm>;aUAJkPi?B*HOzXQkPM7zDJnx z#3XIXCf?u77By?@H}Pmw_H<3BHfN!B6K(8L+%`p?t;yt#A(ToOSOC}Cc-J364oP0T KS4-T?OaBE@EK3yt 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 12bf6effdd0018dad05efb4ce941dd49a2a9cf9f..b8973350a86eee0e42223027c0bd50304ddd24e0 100644 GIT binary patch delta 2392 zcmZvd4Q!2P6vv-)?|t7}RJD4G-D+K}wrJ`rRF!ls^%2&!o%&d`hAQa@{ZiDlE3Kj{ z>cwNDW@6FVEbJ9G@iAG#*d#u-&@fvNAB%2e%v5yj|J?H`i9N}E&v}2(d7pEhbI$YJ z;|==b4Z16L;llYs2)hu}ThQX;f|lGl;K~n(8U;E76S+b-po&rAImSKpz_6sTD{R$GtmMJ1|EzGKkwsmK#DmnALn*EuU@<}=+!`ZsBAn;pv=3$m6Y5oT!m9o^KYNVj31+-Now`q{l} zdy$h~vy_>GX^?UC(JbS)Tm58UDMk6xV!l^)R(Gmsu?ur>Wy+9O{dvoD3Jf<7UheB} zu36x+zsOyP+PP`JebV1slteek^t2qb8G%n*&FI#7eO~kJ-4{c<{msiWv$eJ`RJlTo zXEE)Fs6ukcsmU}$UPz$PW=V6FQ#xbG{laIccXu+i>f~o$DDO&!r=_ueTq=B~ zde3LmU7LDdw8;)rDM#)cORY$=AN}t%cH+^za2M?Gp39|94)57q3Uqky=2L)nsE~p+ zZ?jUp11qSz-Dda5^c8g2oe_>KT`4Han?^-pSu)# zhN40gr3zt#-wG9<=MG4wkBhKo$O!(RM0-yv4CoV?M{AI7w$E#Tp2a-8 zBP4H38@2@cB<3Y5fQ`J))9a#x5R_f(5ro%dbL1W*?8Uu`YPs84#)tX zy*{ER^cstIMnF2Rb8fBL)oPxI?gp8}6MN&Jud(=KNM1=?Tc9_=tHd+Rkb(ZS8%qI{e_D2H?z)mAb~0fa>oAXdnX9vUvw{RGrr|k5?Ju z{?*4%fxdzHFa+Vu;te#Vf}!6qXe#>H>Q~*h4P+zpp8HbI>z?tHCk8uaZ73!1jPl< zd_1}7^}u6dxDY!P$AoG^YiCz~g8rGpf-=-UJ)a`IR2?_9Q^hySX>}B5r<@vDTZcPh trj$pN%-bWI>!|-g>`>#<+WgdYsZJ8UTX597l+;KwWUx{cL{oIdNBGDG zeA=~qlv)#-HPvTgX6aO>shLwVQetI=j~-_ENEC|xch7=O-^_Q<+21|)+;i?Z-`yK) zjRTvF@X6DsKP`l?2|-;1EpQ0(c6%qhFerWy=tNAU3t@*U)bCK?P^xGnG@lGJw*?I% z-Kr0AQRrG9x?`}~gf!V?uTYAp^jPMp@b=cN@Nrb>39xe77E*8kwrsT~vW`dQ>gF$r z5$2BCK=Vp`g4x|;H>bH4nQ5+`R$NT7%_?xuq6kDPoOpe5_wY-93h`i?RU6mNX8!K# zUFk8*4hhjg1lM>;c+?hVaCv)cWW<{BOXFBD%-qg#k zwzrJ2GP;siWWd z+Ed9+`HY)VE$8|DPHXwJaGNRw3&I4#b$M_)7*KjS~g`+pndFUPo_NSrYtxKwCX2~(&hF(bkwT48bxa3 zCu{a*&_zSqJ=A3WTr#!Nvjxcv<|I@mG9Z^GS|4Awt0e!=DG+C-X*Ktx6CCdwNgZ3V z52ZWLB81dA1#2~R#T2B&#-Y{hEu=8ryzGi?SpuVPiYX;P)7nc%8SRT68I4muT{JU) ziqKP*pw9QJVhiE9ChN-R56#s{9-B|yynVo&J~R7gYW^WL2$7S3;Zt7T={)q|ih}KR)`yp)`IG}ik0}V zXo!XM7c{vP`Yh(>zJp9++LD z2(~d8kc*(F%z$3T#*JHL;9>;ZgtD|0bs$s6w8 zAPW^1WT4|>LfHO*YOHeRotI;hi>tqV6>JgncoZGQ^{On4kt(yrJdub?&tF~rYBF^7 zMd49RChq19j;Ib;s(_%xgBbm%(VPVRIlPJ=#~9?ZH~M#kUZF7fX$%JY`ErHIY8g*- zISVlvVVM6e$10T7ObRD`>RFK<=(SPKt zR8Sif7Bo=x7dO6sXcF`n6&7?q{=EG+nZ95P$V<%KQIKeS-_7*;Tlk@(gKfrWjNJM9 zlJU?tDJ-a8U{A|bQZ`QP3&|g*gV(&W65CVL?NC$gm1Zv5AsbWo8BLh{?xfv67|1a(e}J i>u~`kbg{464n(p-{v8OAa5|A8!K(gsN_G}rVzpa 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 + -- 2.49.0