Index: native_client_sdk/src/libraries/ppapi_simple/ps_event.c |
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_event.c b/native_client_sdk/src/libraries/ppapi_simple/ps_event.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9d5199436e6ced445459339fb959b15b6eb90d6e |
--- /dev/null |
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_event.c |
@@ -0,0 +1,271 @@ |
+// Copyright 2013 The Chromium 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 "ppapi_simple/ps_event.h" |
+ |
+#include <assert.h> |
+#include <pthread.h> |
+#include <stdlib.h> |
+#include <string.h> |
+ |
+#include "ppapi_simple/ps_instance.h" |
+#include "ppapi_simple/ps_interface.h" |
+ |
+#define NO_BLOCK 0 |
+#define BLOCK 1 |
+ |
+struct PSMessageHandlerInfo { |
+ char* message_name; |
+ PSMessageHandler_t func; |
+ void* user_data; |
+ struct PSMessageHandlerInfo* prev; |
+ struct PSMessageHandlerInfo* next; |
+}; |
+ |
+static uint32_t s_events_enabled = PSE_NONE; |
+static struct PSEvent* s_event_head; |
+static struct PSEvent* s_event_tail; |
+static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER; |
+static pthread_cond_t s_cond = PTHREAD_COND_INITIALIZER; |
+static struct PSMessageHandlerInfo* s_handler_head; |
+static struct PSMessageHandlerInfo* s_handler_tail; |
+ |
+static struct PSMessageHandlerInfo* FindMessageHandler( |
+ const char* message_name) { |
+ struct PSMessageHandlerInfo* info = s_handler_head; |
+ while (info) { |
+ if (strcmp(info->message_name, message_name) == 0) { |
+ return info; |
+ } |
+ |
+ info = info->next; |
+ } |
+ |
+ return NULL; |
+} |
+ |
+static void EnqueueEvent(struct PSEvent* event) { |
+ pthread_mutex_lock(&s_lock); |
+ |
+ if (!s_event_tail) { |
+ s_event_head = s_event_tail = event; |
+ event->next = NULL; |
+ } else { |
+ s_event_tail->next = event; |
+ s_event_tail = event; |
+ } |
+ |
+ pthread_cond_signal(&s_cond); |
+ pthread_mutex_unlock(&s_lock); |
+} |
+ |
+static struct PSEvent* DequeueEvent(int block) { |
+ pthread_mutex_lock(&s_lock); |
+ |
+ if (block) { |
+ while (s_event_head == NULL) { |
+ pthread_cond_wait(&s_cond, &s_lock); |
+ } |
+ } |
+ |
+ if (s_event_head == NULL) { |
+ pthread_mutex_unlock(&s_lock); |
+ return NULL; |
+ } |
+ |
+ struct PSEvent* item = s_event_head; |
+ |
+ if (s_event_head == s_event_tail) { |
+ s_event_head = s_event_tail = NULL; |
+ } else { |
+ s_event_head = s_event_head->next; |
+ } |
+ |
+ pthread_mutex_unlock(&s_lock); |
+ |
+ return item; |
+} |
+ |
+struct PSEvent* PSEventTryAcquire() { |
+ struct PSEvent* event; |
+ while (1) { |
+ event = DequeueEvent(NO_BLOCK); |
+ if (NULL == event) |
+ break; |
+ if (s_events_enabled & event->type) |
+ break; |
+ /* Release filtered events & continue to acquire. */ |
+ PSEventRelease(event); |
+ } |
+ return event; |
+} |
+ |
+struct PSEvent* PSEventWaitAcquire() { |
+ struct PSEvent* event; |
+ while (1) { |
+ event = DequeueEvent(BLOCK); |
+ if (s_events_enabled & event->type) |
+ break; |
+ /* Release filtered events & continue to acquire. */ |
+ PSEventRelease(event); |
+ } |
+ return event; |
+} |
+ |
+void PSEventRelease(struct PSEvent* event) { |
+ if (event) { |
+ switch (event->type) { |
+ case PSE_INSTANCE_HANDLEMESSAGE: |
+ PSInterfaceVar()->Release(event->as_var); |
+ break; |
+ case PSE_INSTANCE_HANDLEINPUT: |
+ case PSE_INSTANCE_DIDCHANGEVIEW: |
+ if (event->as_resource) { |
+ PSInterfaceCore()->ReleaseResource(event->as_resource); |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+ free(event); |
+ } |
+} |
+ |
+void PSEventSetFilter(PSEventTypeMask filter) { |
+ s_events_enabled = filter; |
+ if (filter == 0) { |
+ static int s_warn_once = 1; |
+ if (s_warn_once) { |
+ PSInstanceWarn( |
+ "PSInstance::SetEnabledEvents(mask) where mask == 0 will block\n"); |
+ PSInstanceWarn( |
+ "all events. This can come from PSEventSetFilter(PSE_NONE);\n"); |
+ s_warn_once = 0; |
+ } |
+ } |
+} |
+ |
+void PSEventPost(PSEventType type) { |
+ assert(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST == type || |
+ PSE_MOUSELOCK_MOUSELOCKLOST == type); |
+ |
+ struct PSEvent* event = malloc(sizeof(struct PSEvent)); |
+ memset(event, 0, sizeof(*event)); |
+ event->type = type; |
+ EnqueueEvent(event); |
+} |
+ |
+void PSEventPostBool(PSEventType type, PP_Bool bool_value) { |
+ assert(PSE_INSTANCE_DIDCHANGEFOCUS == type); |
+ |
+ struct PSEvent* event = malloc(sizeof(struct PSEvent)); |
+ memset(event, 0, sizeof(*event)); |
+ event->type = type; |
+ event->as_bool = bool_value; |
+ EnqueueEvent(event); |
+} |
+ |
+void PSEventPostVar(PSEventType type, struct PP_Var var) { |
+ assert(PSE_INSTANCE_HANDLEMESSAGE == type); |
+ |
+ /* If the message is a dictionary then see if it matches one of the specific |
+ * handlers, then call that handler rather than queuing an event. */ |
+ if (var.type == PP_VARTYPE_DICTIONARY) { |
+ struct PP_Var keys_var = PSInterfaceVarDictionary()->GetKeys(var); |
+ if (PSInterfaceVarArray()->GetLength(keys_var) == 1) { |
+ struct PP_Var key_var = PSInterfaceVarArray()->Get(keys_var, 0); |
+ uint32_t key_len; |
+ const char* key_str = PSInterfaceVar()->VarToUtf8(key_var, &key_len); |
+ char* key_cstr = alloca(key_len + 1); |
+ memcpy(key_cstr, key_str, key_len); |
+ key_cstr[key_len] = 0; |
+ PSInstanceTrace("calling handler for: %s\n", key_cstr); |
+ |
+ struct PSMessageHandlerInfo* handler_info = FindMessageHandler(key_cstr); |
+ if (handler_info) { |
+ struct PP_Var value_var = PSInterfaceVarDictionary()->Get(var, key_var); |
+ handler_info->func(key_var, value_var, handler_info->user_data); |
+ PSInterfaceVar()->Release(value_var); |
+ PSInterfaceVar()->Release(key_var); |
+ PSInterfaceVar()->Release(keys_var); |
+ return; |
+ } |
+ |
+ PSInterfaceVar()->Release(key_var); |
+ } |
+ |
+ PSInterfaceVar()->Release(keys_var); |
+ } |
+ |
+ PSInterfaceVar()->AddRef(var); |
+ struct PSEvent *env = malloc(sizeof(struct PSEvent)); |
+ memset(env, 0, sizeof(*env)); |
+ env->type = type; |
+ env->as_var = var; |
+ EnqueueEvent(env); |
+} |
+ |
+void PSEventPostResource(PSEventType type, PP_Resource resource) { |
+ assert(PSE_INSTANCE_HANDLEINPUT == type || |
+ PSE_INSTANCE_DIDCHANGEVIEW == type); |
+ |
+ if (resource) { |
+ PSInterfaceCore()->AddRefResource(resource); |
+ } |
+ struct PSEvent* event = malloc(sizeof(struct PSEvent)); |
+ memset(event, 0, sizeof(*event)); |
+ event->type = type; |
+ event->as_resource = resource; |
+ EnqueueEvent(event); |
+} |
+ |
+void PSEventRegisterMessageHandler(const char* message_name, |
+ PSMessageHandler_t func, |
+ void* user_data) { |
+ PSInstanceTrace("registering msg handler: %s\n", message_name); |
+ struct PSMessageHandlerInfo* handler = FindMessageHandler(message_name); |
+ |
+ if (func == NULL) { |
+ /* Unregister handler, if it exists */ |
+ if (handler) { |
+ if (handler->prev) { |
+ handler->prev->next = handler->next; |
+ } else { |
+ s_handler_head = handler->next; |
+ } |
+ |
+ if (handler->next) { |
+ handler->next->prev = handler->prev; |
+ } else { |
+ s_handler_tail = handler->prev; |
+ } |
+ |
+ free(handler->message_name); |
+ free(handler); |
+ } |
+ return; |
+ } |
+ |
+ if (handler) { |
+ /* Already registered, change its function */ |
+ handler->func = func; |
+ handler->user_data = user_data; |
+ } else { |
+ /* Not registered, append a new handler info */ |
+ struct PSMessageHandlerInfo* handler_info = |
+ malloc(sizeof(struct PSMessageHandlerInfo)); |
+ handler_info->message_name = strdup(message_name); |
+ handler_info->func = func; |
+ handler_info->user_data = user_data; |
+ handler_info->next = NULL; |
+ handler_info->prev = s_handler_tail; |
+ |
+ if (s_handler_tail) { |
+ s_handler_tail->next = handler_info; |
+ s_handler_tail = handler_info; |
+ } else { |
+ s_handler_head = s_handler_tail = handler_info; |
+ } |
+ } |
+} |