request_keyboard_focus

This commit is contained in:
David Rose 2009-10-02 00:04:53 +00:00
parent f89a811cf6
commit 5e12be142a
13 changed files with 220 additions and 16 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

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