OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ppapi_simple/ps_event.h" |
| 6 |
| 7 #include <assert.h> |
| 8 #include <pthread.h> |
| 9 #include <stdlib.h> |
| 10 #include <string.h> |
| 11 |
| 12 #include "ppapi_simple/ps_instance.h" |
| 13 #include "ppapi_simple/ps_interface.h" |
| 14 |
| 15 #define NO_BLOCK 0 |
| 16 #define BLOCK 1 |
| 17 |
| 18 struct PSMessageHandlerInfo { |
| 19 char* message_name; |
| 20 PSMessageHandler_t func; |
| 21 void* user_data; |
| 22 struct PSMessageHandlerInfo* prev; |
| 23 struct PSMessageHandlerInfo* next; |
| 24 }; |
| 25 |
| 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; |
| 33 |
| 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; |
| 40 } |
| 41 |
| 42 info = info->next; |
| 43 } |
| 44 |
| 45 return NULL; |
| 46 } |
| 47 |
| 48 static void EnqueueEvent(struct PSEvent* event) { |
| 49 pthread_mutex_lock(&s_lock); |
| 50 |
| 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; |
| 57 } |
| 58 |
| 59 pthread_cond_signal(&s_cond); |
| 60 pthread_mutex_unlock(&s_lock); |
| 61 } |
| 62 |
| 63 static struct PSEvent* DequeueEvent(int block) { |
| 64 pthread_mutex_lock(&s_lock); |
| 65 |
| 66 if (block) { |
| 67 while (s_event_head == NULL) { |
| 68 pthread_cond_wait(&s_cond, &s_lock); |
| 69 } |
| 70 } |
| 71 |
| 72 if (s_event_head == NULL) { |
| 73 pthread_mutex_unlock(&s_lock); |
| 74 return NULL; |
| 75 } |
| 76 |
| 77 struct PSEvent* item = s_event_head; |
| 78 |
| 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; |
| 83 } |
| 84 |
| 85 pthread_mutex_unlock(&s_lock); |
| 86 |
| 87 return item; |
| 88 } |
| 89 |
| 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); |
| 100 } |
| 101 return event; |
| 102 } |
| 103 |
| 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); |
| 112 } |
| 113 return event; |
| 114 } |
| 115 |
| 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); |
| 126 } |
| 127 break; |
| 128 default: |
| 129 break; |
| 130 } |
| 131 free(event); |
| 132 } |
| 133 } |
| 134 |
| 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; |
| 145 } |
| 146 } |
| 147 } |
| 148 |
| 149 void PSEventPost(PSEventType type) { |
| 150 assert(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST == type || |
| 151 PSE_MOUSELOCK_MOUSELOCKLOST == type); |
| 152 |
| 153 struct PSEvent* event = malloc(sizeof(struct PSEvent)); |
| 154 memset(event, 0, sizeof(*event)); |
| 155 event->type = type; |
| 156 EnqueueEvent(event); |
| 157 } |
| 158 |
| 159 void PSEventPostBool(PSEventType type, PP_Bool bool_value) { |
| 160 assert(PSE_INSTANCE_DIDCHANGEFOCUS == type); |
| 161 |
| 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); |
| 167 } |
| 168 |
| 169 void PSEventPostVar(PSEventType type, struct PP_Var var) { |
| 170 assert(PSE_INSTANCE_HANDLEMESSAGE == type); |
| 171 |
| 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); |
| 184 |
| 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; |
| 193 } |
| 194 |
| 195 PSInterfaceVar()->Release(key_var); |
| 196 } |
| 197 |
| 198 PSInterfaceVar()->Release(keys_var); |
| 199 } |
| 200 |
| 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); |
| 207 } |
| 208 |
| 209 void PSEventPostResource(PSEventType type, PP_Resource resource) { |
| 210 assert(PSE_INSTANCE_HANDLEINPUT == type || |
| 211 PSE_INSTANCE_DIDCHANGEVIEW == type); |
| 212 |
| 213 if (resource) { |
| 214 PSInterfaceCore()->AddRefResource(resource); |
| 215 } |
| 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); |
| 221 } |
| 222 |
| 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); |
| 228 |
| 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; |
| 236 } |
| 237 |
| 238 if (handler->next) { |
| 239 handler->next->prev = handler->prev; |
| 240 } else { |
| 241 s_handler_tail = handler->prev; |
| 242 } |
| 243 |
| 244 free(handler->message_name); |
| 245 free(handler); |
| 246 } |
| 247 return; |
| 248 } |
| 249 |
| 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; |
| 263 |
| 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; |
| 269 } |
| 270 } |
| 271 } |
OLD | NEW |