| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <errno.h> | 5 #include <errno.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <pthread.h> | 7 #include <pthread.h> |
| 8 #include <stdio.h> | 8 #include <stdio.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <sys/ioctl.h> |
| 10 #include <sys/types.h> | 11 #include <sys/types.h> |
| 11 #include <sys/stat.h> | 12 #include <sys/stat.h> |
| 12 | 13 |
| 13 #include <algorithm> | 14 #include <algorithm> |
| 14 #include <cstdlib> | 15 #include <cstdlib> |
| 15 #include <cstring> | 16 #include <cstring> |
| 16 #include <sstream> | 17 #include <sstream> |
| 17 #include <string> | 18 #include <string> |
| 18 #include <vector> | 19 #include <vector> |
| 19 | 20 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 return ret; | 90 return ret; |
| 90 } | 91 } |
| 91 | 92 |
| 92 PSInstance::PSInstance(PP_Instance instance) | 93 PSInstance::PSInstance(PP_Instance instance) |
| 93 : pp::Instance(instance), | 94 : pp::Instance(instance), |
| 94 pp::MouseLock(this), | 95 pp::MouseLock(this), |
| 95 pp::Graphics3DClient(this), | 96 pp::Graphics3DClient(this), |
| 96 main_loop_(NULL), | 97 main_loop_(NULL), |
| 97 events_enabled_(PSE_NONE), | 98 events_enabled_(PSE_NONE), |
| 98 verbosity_(PSV_WARN), | 99 verbosity_(PSV_WARN), |
| 99 fd_tty_(-1) { | 100 tty_fd_(-1), |
| 101 tty_prefix_(NULL) { |
| 100 // Set the single Instance object | 102 // Set the single Instance object |
| 101 s_InstanceObject = this; | 103 s_InstanceObject = this; |
| 102 | 104 |
| 103 #ifdef NACL_SDK_DEBUG | 105 #ifdef NACL_SDK_DEBUG |
| 104 SetVerbosity(PSV_LOG); | 106 SetVerbosity(PSV_LOG); |
| 105 #endif | 107 #endif |
| 106 | 108 |
| 107 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | | 109 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | |
| 108 PP_INPUTEVENT_CLASS_KEYBOARD | | 110 PP_INPUTEVENT_CLASS_KEYBOARD | |
| 109 PP_INPUTEVENT_CLASS_WHEEL | | 111 PP_INPUTEVENT_CLASS_WHEEL | |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface); | 202 nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface); |
| 201 int fd0 = open(getenv("PS_STDIN"), O_RDONLY); | 203 int fd0 = open(getenv("PS_STDIN"), O_RDONLY); |
| 202 dup2(fd0, 0); | 204 dup2(fd0, 0); |
| 203 | 205 |
| 204 int fd1 = open(getenv("PS_STDOUT"), O_WRONLY); | 206 int fd1 = open(getenv("PS_STDOUT"), O_WRONLY); |
| 205 dup2(fd1, 1); | 207 dup2(fd1, 1); |
| 206 | 208 |
| 207 int fd2 = open(getenv("PS_STDERR"), O_WRONLY); | 209 int fd2 = open(getenv("PS_STDERR"), O_WRONLY); |
| 208 dup2(fd2, 2); | 210 dup2(fd2, 2); |
| 209 | 211 |
| 210 const char* tty_prefix = getenv("PS_TTY_PREFIX"); | 212 tty_prefix_ = getenv("PS_TTY_PREFIX"); |
| 211 if (tty_prefix) { | 213 if (tty_prefix_) { |
| 212 fd_tty_ = open("/dev/tty", O_WRONLY); | 214 tty_fd_ = open("/dev/tty", O_WRONLY); |
| 213 if (fd_tty_ >= 0) { | 215 if (tty_fd_ >= 0) { |
| 214 ioctl(fd_tty_, TIOCNACLPREFIX, const_cast<char*>(tty_prefix)); | 216 RegisterMessageHandler(tty_prefix_, MessageHandlerInputStatic, this); |
| 217 const char* tty_resize = getenv("PS_TTY_RESIZE"); |
| 218 if (tty_resize) |
| 219 RegisterMessageHandler(tty_resize, MessageHandlerResizeStatic, this); |
| 220 |
| 221 tioc_nacl_output handler; |
| 222 handler.handler = TtyOutputHandlerStatic; |
| 223 handler.user_data = this; |
| 224 ioctl(tty_fd_, TIOCNACLOUTPUT, reinterpret_cast<char*>(&handler)); |
| 215 } else { | 225 } else { |
| 216 Error("Failed to open /dev/tty.\n"); | 226 Error("Failed to open /dev/tty.\n"); |
| 217 } | 227 } |
| 218 } | 228 } |
| 219 | 229 |
| 220 // Set line buffering on stdout and stderr | 230 // Set line buffering on stdout and stderr |
| 221 #if !defined(WIN32) | 231 #if !defined(WIN32) |
| 222 setvbuf(stderr, NULL, _IOLBF, 0); | 232 setvbuf(stderr, NULL, _IOLBF, 0); |
| 223 setvbuf(stdout, NULL, _IOLBF, 0); | 233 setvbuf(stdout, NULL, _IOLBF, 0); |
| 224 #endif | 234 #endif |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 if (resource) { | 313 if (resource) { |
| 304 PSInterfaceCore()->AddRefResource(resource); | 314 PSInterfaceCore()->AddRefResource(resource); |
| 305 } | 315 } |
| 306 PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); | 316 PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); |
| 307 memset(env, 0, sizeof(*env)); | 317 memset(env, 0, sizeof(*env)); |
| 308 env->type = type; | 318 env->type = type; |
| 309 env->as_resource = resource; | 319 env->as_resource = resource; |
| 310 event_queue_.Enqueue(env); | 320 event_queue_.Enqueue(env); |
| 311 } | 321 } |
| 312 | 322 |
| 323 ssize_t PSInstance::TtyOutputHandler(const char* buf, size_t count) { |
| 324 // We prepend the prefix_ to the data in buf, then package it up |
| 325 // and post it as a message to javascript. |
| 326 const char* data = static_cast<const char*>(buf); |
| 327 std::string message = tty_prefix_; |
| 328 message.append(data, count); |
| 329 PostMessage(pp::Var(message)); |
| 330 return count; |
| 331 } |
| 332 |
| 333 void PSInstance::MessageHandlerInput(const pp::Var& message) { |
| 334 // Since our message may contain null characters, we can't send it as a |
| 335 // naked C string, so we package it up in this struct before sending it |
| 336 // to the ioctl. |
| 337 assert(message.is_string()); |
| 338 std::string buffer = message.AsString(); |
| 339 |
| 340 struct tioc_nacl_input_string ioctl_message; |
| 341 ioctl_message.length = buffer.size(); |
| 342 ioctl_message.buffer = buffer.c_str(); |
| 343 int ret = |
| 344 ioctl(tty_fd_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message)); |
| 345 if (ret != 0 && errno != ENOTTY) { |
| 346 Error("ioctl returned unexpected error: %d.\n", ret); |
| 347 } |
| 348 } |
| 349 |
| 350 void PSInstance::MessageHandlerResize(const pp::Var& message) { |
| 351 assert(message.is_array()); |
| 352 pp::VarArray array(message); |
| 353 assert(array.GetLength() == 2); |
| 354 |
| 355 struct winsize size; |
| 356 memset(&size, 0, sizeof(size)); |
| 357 size.ws_col = array.Get(0).AsInt(); |
| 358 size.ws_row = array.Get(1).AsInt(); |
| 359 ioctl(tty_fd_, TIOCSWINSZ, reinterpret_cast<char*>(&size)); |
| 360 } |
| 361 |
| 362 ssize_t PSInstance::TtyOutputHandlerStatic(const char* buf, |
| 363 size_t count, |
| 364 void* user_data) { |
| 365 PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); |
| 366 return instance->TtyOutputHandler(buf, count); |
| 367 } |
| 368 |
| 369 void PSInstance::MessageHandlerInputStatic(const pp::Var& key, |
| 370 const pp::Var& value, |
| 371 void* user_data) { |
| 372 PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); |
| 373 instance->MessageHandlerInput(value); |
| 374 } |
| 375 |
| 376 void PSInstance::MessageHandlerResizeStatic(const pp::Var& key, |
| 377 const pp::Var& value, |
| 378 void* user_data) { |
| 379 PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); |
| 380 instance->MessageHandlerResize(value); |
| 381 } |
| 382 |
| 383 void PSInstance::RegisterMessageHandler(std::string message_name, |
| 384 MessageHandler_t handler, |
| 385 void* user_data) { |
| 386 if (handler == NULL) { |
| 387 message_handlers_.erase(message_name); |
| 388 return; |
| 389 } |
| 390 |
| 391 MessageHandler message_handler = { handler, user_data }; |
| 392 message_handlers_[message_name] = message_handler; |
| 393 } |
| 394 |
| 313 void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { | 395 void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { |
| 314 assert(PSE_INSTANCE_HANDLEMESSAGE == type); | 396 assert(PSE_INSTANCE_HANDLEMESSAGE == type); |
| 315 | 397 |
| 316 // If the user has specified a tty_prefix_ (using ioctl), then we'll give the | 398 // If the user has specified a tty_prefix_, then filter out the |
| 317 // tty node a chance to vacuum up any messages beginning with that prefix. If | 399 // matching message here and pass them to the tty node via |
| 318 // the message does not start with the prefix, the ioctl call will return | 400 // ioctl() rather then adding them to the event queue. |
| 319 // ENOENT and we'll pass the message through to the event queue. | 401 pp::Var event(var); |
| 320 if (fd_tty_ >= 0 && var.type == PP_VARTYPE_STRING) { | 402 if (tty_fd_ >= 0 && event.is_string()) { |
| 321 uint32_t message_len; | 403 std::string message = event.AsString(); |
| 322 const char* message = PSInterfaceVar()->VarToUtf8(var, &message_len); | 404 size_t prefix_len = strlen(tty_prefix_); |
| 323 std::string message_str(message, message + message_len); | 405 if (message.size() > prefix_len) { |
| 406 if (!strncmp(message.c_str(), tty_prefix_, prefix_len)) { |
| 407 MessageHandlerInput(pp::Var(message.substr(prefix_len))); |
| 408 return; |
| 409 } |
| 410 } |
| 411 } |
| 324 | 412 |
| 325 // Since our message may contain null characters, we can't send it as a | 413 // If the message is a dictionary then see if it matches one |
| 326 // naked C string, so we package it up in this struct before sending it | 414 // of the specific handlers, then call that handler rather than |
| 327 // to the ioctl. | 415 // queuing an event. |
| 328 struct tioc_nacl_input_string ioctl_message; | 416 if (tty_fd_ >= 0 && event.is_dictionary()) { |
| 329 ioctl_message.length = message_len; | 417 pp::VarDictionary dictionary(var); |
| 330 ioctl_message.buffer = message_str.data(); | 418 pp::VarArray keys = dictionary.GetKeys(); |
| 331 int ret = | 419 if (keys.GetLength() == 1) { |
| 332 ioctl(fd_tty_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message)); | 420 pp::Var key = keys.Get(0); |
| 333 if (ret != 0 && errno != ENOTTY) { | 421 MessageHandlerMap::iterator iter = |
| 334 Error("ioctl returned unexpected error: %d.\n", ret); | 422 message_handlers_.find(key.AsString()); |
| 423 if (iter != message_handlers_.end()) { |
| 424 MessageHandler_t handler = iter->second.handler; |
| 425 void* user_data = iter->second.user_data; |
| 426 handler(key, dictionary.Get(key), user_data); |
| 427 return; |
| 428 } |
| 335 } | 429 } |
| 336 | |
| 337 return; | |
| 338 } | 430 } |
| 339 | 431 |
| 340 PSInterfaceVar()->AddRef(var); | 432 PSInterfaceVar()->AddRef(var); |
| 341 PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); | 433 PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); |
| 342 memset(env, 0, sizeof(*env)); | 434 memset(env, 0, sizeof(*env)); |
| 343 env->type = type; | 435 env->type = type; |
| 344 env->as_var = var; | 436 env->as_var = var; |
| 345 event_queue_.Enqueue(env); | 437 event_queue_.Enqueue(env); |
| 346 } | 438 } |
| 347 | 439 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 | 505 |
| 414 void PSInstance::Graphics3DContextLost() { | 506 void PSInstance::Graphics3DContextLost() { |
| 415 Log("Graphics3DContextLost\n"); | 507 Log("Graphics3DContextLost\n"); |
| 416 PostEvent(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST); | 508 PostEvent(PSE_GRAPHICS3D_GRAPHICS3DCONTEXTLOST); |
| 417 } | 509 } |
| 418 | 510 |
| 419 void PSInstance::MouseLockLost() { | 511 void PSInstance::MouseLockLost() { |
| 420 Log("MouseLockLost\n"); | 512 Log("MouseLockLost\n"); |
| 421 PostEvent(PSE_MOUSELOCK_MOUSELOCKLOST); | 513 PostEvent(PSE_MOUSELOCK_MOUSELOCKLOST); |
| 422 } | 514 } |
| OLD | NEW |