1// Copyright (c) 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#ifndef PPAPI_SIMPLE_PS_INSTANCE_H_
6#define PPAPI_SIMPLE_PS_INSTANCE_H_
7
8#include <stdarg.h>
9
10#include "ppapi/c/pp_instance.h"
11#include "ppapi/c/pp_stdint.h"
12#include "ppapi/c/ppb_core.h"
13#include "ppapi/c/ppb_var.h"
14#include "ppapi/c/ppb_view.h"
15
16#include "ppapi/cpp/fullscreen.h"
17#include "ppapi/cpp/graphics_3d_client.h"
18#include "ppapi/cpp/instance.h"
19#include "ppapi/cpp/message_loop.h"
20#include "ppapi/cpp/mouse_lock.h"
21
22#include "ppapi/utility/completion_callback_factory.h"
23
24#include "ppapi_simple/ps_event.h"
25#include "ppapi_simple/ps_main.h"
26
27#include "sdk_util/thread_safe_queue.h"
28
29typedef void (*MessageHandler_t)(const pp::Var& key,
30                                 const pp::Var& value,
31                                 void* user_data);
32
33struct MessageHandler {
34  MessageHandler_t handler;
35  void* user_data;
36};
37
38// The basic instance class which also inherits the MouseLock and
39// Graphics3DClient interfaces.
40class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient {
41 public:
42  // Verbosity levels, ecplicitly numbered since we pass these
43  // in from html attributes as numberic values.
44  enum Verbosity {
45    PSV_SILENT = 0,
46    PSV_ERROR = 1,
47    PSV_WARN = 2,
48    PSV_LOG = 3,
49    PSV_TRACE = 4,
50  };
51
52  // Returns a pointer to the global instance
53  static PSInstance* GetInstance();
54
55  PSInstance(PP_Instance inst);
56  virtual ~PSInstance();
57
58  // Set a function which will be called on a new thread once initialized.
59  // NOTE:  This must be called by the Factory, once Init is called, this
60  // function will have no effect.
61  void SetMain(PSMainFunc_t func);
62
63  // Started on Init, a thread which can be safely blocked.
64  virtual int MainThread(int argc, char* argv[]);
65
66  // Logging Functions
67  void SetVerbosity(Verbosity verbosity);
68  void Trace(const char *fmt, ...);
69  void Log(const char *fmt, ...);
70  void Warn(const char *fmt, ...);
71  void Error(const char *fmt, ...);
72
73  // Event Functions
74  void SetEnabledEvents(uint32_t mask);
75  void PostEvent(PSEventType type);
76  void PostEvent(PSEventType type, PP_Bool bool_value);
77  void PostEvent(PSEventType type, PP_Resource resource);
78  void PostEvent(PSEventType type, const PP_Var& var);
79
80  PSEvent* TryAcquireEvent();
81  PSEvent* WaitAcquireEvent();
82  void ReleaseEvent(PSEvent* event);
83
84  // Register a message handler for messages that arrive
85  // from JavaScript with a give names.  Messages are of the
86  // form:  { message_name : <value> }.
87  //
88  // PSInstance will then not generate events but instead
89  // cause the handler to be called upon message arrival.
90  // If handler is NULL then the current handler will be
91  // removed. Example usage:
92  //
93  // JavaScript:
94  //   nacl_module.postMessage({'foo': 123});
95  //
96  // C++:
97  //   void MyMessageHandler(const pp::Var& key,
98  //                         const pp::Var& value,
99  //                         void* user_data) {
100  //     assert(key.is_string());
101  //     assert(key.AsString() == "foo");
102  //     assert(value.is_int());
103  //     assert(value.AsInt() == 123);
104  //   }
105  //   ...
106  //   instance_->RegisterMessageHandler("foo", &MyMessageHandler, NULL);
107  //
108  void RegisterMessageHandler(std::string message_name,
109                              MessageHandler_t handler,
110                              void* user_data);
111
112  // Perform exit handshake with JavaScript.
113  // This is called by _exit before the process is terminated to ensure
114  // that all messages sent prior to _exit arrive at the JavaScript side.
115  void ExitHandshake(int status);
116
117 protected:
118  typedef std::map<std::string, MessageHandler> MessageHandlerMap;
119
120  // Callback functions triggered by Pepper
121  //
122  // These functions are called on the main pepper thread, so they must
123  // not block.
124  //
125  // Called by the browser when the NaCl module is loaded and all ready to go.
126  // This function will create a new thread which will run the pseudo main.
127  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
128
129  // Output log message to stderr if the current verbosity is set
130  // at or above the given verbosity.
131  void VALog(Verbosity verbosity, const char *fmt, va_list args);
132
133  // Called whenever the in-browser window changes size, it will pass a
134  // context change request to whichever thread is handling rendering.
135  virtual void DidChangeView(const pp::View& view);
136
137  // Called by the browser when the NaCl canvas gets or loses focus.
138  virtual void DidChangeFocus(bool has_focus);
139
140  // Called by the browser to handle the postMessage() call in Javascript.
141  virtual void HandleMessage(const pp::Var& message);
142
143  // Called by the browser to handle incoming input events.  Events are Q'd
144  // and can later be processed on a sperate processing thread.
145  virtual bool HandleInputEvent(const pp::InputEvent& event);
146
147  // Called by the browser when the 3D context is lost.
148  virtual void Graphics3DContextLost();
149
150  // Called by the browser when the mouselock is lost.
151  virtual void MouseLockLost();
152
153  // Called by Init to processes default and embed tag arguments prior to
154  // launching the 'ppapi_main' thread.
155  virtual bool ProcessProperties();
156
157 private:
158  static void* MainThreadThunk(void *start_info);
159  ssize_t TtyOutputHandler(const char* buf, size_t count);
160  void MessageHandlerExit(const pp::Var& message);
161  void MessageHandlerInput(const pp::Var& key, const pp::Var& message);
162  void MessageHandlerResize(const pp::Var& message);
163  void HandleResize(int width, int height);
164
165  static void HandleExitStatic(int status, void* user_data);
166
167  static ssize_t TtyOutputHandlerStatic(const char* buf, size_t count,
168                                        void* user_data);
169
170  /// Handle exit confirmation message from JavaScript.
171  static void MessageHandlerExitStatic(const pp::Var& key,
172                                       const pp::Var& message,
173                                       void* user_data);
174
175  /// Handle input message from JavaScript.  The value is
176  /// expected to be of type string.
177  static void MessageHandlerInputStatic(const pp::Var& key,
178                                        const pp::Var& message,
179                                        void* user_data);
180
181
182  /// Handle resizs message from JavaScript.  The value is
183  /// expected to be an array of 2 integers representing the
184  /// number of columns and rows in the TTY.
185  static void MessageHandlerResizeStatic(const pp::Var& key,
186                                         const pp::Var& message,
187                                         void* user_data);
188
189 protected:
190  pp::MessageLoop* main_loop_;
191
192  sdk_util::ThreadSafeQueue<PSEvent> event_queue_;
193  uint32_t events_enabled_;
194  Verbosity verbosity_;
195
196  // TTY handling
197  int tty_fd_;
198  const char* tty_prefix_;
199  MessageHandlerMap message_handlers_;
200
201  PSMainFunc_t main_cb_;
202
203  const PPB_Core* ppb_core_;
204  const PPB_Var* ppb_var_;
205  const PPB_View* ppb_view_;
206
207  // Condition variable and lock used to wait for exit confirmation from
208  // JavaScript.
209  pthread_cond_t exit_cond_;
210  pthread_mutex_t exit_lock_;
211
212  // A message to Post to JavaScript instead of exiting, or NULL if exit()
213  // should be called instead.
214  char* exit_message_;
215};
216
217#endif  // PPAPI_SIMPLE_PS_INSTANCE_H_
218