  
  #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
  	/* Allow ourselves to be asynchronously cancelled */
-diff -urN SDL-1.2.14/src/video/SDL_sysvideo.h SDL-1.2.14-nacl/src/video/SDL_sysvideo.h
---- SDL-1.2.14/src/video/SDL_sysvideo.h	2009-10-13 03:07:15.000000000 +0400
-+++ SDL-1.2.14-nacl/src/video/SDL_sysvideo.h	2011-10-13 15:43:08.977067048 +0400
-@@ -317,6 +317,9 @@
- 	SDL_VideoDevice *(*create)(int devindex);
- } VideoBootStrap;
- 
-+#if SDL_VIDEO_DRIVER_NACL
-+extern VideoBootStrap NACL_bootstrap;
-+#endif
- #if SDL_VIDEO_DRIVER_QUARTZ
- extern VideoBootStrap QZ_bootstrap;
- #endif
-diff -urN SDL-1.2.14/src/video/SDL_video.c SDL-1.2.14-nacl/src/video/SDL_video.c
---- SDL-1.2.14/src/video/SDL_video.c	2009-10-13 03:07:15.000000000 +0400
-+++ SDL-1.2.14-nacl/src/video/SDL_video.c	2011-10-13 15:43:08.977067048 +0400
-@@ -33,6 +33,9 @@
- 
- /* Available video drivers */
- static VideoBootStrap *bootstrap[] = {
-+#if SDL_VIDEO_DRIVER_NACL
-+	&NACL_bootstrap,
-+#endif
- #if SDL_VIDEO_DRIVER_QUARTZ
- 	&QZ_bootstrap,
- #endif
-diff -urN SDL-1.2.14/src/video/nacl/SDL_naclevents.cc SDL-1.2.14-nacl/src/video/nacl/SDL_naclevents.cc
+diff -urN SDL-1.2.14/src/video/nacl/eventqueue.h SDL-1.2.14-nacl//src/video/nacl/eventqueue.h
+--- SDL-1.2.14/src/video/nacl/eventqueue.h	1970-01-01 03:00:00.000000000 +0300
++++ SDL-1.2.14-nacl//src/video/nacl/eventqueue.h	2011-11-28 23:43:22.689635148 +0400
+@@ -0,0 +1,43 @@
++#ifndef _SDL_nacl_eventqueue_h
++#define _SDL_nacl_eventqueue_h
++
++#include "SDL_mutex.h"
++
++#include <queue>
++#include <ppapi/c/pp_input_event.h>
++
++struct SDL_NACL_Event;
++
++class EventQueue {
++public:
++  EventQueue() {
++    mu_ = SDL_CreateMutex();
++  }
++
++  ~EventQueue() {
++    SDL_DestroyMutex(mu_);
++  }
++
++  SDL_NACL_Event* PopEvent() {
++    SDL_LockMutex(mu_);
++    SDL_NACL_Event* event = NULL;
++    if (!queue_.empty()) {
++      event = queue_.front();
++      queue_.pop();
++    }
++    SDL_UnlockMutex(mu_);
++    return event;
++  }
++
++   void PushEvent(SDL_NACL_Event* event) {
++    SDL_LockMutex(mu_);
++    queue_.push(event);
++    SDL_UnlockMutex(mu_);
++   } 
++
++private:
++  std::queue<SDL_NACL_Event*> queue_;
++  SDL_mutex* mu_;
++};
++
++#endif // _SDL_nacl_eventqueue_h
+diff -urN SDL-1.2.14/src/video/nacl/MainThreadRunner.cc SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.cc
+--- SDL-1.2.14/src/video/nacl/MainThreadRunner.cc	1970-01-01 03:00:00.000000000 +0300
++++ SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.cc	2011-11-28 23:43:34.019635132 +0400
+@@ -0,0 +1,242 @@
++/*
++ * Copyright (c) 2011 The Native Client Authors. All rights reserved.
++ * Use of this source code is governed by a BSD-style license that can be
++ * found in the LICENSE file.
++ */
++#include "MainThreadRunner.h"
++#include <alloca.h>
++#include <assert.h>
++#include <errno.h>
++
++// Only use pepper in nacl to allow unit testing.
++#ifdef __native_client__
++#  include <ppapi/c/pp_errors.h>
++#  include <ppapi/cpp/completion_callback.h>
++#  include <ppapi/cpp/module.h>
++#  define USE_PEPPER
++#endif
++
++// kWORK_POLL_TIMEOUT sets the time delay (in milliseconds) between checks
++// for available jobs.
++static const int kWorkPollTimeout = 10;
++
++// Stack space to allocate by default to the event handler
++// thread in the presence of an ancillary 'pseudo-thread'.
++// 640K of stack should be enough for anyone.
++static const int kDefaultPseudoThreadHeadroom = 640 * 1024;
++
++// If we're not using pepper, track main thread's id so
++// we can do something sensible.
++#ifndef USE_PEPPER
++static pthread_t main_thread_id_;
++#endif
++
++struct MainThreadRunner::JobEntry {
++  pp::Instance* pepper_instance;
++  MainThreadRunner* runner;
++  MainThreadJob* job;
++  pthread_mutex_t done_mutex;
++  pthread_cond_t done_cond;
++  bool is_done;
++  int32_t result;
++  bool pseudo_thread_job;
++};
++
++
++MainThreadRunner::MainThreadRunner(pp::Instance *instance) {
++#ifndef USE_PEPPER
++  // Record main thread if not using pepper.
++  main_thread_id_ = pthread_self();
++#endif
++
++  pepper_instance_ = instance;
++  pthread_mutex_init(&lock_, NULL);
++
++#ifdef USE_PEPPER
++  // Start work cycling if using pepper.
++  DoWork();
++#endif
++}
++
++MainThreadRunner::~MainThreadRunner() {
++  pthread_mutex_destroy(&lock_);
++}
++
++int32_t MainThreadRunner::RunJob(MainThreadJob* job) {
++  JobEntry entry;
++
++  // initialize the entry
++  entry.runner = this;
++  entry.pepper_instance = pepper_instance_;
++  entry.job = job;
++
++  bool in_main_thread = IsMainThread();
++  // Must be off main thread, or on a pseudothread.
++  assert(!in_main_thread || in_pseudo_thread_);
++
++  // Thread type specific initialization.
++  if (in_main_thread) {
++    entry.pseudo_thread_job = true;
++  } else {
++    entry.pseudo_thread_job = false;
++    // Init condition variable.
++    entry.is_done = false;
++    int ret = pthread_mutex_init(&entry.done_mutex, NULL);
++    assert(!ret);
++    ret = pthread_cond_init(&entry.done_cond, NULL);
++    assert(!ret);
++  }
++
++  // put the job on the queue
++  pthread_mutex_lock(&lock_);
++  job_queue_.push_back(&entry);
++  pthread_mutex_unlock(&lock_);
++
++  // Block differntly on the main thread.
++  if (entry.pseudo_thread_job) {
++    // block pseudothread until job is done
++    PseudoThreadBlock();
++  } else {
++    // wait on condition until the job is done
++    pthread_mutex_lock(&entry.done_mutex);
++    while (!entry.is_done) {
++      pthread_cond_wait(&entry.done_cond, &entry.done_mutex);
++    }
++    pthread_mutex_unlock(&entry.done_mutex);
++    pthread_mutex_destroy(&entry.done_mutex);
++    pthread_cond_destroy(&entry.done_cond);
++  }
++
++  // Cleanup.
++  delete job;
++  return entry.result;
++}
++
++void MainThreadRunner::ResultCompletion(void *arg, int32_t result) {
++  JobEntry* entry = reinterpret_cast<JobEntry*>(arg);
++#ifdef USE_PEPPER
++  MainThreadRunner* runner = entry->runner;
++#endif
++  entry->result = result;
++  // Signal differently depending on if the pseudothread is involved.
++  if (entry->pseudo_thread_job) {
++    PseudoThreadResume();
++  } else {
++    pthread_mutex_lock(&entry->done_mutex);
++    entry->is_done = true;
++    pthread_cond_signal(&entry->done_cond);
++    pthread_mutex_unlock(&entry->done_mutex);
++  }
++#ifdef USE_PEPPER
++  // Do more work now if in pepper.
++  DoWorkShim(runner, 0);
++#endif
++}
++
++void MainThreadRunner::DoWorkShim(void *p, int32_t unused) {
++  MainThreadRunner* mtr = static_cast<MainThreadRunner *>(p);
++  mtr->DoWork();
++}
++
++void MainThreadRunner::DoWork(void) {
++  pthread_mutex_lock(&lock_);
++  if (!job_queue_.empty()) {
++    JobEntry* entry = job_queue_.front();
++    job_queue_.pop_front();
++    // Release lock before doing work.
++    pthread_mutex_unlock(&lock_);
++    entry->job->Run(entry);
++    return;
++  }
++#ifdef USE_PEPPER
++  // Wake ourselves back up if we're using pepper.
++  pp::Module::Get()->core()->CallOnMainThread(kWorkPollTimeout,
++      pp::CompletionCallback(&DoWorkShim, this), PP_OK);
++#endif
++  pthread_mutex_unlock(&lock_);
++}
++
++pp::Instance *MainThreadRunner::ExtractPepperInstance(
++    MainThreadRunner::JobEntry *e) {
++  return e->pepper_instance;
++}
++
++void MainThreadRunner::PseudoThreadFork(void *(*func)(void *arg), void *arg) {
++  PseudoThreadHeadroomFork(kDefaultPseudoThreadHeadroom, func, arg);
++}
++
++void MainThreadRunner::PseudoThreadHeadroomFork(
++    int bytes_headroom, void *(*func)(void *arg), void *arg) {
++  // Must be run from the main thread.
++  assert(IsMainThread());
++  // Only one pseudothread can be forked.
++  assert(!forked_pseudo_thread_);
++  // Leave a gap of bytes_headroom on the stack between
++  alloca(bytes_headroom);
++  // Goto pseudothread, but remeber how to come back here.
++  if (!setjmp(main_thread_state_)) {
++    InnerPseudoThreadFork(func, arg);
++  }
++  in_pseudo_thread_ = false;
++}
++
++// Put things in another scope to keep above headroom,
++// even after thread ends.
++void MainThreadRunner::InnerPseudoThreadFork(
++    void *(func)(void *arg), void *arg) {
++  forked_pseudo_thread_ = true;
++  in_pseudo_thread_ = true;
++  func(arg);
++  forked_pseudo_thread_ = false;
++  in_pseudo_thread_ = false;
++  // Dead, keep kicking back to the main thread.
++  for (;;) {
++    longjmp(main_thread_state_, 1);
++  }
++}
++
++void MainThreadRunner::PseudoThreadBlock(void) {
++  // Must be run from the main thread.
++  assert(IsMainThread());
++  // Pseudothread must have been forked.
++  assert(forked_pseudo_thread_);
++  // Must be run only from the pseudothread.
++  assert(in_pseudo_thread_);
++  if (!setjmp(pseudo_thread_state_)) {
++    // Go back to the main thread after saving state.
++    longjmp(main_thread_state_, 1);
++  }
++  in_pseudo_thread_ = true;
++}
++
++void MainThreadRunner::PseudoThreadResume(void) {
++  // Must be run from the main thread.
++  assert(IsMainThread());
++  // Pseudothread must have been forked.
++  assert(forked_pseudo_thread_);
++  // Can only be run from the main thread.
++  assert(!in_pseudo_thread_);
++  if (!setjmp(main_thread_state_)) {
++    // Go back to the pseudo thread after saving state.
++    longjmp(pseudo_thread_state_, 1);
++  }
++  in_pseudo_thread_ = false;
++}
++
++bool MainThreadRunner::IsMainThread(void) {
++#ifdef USE_PEPPER
++  return pp::Module::Get()->core()->IsMainThread();
++#else
++  return pthread_equal(pthread_self(), main_thread_id_);
++#endif
++}
++
++bool MainThreadRunner::IsPseudoThread(void) {
++  return IsMainThread() && in_pseudo_thread_;
++}
++
++// Static variables in MainThreaadRunner.
++jmp_buf MainThreadRunner::main_thread_state_;
++jmp_buf MainThreadRunner::pseudo_thread_state_;
++bool MainThreadRunner::in_pseudo_thread_ = false;
++bool MainThreadRunner::forked_pseudo_thread_ = false;
+diff -urN SDL-1.2.14/src/video/nacl/MainThreadRunner.h SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.h
+--- SDL-1.2.14/src/video/nacl/MainThreadRunner.h	1970-01-01 03:00:00.000000000 +0300
++++ SDL-1.2.14-nacl//src/video/nacl/MainThreadRunner.h	2011-11-28 23:43:34.019635132 +0400
+@@ -0,0 +1,102 @@
++/*
++ * Copyright (c) 2011 The Native Client Authors. All rights reserved.
++ * Use of this source code is governed by a BSD-style license that can be
++ * found in the LICENSE file.
++ */
++#ifndef LIBRARIES_NACL_MOUNTS_BASE_MAINTHREADRUNNER_H_
++#define LIBRARIES_NACL_MOUNTS_BASE_MAINTHREADRUNNER_H_
++
++#include <pthread.h>
++#include <semaphore.h>
++#include <setjmp.h>
++#include <list>
++
++// Keep pepper specifics out so we can unit test.
++namespace pp {
++  class Instance;
++};
++
++// MainThreadJob is a class that provides a method for running
++// a MainThreadRunner::JobEntry.
++class MainThreadJob;
++
++// MainThreadRunner executes MainThreadJobs asynchronously
++// on the main thread.
++class MainThreadRunner {
++ public:
++  explicit MainThreadRunner(pp::Instance *instance);
++  ~MainThreadRunner();
++
++  // RunJob() creates an entry for the job and submits
++  // that job for execution.
++  int32_t RunJob(MainThreadJob *job);
++
++  // ResultCompletion() is a function for putting result into arg, which
++  // is reinterpreted as a JobEntry pointer.  ResultCompletion()
++  // is intended to be used with pp::CompletionCallback()
++  static void ResultCompletion(void *arg, int32_t result);
++
++  // The JobEntry struct provides all of the information for
++  // a particular job.  It acts as an opaque handle to the job to and
++  // is used by ResultCompletion().
++  struct JobEntry;
++
++  static pp::Instance *ExtractPepperInstance(MainThreadRunner::JobEntry *e);
++
++  // You can have one 'pseudothread' on top of the main thread.
++  // This coroutine (setjmp) based thread can block on Run.
++  // You will have to take some amount of re-entrancy into account.
++  // Assumes 640K of stack is enough for anyone for event handling in the
++  // main thread.
++  static void PseudoThreadFork(void *(*func)(void *arg), void *arg);
++  // Same as above with selectable bytes of headroom.
++  static void PseudoThreadHeadroomFork(
++      int bytes_headroom, void *(*func)(void *arg), void *arg);
++
++  // Returns:
++  //   true - main thread or pseudothread.
++  //   false - other pthreads.
++  static bool IsMainThread(void);
++
++  // Returns true if on the psuedothread.
++  static bool IsPseudoThread(void);
++
++  // Use these directly only if you are interacting with PPAPI
++  // such that you can guarantee you'll resume because of an
++  // asynchronous event you issued.
++  // Block pseudothread until main thread yields.
++  static void PseudoThreadBlock(void);
++  // Yield main thread to pseudothread.
++  static void PseudoThreadResume(void);
++
++  // Do at least one main thread job.
++  // DO NOT use this with pepper (which sets up an event
++  // cycle to call this automatically).
++  // Use directly only for testing.
++  void DoWork(void);
++
++ private:
++  static void DoWorkShim(void *p, int32_t unused);
++
++  // Used to keep things above the headroom.
++  static void InnerPseudoThreadFork(void *(func)(void *arg), void *arg);
++
++  pthread_mutex_t lock_;
++  std::list<JobEntry*> job_queue_;
++  pp::Instance *pepper_instance_;
++
++  static jmp_buf pseudo_thread_state_;
++  static jmp_buf main_thread_state_;
++  static bool in_pseudo_thread_;
++  static bool forked_pseudo_thread_;
++};
++
++class MainThreadJob {
++ public:
++  virtual ~MainThreadJob() {}
++  virtual void Run(MainThreadRunner::JobEntry *entry) = 0;
++};
++
++// MainThreadRunner executes MainThreadJobs asynchronously
++
++#endif  // LIBRARIES_NACL_MOUNTS_BASE_MAINTHREADRUNNER_H_
+diff -urN SDL-1.2.14/src/video/nacl/SDL_naclevents.cc SDL-1.2.14-nacl//src/video/nacl/SDL_naclevents.cc
 --- SDL-1.2.14/src/video/nacl/SDL_naclevents.cc	1970-01-01 03:00:00.000000000 +0300
-+++ SDL-1.2.14-nacl/src/video/nacl/SDL_naclevents.cc	2011-10-13 15:43:44.997030707 +0400
++++ SDL-1.2.14-nacl//src/video/nacl/SDL_naclevents.cc	2011-11-28 23:43:22.689635148 +0400
 @@ -0,0 +1,196 @@
 +#include "SDL_config.h"
 +

+  }
+  SDL_memset(device->hidden, 0, (sizeof *device->hidden));
+
+  device->hidden->flush_mutex = SDL_CreateMutex();
+  device->hidden->flush_cond = SDL_CreateCond();
+
+  device->hidden->flush_pending = false;
+  device->hidden->data_ready = false;
+
+  device->hidden->ow = gNaclVideoWidth;
+  device->hidden->oh = gNaclVideoHeight;
+
+  if (device->hidden->context2d)
+    delete device->hidden->context2d;
+  device->hidden->context2d = new pp::Graphics2D(gNaclPPInstance,
+      pp::Size(device->hidden->ow, device->hidden->oh), false);
+  assert(device->hidden->context2d != NULL);
+
+  if (!gNaclPPInstance->BindGraphics(*device->hidden->context2d)) {
+    fprintf(stderr, "***** Couldn't bind the device context *****\n");
+  }
+
+  // TODO: convert normal RGBA to premultiplied alpha.
+  device->hidden->image_data = new pp::ImageData(gNaclPPInstance,
+      PP_IMAGEDATAFORMAT_BGRA_PREMUL,
+      device->hidden->context2d->size(),
+      false);
+  assert(device->hidden->image_data != NULL);
+
+  /* Set the function pointers */
+  device->VideoInit = NACL_VideoInit;

