Index: gears/base/common/js_runner.h
===================================================================
--- gears/base/common/js_runner.h	(revision 3229)
+++ gears/base/common/js_runner.h	(working copy)
@@ -244,6 +244,9 @@
 // successfully initialize to a stable but unusable state.
 JsRunnerInterface* NewJsRunner(JSRuntime *js_runtime);
 #else
+#ifdef BROWSER_OPERA
+JsRunnerInterface* NewJsRunner(JsContextPtr context, void* object);
+#endif  // BROWSER_OPERA
 JsRunnerInterface* NewJsRunner();
 #endif
 
Index: gears/base/common/js_runner_np.cc
===================================================================
--- gears/base/common/js_runner_np.cc	(revision 3229)
+++ gears/base/common/js_runner_np.cc	(working copy)
@@ -52,8 +52,12 @@
 #include "gears/base/npapi/module_wrapper.h"
 #include "gears/base/npapi/np_utils.h"
 #include "gears/base/npapi/scoped_npapi_handles.h"
+#ifdef BROWSER_OPERA
+#include "gears/base/opera/opera_utils.h"
+#include "third_party/opera/opera_callback_api.h"
+#endif  // BROWSER_OPERA
 #ifdef BROWSER_WEBKIT
-#include "gears/base/safari/npapi_patches.h" 
+#include "gears/base/safari/npapi_patches.h"
 #endif
 
 // We keep a map of active DocumentJsRunners so we can notify them when their
@@ -90,7 +94,7 @@
  public:
   JsRunnerBase() : evaluator_(NULL) {
   }
-  
+
   virtual ~JsRunnerBase() {
     // Should have called Cleanup() to kill this before getting here();
     assert(np_variant_comparator_.get() == NULL);
@@ -99,9 +103,14 @@
       assert(0 == event_handlers_[i].size());
     }
   }
-  
+
+  // Only used by opera. Set an object which can be used to identify the
+  // current thread so it can be run in the correct context
+  virtual void SetThreadIdentifier(){}
+  virtual void ClearThreadIdentifier(){}
+
   virtual NPObject *GetGlobalObject() = 0;
-  
+
   // Because JsRunner destroys the JSEngine in it's destructor, we add this
   // function which cleans up objects that need a valid JSEngine in order
   // to be succesfully destructed.
@@ -109,7 +118,7 @@
     evaluator_.reset(NULL);
     np_variant_comparator_.reset(NULL);
   }
