Browse Source

request_keyboard_focus

David Rose 16 years ago
parent
commit
5e12be142a

+ 5 - 1
direct/src/plugin/p3dCInstance.h

@@ -20,6 +20,7 @@
 #include "p3d_plugin.h"
 #include "pvector.h"
 #include "get_tinyxml.h"
+#include "windowHandle.h"
 
 #include <Python.h>
 
@@ -28,7 +29,7 @@ class P3DSession;
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DCInstance
 // Description : This is an instance of a Panda3D window, as seen in
-//               the parent-level process.
+//               the child-level process.
 ////////////////////////////////////////////////////////////////////
 class P3DCInstance : public P3D_instance {
 public:
@@ -37,6 +38,9 @@ public:
 
   inline int get_instance_id() const;
 
+public:
+  PT(WindowHandle) _parent_window_handle;
+
 private:
   P3D_request_ready_func *_func;
 

+ 16 - 0
direct/src/plugin/p3dInstance.cxx

@@ -1495,6 +1495,9 @@ handle_notify_request(const string &message) {
   } else if (message == "authfinished") {
     // Similarly for the "auth finished" message.
     auth_finished_main_thread();
+
+  } else if (message == "keyboardfocus") {
+    request_keyboard_focus();
   }
 }
 
@@ -1594,6 +1597,19 @@ handle_script_request(const string &operation, P3D_object *object,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::request_keyboard_focus
+//       Access: Private
+//  Description: The Panda window is asking us to manage keyboard
+//               focus in proxy for it.  This is used on Vista, where
+//               the Panda window may be disallowed from directly
+//               assigning itself keyboard focus.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+request_keyboard_focus() {
+  nout << "request_keyboard_focus\n";
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::make_splash_window
 //       Access: Private

+ 2 - 0
direct/src/plugin/p3dInstance.h

@@ -162,6 +162,8 @@ private:
   void handle_script_request(const string &operation, P3D_object *object, 
                              const string &property_name, P3D_object *value,
                              bool needs_response, int unique_id);
+  void request_keyboard_focus();
+
   void make_splash_window();
   void set_background_image(ImageType image_type);
   void set_button_image(ImageType image_type);

+ 70 - 0
direct/src/plugin/p3dPythonRun.cxx

@@ -29,6 +29,8 @@ IMPORT_THIS struct Dtool_PyTypedObject Dtool_WindowHandle;
 // instances of this thing.
 P3DPythonRun *P3DPythonRun::_global_ptr = NULL;
 
+TypeHandle P3DPythonRun::P3DWindowHandle::_type_handle;
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPythonRun::Constructor
 //       Access: Public
@@ -38,6 +40,8 @@ P3DPythonRun::
 P3DPythonRun(const char *program_name, const char *archive_file,
              FHandle input_handle, FHandle output_handle, 
              const char *log_pathname, bool interactive_console) {
+  P3DWindowHandle::init_type();
+
   _read_thread_continue = false;
   _program_continue = true;
   _session_terminated = false;
@@ -112,6 +116,8 @@ P3DPythonRun(const char *program_name, const char *archive_file,
 ////////////////////////////////////////////////////////////////////
 P3DPythonRun::
 ~P3DPythonRun() {
+  nassertv(_instances.empty());
+
   // Close the write pipe, so the parent process will terminate us.
   _pipe_write.close();
 
@@ -380,6 +386,35 @@ run_python() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::request_keyboard_focus
+//       Access: Public
+//  Description: Called from low-level Panda (via the P3DWindowHandle
+//               object) when its main window requires keyboard focus,
+//               but is unable to assign it directly.  This is
+//               particularly necessary under Windows Vista, where a
+//               child window of the browser is specifically
+//               disallowed from being given keyboard focus.
+//
+//               This sends a notify request up to the parent process,
+//               to ask the parent to manage keyboard events by proxy,
+//               and send them back down to Panda, again via the
+//               P3DWindowHandle.
+////////////////////////////////////////////////////////////////////
+void P3DPythonRun::
+request_keyboard_focus(P3DCInstance *inst) {
+  cerr << "requesting keyboard focus\n";
+
+  TiXmlDocument doc;
+  TiXmlElement *xrequest = new TiXmlElement("request");
+  xrequest->SetAttribute("instance_id", inst->get_instance_id());
+  xrequest->SetAttribute("rtype", "notify");
+  xrequest->SetAttribute("message", "keyboardfocus");
+  doc.LinkEndChild(xrequest);
+
+  write_xml(_pipe_write, &doc, nout);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPythonRun::run_interactive_console
 //       Access: Private
@@ -1299,6 +1334,15 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
 
   PyObject *py_handle = Py_None;
   if (parent_window_handle != NULL) {
+
+    // We have a valid parent WindowHandle, but replace it with a
+    // P3DWindowHandle so we can get the callbacks.
+    parent_window_handle = new P3DWindowHandle(this, inst, *parent_window_handle);
+    inst->_parent_window_handle = parent_window_handle;
+
+    // Also pass this P3DWindowHandle object down into Panda, via the
+    // setupWindow() call.  For this, we need to create a Python
+    // wrapper objcet.
     parent_window_handle->ref();
     py_handle = DTool_CreatePyInstanceTyped(parent_window_handle, Dtool_WindowHandle, true, false, parent_window_handle->get_type_index());
   }
@@ -1666,3 +1710,29 @@ rt_thread_run() {
     RELEASE_LOCK(_commands_lock);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::P3DWindowHandle::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+P3DPythonRun::P3DWindowHandle::
+P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst,
+                const WindowHandle &copy) :
+  WindowHandle(copy.get_os_handle()),
+  _p3dpython(p3dpython),
+  _inst(inst)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPythonRun::P3DWindowHandle::request_keyboard_focus
+//       Access: Public, Virtual
+//  Description: Called on a parent handle to indicate a child
+//               window's wish to receive keyboard button events.
+////////////////////////////////////////////////////////////////////
+void P3DPythonRun::P3DWindowHandle::
+request_keyboard_focus(WindowHandle *child) {
+  WindowHandle::request_keyboard_focus(child);
+  _p3dpython->request_keyboard_focus(_inst);
+}

+ 38 - 0
direct/src/plugin/p3dPythonRun.h

@@ -74,6 +74,8 @@ public:
 
   bool run_python();
 
+  void request_keyboard_focus(P3DCInstance *inst);
+
 private:
   void run_interactive_console();
   void handle_command(TiXmlDocument *doc);
@@ -105,6 +107,42 @@ private:
   TiXmlElement *pyobj_to_xml(PyObject *value);
   PyObject *xml_to_pyobj(TiXmlElement *xvalue);
 
+private:
+  // This subclass of P3DWindowHandle is associated with the parent
+  // window we are given by the parent process.  We use it to add
+  // hooks for communicating with the parent window, for instance to
+  // ask for the parent window to manage keyboard focus when
+  // necessary.
+  class P3DWindowHandle : public WindowHandle {
+  public:
+    P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst,
+                    const WindowHandle &copy);
+
+  private:
+    P3DPythonRun *_p3dpython;
+    P3DCInstance *_inst;
+
+  protected:
+    virtual void request_keyboard_focus(WindowHandle *child);
+
+  public:
+    static TypeHandle get_class_type() {
+      return _type_handle;
+    }
+    static void init_type() {
+      WindowHandle::init_type();
+      register_type(_type_handle, "P3DWindowHandle",
+                    WindowHandle::get_class_type());
+    }
+    virtual TypeHandle get_type() const {
+      return get_class_type();
+    }
+    virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+    
+  private:
+    static TypeHandle _type_handle;
+  };
+
 private:
   // This method runs only within the read thread.
   THREAD_CALLBACK_DECLARATION(P3DPythonRun, rt_thread_run);

+ 9 - 0
panda/src/display/graphicsWindow.cxx

@@ -749,6 +749,15 @@ void GraphicsWindow::
 close_window() {
   display_cat.info()
     << "Closing " << get_type() << "\n";
+
+  // Tell our parent window (if any) that we're no longer its child.
+  if (_window_handle != (WindowHandle *)NULL &&
+      _parent_window_handle != (WindowHandle *)NULL) {
+    _parent_window_handle->detach_child(_window_handle);
+  }
+
+  _window_handle = NULL;
+  _parent_window_handle = NULL;
   _is_valid = false;
 }
 

+ 1 - 0
panda/src/display/graphicsWindow.h

@@ -132,6 +132,7 @@ protected:
 protected:
   WindowProperties _properties;
   PT(WindowHandle) _window_handle;
+  PT(WindowHandle) _parent_window_handle;
 
 private:
   LightReMutex _properties_lock; 

+ 35 - 7
panda/src/display/windowHandle.cxx

@@ -26,6 +26,22 @@ WindowHandle::
 ~WindowHandle() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WindowHandle::send_keyboard_event
+//       Access: Published
+//  Description: Call this method on a parent WindowHandle to deliver
+//               a button event to the current child window, if any.
+//               This is used in the web plugin system to deliver
+//               button events detected directly by the browser system
+//               into Panda.
+////////////////////////////////////////////////////////////////////
+void WindowHandle::
+send_keyboard_event(const ButtonEvent &event) {
+  if (_keyboard_window != NULL) {
+    _keyboard_window->receive_keyboard_event(event);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowHandle::get_int_handle
 //       Access: Published
@@ -57,7 +73,7 @@ output(ostream &out) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowHandle::attach_child
-//       Access: Protected, Virtual
+//       Access: Public, Virtual
 //  Description: Called on a parent handle to indicate a child
 //               window's intention to attach itself.
 ////////////////////////////////////////////////////////////////////
@@ -67,25 +83,37 @@ attach_child(WindowHandle *child) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowHandle::detach_child
-//       Access: Protected, Virtual
+//       Access: Public, Virtual
 //  Description: Called on a parent handle to indicate a child
 //               window's intention to detach itself.
 ////////////////////////////////////////////////////////////////////
 void WindowHandle::
 detach_child(WindowHandle *child) {
+  if (_keyboard_window == child) {
+    _keyboard_window = NULL;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WindowHandle::set_keyboard_focus
-//       Access: Protected, Virtual
+//     Function: WindowHandle::request_keyboard_focus
+//       Access: Public, Virtual
 //  Description: Called on a parent handle to indicate a child
-//               window's intention to set itself as the recipient of
-//               keyboard events.
+//               window's wish to receive keyboard button events.
 ////////////////////////////////////////////////////////////////////
 void WindowHandle::
-set_keyboard_focus(WindowHandle *child) {
+request_keyboard_focus(WindowHandle *child) {
+  _keyboard_window = child;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WindowHandle::receive_keyboard_event
+//       Access: Public, Virtual
+//  Description: Called on a child handle to deliver a keyboard button
+//               event generated in the parent window.
+////////////////////////////////////////////////////////////////////
+void WindowHandle::
+receive_keyboard_event(const ButtonEvent &event) {
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowHandle::OSHandle::Destructor

+ 15 - 7
panda/src/display/windowHandle.h

@@ -20,6 +20,8 @@
 #include "typedReferenceCount.h"
 #include "pointerTo.h"
 
+class ButtonEvent;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : WindowHandle
 // Description : This object represents a window on the desktop, not
@@ -48,10 +50,21 @@ PUBLISHED:
   INLINE OSHandle *get_os_handle() const;
   INLINE void set_os_handle(OSHandle *os_handle);
 
+  void send_keyboard_event(const ButtonEvent &event);
+
   size_t get_int_handle() const;
 
   void output(ostream &out) const;
 
+public:
+  // Callbacks for communication with the parent window.
+  virtual void attach_child(WindowHandle *child);
+  virtual void detach_child(WindowHandle *child);
+
+  virtual void request_keyboard_focus(WindowHandle *child);
+  virtual void receive_keyboard_event(const ButtonEvent &event);
+
+PUBLISHED:
   // This internal pointer within WindowHandle stores the actual
   // OS-specific window handle type, whatever type that is.  It is
   // subclassed for each OS.
@@ -82,16 +95,11 @@ PUBLISHED:
     static TypeHandle _type_handle;
   };
 
-protected:
-  // Callbacks for communication with the parent window.
-  virtual void attach_child(WindowHandle *child);
-  virtual void detach_child(WindowHandle *child);
-
-  virtual void set_keyboard_focus(WindowHandle *child);
-
 protected:
   PT(OSHandle) _os_handle;
 
+  PT(WindowHandle) _keyboard_window;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 9 - 0
panda/src/egldisplay/eglGraphicsWindow.cxx

@@ -685,6 +685,7 @@ open_window() {
       }
     }
   }
+  _parent_window_handle = window_handle;
 
   setup_colormap(visual_info);
 
@@ -774,6 +775,14 @@ open_window() {
     }
   }
 
+  // Create a WindowHandle for ourselves
+  _window_handle = NativeWindowHandle::make_x11(_xwindow);
+
+  // And tell our parent window that we're now its child.
+  if (_parent_window_handle != (WindowHandle *)NULL) {
+    _parent_window_handle->attach_child(_window_handle);
+  }
+
   return true;
 }
 

+ 10 - 1
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -216,6 +216,7 @@ open_window() {
       }
     }
   }
+  _parent_window_handle = window_handle;
   
 #ifdef HAVE_GLXFBCONFIG
   if (glxgsg->_fbconfig != None) {
@@ -302,7 +303,15 @@ open_window() {
         << "Raw mice not requested.\n";
     }
   }
-  
+
+  // Create a WindowHandle for ourselves
+  _window_handle = NativeWindowHandle::make_x11(_xwindow);
+
+  // And tell our parent window that we're now its child.
+  if (_parent_window_handle != (WindowHandle *)NULL) {
+    _parent_window_handle->attach_child(_window_handle);
+  }
+
   return true;
 }
 

+ 9 - 0
panda/src/tinydisplay/tinyXGraphicsWindow.cxx

@@ -531,6 +531,7 @@ open_window() {
       }
     }
   }
+  _parent_window_handle = window_handle;
 
   setup_colormap(visual_info);
 
@@ -616,6 +617,14 @@ open_window() {
         << "Raw mice not requested.\n";
     }
   }
+
+  // Create a WindowHandle for ourselves
+  _window_handle = NativeWindowHandle::make_x11(_xwindow);
+
+  // And tell our parent window that we're now its child.
+  if (_parent_window_handle != (WindowHandle *)NULL) {
+    _parent_window_handle->attach_child(_window_handle);
+  }
   
   return true;
 }

+ 1 - 0
panda/src/x11display/x11GraphicsWindow.cxx

@@ -634,6 +634,7 @@ close_window() {
     // application, so the server hears the close request.
     XFlush(_display);
   }
+
   GraphicsWindow::close_window();
 }