+struct SDL_PrivateVideoData {
+  int bpp;
+  int w, h;
+  void *buffer;
+
+  int ow, oh; // plugin output dimensions
+  int fsw, fsh; // fullscreen dimensions
+
+  pp::ImageData* image_data;
+  pp::Graphics2D* context2d;  // The PPAPI 2D drawing context.
+
+  int numrects;
+  SDL_Rect* rects;
+};
+
+#endif /* _SDL_naclvideo_h */
diff -urN SDL-1.2.14/src/video/SDL_sysvideo.h SDL-1.2.14-nacl//src/video/SDL_sysvideo.h
--- SDL-1.2.14/src/video/SDL_sysvideo.h	2009-10-13 03:07:15.000000000 +0400
+++ SDL-1.2.14-nacl//src/video/SDL_sysvideo.h	2011-11-28 23:43:22.679635058 +0400
@@ -317,6 +317,9 @@
 	SDL_VideoDevice *(*create)(int devindex);
 } VideoBootStrap;
 
+#if SDL_VIDEO_DRIVER_NACL
+extern VideoBootStrap NACL_bootstrap;
+#endif
 #if SDL_VIDEO_DRIVER_QUARTZ
 extern VideoBootStrap QZ_bootstrap;
 #endif
diff -urN SDL-1.2.14/src/video/SDL_video.c SDL-1.2.14-nacl//src/video/SDL_video.c
--- SDL-1.2.14/src/video/SDL_video.c	2009-10-13 03:07:15.000000000 +0400
+++ SDL-1.2.14-nacl//src/video/SDL_video.c	2011-11-28 23:43:22.689635148 +0400
@@ -33,6 +33,9 @@
 
 /* Available video drivers */
 static VideoBootStrap *bootstrap[] = {
+#if SDL_VIDEO_DRIVER_NACL
+	&NACL_bootstrap,
+#endif
 #if SDL_VIDEO_DRIVER_QUARTZ
 	&QZ_bootstrap,
 #endif
