Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / native_client_sdk / src / libraries / ppapi_simple / ps_event.c
blob9d5199436e6ced445459339fb959b15b6eb90d6e
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi_simple/ps_event.h"
7 #include <assert.h>
8 #include <pthread.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "ppapi_simple/ps_instance.h"
13 #include "ppapi_simple/ps_interface.h"
15 #define NO_BLOCK 0
16 #define BLOCK 1
18 struct PSMessageHandlerInfo {
19 char* message_name;
20 PSMessageHandler_t func;
21 void* user_data;
22 struct PSMessageHandlerInfo* prev;
23 struct PSMessageHandlerInfo* next;
26 static uint32_t s_events_enabled = PSE_NONE;
27 static struct PSEvent* s_event_head;
28 static struct PSEvent* s_event_tail;
29 static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER;
30 static pthread_cond_t s_cond = PTHREAD_COND_INITIALIZER;
31 static struct PSMessageHandlerInfo* s_handler_head;
32 static struct PSMessageHandlerInfo* s_handler_tail;
34 static struct PSMessageHandlerInfo* FindMessageHandler(
35 const char* message_name) {
36 struct PSMessageHandlerInfo* info = s_handler_head;
37 while (info) {
38 if (strcmp(info->message_name, message_name) == 0) {
39 return info;
42 info = info->next;
45 return NULL;
48 static void EnqueueEvent(struct PSEvent* event) {
49 pthread_mutex_lock(&s_lock);
51 if (!s_event_tail) {
52 s_event_head = s_event_tail = event;
53 event->next = NULL;
54 } else {
55 s_event_tail->next = event;
56 s_event_tail = event;
59 pthread_cond_signal(&s_cond);
60 pthread_mutex_unlock(&s_lock);
63 static struct PSEvent* DequeueEvent(int block) {
64 pthread_mutex_lock(&s_lock);
66 if (block) {
67 while (s_event_head == NULL) {
68 pthread_cond_wait(&s_cond, &s_lock);
72 if (s_event_head == NULL) {
73 pthread_mutex_unlock(&s_lock);
74 return NULL;
77 struct PSEvent* item = s_event_head;
79 if (s_event_head == s_event_tail) {
80 s_event_head = s_event_tail = NULL;
81 } else {
82 s_event_head = s_event_head->next;
85 pthread_mutex_unlock(&s_lock);
87 return item;
90 struct PSEvent* PSEventTryAcquire() {
91 struct PSEvent* event;
92 while (1) {
93 event = DequeueEvent(NO_BLOCK);
94 if (NULL == event)
95 break;
96 if (s_events_enabled & event->type)
97 break;
98 /* Release filtered events & continue to acquire. */
99 PSEventRelease(event);
101 return event;
104 struct PSEvent* PSEventWaitAcquire() {
105 struct PSEvent* event;
106 while (1) {
107 event = DequeueEvent(BLOCK);
108 if (s_events_enabled & event->type)
109 break;
110 /* Release filtered events & continue to acquire. */
111 PSEventRelease(event);
113 return event;
116 void PSEventRelease(struct PSEvent* event) {
117 if (event) {
118 switch (event->type) {
119 case PSE_INSTANCE_HANDLEMESSAGE:
120 PSInterfaceVar()->Release(event->as_var);
121 break;
122 case PSE_INSTANCE_HANDLEINPUT:
123 case PSE_INSTANCE_DIDCHANGEVIEW:
124 if (event->as_resource) {
125 PSInterfaceCore()->ReleaseResource(event->as_resource);
127 break;
128 default:
129 break;
131 free(event);
135 void PSEventSetFilter(PSEventTypeMask filter) {
136 s_events_enabled = filter;
137 if (filter == 0) {
138 static int s_warn_once = 1;
139 if (s_warn_once) {
140 PSInstanceWarn(
141 "PSInstance::SetEnabledEvents(mask) where mask == 0 will block\n");
142 PSInstanceWarn(
143 "all events. This can come from PSEventSetFilter(PSE_NONE);\n");
144 s_warn_once = 0;
149 void PSEventPost(PSEventType type) {
150 assert(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST == type ||
151 PSE_MOUSELOCK_MOUSELOCKLOST == type);
153 struct PSEvent* event = malloc(sizeof(struct PSEvent));
154 memset(event, 0, sizeof(*event));
155 event->type = type;
156 EnqueueEvent(event);
159 void PSEventPostBool(PSEventType type, PP_Bool bool_value) {
160 assert(PSE_INSTANCE_DIDCHANGEFOCUS == type);
162 struct PSEvent* event = malloc(sizeof(struct PSEvent));
163 memset(event, 0, sizeof(*event));
164 event->type = type;
165 event->as_bool = bool_value;
166 EnqueueEvent(event);
169 void PSEventPostVar(PSEventType type, struct PP_Var var) {
170 assert(PSE_INSTANCE_HANDLEMESSAGE == type);
172 /* If the message is a dictionary then see if it matches one of the specific
173 * handlers, then call that handler rather than queuing an event. */
174 if (var.type == PP_VARTYPE_DICTIONARY) {
175 struct PP_Var keys_var = PSInterfaceVarDictionary()->GetKeys(var);
176 if (PSInterfaceVarArray()->GetLength(keys_var) == 1) {
177 struct PP_Var key_var = PSInterfaceVarArray()->Get(keys_var, 0);
178 uint32_t key_len;
179 const char* key_str = PSInterfaceVar()->VarToUtf8(key_var, &key_len);
180 char* key_cstr = alloca(key_len + 1);
181 memcpy(key_cstr, key_str, key_len);
182 key_cstr[key_len] = 0;
183 PSInstanceTrace("calling handler for: %s\n", key_cstr);
185 struct PSMessageHandlerInfo* handler_info = FindMessageHandler(key_cstr);
186 if (handler_info) {
187 struct PP_Var value_var = PSInterfaceVarDictionary()->Get(var, key_var);
188 handler_info->func(key_var, value_var, handler_info->user_data);
189 PSInterfaceVar()->Release(value_var);
190 PSInterfaceVar()->Release(key_var);
191 PSInterfaceVar()->Release(keys_var);
192 return;
195 PSInterfaceVar()->Release(key_var);
198 PSInterfaceVar()->Release(keys_var);
201 PSInterfaceVar()->AddRef(var);
202 struct PSEvent *env = malloc(sizeof(struct PSEvent));
203 memset(env, 0, sizeof(*env));
204 env->type = type;
205 env->as_var = var;
206 EnqueueEvent(env);
209 void PSEventPostResource(PSEventType type, PP_Resource resource) {
210 assert(PSE_INSTANCE_HANDLEINPUT == type ||
211 PSE_INSTANCE_DIDCHANGEVIEW == type);
213 if (resource) {
214 PSInterfaceCore()->AddRefResource(resource);
216 struct PSEvent* event = malloc(sizeof(struct PSEvent));
217 memset(event, 0, sizeof(*event));
218 event->type = type;
219 event->as_resource = resource;
220 EnqueueEvent(event);
223 void PSEventRegisterMessageHandler(const char* message_name,
224 PSMessageHandler_t func,
225 void* user_data) {
226 PSInstanceTrace("registering msg handler: %s\n", message_name);
227 struct PSMessageHandlerInfo* handler = FindMessageHandler(message_name);
229 if (func == NULL) {
230 /* Unregister handler, if it exists */
231 if (handler) {
232 if (handler->prev) {
233 handler->prev->next = handler->next;
234 } else {
235 s_handler_head = handler->next;
238 if (handler->next) {
239 handler->next->prev = handler->prev;
240 } else {
241 s_handler_tail = handler->prev;
244 free(handler->message_name);
245 free(handler);
247 return;
250 if (handler) {
251 /* Already registered, change its function */
252 handler->func = func;
253 handler->user_data = user_data;
254 } else {
255 /* Not registered, append a new handler info */
256 struct PSMessageHandlerInfo* handler_info =
257 malloc(sizeof(struct PSMessageHandlerInfo));
258 handler_info->message_name = strdup(message_name);
259 handler_info->func = func;
260 handler_info->user_data = user_data;
261 handler_info->next = NULL;
262 handler_info->prev = s_handler_tail;
264 if (s_handler_tail) {
265 s_handler_tail->next = handler_info;
266 s_handler_tail = handler_info;
267 } else {
268 s_handler_head = s_handler_tail = handler_info;