Chromium Code Reviews| Index: native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc |
| diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc |
| index 2c073f02a6912fa9dedf0e4c8646a53cb36c369f..b47e6a9cbaede15bba65846632f0b1e86dbb1650 100644 |
| --- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc |
| +++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc |
| @@ -7,6 +7,7 @@ |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| +#include <sys/ioctl.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| @@ -96,7 +97,7 @@ PSInstance::PSInstance(PP_Instance instance) |
| main_loop_(NULL), |
| events_enabled_(PSE_NONE), |
| verbosity_(PSV_WARN), |
| - fd_tty_(-1) { |
| + tty_fd_(-1) { |
|
binji
2013/08/22 18:09:36
init tty_prefix_ and tty_resize_ to NULL?
Sam Clegg
2013/08/22 19:52:25
Done.
|
| // Set the single Instance object |
| s_InstanceObject = this; |
| @@ -207,11 +208,17 @@ bool PSInstance::ProcessProperties() { |
| int fd2 = open(getenv("PS_STDERR"), O_WRONLY); |
| dup2(fd2, 2); |
| - const char* tty_prefix = getenv("PS_TTY_PREFIX"); |
| - if (tty_prefix) { |
| - fd_tty_ = open("/dev/tty", O_WRONLY); |
| - if (fd_tty_ >= 0) { |
| - ioctl(fd_tty_, TIOCNACLPREFIX, const_cast<char*>(tty_prefix)); |
| + tty_prefix_ = getenv("PS_TTY_PREFIX"); |
| + if (tty_prefix_) { |
| + tty_fd_ = open("/dev/tty", O_WRONLY); |
| + if (tty_fd_ >= 0) { |
| + RegisterMessageHandler(tty_prefix_, MessageHandlerInputStatic, this); |
| + tty_resize_ = getenv("PS_TTY_RESIZE"); |
| + if (tty_resize_) |
|
binji
2013/08/22 18:09:36
tty_resize_ is only used in this function, does it
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + RegisterMessageHandler(tty_resize_, MessageHandlerResizeStatic, this); |
| + |
| + char* handler = reinterpret_cast<char*>(TtyOutputHandlerStatic); |
| + ioctl(tty_fd_, TIOCNACLOUTPUT, handler); |
| } else { |
| Error("Failed to open /dev/tty.\n"); |
| } |
| @@ -310,31 +317,110 @@ void PSInstance::PostEvent(PSEventType type, PP_Resource resource) { |
| event_queue_.Enqueue(env); |
| } |
| +void PSInstance::MessageHandlerInput(const pp::Var& message) { |
| + // Since our message may contain null characters, we can't send it as a |
| + // naked C string, so we package it up in this struct before sending it |
| + // to the ioctl. |
| + assert(message.is_string()); |
| + std::string buffer = message.AsString(); |
| + |
| + struct tioc_nacl_input_string ioctl_message; |
| + ioctl_message.length = buffer.size(); |
| + ioctl_message.buffer = buffer.c_str(); |
| + int ret = |
| + ioctl(tty_fd_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message)); |
| + if (ret != 0 && errno != ENOTTY) { |
| + Error("ioctl returned unexpected error: %d.\n", ret); |
| + } |
| +} |
| + |
| +int PSInstance::TtyOutputHandlerStatic(const char* buf, int count) { |
| + return PSInstance::GetInstance()->TtyOutputHandler(buf, count); |
| +} |
| + |
| +int PSInstance::TtyOutputHandler(const char* buf, int count) { |
| + // We prepend the prefix_ to the data in buf, then package it up |
| + // and post it as a message to javascript. |
| + const char* data = static_cast<const char*>(buf); |
| + std::string message = tty_prefix_; |
| + message.append(data, count); |
| + PostMessage(pp::Var(message)); |
| + return count; |
| +} |
| + |
| +void PSInstance::MessageHandlerInputStatic(const pp::Var& key, |
| + const pp::Var& value, |
| + void* user_data) { |
| + PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); |
| + instance->MessageHandlerInput(value); |
| +} |
| + |
| +void PSInstance::MessageHandlerResizeStatic(const pp::Var& key, |
|
binji
2013/08/22 18:09:36
nit: the ordering of functions here is strange, I'
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + const pp::Var& value, |
| + void* user_data) { |
| + PSInstance* instance = reinterpret_cast<PSInstance*>(user_data); |
| + instance->MessageHandlerResize(value); |
| +} |
| + |
| +void PSInstance::MessageHandlerResize(const pp::Var& message) { |
| + assert(message.is_array()); |
|
binji
2013/08/22 18:09:36
document this message somewhere in the header?
va
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + pp::VarArray array(message); |
| + assert(array.GetLength() == 2); |
| + |
| + struct winsize size; |
| + memset(&size, 0, sizeof(size)); |
| + size.ws_col = array.Get(0).AsInt(); |
| + size.ws_row = array.Get(1).AsInt(); |
| + ioctl(tty_fd_, TIOCSWINSZ, reinterpret_cast<char*>(&size)); |
| +} |
| + |
| +void PSInstance::RegisterMessageHandler(std::string message_name, |
| + MessageHandler_t handler, |
| + void* user_data) { |
| + if (handler == NULL) { |
| + message_handlers_.erase(message_name); |
| + return; |
| + } |
| + |
| + MessageHandler message_handler = { handler, user_data }; |
| + message_handlers_[message_name] = message_handler; |
| +} |
| + |
| void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { |
| assert(PSE_INSTANCE_HANDLEMESSAGE == type); |
| - // If the user has specified a tty_prefix_ (using ioctl), then we'll give the |
| - // tty node a chance to vacuum up any messages beginning with that prefix. If |
| - // the message does not start with the prefix, the ioctl call will return |
| - // ENOENT and we'll pass the message through to the event queue. |
| - if (fd_tty_ >= 0 && var.type == PP_VARTYPE_STRING) { |
| - uint32_t message_len; |
| - const char* message = PSInterfaceVar()->VarToUtf8(var, &message_len); |
| - std::string message_str(message, message + message_len); |
| - |
| - // Since our message may contain null characters, we can't send it as a |
| - // naked C string, so we package it up in this struct before sending it |
| - // to the ioctl. |
| - struct tioc_nacl_input_string ioctl_message; |
| - ioctl_message.length = message_len; |
| - ioctl_message.buffer = message_str.data(); |
| - int ret = |
| - ioctl(fd_tty_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message)); |
| - if (ret != 0 && errno != ENOTTY) { |
| - Error("ioctl returned unexpected error: %d.\n", ret); |
| + // If the user has specified a tty_prefix_, then filter out the |
| + // matching message here and pass them to the tty node via |
| + // ioctl() rather then adding them to the even queue. |
|
binji
2013/08/22 18:09:36
sp: event
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + pp::Var event(var); |
| + if (tty_fd_ >= 0 && event.is_string()) { |
| + std::string message = event.AsString(); |
| + size_t prefix_len = strlen(tty_prefix_); |
| + if (message.size() > prefix_len) { |
| + if (!strncmp(message.c_str(), tty_prefix_, prefix_len)) { |
| + MessageHandlerInput(pp::Var(message.substr(prefix_len))); |
| + return; |
| + } |
| } |
| + } |
| - return; |
| + // 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 (tty_fd_ >= 0 && event.is_dictionary()) { |
| + pp::VarDictionary dictionary(var); |
| + pp::VarArray keys = dictionary.GetKeys(); |
| + if (keys.GetLength() == 1) { |
| + pp::Var key = keys.Get(0); |
| + std::map<std::string, MessageHandler>::iterator iter = |
|
binji
2013/08/22 18:09:36
I find that this is a bit more readable if you mak
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + message_handlers_.find(key.AsString()); |
| + if (iter != message_handlers_.end()) { |
| + MessageHandler_t handler = iter->second.handler; |
| + void* user_data = iter->second.user_data; |
| + handler(key, dictionary.Get(key), user_data); |
| + return; |
| + } |
| + } |
| } |
| PSInterfaceVar()->AddRef(var); |