Panda3D
subprocessWindow.cxx
1 // Filename: subprocessWindow.cxx
2 // Created by: drose (11Jul09)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "subprocessWindow.h"
16 
17 #ifdef SUPPORT_SUBPROCESS_WINDOW
18 
19 #include "graphicsEngine.h"
20 #include "config_display.h"
21 #include "nativeWindowHandle.h"
22 
23 TypeHandle SubprocessWindow::_type_handle;
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: SubprocessWindow::Constructor
27 // Access: Protected
28 // Description: Normally, the SubprocessWindow constructor is not
29 // called directly; these are created instead via the
30 // GraphicsEngine::make_window() function.
31 ////////////////////////////////////////////////////////////////////
32 SubprocessWindow::
33 SubprocessWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
34  const string &name,
35  const FrameBufferProperties &fb_prop,
36  const WindowProperties &win_prop,
37  int flags,
39  GraphicsOutput *host) :
40  GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
41 {
44  _input_devices.push_back(device);
45 
46  // This will be an offscreen buffer that we use to render the actual
47  // contents.
48  _buffer = NULL;
49 
50  // Create a texture to receive the contents of the framebuffer from
51  // the offscreen buffer.
52  _texture = new Texture(name);
53 
54  _fd = -1;
55  _mmap_size = 0;
56  _filename = string();
57  _swbuffer = NULL;
58  _last_event_flags = 0;
59 }
60 
61 ////////////////////////////////////////////////////////////////////
62 // Function: SubprocessWindow::Destructor
63 // Access: Published, Virtual
64 // Description:
65 ////////////////////////////////////////////////////////////////////
66 SubprocessWindow::
67 ~SubprocessWindow() {
68  nassertv(_buffer == NULL);
69  nassertv(_swbuffer == NULL);
70 }
71 
72 ////////////////////////////////////////////////////////////////////
73 // Function: SubprocessWindow::process_events
74 // Access: Public, Virtual
75 // Description: Do whatever processing is necessary to ensure that
76 // the window responds to user events. Also, honor any
77 // requests recently made via request_properties().
78 //
79 // This function is called only within the window
80 // thread.
81 ////////////////////////////////////////////////////////////////////
82 void SubprocessWindow::
83 process_events() {
85 
86  if (_swbuffer != NULL) {
88  while (_swbuffer->get_event(swb_event)) {
89  // Deal with this event.
90  if (swb_event._flags & SubprocessWindowBuffer::EF_mouse_position) {
91  _input_devices[0].set_pointer_in_window(swb_event._x, swb_event._y);
92  } else if ((swb_event._flags & SubprocessWindowBuffer::EF_has_mouse) == 0) {
93  _input_devices[0].set_pointer_out_of_window();
94  }
95 
96  unsigned int diff = swb_event._flags ^ _last_event_flags;
97  _last_event_flags = swb_event._flags;
98 
99  if (diff & SubprocessWindowBuffer::EF_shift_held) {
100  transition_button(swb_event._flags & SubprocessWindowBuffer::EF_shift_held, KeyboardButton::shift());
101  }
102  if (diff & SubprocessWindowBuffer::EF_control_held) {
103  transition_button(swb_event._flags & SubprocessWindowBuffer::EF_control_held, KeyboardButton::control());
104  }
105  if (diff & SubprocessWindowBuffer::EF_alt_held) {
106  transition_button(swb_event._flags & SubprocessWindowBuffer::EF_alt_held, KeyboardButton::alt());
107  }
108  if (diff & SubprocessWindowBuffer::EF_meta_held) {
109  transition_button(swb_event._flags & SubprocessWindowBuffer::EF_meta_held, KeyboardButton::meta());
110  }
111 
112  ButtonHandle button = ButtonHandle::none();
113  if (swb_event._source == SubprocessWindowBuffer::ES_mouse) {
114  button = MouseButton::button(swb_event._code);
115 
116  } else if (swb_event._source == SubprocessWindowBuffer::ES_keyboard) {
117  int keycode;
118  button = translate_key(keycode, swb_event._code, swb_event._flags);
119  if (keycode != 0 && swb_event._type != SubprocessWindowBuffer::ET_button_up) {
120  _input_devices[0].keystroke(keycode);
121  }
122  }
123 
124  if (swb_event._type == SubprocessWindowBuffer::ET_button_up) {
125  _input_devices[0].button_up(button);
126  } else if (swb_event._type == SubprocessWindowBuffer::ET_button_down) {
127  _input_devices[0].button_down(button);
128  }
129  }
130  }
131 }
132 
133 ////////////////////////////////////////////////////////////////////
134 // Function: SubprocessWindow::begin_frame
135 // Access: Public, Virtual
136 // Description: This function will be called within the draw thread
137 // before beginning rendering for a given frame. It
138 // should do whatever setup is required, and return true
139 // if the frame should be rendered, or false if it
140 // should be skipped.
141 ////////////////////////////////////////////////////////////////////
142 bool SubprocessWindow::
143 begin_frame(FrameMode mode, Thread *current_thread) {
144  if (_swbuffer == NULL || _buffer == NULL) {
145  return false;
146  }
147 
148  bool result = _buffer->begin_frame(mode, current_thread);
149  return result;
150 }
151 
152 ////////////////////////////////////////////////////////////////////
153 // Function: SubprocessWindow::end_frame
154 // Access: Public, Virtual
155 // Description: This function will be called within the draw thread
156 // after rendering is completed for a given frame. It
157 // should do whatever finalization is required.
158 ////////////////////////////////////////////////////////////////////
159 void SubprocessWindow::
160 end_frame(FrameMode mode, Thread *current_thread) {
161  _buffer->end_frame(mode, current_thread);
162 
163  if (mode == FM_render) {
164  _flip_ready = true;
165  }
166 }
167 
168 ////////////////////////////////////////////////////////////////////
169 // Function: SubprocessWindow::begin_flip
170 // Access: Public, Virtual
171 // Description: This function will be called within the draw thread
172 // after end_frame() has been called on all windows, to
173 // initiate the exchange of the front and back buffers.
174 //
175 // This should instruct the window to prepare for the
176 // flip at the next video sync, but it should not wait.
177 //
178 // We have the two separate functions, begin_flip() and
179 // end_flip(), to make it easier to flip all of the
180 // windows at the same time.
181 ////////////////////////////////////////////////////////////////////
182 void SubprocessWindow::
183 begin_flip() {
184  nassertv(_buffer != (GraphicsBuffer *)NULL);
185  if (_swbuffer == NULL) {
186  return;
187  }
188 
189  RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(RTP_color));
190  buffer = _gsg->get_render_buffer(_buffer->get_draw_buffer_type(),
191  _buffer->get_fb_properties());
192 
193  bool copied =
194  _gsg->framebuffer_copy_to_ram(_texture, 0, -1,
195  _overlay_display_region, buffer);
196 
197  if (copied) {
198  CPTA_uchar image = _texture->get_ram_image();
199  size_t framebuffer_size = _swbuffer->get_framebuffer_size();
200  nassertv(image.size() == framebuffer_size);
201 
202  if (!_swbuffer->ready_for_write()) {
203  // We have to wait for the other end to remove the last frame we
204  // rendered. We only wait so long before we give up, so we
205  // don't completely starve the Python process just because the
206  // render window is offscreen or something.
207 
209  double start = clock->get_real_time();
210  while (!_swbuffer->ready_for_write()) {
212  double now = clock->get_real_time();
213  if (now - start > subprocess_window_max_wait) {
214  // Never mind.
215  return;
216  }
217  }
218  }
219 
220  // We're ready to go. Copy the image to our shared framebuffer.
221  void *target = _swbuffer->open_write_framebuffer();
222  memcpy(target, image.p(), framebuffer_size);
223  _swbuffer->close_write_framebuffer();
224  }
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: SubprocessWindow::set_properties_now
229 // Access: Public, Virtual
230 // Description: Applies the requested set of properties to the
231 // window, if possible, for instance to request a change
232 // in size or minimization status.
233 //
234 // The window properties are applied immediately, rather
235 // than waiting until the next frame. This implies that
236 // this method may *only* be called from within the
237 // window thread.
238 //
239 // The properties that have been applied are cleared
240 // from the structure by this function; so on return,
241 // whatever remains in the properties structure are
242 // those that were unchanged for some reason (probably
243 // because the underlying interface does not support
244 // changing that property on an open window).
245 ////////////////////////////////////////////////////////////////////
246 void SubprocessWindow::
247 set_properties_now(WindowProperties &properties) {
248  Filename filename;
249  WindowHandle *window_handle = properties.get_parent_window();
250  if (window_handle != NULL) {
251  WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
252  if (os_handle != NULL) {
253  if (os_handle->is_of_type(NativeWindowHandle::SubprocessHandle::get_class_type())) {
254  NativeWindowHandle::SubprocessHandle *subprocess_handle = DCAST(NativeWindowHandle::SubprocessHandle, os_handle);
255  filename = subprocess_handle->get_filename();
256  }
257  }
258  }
259 
260  if (!filename.empty() && filename != _filename) {
261  // We're changing the subprocess buffer filename; that means we
262  // might as well completely close and re-open the window.
263  display_cat.info() << "Re-opening SubprocessWindow\n";
264  internal_close_window();
265 
266  _properties.add_properties(properties);
267  properties.clear();
268 
269  internal_open_window();
270  set_size_and_recalc(_properties.get_x_size(), _properties.get_y_size());
271  throw_event(get_window_event(), this);
272  return;
273  }
274 
276  if (!properties.is_any_specified()) {
277  // The base class has already handled this case.
278  return;
279  }
280 
281  if (properties.has_parent_window()) {
282  // Redundant parent-window specification.
283  properties.clear_parent_window();
284  }
285 }
286 
287 ////////////////////////////////////////////////////////////////////
288 // Function: SubprocessWindow::close_window
289 // Access: Protected, Virtual
290 // Description: Closes the window right now. Called from the window
291 // thread.
292 ////////////////////////////////////////////////////////////////////
293 void SubprocessWindow::
294 close_window() {
295  internal_close_window();
296 
297  WindowProperties properties;
298  properties.set_open(false);
299  properties.set_foreground(false);
300  system_changed_properties(properties);
301 }
302 
303 ////////////////////////////////////////////////////////////////////
304 // Function: SubprocessWindow::open_window
305 // Access: Protected, Virtual
306 // Description: Opens the window right now. Called from the window
307 // thread. Returns true if the window is successfully
308 // opened, or false if there was a problem.
309 ////////////////////////////////////////////////////////////////////
310 bool SubprocessWindow::
311 open_window() {
312  if (!internal_open_window()) {
313  return false;
314  }
315 
316  WindowProperties properties;
317  properties.set_open(true);
318  properties.set_foreground(true);
319  system_changed_properties(properties);
320 
321  return true;
322 }
323 
324 ////////////////////////////////////////////////////////////////////
325 // Function: SubprocessWindow::internal_close_window
326 // Access: Private
327 // Description: Closes the "window" and resets the buffer, without
328 // changing the WindowProperties.
329 ////////////////////////////////////////////////////////////////////
330 void SubprocessWindow::
331 internal_close_window() {
332  if (_swbuffer != NULL) {
334  (_fd, _mmap_size, _filename.to_os_specific(), _swbuffer);
335  _fd = -1;
336  _filename = string();
337 
338  _swbuffer = NULL;
339  }
340 
341  if (_buffer != NULL) {
342  _buffer->request_close();
343  _buffer->process_events();
344  _engine->remove_window(_buffer);
345  _buffer = NULL;
346  }
347 
348  // Tell our parent window (if any) that we're no longer its child.
349  if (_window_handle != (WindowHandle *)NULL &&
350  _parent_window_handle != (WindowHandle *)NULL) {
351  _parent_window_handle->detach_child(_window_handle);
352  }
353 
354  _window_handle = NULL;
355  _parent_window_handle = NULL;
356  _is_valid = false;
357 }
358 
359 ////////////////////////////////////////////////////////////////////
360 // Function: SubprocessWindow::internal_open_window
361 // Access: Private
362 // Description: Opens the "window" and the associated offscreen
363 // buffer, without changing the WindowProperties.
364 ////////////////////////////////////////////////////////////////////
365 bool SubprocessWindow::
366 internal_open_window() {
367  nassertr(_buffer == NULL, false);
368 
369  // Create a buffer with the same properties as the window.
370  int flags = _creation_flags;
371  flags = ((flags & ~GraphicsPipe::BF_require_window) | GraphicsPipe::BF_refuse_window);
372  WindowProperties win_props = WindowProperties::size(_properties.get_x_size(), _properties.get_y_size());
373 
374  GraphicsOutput *buffer =
375  _engine->make_output(_pipe, _name, 0, _fb_properties, win_props,
376  flags, _gsg, _host);
377  if (buffer != NULL) {
378  _buffer = DCAST(GraphicsBuffer, buffer);
379  // However, the buffer is not itself intended to be rendered. We
380  // only render it indirectly, via callbacks in here.
381  _buffer->set_active(false);
382 
383  _buffer->request_open();
384  _buffer->process_events();
385 
386  _is_valid = _buffer->is_valid();
387  }
388 
389  if (!_is_valid) {
390  display_cat.error()
391  << "Failed to open SubprocessWindowBuffer's internal offscreen buffer.\n";
392  return false;
393  }
394 
395  _gsg = _buffer->get_gsg();
396 
397  WindowHandle *window_handle = _properties.get_parent_window();
398  if (window_handle != NULL) {
399  WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
400  if (os_handle != NULL) {
401  if (os_handle->is_of_type(NativeWindowHandle::SubprocessHandle::get_class_type())) {
402  NativeWindowHandle::SubprocessHandle *subprocess_handle = DCAST(NativeWindowHandle::SubprocessHandle, os_handle);
403  _filename = subprocess_handle->get_filename();
404  }
405  }
406  }
407  _parent_window_handle = window_handle;
408 
409  if (_filename.empty()) {
410  _is_valid = false;
411  display_cat.error()
412  << "No filename given to SubprocessWindow.\n";
413  return false;
414  }
415 
417  (_fd, _mmap_size, _filename.to_os_specific());
418 
419  if (_swbuffer == NULL) {
420  close(_fd);
421  _fd = -1;
422  _filename = string();
423  _is_valid = false;
424  display_cat.error()
425  << "Failed to open SubprocessWindowBuffer's shared-memory buffer "
426  << _filename << "\n";
427  return false;
428  }
429 
430  if (display_cat.is_debug()) {
431  display_cat.debug()
432  << "SubprocessWindow reading " << _filename << "\n";
433  }
434 
435  // Create a WindowHandle for ourselves
436  _window_handle = NativeWindowHandle::make_subprocess(_filename);
437 
438  // And tell our parent window that we're now its child.
439  if (_parent_window_handle != (WindowHandle *)NULL) {
440  _parent_window_handle->attach_child(_window_handle);
441  }
442 
443  return true;
444 }
445 
446 ////////////////////////////////////////////////////////////////////
447 // Function: SubprocessWindow::translate_key
448 // Access: Private
449 // Description: Converts the os-specific keycode into the appropriate
450 // ButtonHandle object. Also stores the corresponding
451 // Unicode keycode in keycode, if any; or 0 otherwise.
452 ////////////////////////////////////////////////////////////////////
453 ButtonHandle SubprocessWindow::
454 translate_key(int &keycode, int os_code, unsigned int flags) const {
455  keycode = 0;
457 
458 #ifdef __APPLE__
459  switch ((os_code >> 8) & 0xff) {
460  case 0: nk = KeyboardButton::ascii_key('a'); break;
461  case 11: nk = KeyboardButton::ascii_key('b'); break;
462  case 8: nk = KeyboardButton::ascii_key('c'); break;
463  case 2: nk = KeyboardButton::ascii_key('d'); break;
464  case 14: nk = KeyboardButton::ascii_key('e'); break;
465  case 3: nk = KeyboardButton::ascii_key('f'); break;
466  case 5: nk = KeyboardButton::ascii_key('g'); break;
467  case 4: nk = KeyboardButton::ascii_key('h'); break;
468  case 34: nk = KeyboardButton::ascii_key('i'); break;
469  case 38: nk = KeyboardButton::ascii_key('j'); break;
470  case 40: nk = KeyboardButton::ascii_key('k'); break;
471  case 37: nk = KeyboardButton::ascii_key('l'); break;
472  case 46: nk = KeyboardButton::ascii_key('m'); break;
473  case 45: nk = KeyboardButton::ascii_key('n'); break;
474  case 31: nk = KeyboardButton::ascii_key('o'); break;
475  case 35: nk = KeyboardButton::ascii_key('p'); break;
476  case 12: nk = KeyboardButton::ascii_key('q'); break;
477  case 15: nk = KeyboardButton::ascii_key('r'); break;
478  case 1: nk = KeyboardButton::ascii_key('s'); break;
479  case 17: nk = KeyboardButton::ascii_key('t'); break;
480  case 32: nk = KeyboardButton::ascii_key('u'); break;
481  case 9: nk = KeyboardButton::ascii_key('v'); break;
482  case 13: nk = KeyboardButton::ascii_key('w'); break;
483  case 7: nk = KeyboardButton::ascii_key('x'); break;
484  case 16: nk = KeyboardButton::ascii_key('y'); break;
485  case 6: nk = KeyboardButton::ascii_key('z'); break;
486 
487  // top row numbers
488  case 29: nk = KeyboardButton::ascii_key('0'); break;
489  case 18: nk = KeyboardButton::ascii_key('1'); break;
490  case 19: nk = KeyboardButton::ascii_key('2'); break;
491  case 20: nk = KeyboardButton::ascii_key('3'); break;
492  case 21: nk = KeyboardButton::ascii_key('4'); break;
493  case 23: nk = KeyboardButton::ascii_key('5'); break;
494  case 22: nk = KeyboardButton::ascii_key('6'); break;
495  case 26: nk = KeyboardButton::ascii_key('7'); break;
496  case 28: nk = KeyboardButton::ascii_key('8'); break;
497  case 25: nk = KeyboardButton::ascii_key('9'); break;
498 
499  // key pad ... do they really map to the top number in panda ?
500  case 82: nk = KeyboardButton::ascii_key('0'); break;
501  case 83: nk = KeyboardButton::ascii_key('1'); break;
502  case 84: nk = KeyboardButton::ascii_key('2'); break;
503  case 85: nk = KeyboardButton::ascii_key('3'); break;
504  case 86: nk = KeyboardButton::ascii_key('4'); break;
505  case 87: nk = KeyboardButton::ascii_key('5'); break;
506  case 88: nk = KeyboardButton::ascii_key('6'); break;
507  case 89: nk = KeyboardButton::ascii_key('7'); break;
508  case 91: nk = KeyboardButton::ascii_key('8'); break;
509  case 92: nk = KeyboardButton::ascii_key('9'); break;
510 
511  // case 36: nk = KeyboardButton::ret(); break; // no return in panda ???
512  case 49: nk = KeyboardButton::space(); break;
513  case 51: nk = KeyboardButton::backspace(); break;
514  case 48: nk = KeyboardButton::tab(); break;
515  case 53: nk = KeyboardButton::escape(); break;
516  case 76: nk = KeyboardButton::enter(); break;
517  case 36: nk = KeyboardButton::enter(); break;
518 
519  case 123: nk = KeyboardButton::left(); break;
520  case 124: nk = KeyboardButton::right(); break;
521  case 125: nk = KeyboardButton::down(); break;
522  case 126: nk = KeyboardButton::up(); break;
523  case 116: nk = KeyboardButton::page_up(); break;
524  case 121: nk = KeyboardButton::page_down(); break;
525  case 115: nk = KeyboardButton::home(); break;
526  case 119: nk = KeyboardButton::end(); break;
527  case 114: nk = KeyboardButton::help(); break;
528  case 117: nk = KeyboardButton::del(); break;
529 
530  // case 71: nk = KeyboardButton::num_lock() break;
531 
532  case 122: nk = KeyboardButton::f1(); break;
533  case 120: nk = KeyboardButton::f2(); break;
534  case 99: nk = KeyboardButton::f3(); break;
535  case 118: nk = KeyboardButton::f4(); break;
536  case 96: nk = KeyboardButton::f5(); break;
537  case 97: nk = KeyboardButton::f6(); break;
538  case 98: nk = KeyboardButton::f7(); break;
539  case 100: nk = KeyboardButton::f8(); break;
540  case 101: nk = KeyboardButton::f9(); break;
541  case 109: nk = KeyboardButton::f10(); break;
542  case 103: nk = KeyboardButton::f11(); break;
543  case 111: nk = KeyboardButton::f12(); break;
544 
545  case 105: nk = KeyboardButton::f13(); break;
546  case 107: nk = KeyboardButton::f14(); break;
547  case 113: nk = KeyboardButton::f15(); break;
548  case 106: nk = KeyboardButton::f16(); break;
549 
550  // shiftable chartablet
551  case 50: nk = KeyboardButton::ascii_key('`'); break;
552  case 27: nk = KeyboardButton::ascii_key('-'); break;
553  case 24: nk = KeyboardButton::ascii_key('='); break;
554  case 33: nk = KeyboardButton::ascii_key('['); break;
555  case 30: nk = KeyboardButton::ascii_key(']'); break;
556  case 42: nk = KeyboardButton::ascii_key('\\'); break;
557  case 41: nk = KeyboardButton::ascii_key(';'); break;
558  case 39: nk = KeyboardButton::ascii_key('\''); break;
559  case 43: nk = KeyboardButton::ascii_key(','); break;
560  case 47: nk = KeyboardButton::ascii_key('.'); break;
561  case 44: nk = KeyboardButton::ascii_key('/'); break;
562 
563  default:
564  // Punt.
565  nk = KeyboardButton::ascii_key(os_code & 0xff);
566  }
567 
568  if (nk.has_ascii_equivalent()) {
569  // If we assigned an ASCII button, then get the original ASCII
570  // code from the event (it will include shift et al).
571 
572  // TODO: is it possible to get any international characters via
573  // this old EventRecord interface?
574  keycode = os_code & 0xff;
575  }
576 
577 #endif // __APPLE__
578 
579  return nk;
580 }
581 
582 ////////////////////////////////////////////////////////////////////
583 // Function: SubprocessWindow::transition_button
584 // Access: Private
585 // Description: Sends the appropriate up/down transition for the
586 // indicated modifier key, as determined implicitly from
587 // the flags.
588 ////////////////////////////////////////////////////////////////////
589 void SubprocessWindow::
590 transition_button(unsigned int flags, ButtonHandle button) {
591  if (flags) {
592  _input_devices[0].button_down(button);
593  } else {
594  _input_devices[0].button_up(button);
595  }
596 }
597 
598 
599 #endif // SUPPORT_SUBPROCESS_WINDOW
static GraphicsWindowInputDevice pointer_and_keyboard(GraphicsWindow *host, const string &name)
This named constructor returns an input device that has both a keyboard and pointer.
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
static int get_renderbuffer_type(int plane)
Returns the RenderBuffer::Type that corresponds to a RenderTexturePlane.
static ButtonHandle none()
Returns a special zero-valued ButtonHandle that is used to indicate no button.
Definition: buttonHandle.I:205
void clear()
Unsets all properties that have been specified so far, and resets the WindowProperties structure to i...
This object represents a window on the desktop, not necessarily a Panda window.
Definition: windowHandle.h:40
static WindowProperties size(int x_size, int y_size)
Returns a WindowProperties structure with only the size specified.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
bool has_parent_window() const
Checks the S_parent_window specification from the properties.
virtual void detach_child(WindowHandle *child)
Called on a parent handle to indicate a child window&#39;s intention to detach itself.
void clear_parent_window()
Removes the S_parent_window specification from the properties.
static void force_yield()
Suspends the current thread for the rest of the current epoch.
Definition: thread.I:248
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:28
static void close_buffer(int fd, size_t mmap_size, const string &filename, SubprocessWindowBuffer *buffer)
Closes a buffer object created via a previous call to open_buffer().
A container for the various kinds of properties we might ask to have on a graphics window before we o...
bool has_ascii_equivalent() const
Returns true if the button was created with an ASCII equivalent code (e.g.
Definition: buttonHandle.I:140
An offscreen buffer for rendering into.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
OSHandle * get_os_handle() const
Returns the OS-specific handle stored internally to the WindowHandle wrapper.
Definition: windowHandle.I:41
static ButtonHandle button(int button_number)
Returns the ButtonHandle associated with the particular numbered mouse button (zero-based), if there is one, or ButtonHandle::none() if there is not.
Definition: mouseButton.cxx:36
const Element * p() const
Function p() is similar to the function from ConstPointerTo.
A ClockObject keeps track of elapsed real time and discrete time.
Definition: clockObject.h:66
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
double get_real_time() const
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
Definition: clockObject.I:68
This is a structure representing a single input device that may be associated with a window...
This is a base class for the various different classes that represent the result of a frame of render...
void set_foreground(bool foreground)
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
A thread; that is, a lightweight process.
Definition: thread.h:51
Encapsulates all the communication with a particular instance of a given rendering backend...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
This class is the main interface to controlling the render process.
WindowHandle * get_parent_window() const
Returns the parent window specification, or NULL if there is no parent window specified.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
static ButtonHandle ascii_key(char ascii_equivalent)
Returns the ButtonHandle associated with the particular ASCII character, if there is one...
void set_open(bool open)
Specifies whether the window should be open.
static SubprocessWindowBuffer * open_buffer(int &fd, size_t &mmap_size, const string &filename)
Call this method to open a reference to an existing buffer in shared memory space.
A RenderBuffer is an arbitrary subset of the various layers (depth buffer, color buffer, etc.) of a drawing region.
Definition: renderBuffer.h:30