-  
+
   bool AddGlobal(const std::string16 &name, ModuleImplBaseClass *object) {
     NPVariant np_window;
     OBJECT_TO_NPVARIANT(GetGlobalObject(), np_window);
@@ -161,8 +170,10 @@
 
     NPIdentifier get_time_id = NPN_GetStringIdentifier("getTime");
 
+    SetThreadIdentifier();
     ScopedNPVariant result;
     bool rv = NPN_Invoke(GetContext(), np_obj, get_time_id, NULL, 0, &result);
+    ClearThreadIdentifier();
     if (!rv) {
       return false;
     }
@@ -179,8 +190,10 @@
   bool InitializeModuleWrapper(ModuleImplBaseClass *module,
                                DispatcherInterface *dispatcher,
                                JsCallContext *context) {
+    SetThreadIdentifier();
     ModuleWrapper *module_wrapper = static_cast<ModuleWrapper *>(
         NPN_CreateObject(GetContext(), ModuleWrapper::GetNPClass()));
+    ClearThreadIdentifier();
     if (!module_wrapper) {
       if (context) {
         context->SetException(STRING16(L"Module creation failed."));
@@ -216,8 +229,10 @@
 
     // Invoke the method.
     ScopedNPVariant result;
+    SetThreadIdentifier();
     bool rv = NPN_InvokeDefault(GetContext(), evaluator,
                                 evaluator_args.get(), evaluator_argc, &result);
+    ClearThreadIdentifier();
     if (!rv) { return false; }
 
     if (!NPVARIANT_IS_OBJECT(result)) {
@@ -250,7 +265,7 @@
 
     return true;
   }
-  
+
   bool EvalImpl(const std::string16 &script, bool catch_exceptions) {
     NPObject *global_object = GetGlobalObject();
 
@@ -259,7 +274,7 @@
       LOG(("Could not convert script to UTF8."));
       return false;
     }
-    
+
     if (catch_exceptions) {
       const char kEvaluatorTry[] = "try { ";
       const char kEvaluatorCatch[] =
@@ -269,7 +284,10 @@
 
     NPString np_script = {script_utf8.data(), script_utf8.length()};
     ScopedNPVariant result;
-    if (!NPN_Evaluate(GetContext(), global_object, &np_script, &result))
+    SetThreadIdentifier();
+    bool rv = NPN_Evaluate(GetContext(), global_object, &np_script, &result);
+    ClearThreadIdentifier();
+	if (!rv)
       return false;
 
     if (catch_exceptions && NPVARIANT_IS_STRING(result)) {
@@ -286,7 +304,7 @@
       SetException(exception16);
       return false;
     }
- 
+
     return true;
   }
 
@@ -452,14 +470,14 @@
     NPIdentifier np_name = NPN_GetStringIdentifier(name_utf8.c_str());
     return NPN_SetProperty(GetContext(), np_object, np_name, &value);
   }
-  
+
   NPObject *GetEvaluator() {
     if (evaluator_.get())
       return evaluator_.get();
 
     // Wierd Safari bug: if you remove the surrounding parenthesis, this ceases
     // to work.
-    const char kEvaluatorScript[] = 
+    const char kEvaluatorScript[] =
       "(function () {"  // variable number of arguments
       "  var fn = arguments[0];"
       "  var args = Array.prototype.slice.call(arguments, 1);"
@@ -474,8 +492,10 @@
     NPObject *global = GetGlobalObject();
     NPString np_script = { kEvaluatorScript, ARRAYSIZE(kEvaluatorScript) - 1};
     ScopedNPVariant evaluator;
-    if (!NPN_Evaluate(GetContext(), global, &np_script, &evaluator) ||
-        !NPVARIANT_IS_OBJECT(evaluator)) {
+    SetThreadIdentifier();
+	bool rv = NPN_Evaluate(GetContext(), global, &np_script, &evaluator);
+    ClearThreadIdentifier();
+    if (!rv || !NPVARIANT_IS_OBJECT(evaluator)) {
       assert(false);
       return NULL;
     }
@@ -495,7 +515,9 @@
     // Evaluate javascript code: 'ConstructorName()'
     NPString script = {string_to_eval.c_str(), string_to_eval.length()};
     ScopedNPVariant object;
+    SetThreadIdentifier();
     bool rv = NPN_Evaluate(GetContext(), global_object, &script, &object);
+    ClearThreadIdentifier();
     if (!rv) {
       LOG(("Could not invoke object constructor."));
       return NULL;
@@ -533,25 +555,25 @@
     LEAK_COUNTER_INCREMENT(JsRunner);
 
     if (!initialized) {
-      MutexLock lock(&browser_callbacks_mutex); 
+      MutexLock lock(&browser_callbacks_mutex);
       JSStandaloneEngine::GetNPNEntryPoints(
           (NPNetscapeFuncs *)&browser_callbacks);
       initialized = true;
     }
-    
+
     JSStandaloneEngine::InitEngine(this, &np_instance_data_);
     ThreadLocals::SetValue(kNPNFuncsKey, &browser_callbacks, NULL);
     NPN_GetValue(GetContext(), NPNVWindowNPObject, &global_object_);
   }
-  
+
   virtual ~JsRunner() {
     LEAK_COUNTER_DECREMENT(JsRunner);
     // Alert modules that the engine is unloading.
     SendEvent(JSEVENT_UNLOAD);
-    
+
     // Must do this here as cannot call after TerminateEngine().
     Cleanup();
-    
+
     NPN_ReleaseObject(global_object_);
     JSStandaloneEngine::TerminateEngine();
   }
@@ -571,18 +593,18 @@
   NPObject *GetGlobalObject() {
     return global_object_;
   }
-  
+
   bool Start(const std::string16 &full_script) {
     LOG(("Starting Worker\n"));
     return Eval(full_script);
   }
-  
+
   bool Stop() {
     LOG(("Worker Stopped\n"));
     // TODO(mpcomplete): what does this mean?
     return false;
   }
-  
+
 #ifdef DEBUG
   void ForceGC() {
     Eval(STRING16(L"GearsInternalCollectGarbage();"));
@@ -600,11 +622,11 @@
     // external JS engine to capture exceptions thrown here.
     return EvalImpl(script, false);
   }
-  
+
   void SetErrorHandler(JsErrorHandlerInterface *error_handler) {
     error_handler_ = error_handler;
   }
-  
+
   virtual void ThrowGlobalError(const std::string16 &message) {
     if (error_handler_) {
       JsErrorInfo error_info;
@@ -617,14 +639,83 @@
  private:
   // Needs access to error_handler_.
   friend void HandleJSError(const JsRunner *js_runner, JsErrorInfo &error_info);
-   
+
   NPP_t np_instance_data_;
   NPObject *global_object_;
   JsErrorHandlerInterface *error_handler_;
   DISALLOW_EVIL_CONSTRUCTORS(JsRunner);
 };
 
+#ifdef BROWSER_OPERA
+class OperaJsRunner : public JsRunnerBase {
+ public:
+  OperaJsRunner(NPP instance, void* object)
+      : np_instance_(instance), global_object_((NPObject*)object) {
+  }
 
+  virtual ~OperaJsRunner() {
+    // Alert modules that the engine is unloading.
+    SendEvent(JSEVENT_UNLOAD);
+
+    Cleanup();
+    //NPN_ReleaseObject(global_object_);
+  }
+
+  virtual void OnModuleEnvironmentAttach() { };
+  virtual void OnModuleEnvironmentDetach() { };
+
+  NPObject *GetGlobalObject() {
+    return global_object_;
+  }
+
+  JsContextPtr GetContext() {
+    return np_instance_;
+  }
+
+  virtual void SetThreadIdentifier(){
+	  OperaUtils::GetBrowserApiForGears()->
+        SetCurrentGlobalObject(np_instance_, global_object_);
+  }
+  virtual void ClearThreadIdentifier(){
+	  OperaUtils::GetBrowserApiForGears()->
+        SetCurrentGlobalObject(np_instance_, NULL);
+  }
+
+  bool Start(const std::string16 &full_script) {
+    assert(false); // Should not be called on the OperaJsRunner.
+    return false;
+  }
+
+  bool Stop() {
+    assert(false); // Should not be called on the OperaJsRunner.
+    return false;
+  }
+
+#ifdef DEBUG
+  void ForceGC() {
+    // TODO(timj): implement for opera worker threads.
+  }
+#endif
+
+  bool Eval(const std::string16 &script) {
+    return EvalImpl(script, true);
+  }
+
+  void SetErrorHandler(JsErrorHandlerInterface *handler) {
+    assert(false); // Should not be called on the OperaJsRunner.
+  }
+
+  virtual void ThrowGlobalError(const std::string16 &message) {
+	  std::string16 script = STRING16(L"throw new Error('") + EscapeMessage(message) + STRING16(L"');");
+	  EvalImpl(script, false);
+  }
+ private:
+  NPP np_instance_;
+  NPObject *global_object_;
+  DISALLOW_EVIL_CONSTRUCTORS(OperaJsRunner);
+};
+#endif // BROWSER_OPERA
+
 // This class is a stub that is used to present a uniform interface to
 // common functionality to both workers and the main thread.
 class DocumentJsRunner : public JsRunnerBase {
@@ -645,7 +736,7 @@
     UnregisterDocumentJsRunner(np_instance_);
     NPN_ReleaseObject(global_object_);
   }
-   
+
   void OnModuleEnvironmentAttach() {
     is_module_environment_detached_ = false;
   }
@@ -672,7 +763,7 @@
     assert(false); // Should not be called on the DocumentJsRunner.
     return false;
   }
-  
+
 #ifdef DEBUG
   void ForceGC() {
     // TODO(playmobil): implement for main thread.
@@ -735,6 +826,12 @@
   }
 }
 
+#ifdef BROWSER_OPERA
+JsRunnerInterface *NewJsRunner(JsContextPtr context, void* object) {
+  return static_cast<JsRunnerInterface *>(new OperaJsRunner(context, object));
+}
+#endif // BROWSER_OPERA
+
 JsRunnerInterface *NewJsRunner() {
   return static_cast<JsRunnerInterface *>(new JsRunner());
 }
Index: gears/base/common/js_types.cc
===================================================================
--- gears/base/common/js_types.cc	(revision 3229)
+++ gears/base/common/js_types.cc	(working copy)
@@ -2371,16 +2371,21 @@
 #endif
 
   is_exception_set_ = true;
-  
+
   std::string message_utf8;
   if (!String16ToUTF8(message.data(), message.length(), &message_utf8))
     message_utf8 = "Unknown Gears Error";  // better to throw *something*
 
+#ifdef BROWSER_OPERA
+  // set the exception on the plugin object instead of the window
+  NPN_SetException(object_, message_utf8.c_str());
+#else  // BROWSER_OPERA
   NPObject *window;
   if (NPN_GetValue(js_context(), NPNVWindowNPObject, &window) != NPERR_NO_ERROR)
     return;
   ScopedNPObject window_scoped(window);
   NPN_SetException(window, message_utf8.c_str());
+#endif  // BROWSER_OPERA
 }
 
 #endif
