| 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;
|
| + }
|
| + }
|
| +}
|
|
|