00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pandabase.h"
00016
00017 #ifdef HAVE_X11
00018
00019 #include "tinyXGraphicsWindow.h"
00020 #include "tinyGraphicsStateGuardian.h"
00021 #include "tinyXGraphicsPipe.h"
00022 #include "config_tinydisplay.h"
00023
00024 #include "graphicsPipe.h"
00025 #include "keyboardButton.h"
00026 #include "mouseButton.h"
00027 #include "clockObject.h"
00028 #include "pStatTimer.h"
00029 #include "textEncoder.h"
00030 #include "throw_event.h"
00031 #include "lightReMutexHolder.h"
00032 #include "nativeWindowHandle.h"
00033
00034 TypeHandle TinyXGraphicsWindow::_type_handle;
00035
00036
00037
00038
00039
00040
00041 TinyXGraphicsWindow::
00042 TinyXGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
00043 const string &name,
00044 const FrameBufferProperties &fb_prop,
00045 const WindowProperties &win_prop,
00046 int flags,
00047 GraphicsStateGuardian *gsg,
00048 GraphicsOutput *host) :
00049 x11GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00050 {
00051 _gc = (GC)NULL;
00052
00053 _reduced_frame_buffer = NULL;
00054 _full_frame_buffer = NULL;
00055 _ximage = NULL;
00056 update_pixel_factor();
00057 }
00058
00059
00060
00061
00062
00063
00064 TinyXGraphicsWindow::
00065 ~TinyXGraphicsWindow() {
00066 if (_gc != NULL && _display != NULL) {
00067 XFreeGC(_display, _gc);
00068 }
00069 if (_ximage != NULL) {
00070 PANDA_FREE_ARRAY(_ximage->data);
00071 _ximage->data = NULL;
00072 XDestroyImage(_ximage);
00073 }
00074 }
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 bool TinyXGraphicsWindow::
00086 begin_frame(FrameMode mode, Thread *current_thread) {
00087 PStatTimer timer(_make_current_pcollector, current_thread);
00088
00089 if (_xwindow == (X11_Window)NULL) {
00090 return false;
00091 }
00092
00093 begin_frame_spam(mode);
00094 if (_gsg == (GraphicsStateGuardian *)NULL) {
00095 return false;
00096 }
00097 if (_awaiting_configure) {
00098
00099
00100 return false;
00101 }
00102
00103 TinyGraphicsStateGuardian *tinygsg;
00104 DCAST_INTO_R(tinygsg, _gsg, false);
00105
00106 if (_reduced_frame_buffer != (ZBuffer *)NULL) {
00107 tinygsg->_current_frame_buffer = _reduced_frame_buffer;
00108 } else {
00109 tinygsg->_current_frame_buffer = _full_frame_buffer;
00110 }
00111 tinygsg->reset_if_new();
00112
00113 _gsg->set_current_properties(&get_fb_properties());
00114 return _gsg->begin_frame(current_thread);
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124 void TinyXGraphicsWindow::
00125 end_frame(FrameMode mode, Thread *current_thread) {
00126 end_frame_spam(mode);
00127 nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00128
00129 if (mode == FM_render) {
00130
00131 copy_to_textures();
00132 }
00133
00134 _gsg->end_frame(current_thread);
00135
00136 if (mode == FM_render) {
00137 trigger_flip();
00138 clear_cube_map_selection();
00139 }
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 void TinyXGraphicsWindow::
00153 end_flip() {
00154 if (_xwindow == (X11_Window)NULL || !_flip_ready) {
00155 GraphicsWindow::end_flip();
00156 return;
00157 }
00158
00159 if (_reduced_frame_buffer != (ZBuffer *)NULL) {
00160
00161 ZB_zoomFrameBuffer(_full_frame_buffer, 0, 0,
00162 _full_frame_buffer->xsize, _full_frame_buffer->ysize,
00163 _reduced_frame_buffer, 0, 0,
00164 _reduced_frame_buffer->xsize, _reduced_frame_buffer->ysize);
00165 }
00166
00167
00168
00169
00170
00171
00172 ZB_copyFrameBufferNoAlpha(_full_frame_buffer, _ximage->data, _pitch);
00173
00174 XPutImage(_display, _xwindow, _gc, _ximage, 0, 0, 0, 0,
00175 _full_frame_buffer->xsize, _full_frame_buffer->ysize);
00176 XFlush(_display);
00177 GraphicsWindow::end_flip();
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 bool TinyXGraphicsWindow::
00195 supports_pixel_zoom() const {
00196 return true;
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 void TinyXGraphicsWindow::
00210 process_events() {
00211 LightReMutexHolder holder(TinyXGraphicsPipe::_x_mutex);
00212
00213 GraphicsWindow::process_events();
00214
00215 if (_xwindow == (X11_Window)0) {
00216 return;
00217 }
00218
00219 poll_raw_mice();
00220
00221 XEvent event;
00222 XKeyEvent keyrelease_event;
00223 bool got_keyrelease_event = false;
00224
00225 while (XCheckIfEvent(_display, &event, check_event, (char *)this)) {
00226 if (XFilterEvent(&event, None)) {
00227 continue;
00228 }
00229
00230 if (got_keyrelease_event) {
00231
00232
00233
00234
00235
00236 got_keyrelease_event = false;
00237
00238 if (event.type == KeyPress &&
00239 event.xkey.keycode == keyrelease_event.keycode &&
00240 (event.xkey.time - keyrelease_event.time <= 1)) {
00241
00242
00243 handle_keystroke(event.xkey);
00244
00245
00246
00247 handle_keypress(event.xkey);
00248 continue;
00249
00250 } else {
00251
00252
00253 handle_keyrelease(keyrelease_event);
00254 }
00255 }
00256
00257 WindowProperties properties;
00258 ButtonHandle button;
00259
00260 switch (event.type) {
00261 case ReparentNotify:
00262 break;
00263
00264 case ConfigureNotify:
00265 _awaiting_configure = false;
00266 if (_properties.get_fixed_size()) {
00267
00268
00269
00270
00271
00272
00273 WindowProperties current_props = get_properties();
00274 if (event.xconfigure.width != current_props.get_x_size() ||
00275 event.xconfigure.height != current_props.get_y_size()) {
00276 XWindowChanges changes;
00277 changes.width = current_props.get_x_size();
00278 changes.height = current_props.get_y_size();
00279 int value_mask = (CWWidth | CWHeight);
00280 XConfigureWindow(_display, _xwindow, value_mask, &changes);
00281 }
00282
00283 } else {
00284
00285 properties.set_size(event.xconfigure.width, event.xconfigure.height);
00286 system_changed_properties(properties);
00287 ZB_resize(_full_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size());
00288 _pitch = (_full_frame_buffer->xsize * _bytes_per_pixel + 3) & ~3;
00289 create_reduced_frame_buffer();
00290 create_ximage();
00291 }
00292 break;
00293
00294 case ButtonPress:
00295
00296 button = get_mouse_button(event.xbutton);
00297 _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
00298 _input_devices[0].button_down(button);
00299 break;
00300
00301 case ButtonRelease:
00302 button = get_mouse_button(event.xbutton);
00303 _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
00304 _input_devices[0].button_up(button);
00305 break;
00306
00307 case MotionNotify:
00308 _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y);
00309 break;
00310
00311 case KeyPress:
00312 handle_keystroke(event.xkey);
00313 handle_keypress(event.xkey);
00314 break;
00315
00316 case KeyRelease:
00317
00318
00319
00320 keyrelease_event = event.xkey;
00321 got_keyrelease_event = true;
00322 break;
00323
00324 case EnterNotify:
00325 _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
00326 break;
00327
00328 case LeaveNotify:
00329 _input_devices[0].set_pointer_out_of_window();
00330 break;
00331
00332 case FocusIn:
00333 properties.set_foreground(true);
00334 system_changed_properties(properties);
00335 break;
00336
00337 case FocusOut:
00338 _input_devices[0].focus_lost();
00339 properties.set_foreground(false);
00340 system_changed_properties(properties);
00341 break;
00342
00343 case UnmapNotify:
00344 properties.set_minimized(true);
00345 system_changed_properties(properties);
00346 break;
00347
00348 case MapNotify:
00349 properties.set_minimized(false);
00350 system_changed_properties(properties);
00351
00352
00353 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
00354 break;
00355
00356 case ClientMessage:
00357 if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
00358
00359
00360 string close_request_event = get_close_request_event();
00361 if (!close_request_event.empty()) {
00362
00363
00364 throw_event(close_request_event);
00365
00366 } else {
00367
00368
00369
00370
00371 close_window();
00372 properties.set_open(false);
00373 system_changed_properties(properties);
00374 }
00375 }
00376 break;
00377
00378 case DestroyNotify:
00379
00380
00381
00382 tinydisplay_cat.info()
00383 << "DestroyNotify\n";
00384 break;
00385
00386 default:
00387 tinydisplay_cat.error()
00388 << "unhandled X event type " << event.type << "\n";
00389 }
00390 }
00391
00392 if (got_keyrelease_event) {
00393
00394
00395 handle_keyrelease(keyrelease_event);
00396 }
00397 }
00398
00399
00400
00401
00402
00403
00404
00405 void TinyXGraphicsWindow::
00406 close_window() {
00407 if (_gsg != (GraphicsStateGuardian *)NULL) {
00408 TinyGraphicsStateGuardian *tinygsg;
00409 DCAST_INTO_V(tinygsg, _gsg);
00410 tinygsg->_current_frame_buffer = NULL;
00411 _gsg.clear();
00412 }
00413
00414 x11GraphicsWindow::close_window();
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424 bool TinyXGraphicsWindow::
00425 open_window() {
00426 TinyXGraphicsPipe *tinyx_pipe;
00427 DCAST_INTO_R(tinyx_pipe, _pipe, false);
00428
00429
00430 TinyGraphicsStateGuardian *tinygsg;
00431 if (_gsg == 0) {
00432
00433 tinygsg = new TinyGraphicsStateGuardian(_engine, _pipe, NULL);
00434 _gsg = tinygsg;
00435 } else {
00436 DCAST_INTO_R(tinygsg, _gsg, false);
00437 }
00438
00439 XVisualInfo vinfo_template;
00440 vinfo_template.screen = _screen;
00441 vinfo_template.depth = 32;
00442 vinfo_template.c_class = TrueColor;
00443
00444
00445 int try_masks[] = {
00446 VisualScreenMask | VisualDepthMask | VisualClassMask,
00447 VisualScreenMask | VisualClassMask,
00448 VisualScreenMask | VisualDepthMask,
00449 VisualScreenMask,
00450 0,
00451 };
00452
00453 int i = 0;
00454 int num_vinfos = 0;
00455 XVisualInfo *vinfo_array;
00456 while (try_masks[i] != 0 && num_vinfos == 0) {
00457 vinfo_array =
00458 XGetVisualInfo(_display, try_masks[i], &vinfo_template, &num_vinfos);
00459 ++i;
00460 }
00461
00462 if (num_vinfos == 0) {
00463
00464 tinydisplay_cat.error()
00465 << "No suitable X Visual available; cannot open window.\n";
00466 return false;
00467 }
00468 _visual_info = &vinfo_array[0];
00469
00470 _visual = _visual_info->visual;
00471 _depth = _visual_info->depth;
00472 _bytes_per_pixel = _depth / 8;
00473 if (_bytes_per_pixel == 3) {
00474
00475 _bytes_per_pixel = 4;
00476 }
00477 tinydisplay_cat.info()
00478 << "Got X Visual with depth " << _depth << " (bpp " << _bytes_per_pixel << ") and class ";
00479 switch (_visual_info->c_class) {
00480 case TrueColor:
00481 tinydisplay_cat.info(false) << "TrueColor\n";
00482 break;
00483
00484 case DirectColor:
00485 tinydisplay_cat.info(false) << "DirectColor\n";
00486 break;
00487
00488 case StaticColor:
00489 tinydisplay_cat.info(false) << "StaticColor\n";
00490 break;
00491
00492 case StaticGray:
00493 tinydisplay_cat.info(false) << "StaticGray\n";
00494 break;
00495
00496 case GrayScale:
00497 tinydisplay_cat.info(false) << "GrayScale\n";
00498 break;
00499
00500 case PseudoColor:
00501 tinydisplay_cat.info(false) << "PseudoColor\n";
00502 break;
00503 }
00504
00505 setup_colormap(_visual_info);
00506
00507 if (!x11GraphicsWindow::open_window()) {
00508 return false;
00509 }
00510
00511 _gc = XCreateGC(_display, _xwindow, 0, NULL);
00512
00513 create_full_frame_buffer();
00514 if (_full_frame_buffer == NULL) {
00515 tinydisplay_cat.error()
00516 << "Could not create frame buffer.\n";
00517 return false;
00518 }
00519 create_reduced_frame_buffer();
00520 create_ximage();
00521 nassertr(_ximage != NULL, false);
00522
00523 tinygsg->_current_frame_buffer = _full_frame_buffer;
00524
00525 tinygsg->reset_if_new();
00526 if (!tinygsg->is_valid()) {
00527 close_window();
00528 return false;
00529 }
00530
00531 XMapWindow(_display, _xwindow);
00532
00533 if (_properties.get_raw_mice()) {
00534 open_raw_mice();
00535 } else {
00536 if (tinydisplay_cat.is_debug()) {
00537 tinydisplay_cat.debug()
00538 << "Raw mice not requested.\n";
00539 }
00540 }
00541
00542
00543 _window_handle = NativeWindowHandle::make_x11(_xwindow);
00544
00545
00546 if (_parent_window_handle != (WindowHandle *)NULL) {
00547 _parent_window_handle->attach_child(_window_handle);
00548 }
00549
00550 return true;
00551 }
00552
00553
00554
00555
00556
00557
00558 void TinyXGraphicsWindow::
00559 pixel_factor_changed() {
00560 x11GraphicsWindow::pixel_factor_changed();
00561 create_reduced_frame_buffer();
00562 }
00563
00564
00565
00566
00567
00568
00569
00570 void TinyXGraphicsWindow::
00571 create_full_frame_buffer() {
00572 if (_full_frame_buffer != NULL) {
00573 ZB_close(_full_frame_buffer);
00574 _full_frame_buffer = NULL;
00575 }
00576
00577 int mode;
00578 switch (_bytes_per_pixel) {
00579 case 1:
00580 tinydisplay_cat.error()
00581 << "Palette images are currently not supported.\n";
00582 return;
00583
00584 case 2:
00585 mode = ZB_MODE_5R6G5B;
00586 break;
00587 case 4:
00588 mode = ZB_MODE_RGBA;
00589 break;
00590
00591 default:
00592 return;
00593 }
00594
00595 _full_frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), mode, 0, 0, 0, 0);
00596 _pitch = (_full_frame_buffer->xsize * _bytes_per_pixel + 3) & ~3;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605 void TinyXGraphicsWindow::
00606 create_reduced_frame_buffer() {
00607 if (_reduced_frame_buffer != NULL) {
00608 ZB_close(_reduced_frame_buffer);
00609 _reduced_frame_buffer = NULL;
00610 }
00611
00612 int x_size = get_fb_x_size();
00613 int y_size = get_fb_y_size();
00614
00615 if (x_size == _full_frame_buffer->xsize) {
00616
00617
00618 } else {
00619
00620
00621 _reduced_frame_buffer = ZB_open(x_size, y_size, _full_frame_buffer->mode, 0, 0, 0, 0);
00622 }
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632 void TinyXGraphicsWindow::
00633 create_ximage() {
00634 if (_ximage != NULL) {
00635 PANDA_FREE_ARRAY(_ximage->data);
00636 _ximage->data = NULL;
00637 XDestroyImage(_ximage);
00638 _ximage = NULL;
00639 }
00640
00641 int image_size = _full_frame_buffer->ysize * _pitch;
00642 char *data = (char *)PANDA_MALLOC_ARRAY(image_size);
00643
00644 _ximage = XCreateImage(_display, _visual, _depth, ZPixmap, 0, data,
00645 _full_frame_buffer->xsize, _full_frame_buffer->ysize,
00646 32, 0);
00647 }
00648
00649 #endif // HAVE_X11
00650