[Spice-devel] [PATCH] client: port for Mac OS X

Attila Sukosd attila.sukosd at gmail.com
Sun Sep 26 05:57:46 PDT 2010


Hi All,

I finally had a bit of time to gather the changes to the spice client in
order to get it working under Mac.
Changes:
- initializing variables so the compiler doesn't complain
- fixed socket flags (MSG_NOSIGNAL => SO_NOSIGPIPE)
- implemented missing pthread_mutex_timedlock()
- replaced clock_gettime with gettimeofday
- added some different headers
- replaced the event handler with a select() based one instead of epoll
- pthread_yield() replaced with pthread_yield_np() for OS X
- disabled clipboard (XConvertSelection), it seem to break things right now
- added initial audio playback using PortAudio (no recording yet, sorry!) +
configure changes to detect OS X and not check for alsa
- force X11 keycodes for OSX instead of evdev

I'm not saying its beautiful, but it does the job :)

- Attila


 client/application.cpp         |    2 +-
 client/client_net_socket.cpp   |    7 ++
 client/cmd_line_parser.cpp     |    8 ++-
 client/threads.cpp             |   40 +++++++++
 client/x11/Makefile.am         |    4 +-
 client/x11/atomic_count.h      |   23 +++--
 client/x11/event_sources_p.cpp |  188
++++++++++++++++++++--------------------
 client/x11/event_sources_p.h   |   42 ++++++---
 client/x11/named_pipe.cpp      |    2 +-
 client/x11/platform.cpp        |   33 +++++++-
 client/x11/playback.cpp        |   80 ++++++++++++++++-
 client/x11/playback.h          |   11 +++
 client/x11/record.cpp          |   14 ++-
 client/x11/record.h            |    4 +
 client/x11/red_window.cpp      |    4 +-
 common/lines.c                 |    1 +
 configure.ac                   |   31 +++++--
 17 files changed, 353 insertions(+), 141 deletions(-)

diff --git a/client/application.cpp b/client/application.cpp
index 490cd8c..7ebeea2 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -648,7 +648,7 @@ RedScreen* Application::get_screen(int id)
     if (!(screen = _screens[id])) {
         Monitor* mon = find_monitor(id);
         SpicePoint size;
-
+    size.x = size.y = 0;
         if (_full_screen && mon) {
             size = mon->get_size();
         } else {
diff --git a/client/client_net_socket.cpp b/client/client_net_socket.cpp
index 6ce44c5..014d5a6 100644
--- a/client/client_net_socket.cpp
+++ b/client/client_net_socket.cpp
@@ -25,6 +25,13 @@
 #include <spice/error_codes.h>
 #include "utils.h"

+#if defined(__APPLE__) || defined(__MACH__)
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+#endif
+
+
 ClientNetSocket::ClientNetSocket(uint16_t id, const struct in_addr&
dst_addr, uint16_t dst_port,
                                  ProcessLoop& process_loop, EventHandler&
event_handler)
     : _id (id)
diff --git a/client/cmd_line_parser.cpp b/client/cmd_line_parser.cpp
index ef72dba..ba0bd5b 100644
--- a/client/cmd_line_parser.cpp
+++ b/client/cmd_line_parser.cpp
@@ -26,6 +26,12 @@

 #define DISABLE_ABBREVIATE

+#if defined(__APPLE__) || defined(__MACH__)
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+#endif
+

 CmdLineParser::Option::Option(int in_id, const std::string& in_name, char
in_short_name,
                               OptionType in_type, const std::string&
in_help,
@@ -450,7 +456,7 @@ void CmdLineParser::show_help()
     static const int HELP_WIDTH = 80 - HELP_START_POS;
     std::ostringstream os;

-    os << basename(_argv[0]) << " - " << _description.c_str() <<
"\n\noptions:\n\n";
+    os << _argv[0] << " - " << _description.c_str() << "\n\noptions:\n\n";

     Options::iterator iter = _options.begin();
     for (; iter != _options.end(); ++iter) {
diff --git a/client/threads.cpp b/client/threads.cpp
index a9b8ea5..098134a 100644
--- a/client/threads.cpp
+++ b/client/threads.cpp
@@ -21,6 +21,38 @@
 #include "debug.h"
 #ifdef WIN32
 #include <sys/timeb.h>
+#elif defined(__MACH__) || defined(__APPLE__)
+#include <sys/time.h>
+#define _x_min(a, b) ((a) < (b) ? (a) : (b))
+#if _POSIX_TIMERS <= 0
+// FIXME: workaround to missing pthread_mutex_timedlock in Mac OS X
+int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec
*abs_timeout)
+{
+    int pthread_rc;
+    struct timespec remaining, slept, ts;
+
+    remaining = *abs_timeout;
+    while ((pthread_rc = pthread_mutex_trylock(mutex)) == EBUSY) {
+        ts.tv_sec = 0;
+        ts.tv_nsec = (remaining.tv_sec > 0 ? 10000000 :
_x_min(remaining.tv_nsec,10000000));
+        nanosleep(&ts, &slept);
+        ts.tv_nsec -= slept.tv_nsec;
+        if (ts.tv_nsec <= remaining.tv_nsec) {
+            remaining.tv_nsec -= ts.tv_nsec;
+        }
+        else {
+            remaining.tv_sec--;
+            remaining.tv_nsec = (1000000 - (ts.tv_nsec -
remaining.tv_nsec));
+        }
+        if (remaining.tv_sec < 0 || (!remaining.tv_sec && remaining.tv_nsec
<= 0)) {
+            return ETIMEDOUT;
+        }
+    }
+
+    return pthread_rc;
+}
+
+#endif
 #endif

 Thread::Thread(thread_main_t thread_main, void* opaque)
@@ -43,6 +75,11 @@ static inline void rel_time(struct timespec& time,
uint64_t delta_nano)
     _ftime_s(&now);
     time.tv_sec = (long)now.time;
     time.tv_nsec = now.millitm * 1000 * 1000;
+#elif defined(__APPLE__) || defined(__MACH__)
+    struct timeval tv;
+    gettimeofday(&tv,NULL);
+    time.tv_sec = tv.tv_sec;
+    time.tv_nsec = tv.tv_usec*1000;
 #else
     clock_gettime(CLOCK_MONOTONIC, &time);
 #endif
@@ -75,10 +112,13 @@ Condition::Condition()
 #else
     pthread_condattr_t attr;
     pthread_condattr_init(&attr);
+#if defined(__MACH__) || defined(__APPLE__)
+#else
     int r;
     if ((r = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))) {
         THROW("set clock failed %d", r);
     }
+#endif
     pthread_cond_init(&_condition, &attr);
     pthread_condattr_destroy(&attr);
 #endif
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 101f6dd..ceb07ef 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -200,8 +200,10 @@ spicec_LDFLAGS = \
 spicec_LDADD =                        \
     $(PIXMAN_LIBS)                    \
     $(ALSA_LIBS)                    \
+    $(PA_LIBS)                    \
     $(GL_LIBS)                    \
     $(XRANDR_LIBS)                    \
     $(MISC_X_LIBS)                    \
     $(CEGUI_LIBS)                    \
-    -lrt
+    $(LIBRT)
+
diff --git a/client/x11/atomic_count.h b/client/x11/atomic_count.h
index f48c667..8e6fd15 100644
--- a/client/x11/atomic_count.h
+++ b/client/x11/atomic_count.h
@@ -1,23 +1,28 @@
 /*
    Copyright (C) 2009 Red Hat, Inc.

-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.

-   This library is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.

-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <
http://www.gnu.org/licenses/>.
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

 #ifndef _H_ATOMIC_COUNT
 #define _H_ATOMIC_COUNT

+#if defined(__MACH__) || defined(__APPLE__)
+#include <stdint.h>
+#endif
+
+
 class AtomicCount {
 public:
     AtomicCount(uint32_t count = 0) : _count (count) {}
diff --git a/client/x11/event_sources_p.cpp b/client/x11/event_sources_p.cpp
index d59bffd..c164500 100644
--- a/client/x11/event_sources_p.cpp
+++ b/client/x11/event_sources_p.cpp
@@ -1,40 +1,29 @@
 /*
    Copyright (C) 2009 Red Hat, Inc.

-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.

-   This library is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.

-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <
http://www.gnu.org/licenses/>.
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
-
-#include <sys/epoll.h>
 #include <sys/fcntl.h>
-
 #include "event_sources.h"
-#include "debug.h"
-#include "utils.h"
-
-#ifdef USING_EVENT_FD
-#include <sys/eventfd.h>
-#endif

-#define NUM_EPOLL_EVENTS 10
+#include <sys/select.h>

-#ifdef USING_EVENT_FD
-#define WRITE_FD _event_fd
-#define EVENT_DATA_TYPE eventfd_t
-#else
 #define WRITE_FD _event_write_fd
 #define EVENT_DATA_TYPE uint8_t
-#endif
+
+#include "debug.h"
+#include "utils.h"

 class EventWrapper {
 public:
@@ -77,9 +66,12 @@ private:

 EventSources::EventSources()
 {
-    _epoll = epoll_create(NUM_EPOLL_EVENTS);
-    if (_epoll == -1) {
-        THROW("create epool failed");
+    FD_ZERO(&_readfds);
+    FD_ZERO(&_writefds);
+    for(int i=0;i<NUM_EVENTS;i++) {
+    _lofds[i].fd = 0;
+    _lofds[i].fd = NULL;
+    _lofds[i].rw = 0;
     }
 }

@@ -89,48 +81,82 @@ EventSources::~EventSources()
     for (; iter != _events.end(); iter++) {
         delete *iter;
     }
-    close(_epoll);
 }

-bool EventSources::wait_events(int timeout_ms)
+bool EventSources::wait_events(int timeout_milli)
 {
-    struct epoll_event events[NUM_EPOLL_EVENTS];
-    int num_events = epoll_wait(_epoll, events, NUM_EPOLL_EVENTS,
timeout_ms);
+    int num_events = 0;
+    struct timeval tmout;
+    tmout.tv_sec = 0;
+    tmout.tv_usec = timeout_milli*1000;
+    fd_set tmpreadfds, tmpwritefds;
+
+    tmpreadfds = _readfds;
+    tmpwritefds = _writefds;

+    if (timeout_milli == -1) {
+    num_events = select(_hfd+1, &tmpreadfds, &tmpwritefds, NULL, NULL);
+    } else {
+    num_events = select(_hfd+1, &tmpreadfds, &tmpwritefds, NULL, &tmout);
+    }
     if (num_events == -1) {
-        if (errno == EINTR) {
-            return false;
-        }
-        THROW("wait error eventfd failed");
+    //THROW("select() failed");
+        return false;
+    } else if (num_events == 0) {
+    return false;
+    } else {
+    for (int i = 0; i < NUM_EVENTS; i++) {
+        if ((_lofds[i].rw && FD_ISSET(_lofds[i].fd, &tmpwritefds)) ||
+            FD_ISSET(_lofds[i].fd, &tmpreadfds)) {
+            EventWrapper* wrapper;
+            EventSource* event;
+            wrapper = (EventWrapper *)_lofds[i].wrapper;
+            wrapper->ref();
+            if ((event = wrapper->get_event())) {
+                event->action();
+            }
+            wrapper->unref();
+        }
+    }
     }
+    return false;
+}

-    for (int i = 0; i < num_events; i++) {
-        ((EventWrapper*)events[i].data.ptr)->ref();
+void EventSources_p::add_fd(int fd,EventWrapper *wrapper, unsigned char rw)
{
+    // save the highest fd
+    if (fd > _hfd)
+    _hfd = fd;
+    for(int i=0;i<NUM_EVENTS;i++) {
+    if (_lofds[i].fd == 0) {
+        _lofds[i].fd = fd;
+        _lofds[i].wrapper = wrapper;
+        _lofds[i].rw = rw;
+        FD_SET(fd, &_readfds);
+        if (rw)
+            FD_SET(fd, &_writefds);
+        break;
+    }
     }
+}

-    for (int i = 0; i < num_events; i++) {
-        EventWrapper* wrapper;
-        EventSource* event;
-
-        wrapper = (EventWrapper *)events[i].data.ptr;
-        if ((event = wrapper->get_event())) {
-            event->action();
-        }
-        wrapper->unref();
-    }
-    return false;
+void EventSources_p::del_fd(int fd) {
+   for(int i=0;i<NUM_EVENTS;i++) {
+    if (_lofds[i].fd == fd) {
+        FD_CLR(fd, &_readfds);
+        if (_lofds[i].rw)
+            FD_CLR(fd, &_writefds);
+        _lofds[i].fd = 0;
+        _lofds[i].wrapper = NULL;
+        _lofds[i].rw = 0;
+    }
+   }
 }

 void EventSources::add_trigger(Trigger& trigger)
 {
     int fd = trigger.get_fd();
     EventWrapper* wrapper = new EventWrapper(*this, trigger);
-    struct epoll_event event;
-    event.data.ptr = wrapper;
-    event.events = EPOLLIN;
-    if (epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, &event) == -1) {
-        THROW("epoll add failed");
-    }
+    add_fd(fd, wrapper, 0);
     _events.push_back(wrapper);
 }

@@ -162,26 +188,18 @@ void EventSources::remove_trigger(Trigger& trigger)
         }
     }
     int fd = trigger.get_fd();
-    if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
-        THROW("epoll remove failed");
-    }
+    del_fd(fd);
 }

 EventSources::Trigger::Trigger()
 {
-#ifdef USING_EVENT_FD
-    _event_fd = eventfd(0, 0);
-    if (_event_fd == -1) {
-        THROW("create eventfd failed");
-    }
-#else
     int fd[2];
     if (pipe(fd) == -1) {
         THROW("create pipe failed");
     }
     _event_fd = fd[0];
     _event_write_fd = fd[1];
-#endif
+
     int flags;
     if ((flags = fcntl(_event_fd, F_GETFL)) == -1) {
         THROW("failed to set eventfd non block: %s", strerror(errno));
@@ -195,9 +213,6 @@ EventSources::Trigger::Trigger()
 EventSources::Trigger::~Trigger()
 {
     close(_event_fd);
-#ifndef USING_EVENT_FD
-    close(_event_write_fd);
-#endif
 }

 void EventSources::Trigger::trigger()
@@ -263,25 +278,6 @@ static void set_blocking(int fd)
     }
 }

-static void add_to_poll(int fd, int epoll, EventWrapper* wrapper)
-{
-    struct epoll_event event;
-    event.data.ptr = wrapper;
-    event.events = EPOLLIN | EPOLLOUT | EPOLLET;
-    if (epoll_ctl(epoll, EPOLL_CTL_ADD, fd, &event) == -1) {
-        THROW("epoll add failed");
-    }
-}
-
-void EventSources::add_socket(Socket& socket)
-{
-    int fd = socket.get_socket();
-    set_non_blocking(fd);
-    EventWrapper* wrapper = new EventWrapper(*this, socket);
-    add_to_poll(fd, _epoll, wrapper);
-    _events.push_back(wrapper);
-}
-
 static bool remove_event(EventSources_p::Events& events, EventSource&
event)
 {
     EventSources_p::Events::iterator iter = events.begin();
@@ -296,6 +292,15 @@ static bool remove_event(EventSources_p::Events&
events, EventSource& event)
         }
     }
 }
+void EventSources::add_socket(Socket& socket)
+{
+    int fd = socket.get_socket();
+    set_non_blocking(fd);
+    EventWrapper* wrapper = new EventWrapper(*this, socket);
+    add_fd(fd, wrapper, 0); // last parameter should be 1 to monitor for
write availability?
+    _events.push_back(wrapper);
+}
+

 void EventSources::remove_socket(Socket& socket)
 {
@@ -303,9 +308,7 @@ void EventSources::remove_socket(Socket& socket)
         THROW("socket not found");
     }
     int fd = socket.get_socket();
-    if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
-        THROW("epoll remove failed");
-    }
+    del_fd(fd);
     set_blocking(fd);
 }

@@ -314,7 +317,7 @@ void EventSources::add_file(File& file)
     int fd = file.get_fd();
     set_non_blocking(fd);
     EventWrapper* wrapper = new EventWrapper(*this, file);
-    add_to_poll(fd, _epoll, wrapper);
+    add_fd(fd, wrapper, 0);
     _events.push_back(wrapper);
 }

@@ -324,9 +327,7 @@ void EventSources::remove_file(File& file)
         THROW("file not found");
     }
     int fd = file.get_fd();
-    if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
-        THROW("epoll remove failed");
-    }
+    del_fd(fd);
     set_blocking(fd);
 }

@@ -337,3 +338,4 @@ void EventSources::add_handle(Handle& file)
 void EventSources::remove_handle(Handle& file)
 {
 }
+
diff --git a/client/x11/event_sources_p.h b/client/x11/event_sources_p.h
index 09703c0..027ac9e 100644
--- a/client/x11/event_sources_p.h
+++ b/client/x11/event_sources_p.h
@@ -1,22 +1,26 @@
 /*
    Copyright (C) 2009 Red Hat, Inc.

-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.

-   This library is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.

-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <
http://www.gnu.org/licenses/>.
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

-#ifndef _H_EVENT_SOURCES_P
-#define _H_EVENT_SOURCES_P
+#ifndef _H_EVENTS_LOOP_P
+#define _H_EVENTS_LOOP_P
+
+#define NUM_EVENTS 10
+
+#include <sys/select.h>

 #include "common.h"
 #include "threads.h"
@@ -29,12 +33,24 @@

 class EventWrapper;

+struct fd_to_ptr {
+    int fd;
+    EventWrapper *wrapper;
+    unsigned char rw;
+};
+
 class EventSources_p {
 public:
+    void add_fd(int, EventWrapper*, unsigned char);
+    void del_fd(int);
     void remove_wrapper(EventWrapper*);

 public:
-    int _epoll;
+    int _hfd;
+    fd_set _readfds;
+    fd_set _writefds;
+    struct fd_to_ptr _lofds[NUM_EVENTS];
+
     typedef std::list<EventWrapper*> Events;
     Events _events;

@@ -49,9 +65,7 @@ public:

 public:
     int _event_fd;
-#ifndef USING_EVENT_FD
     int _event_write_fd;
-#endif
     bool _pending_int;
     Mutex _lock;
 };
diff --git a/client/x11/named_pipe.cpp b/client/x11/named_pipe.cpp
index c6f38da..db3930b 100644
--- a/client/x11/named_pipe.cpp
+++ b/client/x11/named_pipe.cpp
@@ -17,7 +17,7 @@

 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/epoll.h>
+//#include <sys/epoll.h>
 #include <sys/un.h>
 #include "named_pipe.h"
 #include "utils.h"
diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index cc1502b..e8d89b0 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -30,15 +30,13 @@
 #include <X11/extensions/XShm.h>
 #include <unistd.h>
 #include <sys/socket.h>
-#include <sys/epoll.h>
+//#include <sys/epoll.h>
 #include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
-#include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <set>
-#include <values.h>
 #include <signal.h>
 #include <config.h>
 #include <sys/shm.h>
@@ -61,6 +59,18 @@
 #define BOOL bool
 #include "named_pipe.h"

+#if defined(__LINUX__)
+#include <values.h>
+#elif defined(__APPLE__) || defined(__MACH__)
+#include <float.h>
+#include <machine/limits.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <assert.h>
+#define MAXINT INT_MAX
+#define MININT INT_MIN
+#endif
+
 //#define X_DEBUG_SYNC(display) XSync(display, False)
 #define X_DEBUG_SYNC(display)
 #ifdef HAVE_XRANDR12
@@ -427,7 +437,14 @@ void Platform::send_quit_request()
 uint64_t Platform::get_monolithic_time()
 {
     struct timespec time_space;
+#if defined(__LINUX__)
     clock_gettime(CLOCK_MONOTONIC, &time_space);
+#elif defined(__APPLE__) || defined(__MACH__)
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    time_space.tv_sec = tv.tv_sec;
+    time_space.tv_nsec = tv.tv_usec*1000;
+#endif
     return uint64_t(time_space.tv_sec) * 1000 * 1000 * 1000 +
uint64_t(time_space.tv_nsec);
 }

@@ -463,7 +480,11 @@ void Platform::msleep(unsigned int millisec)

 void Platform::yield()
 {
+#if defined(__APPLE__) || defined(__MACH__)
+    pthread_yield_np();
+#else
     pthread_yield();
+#endif
 }

 void Platform::term_printf(const char* format, ...)
@@ -3016,8 +3037,14 @@ void
Platform::set_clipboard_listener(ClipboardListener* listener)
         return;
     }
     clipboard_listener = listener;
+
+    // FIXME: Tis seems broken on Mac OS X...
+    // Fails with the following error:
+    // 1285496484 ERROR [87445:18446744073709551615] x_error_handler: x
error on display /tmp/launch-h1OMho/org.x:0 error BadWindow (invalid Window
parameter) minor 0 request X_ConvertSelection
+#if !defined(__APPLE__) && !defined(__MACH__)
     XConvertSelection(x_display, XA_PRIMARY, utf8_atom, clipboard_prop,
         platform_win, CurrentTime);
+#endif
 }

 bool Platform::set_clipboard_data(uint32_t type, const uint8_t* data,
int32_t size)
diff --git a/client/x11/playback.cpp b/client/x11/playback.cpp
index be89a98..75f1bb0 100644
--- a/client/x11/playback.cpp
+++ b/client/x11/playback.cpp
@@ -22,9 +22,6 @@
 #define REING_SIZE_MS 300

 WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample,
uint32_t channels)
-    : _pcm (NULL)
-    , _hw_params (NULL)
-    , _sw_params (NULL)
 {
     if (!init(sampels_per_sec, bits_per_sample, channels)) {
         cleanup();
@@ -34,6 +31,7 @@ WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t
bits_per_sample, uint3

 void WavePlayer::cleanup()
 {
+#if defined(__LINUX__)
     if (_pcm) {
         snd_pcm_close(_pcm);
     }
@@ -45,6 +43,10 @@ void WavePlayer::cleanup()
     if (_sw_params) {
         snd_pcm_sw_params_free(_sw_params);
     }
+#elif defined(__MACH__) || defined(__APPLE__)
+    Pa_Terminate();
+    _stopped = 1;
+#endif
 }

 WavePlayer::~WavePlayer()
@@ -57,6 +59,8 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
                       uint32_t channels)
 {
     const int frame_size = WavePlaybackAbstract::FRAME_SIZE;
+    _sampels_per_ms = sampels_per_sec / 1000;
+#if defined(__LINUX__)
     const char* pcm_device = "default";
     snd_pcm_format_t format;
     int err;
@@ -71,7 +75,6 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
     default:
         return false;
     }
-    _sampels_per_ms = sampels_per_sec / 1000;

     if ((err = snd_pcm_open(&_pcm, pcm_device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK)) < 0) {
         LOG_ERROR("cannot open audio playback device %s %s", pcm_device,
snd_strerror(err));
@@ -174,12 +177,44 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
         LOG_ERROR("cannot prepare pcm device %s", snd_strerror(err));
         return false;
     }
-
+#elif defined(__MACH__) || defined(__APPLE__)
+    _err = Pa_Initialize();
+    if (_err != paNoError) {
+    LOG_ERROR("PortAudio initialization failure!");
+    return false;
+    }
+
+    _outputParameters.device = Pa_GetDefaultOutputDevice();
+    if (_outputParameters.device == paNoDevice) {
+    LOG_ERROR("PortAudio: No dfault output device");
+    return false;
+    }
+    _outputParameters.channelCount = channels;
+    _outputParameters.hostApiSpecificStreamInfo = NULL;
+    switch (bits_per_sample) {
+    case 8:
+        _outputParameters.sampleFormat = paInt8;
+        break;
+    case 16:
+        _outputParameters.sampleFormat = paInt16;
+        break;
+    default:
+        return false;
+    }
+    _outputParameters.suggestedLatency =
Pa_GetDeviceInfo(_outputParameters.device)->defaultLowOutputLatency;
+    _err = Pa_OpenStream(&_stream, NULL, &_outputParameters,
sampels_per_sec, frame_size, paClipOff, NULL, NULL);
+    if (_err != paNoError) {
+    DBG(0,"PortAudio: Error number: %d message: %s", _err,
Pa_GetErrorText(_err));
+    return false;
+    }
+    DBG(0, "Initialized PortAudio: samples/sec: %d channels: %d
bits/sample: %d",sampels_per_sec, channels, bits_per_sample);
+#endif
     return true;
 }

 bool WavePlayer::write(uint8_t* frame)
 {
+#if defined(__LINUX__)
     snd_pcm_sframes_t ret = snd_pcm_writei(_pcm, frame,
WavePlaybackAbstract::FRAME_SIZE);
     if (ret < 0) {
         if (ret == -EAGAIN) {
@@ -190,13 +225,43 @@ bool WavePlayer::write(uint8_t* frame)
             snd_pcm_writei(_pcm, frame, WavePlaybackAbstract::FRAME_SIZE);
         }
     }
+#elif defined(__MACH__) || defined(__APPLE__)
+    if (_stopped) {
+    _err = Pa_StartStream(_stream);
+    if (_err) {
+        LOG_ERROR("PortAudio: write errcode: %d message: %s", _err,
Pa_GetErrorText(_err));
+    }
+    _stopped = 0;
+    }
+    _err = Pa_WriteStream(_stream, frame,
WavePlaybackAbstract::FRAME_SIZE);
+    if (_err == paStreamIsStopped) {
+       _err = Pa_StartStream(_stream);
+    _stopped = 0;
+    }
+    // FIXME: error handling?
+    if (_err) {
+//    Pa_AbortStream(_stream);
+//    Pa_CloseStream(_stream);
+    LOG_ERROR("PortAudio dang: num %d message: %s", _err,
Pa_GetErrorText(_err));
+    } else {
+    //Pa_CloseStream(_stream);
+    }
+#endif
     return true;
 }

 void WavePlayer::stop()
 {
+#if defined(__LINUX__)
     snd_pcm_drain(_pcm);
     snd_pcm_prepare(_pcm);
+#elif defined(__MACH__) || defined(__APPLE__)
+    _err = Pa_StopStream(_stream);
+    if (_err != paNoError) {
+    DBG(0, "PortAudio stop: errcode %d message: %s", _err,
Pa_GetErrorText(_err));
+    }
+    _stopped = 1;
+#endif
 }

 bool WavePlayer::abort()
@@ -206,6 +271,7 @@ bool WavePlayer::abort()

 uint32_t WavePlayer::get_delay_ms()
 {
+#if defined(__LINUX__)
     ASSERT(_pcm);

     snd_pcm_sframes_t delay;
@@ -214,5 +280,9 @@ uint32_t WavePlayer::get_delay_ms()
         return 0;
     }
     return delay / _sampels_per_ms;
+#else
+    // anything more precise than this?
+    return WavePlaybackAbstract::FRAME_SIZE / _sampels_per_ms;
+#endif
 }

diff --git a/client/x11/playback.h b/client/x11/playback.h
index d8efd7e..f503ed5 100644
--- a/client/x11/playback.h
+++ b/client/x11/playback.h
@@ -18,7 +18,11 @@
 #ifndef _H_LINUX_PLAYBACK
 #define _H_LINUX_PLAYBACK

+#if defined(__LINUX__)
 #include <alsa/asoundlib.h>
+#elif defined(__MACH__) || defined(__APPLE__)
+#include <portaudio.h>
+#endif

 #include "common.h"
 #include "audio_devices.h"
@@ -38,9 +42,16 @@ private:
     void cleanup();

 private:
+#if defined(__LINUX__)
     snd_pcm_t* _pcm;
     snd_pcm_hw_params_t* _hw_params;
     snd_pcm_sw_params_t* _sw_params;
+#elif defined(__MACH__) || defined(__APPLE__)
+    PaStreamParameters _outputParameters;
+    PaStream *_stream;
+    PaError _err;
+    unsigned char _stopped;
+#endif
     uint32_t _sampels_per_ms;
 };

diff --git a/client/x11/record.cpp b/client/x11/record.cpp
index 4ef9228..77cba4a 100644
--- a/client/x11/record.cpp
+++ b/client/x11/record.cpp
@@ -47,9 +47,6 @@ WaveRecorder::WaveRecorder(Platform::RecordClient& client,
                            uint32_t bits_per_sample,
                            uint32_t channels)
     : _client (client)
-    , _pcm (NULL)
-    , _hw_params (NULL)
-    , _sw_params (NULL)
     , _sample_bytes (bits_per_sample * channels / 8)
     , _frame (new uint8_t[_sample_bytes * WaveRecordAbstract::FRAME_SIZE])
     , _frame_pos (_frame)
@@ -74,7 +71,7 @@ void WaveRecorder::cleanup()
         _client.remove_event_source(*_event_trigger);
         delete _event_trigger;
     }
-
+#if defined(__LINUX__)
     if (_sw_params) {
         snd_pcm_sw_params_free(_sw_params);
     }
@@ -86,12 +83,14 @@ void WaveRecorder::cleanup()
     if (_pcm) {
         snd_pcm_close(_pcm);
     }
+#endif
 }

 bool WaveRecorder::init(uint32_t sampels_per_sec,
                         uint32_t bits_per_sample,
                         uint32_t channels)
 {
+#if defined(__LINUX__)
     const int frame_size = WaveRecordAbstract::FRAME_SIZE;
     const char* pcm_device = "hw:0,0"; // "default" ???
     snd_pcm_format_t format;
@@ -195,21 +194,26 @@ bool WaveRecorder::init(uint32_t sampels_per_sec,
     }
     _event_trigger = new WaveRecorder::EventTrigger(*this, pfd.fd);
     _client.add_event_source(*_event_trigger);
+#endif
     return true;
 }

 void WaveRecorder::start()
 {
     _frame_pos = _frame;
+#if defined(__LINUX__)
     snd_pcm_prepare(_pcm);
     snd_pcm_start(_pcm);
     snd_pcm_nonblock(_pcm, 1);
+#endif
 }

 void WaveRecorder::stop()
 {
+#if defined(__LINUX__)
     snd_pcm_drop(_pcm);
     snd_pcm_prepare(_pcm);
+#endif
 }

 bool WaveRecorder::abort()
@@ -219,6 +223,7 @@ bool WaveRecorder::abort()

 void WaveRecorder::on_event()
 {
+#if defined(__LINUX__)
     for (;;) {
         snd_pcm_sframes_t size = (_frame_end - _frame_pos) / _sample_bytes;
         size = snd_pcm_readi(_pcm, _frame_pos, size);
@@ -234,5 +239,6 @@ void WaveRecorder::on_event()
             _frame_pos = _frame;
         }
     }
+#endif
 }

diff --git a/client/x11/record.h b/client/x11/record.h
index fde58c7..0181b09 100644
--- a/client/x11/record.h
+++ b/client/x11/record.h
@@ -18,7 +18,9 @@
 #ifndef _H_LINUX_RECORD
 #define _H_LINUX_RECORD

+#if defined(__LINUX__)
 #include <alsa/asoundlib.h>
+#endif

 #include "common.h"
 #include "audio_devices.h"
@@ -45,9 +47,11 @@ private:

 private:
     Platform::RecordClient& _client;
+#if defined(__LINUX__)
     snd_pcm_t* _pcm;
     snd_pcm_hw_params_t* _hw_params;
     snd_pcm_sw_params_t* _sw_params;
+#endif
     uint32_t _sample_bytes;
     uint8_t* _frame;
     uint8_t* _frame_pos;
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index 5a0886a..c2a0975 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -55,7 +55,6 @@

 static Display* x_display = NULL;
 static XContext user_data_context;
-static bool using_evdev = false;
 static XIC x_input_context = NULL;

 static Atom wm_protocol_atom;
@@ -73,7 +72,10 @@ static Atom wm_user_time;
 static RedWindow* focus_window;
 static unsigned long focus_serial = 0;

+#ifndef __MACH__ || __APPLE__
 #define USE_X11_KEYCODE
+static bool using_evdev = false;
+#endif

 #ifdef USE_X11_KEYCODE

diff --git a/common/lines.c b/common/lines.c
index d2e997e..1c67692 100644
--- a/common/lines.c
+++ b/common/lines.c
@@ -2986,6 +2986,7 @@ miWideDashSegment (GCPtr pGC,
     double k;
     PolyVertexRec vertices[4];
     PolyVertexRec saveRight, saveBottom;
+    saveRight.x = saveRight.y = saveBottom.x = saveBottom.y = 0;
     PolySlopeRec slopes[4];
     PolyEdgeRec left[2], right[2];
     LineFaceRec lcapFace, rcapFace;
diff --git a/configure.ac b/configure.ac
index 3369dde..6ef5938 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,11 +59,16 @@ case "$host" in
 esac
 AC_MSG_RESULT([$os_win32])

+AC_MSG_CHECKING([for Mac OS X])
 case $host in
   *-*-linux*)
     os_linux=yes
     ;;
+  *darwin*|*macosx*)
+    os_mac=yes
+    ;;
 esac
+AC_MSG_RESULT([$os_mac])

 dnl
=========================================================================
 dnl Check OS target
@@ -88,7 +93,7 @@ AC_SUBST(red_target)
 AM_CONDITIONAL(OS_WIN32, test "$os_win32" = "yes")
 AM_CONDITIONAL(OS_UNIX, test "$os_win32" != "yes")
 AM_CONDITIONAL(OS_LINUX, test "$os_linux" = "yes")
-
+AM_CONDITIONAL(OS_MAC, test "$os_mac" = "yes")
 dnl
=========================================================================
 dnl Chek optional features
 have_tunnel=no
@@ -119,12 +124,15 @@ AC_SUBST(PROTOCOL_CFLAGS)

 AC_CHECK_LIBM
 AC_SUBST(LIBM)
-
-AC_CHECK_LIB(rt, clock_gettime,
+if test "x$os_mac" != "yes"; then
+   AC_CHECK_LIB(rt, clock_gettime,
    AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Defined if we have clock_gettime()])
    LIBRT=-lrt
    )
-AC_SUBST(LIBRT)
+   AC_SUBST(LIBRT)
+else
+   LIBRT=""
+fi

 SPICE_NONPKGCONFIG_LIBS+=" -pthread $LIBM $LIBRT"

@@ -157,10 +165,17 @@ AC_SUBST(CELT051_LIBS)
 AC_SUBST(CELT051_LIBDIR)
 SPICE_REQUIRES+=" celt051 >= 0.5.1.1"

-PKG_CHECK_MODULES(ALSA, alsa)
-AC_SUBST(ALSA_CFLAGS)
-AC_SUBST(ALSA_LIBS)
-SPICE_REQUIRES+=" alsa"
+if test "x$os_mac" != "xyes"; then
+     PKG_CHECK_MODULES(ALSA, alsa)
+     AC_SUBST(ALSA_CFLAGS)
+     AC_SUBST(ALSA_LIBS)
+     SPICE_REQUIRES+=" alsa"
+else
+     PKG_CHECK_MODULES(PA, portaudio-2.0 >= 2.0)
+     AC_SUBST(PA_CFLAGS)
+     AC_SUBST(PA_LIBS)
+     SPICE_REQUIRES+=" portaudio-2.0"
+fi

 PKG_CHECK_MODULES(SSL, openssl)
 AC_SUBST(SSL_CFLAGS)



<http://www.zsuatt.com/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20100926/545a59a7/attachment-0001.html>


More information about the Spice-devel mailing list