38 using std::ostringstream;
43 int (*read)(XcursorFile *,
unsigned char *, int);
44 int (*write)(XcursorFile *,
unsigned char *, int);
45 int (*seek)(XcursorFile *, long, int);
48 typedef struct _XcursorImage {
59 static int xcursor_read(XcursorFile *file,
unsigned char *buf,
int len) {
60 istream* str = (istream*) file->closure;
61 str->read((
char*) buf, len);
65 static int xcursor_write(XcursorFile *file,
unsigned char *buf,
int len) {
67 nassertr_always(
false, 0);
71 static int xcursor_seek(XcursorFile *file,
long offset,
int whence) {
72 istream* str = (istream*) file->closure;
75 str->seekg(offset, istream::beg);
78 str->seekg(offset, istream::cur);
81 str->seekg(offset, istream::end);
100 GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
103 DCAST_INTO_V(x11_pipe, _pipe);
106 _xwindow = (X11_Window)
nullptr;
108 _visual_info =
nullptr;
111 if (x11_pipe->_have_xrandr) {
114 _XRRGetScreenInfo = x11_pipe->_XRRGetScreenInfo;
115 _XRRSetScreenConfig = x11_pipe->_XRRSetScreenConfig;
118 _awaiting_configure =
false;
119 _dga_mouse_enabled =
false;
120 _override_redirect = False;
121 _wm_delete_window = x11_pipe->_wm_delete_window;
124 add_input_device(device);
132 ~x11GraphicsWindow() {
133 if (!_cursor_filenames.empty()) {
135 for (
auto item : _cursor_filenames) {
136 XFreeCursor(_display, item.second);
151 nassertr(device >= 0 && device < (
int)_input_devices.size(),
MouseData());
157 if (device == 0 && !_dga_mouse_enabled && result._in_window &&
158 x11GraphicsPipe::_x_mutex.
try_lock()) {
160 if (_xwindow != None &&
161 XQueryPointer(_display, _xwindow, &event.xbutton.root,
162 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
163 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state)) {
165 result._xpos =
event.xbutton.x;
166 result._ypos =
event.xbutton.y;
169 x11GraphicsPipe::_x_mutex.
release();
196 if (!md.
get_in_window() || md.get_x() != x || md.get_y() != y) {
197 if (!_dga_mouse_enabled) {
199 XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
235 PStatTimer timer(_make_current_pcollector, current_thread);
237 begin_frame_spam(mode);
238 if (_gsg ==
nullptr) {
241 if (_awaiting_configure) {
250 _gsg->reset_if_new();
252 if (mode == FM_render) {
254 clear_cube_map_selection();
258 return _gsg->begin_frame(current_thread);
268 end_frame_spam(mode);
269 nassertv(_gsg !=
nullptr);
271 if (mode == FM_render) {
276 _gsg->end_frame(current_thread);
278 if (mode == FM_render) {
280 clear_cube_map_selection();
297 if (_xwindow == (X11_Window)0) {
302 XKeyEvent keyrelease_event;
303 bool got_keyrelease_event =
false;
305 XConfigureEvent configure_event;
306 bool got_configure_event =
false;
309 bool changed_properties =
false;
311 while (XCheckIfEvent(_display, &event, check_event, (
char *)
this)) {
312 if (got_keyrelease_event) {
317 got_keyrelease_event =
false;
319 if (event.type == KeyPress &&
320 event.xkey.keycode == keyrelease_event.keycode &&
321 (event.xkey.time - keyrelease_event.time <= 1)) {
322 if (!XFilterEvent(&event, None)) {
325 handle_keystroke(event.xkey);
329 handle_keypress(event.xkey);
336 ButtonHandle raw_button = map_raw_button(keyrelease_event.keycode);
337 if (raw_button != ButtonHandle::none()) {
341 handle_keyrelease(keyrelease_event);
347 if (event.type == KeyPress) {
348 ButtonHandle raw_button = map_raw_button(event.xkey.keycode);
349 if (raw_button != ButtonHandle::none()) {
354 if (XFilterEvent(&event, None)) {
360 switch (event.type) {
364 case ConfigureNotify:
367 configure_event =
event.xconfigure;
368 got_configure_event =
true;
373 button = get_mouse_button(event.xbutton);
374 if (!_dga_mouse_enabled) {
381 button = get_mouse_button(event.xbutton);
382 if (!_dga_mouse_enabled) {
389 if (_dga_mouse_enabled) {
398 handle_keystroke(event.xkey);
399 handle_keypress(event.xkey);
406 keyrelease_event =
event.xkey;
407 got_keyrelease_event =
true;
411 if (_dga_mouse_enabled) {
425 changed_properties =
true;
431 changed_properties =
true;
436 changed_properties =
true;
441 changed_properties =
true;
444 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
448 if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
452 if (!close_request_event.empty()) {
455 throw_event(close_request_event);
464 system_changed_properties(properties);
472 x11display_cat.info()
473 <<
"DestroyNotify\n";
477 x11display_cat.warning()
478 <<
"unhandled X event type " <<
event.type <<
"\n";
482 if (got_configure_event) {
484 _awaiting_configure =
false;
491 properties.
set_origin(configure_event.x, configure_event.y);
492 properties.
set_size(configure_event.width, configure_event.height);
494 if (_properties.get_fixed_size()) {
500 if (configure_event.width != _fixed_size.get_x() ||
501 configure_event.height != _fixed_size.get_y()) {
502 XWindowChanges changes;
503 changes.width = _fixed_size.get_x();
504 changes.height = _fixed_size.get_y();
505 int value_mask = (CWWidth | CWHeight);
506 XConfigureWindow(_display, _xwindow, value_mask, &changes);
512 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
513 X11_Cursor cursor = None;
514 if (_properties.get_cursor_hidden()) {
516 DCAST_INTO_V(x11_pipe, _pipe);
520 XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
521 _xwindow, cursor, CurrentTime);
524 changed_properties =
true;
528 _properties.get_mouse_mode() == WindowProperties::M_confined ||
529 _dga_mouse_enabled)) {
531 DCAST_INTO_V(x11_pipe, _pipe);
536 X11_Cursor cursor = None;
537 if (_properties.get_cursor_hidden()) {
541 XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
542 _xwindow, cursor, CurrentTime);
543 if (_dga_mouse_enabled) {
549 if (_dga_mouse_enabled) {
551 }
else if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
552 XUngrabPointer(_display, CurrentTime);
557 if (changed_properties) {
558 system_changed_properties(properties);
561 if (got_keyrelease_event) {
564 ButtonHandle raw_button = map_raw_button(keyrelease_event.keycode);
565 if (raw_button != ButtonHandle::none()) {
569 handle_keyrelease(keyrelease_event);
587 if (_pipe ==
nullptr) {
594 DCAST_INTO_V(x11_pipe, _pipe);
600 bool is_fullscreen = _properties.has_fullscreen() && _properties.get_fullscreen();
603 if (want_fullscreen && properties.
has_origin()) {
609 if (want_fullscreen) {
613 LPoint2i center(0, 0);
614 if (_properties.has_origin()) {
615 center = _properties.get_origin();
616 if (_properties.has_size()) {
617 center += _properties.get_size() / 2;
620 int x, y, width, height;
624 int reqsizex, reqsizey;
628 }
else if (_properties.has_size()) {
629 reqsizex = _properties.get_x_size();
630 reqsizey = _properties.get_y_size();
642 || (width == reqsizex && height == reqsizey)
643 || !x11_pipe->_have_xrandr) {
649 if (x11display_cat.is_debug()) {
650 x11display_cat.debug()
651 <<
"Setting window to fullscreen on CRTC "
652 << width <<
"x" << height <<
"+" << x <<
"+" << y <<
"\n";
658 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, _xwindow ? _xwindow : x11_pipe->
get_root());
659 SizeID old_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation);
660 SizeID new_size_id = (SizeID) -1;
664 xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes);
665 for (
int i = 0; i < num_sizes; ++i) {
666 if (xrrs[i].width == reqsizex &&
667 xrrs[i].height == reqsizey) {
671 if (new_size_id == (SizeID) -1) {
672 x11display_cat.error()
673 <<
"Videocard has no supported display resolutions at specified res ("
674 << reqsizex <<
" x " << reqsizey <<
")\n";
680 if (x11display_cat.is_debug()) {
681 x11display_cat.debug()
682 <<
"Switching to fullscreen with resolution "
683 << reqsizex <<
"x" << reqsizey <<
"\n";
686 if (new_size_id != old_size_id) {
687 _XRRSetScreenConfig(_display, conf, x11_pipe->
get_root(), new_size_id, _orig_rotation, CurrentTime);
688 if (_orig_size_id == (SizeID) -1) {
690 _orig_size_id = old_size_id;
702 if (_orig_size_id != (SizeID) -1) {
703 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, x11_pipe->
get_root());
704 _XRRSetScreenConfig(_display, conf, x11_pipe->
get_root(), _orig_size_id, _orig_rotation, CurrentTime);
705 _orig_size_id = (SizeID) -1;
708 if (!properties.
has_origin() && _properties.has_origin()) {
709 properties.
set_origin(_properties.get_x_origin(), _properties.get_y_origin());
720 if (x_origin == -2) {
723 if (y_origin == -2) {
727 if (x_origin == -2) {
730 if (y_origin == -2) {
748 set_wm_properties(properties,
true);
753 _properties.set_title(properties.
get_title());
767 XWindowChanges changes;
770 if (_properties.get_fullscreen()) {
773 value_mask |= CWX | CWY;
779 if (changes.x != -1) value_mask |= CWX;
780 if (changes.y != -1) value_mask |= CWY;
788 _fixed_size = _properties.get_size();
794 value_mask |= (CWWidth | CWHeight);
796 if (_properties.get_fixed_size()) {
797 _fixed_size = properties.
get_size();
808 case WindowProperties::Z_bottom:
809 changes.stack_mode = Below;
812 case WindowProperties::Z_normal:
813 changes.stack_mode = TopIf;
816 case WindowProperties::Z_top:
817 changes.stack_mode = Above;
821 value_mask |= (CWStackMode);
835 _properties.set_cursor_filename(cursor_filename);
839 _properties.set_cursor_filename(filename);
841 if (_properties.get_cursor_hidden()) {
844 }
else if (!cursor_filename.empty()) {
846 X11_Cursor cursor = get_cursor(cursor_filename);
847 XDefineCursor(_display, _xwindow, cursor);
850 XDefineCursor(_display, _xwindow, None);
854 if (!properties.has_mouse_mode() &&
855 _properties.get_mouse_mode() != WindowProperties::M_absolute) {
862 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
864 XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime);
869 if (properties.has_mouse_mode()) {
871 case WindowProperties::M_absolute:
872 XUngrabPointer(_display, CurrentTime);
873 if (_dga_mouse_enabled) {
875 _dga_mouse_enabled =
false;
877 _properties.set_mouse_mode(WindowProperties::M_absolute);
881 case WindowProperties::M_relative:
882 if (!_dga_mouse_enabled) {
884 X11_Cursor cursor = None;
885 if (_properties.get_cursor_hidden()) {
887 DCAST_INTO_V(x11_pipe, _pipe);
891 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
892 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
893 x11display_cat.error() <<
"Failed to grab pointer!\n";
897 _properties.set_mouse_mode(WindowProperties::M_relative);
899 _dga_mouse_enabled =
true;
904 XQueryPointer(_display, _xwindow, &event.xbutton.root,
905 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
906 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
910 x11display_cat.warning()
911 <<
"XF86DGA extension not available, cannot enable relative mouse mode\n";
912 _dga_mouse_enabled =
false;
917 case WindowProperties::M_confined:
920 DCAST_INTO_V(x11_pipe, _pipe);
922 if (_dga_mouse_enabled) {
924 _dga_mouse_enabled =
false;
926 X11_Cursor cursor = None;
927 if (_properties.get_cursor_hidden()) {
931 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
932 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
933 x11display_cat.error() <<
"Failed to grab pointer!\n";
935 _properties.set_mouse_mode(WindowProperties::M_confined);
943 if (value_mask != 0) {
946 XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
949 _awaiting_configure =
true;
956 void x11GraphicsWindow::
957 mouse_mode_absolute() {
964 void x11GraphicsWindow::
965 mouse_mode_relative() {
972 void x11GraphicsWindow::
974 if (_gsg !=
nullptr) {
979 if (_ic != (XIC)
nullptr) {
984 if (_xwindow != (X11_Window)
nullptr) {
985 XDestroyWindow(_display, _xwindow);
986 _xwindow = (X11_Window)
nullptr;
995 if (_orig_size_id != (SizeID) -1) {
997 if (_pipe !=
nullptr) {
999 DCAST_INTO_V(x11_pipe, _pipe);
1004 root = RootWindow(_display, _screen);
1006 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, root);
1007 _XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime);
1011 GraphicsWindow::close_window();
1018 bool x11GraphicsWindow::
1020 if (_visual_info ==
nullptr) {
1022 x11display_cat.error()
1023 <<
"No X visual: cannot open window.\n";
1028 DCAST_INTO_R(x11_pipe, _pipe,
false);
1030 if (!_properties.has_origin()) {
1031 _properties.set_origin(0, 0);
1033 if (!_properties.has_size()) {
1034 _properties.set_size(100, 100);
1040 X11_Window parent_window = x11_pipe->
get_root();
1041 WindowHandle *window_handle = _properties.get_parent_window();
1042 if (window_handle !=
nullptr) {
1043 x11display_cat.info()
1044 <<
"Got parent_window " << *window_handle <<
"\n";
1046 if (os_handle !=
nullptr) {
1047 x11display_cat.info()
1048 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1050 if (os_handle->
is_of_type(NativeWindowHandle::X11Handle::get_class_type())) {
1051 NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle);
1052 parent_window = x11_handle->get_handle();
1053 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1055 parent_window = (X11_Window)int_handle->get_handle();
1059 _parent_window_handle = window_handle;
1062 ButtonPressMask | ButtonReleaseMask |
1063 KeyPressMask | KeyReleaseMask |
1064 EnterWindowMask | LeaveWindowMask |
1066 FocusChangeMask | StructureNotifyMask;
1069 XSetWindowAttributes wa;
1070 wa.background_pixel = XBlackPixel(_display, _screen);
1071 wa.border_pixel = 0;
1072 wa.colormap = _colormap;
1073 wa.event_mask = _event_mask;
1074 wa.override_redirect = _override_redirect;
1076 unsigned long attrib_mask =
1077 CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
1079 _xwindow = XCreateWindow
1080 (_display, parent_window,
1081 _properties.get_x_origin(), _properties.get_y_origin(),
1082 _properties.get_x_size(), _properties.get_y_size(),
1083 0, _visual_info->depth, InputOutput,
1084 _visual_info->visual, attrib_mask, &wa);
1086 if (_xwindow == (X11_Window)0) {
1087 x11display_cat.error()
1088 <<
"failed to create X window.\n";
1092 if (_properties.get_fixed_size()) {
1093 _fixed_size = _properties.get_size();
1096 set_wm_properties(_properties,
false);
1102 XIM im = x11_pipe->
get_im();
1105 _ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
1106 XNClientWindow, _xwindow,
nullptr);
1107 if (_ic == (XIC)
nullptr) {
1108 x11display_cat.warning()
1109 <<
"Couldn't create input context.\n";
1113 if (_properties.get_cursor_hidden()) {
1116 }
else if (_properties.has_cursor_filename() && !_properties.get_cursor_filename().empty()) {
1118 X11_Cursor cursor = get_cursor(_properties.get_cursor_filename());
1119 XDefineCursor(_display, _xwindow, cursor);
1122 XMapWindow(_display, _xwindow);
1124 if (_properties.get_raw_mice()) {
1127 if (x11display_cat.is_debug()) {
1128 x11display_cat.debug()
1129 <<
"Raw mice not requested.\n";
1134 _window_handle = NativeWindowHandle::make_x11(_xwindow);
1137 if (_parent_window_handle !=
nullptr) {
1138 _parent_window_handle->attach_child(_window_handle);
1156 void x11GraphicsWindow::
1157 set_wm_properties(
const WindowProperties &properties,
bool already_mapped) {
1159 DCAST_INTO_V(x11_pipe, _pipe);
1162 XTextProperty window_name;
1163 XTextProperty *window_name_p =
nullptr;
1165 const char *name = properties.
get_title().c_str();
1166 if (XStringListToTextProperty((
char **)&name, 1, &window_name) != 0) {
1167 window_name_p = &window_name;
1173 XSizeHints *size_hints_p =
nullptr;
1175 size_hints_p = XAllocSizeHints();
1176 if (size_hints_p !=
nullptr) {
1180 size_hints_p->flags |= USPosition;
1182 LVecBase2i size = _properties.get_size();
1185 size_hints_p->width = size.get_x();
1186 size_hints_p->height = size.get_y();
1187 size_hints_p->flags |= USSize;
1190 size_hints_p->min_width = size.get_x();
1191 size_hints_p->min_height = size.get_y();
1192 size_hints_p->max_width = size.get_x();
1193 size_hints_p->max_height = size.get_y();
1194 size_hints_p->flags |= (PMinSize | PMaxSize);
1201 XWMHints *wm_hints_p =
nullptr;
1202 wm_hints_p = XAllocWMHints();
1203 if (wm_hints_p !=
nullptr) {
1205 wm_hints_p->initial_state = IconicState;
1207 wm_hints_p->initial_state = NormalState;
1209 wm_hints_p->flags = StateHint;
1215 static const int max_type_data = 32;
1216 int32_t type_data[max_type_data];
1217 int next_type_data = 0;
1219 static const int max_state_data = 32;
1220 int32_t state_data[max_state_data];
1221 int next_state_data = 0;
1223 static const int max_set_data = 32;
1226 inline SetAction() { }
1227 inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
1231 SetAction set_data[max_set_data];
1232 int next_set_data = 0;
1238 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_fullscreen;
1241 state_data[next_state_data++] = x11_pipe->_net_wm_state_fullscreen;
1244 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 1);
1247 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 0);
1260 XClassHint *class_hints_p =
nullptr;
1261 if (!x_wm_class.empty()) {
1263 class_hints_p = XAllocClassHint();
1264 class_hints_p->res_class = (
char*) x_wm_class.c_str();
1265 if (!x_wm_class_name.empty()) {
1266 class_hints_p->res_name = (
char*) x_wm_class_name.c_str();
1270 class_hints_p = XAllocClassHint();
1271 class_hints_p->res_class = (
char*)
"Undecorated";
1275 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_splash;
1280 case WindowProperties::Z_bottom:
1281 state_data[next_state_data++] = x11_pipe->_net_wm_state_below;
1282 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1283 x11_pipe->_net_wm_state_add);
1284 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1285 x11_pipe->_net_wm_state_remove);
1288 case WindowProperties::Z_normal:
1289 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1290 x11_pipe->_net_wm_state_remove);
1291 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1292 x11_pipe->_net_wm_state_remove);
1295 case WindowProperties::Z_top:
1296 state_data[next_state_data++] = x11_pipe->_net_wm_state_above;
1297 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1298 x11_pipe->_net_wm_state_remove);
1299 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1300 x11_pipe->_net_wm_state_add);
1305 nassertv(next_type_data < max_type_data);
1306 nassertv(next_state_data < max_state_data);
1307 nassertv(next_set_data < max_set_data);
1310 int32_t pid = getpid();
1311 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_pid,
1312 XA_CARDINAL, 32, PropModeReplace,
1313 (
unsigned char *)&pid, 1);
1318 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_bypass_compositor,
1319 XA_CARDINAL, 32, PropModeReplace,
1320 (
unsigned char *)&compositor, 1);
1323 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_window_type,
1324 XA_ATOM, 32, PropModeReplace,
1325 (
unsigned char *)type_data, next_type_data);
1328 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_state,
1329 XA_ATOM, 32, PropModeReplace,
1330 (
unsigned char *)state_data, next_state_data);
1332 if (already_mapped) {
1338 DCAST_INTO_V(x11_pipe, _pipe);
1340 for (
int i = 0; i < next_set_data; ++i) {
1341 XClientMessageEvent event;
1342 memset(&event, 0,
sizeof(event));
1343 event.type = ClientMessage;
1344 event.send_event = True;
1345 event.display = _display;
1346 event.window = _xwindow;
1347 event.message_type = x11_pipe->_net_wm_state;
1349 event.data.l[0] = set_data[i]._action;
1350 event.data.l[1] = set_data[i]._state;
1351 event.data.l[2] = 0;
1352 event.data.l[3] = 1;
1354 XSendEvent(_display, x11_pipe->
get_root(), True, SubstructureNotifyMask | SubstructureRedirectMask, (XEvent *)&event);
1358 XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
1359 nullptr, 0, size_hints_p, wm_hints_p, class_hints_p);
1361 if (size_hints_p !=
nullptr) {
1362 XFree(size_hints_p);
1364 if (wm_hints_p !=
nullptr) {
1367 if (class_hints_p !=
nullptr) {
1368 XFree(class_hints_p);
1374 Atom protocols[] = {
1378 XSetWMProtocols(_display, _xwindow, protocols,
1379 sizeof(protocols) /
sizeof(Atom));
1386 void x11GraphicsWindow::
1387 setup_colormap(XVisualInfo *visual) {
1389 DCAST_INTO_V(x11_pipe, _pipe);
1390 X11_Window root_window = x11_pipe->
get_root();
1392 _colormap = XCreateColormap(_display, root_window,
1393 visual->visual, AllocNone);
1400 void x11GraphicsWindow::
1402 #ifdef PHAVE_LINUX_INPUT_H
1403 bool any_present =
false;
1404 bool any_mice =
false;
1406 for (
int i=0; i<64; i++) {
1408 fnb <<
"/dev/input/event" << i;
1409 string fn = fnb.str();
1410 int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
1412 EvdevInputDevice *device =
new EvdevInputDevice(
nullptr, fd);
1413 nassertd(device != NULL)
continue;
1415 if (device->has_pointer()) {
1416 add_input_device(device);
1418 x11display_cat.info()
1419 <<
"Raw mouse " << _input_devices.size()
1420 <<
" detected: " << device->get_name() <<
"\n";
1426 if (errno == ENOENT || errno == ENOTDIR) {
1430 x11display_cat.error()
1431 <<
"Opening raw mice: " << strerror(errno) <<
" " << fn <<
"\n";
1437 _properties.set_raw_mice(
true);
1439 }
else if (!any_present) {
1440 x11display_cat.error() <<
1441 "Opening raw mice: files not found: /dev/input/event*\n";
1444 x11display_cat.error() <<
1445 "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
1448 x11display_cat.error() <<
1449 "Opening raw mice: panda not compiled with raw mouse support.\n";
1456 void x11GraphicsWindow::
1457 handle_keystroke(XKeyEvent &event) {
1458 if (!_dga_mouse_enabled) {
1464 static const int buffer_size = 256;
1465 wchar_t buffer[buffer_size];
1467 int len = XwcLookupString(_ic, &event, buffer, buffer_size,
nullptr,
1469 if (status == XBufferOverflow) {
1470 x11display_cat.error()
1471 <<
"Overflowed input buffer.\n";
1475 for (
int i = 0; i < len; i++) {
1491 void x11GraphicsWindow::
1492 handle_keypress(XKeyEvent &event) {
1493 if (!_dga_mouse_enabled) {
1499 if (button != ButtonHandle::none()) {
1500 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1503 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1506 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1509 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1519 void x11GraphicsWindow::
1520 handle_keyrelease(XKeyEvent &event) {
1521 if (!_dga_mouse_enabled) {
1527 if (button != ButtonHandle::none()) {
1528 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1529 _input->
button_up(KeyboardButton::control());
1531 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1532 _input->
button_up(KeyboardButton::shift());
1534 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1535 _input->
button_up(KeyboardButton::alt());
1537 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1538 _input->
button_up(KeyboardButton::meta());
1549 get_button(XKeyEvent &key_event,
bool allow_shift) {
1550 KeySym key = XLookupKeysym(&key_event, 0);
1552 if ((key_event.state & Mod2Mask) != 0) {
1567 case XK_KP_Multiply:
1569 case XK_KP_Separator:
1570 case XK_KP_Subtract:
1593 k2 = XLookupKeysym(&key_event, 1);
1594 button = map_button(k2);
1595 if (button != ButtonHandle::none()) {
1609 if ((key_event.state & ShiftMask) != 0) {
1610 KeySym k2 = XLookupKeysym(&key_event, 1);
1612 if (button != ButtonHandle::none()) {
1620 if ((key_event.state & (ShiftMask | LockMask)) != 0) {
1621 if (key >= XK_a && key <= XK_z) {
1622 key += (XK_A - XK_a);
1627 return map_button(key);
1635 map_button(KeySym key)
const {
1638 return ButtonHandle::none();
1640 return KeyboardButton::backspace();
1643 return KeyboardButton::tab();
1646 return KeyboardButton::enter();
1648 return KeyboardButton::escape();
1651 return KeyboardButton::space();
1672 case XK_KP_Multiply:
1678 case XK_KP_Separator:
1681 case XK_KP_Subtract:
1786 case XK_bracketleft:
1790 case XK_bracketright:
1792 case XK_asciicircum:
1861 return KeyboardButton::f1();
1864 return KeyboardButton::f2();
1867 return KeyboardButton::f3();
1870 return KeyboardButton::f4();
1872 return KeyboardButton::f5();
1874 return KeyboardButton::f6();
1876 return KeyboardButton::f7();
1878 return KeyboardButton::f8();
1880 return KeyboardButton::f9();
1882 return KeyboardButton::f10();
1884 return KeyboardButton::f11();
1886 return KeyboardButton::f12();
1889 return KeyboardButton::left();
1892 return KeyboardButton::up();
1895 return KeyboardButton::right();
1898 return KeyboardButton::down();
1901 return KeyboardButton::page_up();
1904 return KeyboardButton::page_down();
1907 return KeyboardButton::home();
1910 return KeyboardButton::end();
1913 return KeyboardButton::insert();
1916 return KeyboardButton::del();
1918 return KeyboardButton::num_lock();
1919 case XK_Scroll_Lock:
1920 return KeyboardButton::scroll_lock();
1922 return KeyboardButton::print_screen();
1924 return KeyboardButton::pause();
1926 return KeyboardButton::menu();
1928 return KeyboardButton::lshift();
1930 return KeyboardButton::rshift();
1932 return KeyboardButton::lcontrol();
1934 return KeyboardButton::rcontrol();
1936 return KeyboardButton::lalt();
1938 return KeyboardButton::ralt();
1941 return KeyboardButton::lmeta();
1944 return KeyboardButton::rmeta();
1946 return KeyboardButton::caps_lock();
1948 return KeyboardButton::shift_lock();
1950 if (x11display_cat.is_debug()) {
1951 x11display_cat.debug()
1952 <<
"Unrecognized keysym 0x" << std::hex << key << std::dec <<
"\n";
1954 return ButtonHandle::none();
1961 map_raw_button(KeyCode key)
const {
1962 #ifdef PHAVE_LINUX_INPUT_H
1967 int index = key - 8;
1968 if (index > 0 && index < 128) {
1969 return EvdevInputDevice::map_button(index);
1972 return ButtonHandle::none();
1980 get_mouse_button(XButtonEvent &button_event) {
1981 int index = button_event.button;
1982 if (index == x_wheel_up_button) {
1984 }
else if (index == x_wheel_down_button) {
1986 }
else if (index == x_wheel_left_button) {
1988 }
else if (index == x_wheel_right_button) {
2000 get_keyboard_map()
const {
2007 for (
int k = 9; k <= 135; ++k) {
2008 if (k >= 78 && k <= 91) {
2016 if (raw_button == ButtonHandle::none()) {
2020 KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0);
2026 if (sym >= XK_exclam && sym <= XK_asciitilde) {
2027 label = toupper((
char)sym);
2029 else if (sym >= XK_F1 && sym <= XK_F35) {
2030 label =
"F" + format_string(sym - XK_F1 + 1);
2032 else if (sym > 0x1000000 && sym < 0x1110000) {
2034 char32_t ch = sym & 0x0ffffff;
2035 if ((ch & ~0x7f) == 0) {
2036 label = string(1, (
char)ch);
2038 else if ((ch & ~0x7ff) == 0) {
2040 string(1, (
char)((ch >> 6) | 0xc0)) +
2041 string(1, (
char)((ch & 0x3f) | 0x80));
2043 else if ((ch & ~0xffff) == 0) {
2045 string(1, (
char)((ch >> 12) | 0xe0)) +
2046 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2047 string(1, (
char)((ch & 0x3f) | 0x80));
2051 string(1, (
char)((ch >> 18) | 0xf0)) +
2052 string(1, (
char)(((ch >> 12) & 0x3f) | 0x80)) +
2053 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2054 string(1, (
char)((ch & 0x3f) | 0x80));
2057 else if ((sym >= XK_exclamdown && sym <= XK_umacron)
2058 || (sym >= XK_OE && sym <= XK_Ydiaeresis)
2059 || (sym >= XK_Serbian_dje && sym <= XK_Cyrillic_HARDSIGN)
2060 || (sym >= XK_kana_fullstop && sym <= XK_semivoicedsound)
2061 || (sym >= XK_Arabic_comma && sym <= XK_Arabic_sukun)
2062 || (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_omega)
2063 || (sym >= XK_hebrew_doublelowline && sym <= XK_hebrew_taw)
2064 || (sym >= XK_Thai_kokai && sym <= XK_Thai_lekkao)
2065 || (sym >= XK_Hangul_Kiyeog && sym <= XK_Hangul_J_YeorinHieuh)
2066 || sym == XK_EuroSign
2067 || sym == XK_Korean_Won) {
2070 int nbytes = XkbTranslateKeySym(_display, &sym, 0, buffer, 255, 0);
2072 label.assign(buffer, nbytes);
2076 if (button == ButtonHandle::none() && label.empty()) {
2091 Bool x11GraphicsWindow::
2092 check_event(X11_Display *display, XEvent *event,
char *arg) {
2096 return (event->xany.window == self->_xwindow);
2103 X11_Cursor x11GraphicsWindow::
2104 get_cursor(
const Filename &filename) {
2106 DCAST_INTO_R(x11_pipe, _pipe, None);
2108 if (x11_pipe->_xcursor_size == -1) {
2109 x11display_cat.info()
2110 <<
"libXcursor.so.1 not available; cannot change mouse cursor.\n";
2116 if (fi != _cursor_filenames.end()) {
2125 x11display_cat.warning()
2126 <<
"Could not find cursor filename " << filename <<
"\n";
2129 fi = _cursor_filenames.find(resolved);
2130 if (fi != _cursor_filenames.end()) {
2136 if (str ==
nullptr) {
2137 x11display_cat.warning()
2138 <<
"Could not open cursor file " << filename <<
"\n";
2144 str->read(magic, 4);
2146 x11display_cat.warning()
2147 <<
"Could not read from cursor file " << filename <<
"\n";
2153 str->putback(magic[3]);
2154 str->putback(magic[2]);
2155 str->putback(magic[1]);
2156 str->putback(magic[0]);
2158 X11_Cursor h = None;
2159 if (memcmp(magic,
"Xcur", 4) == 0) {
2161 x11display_cat.debug()
2162 <<
"Loading X11 cursor " << filename <<
"\n";
2164 xcfile.closure = str;
2165 xcfile.read = &xcursor_read;
2166 xcfile.write = &xcursor_write;
2167 xcfile.seek = &xcursor_seek;
2169 XcursorImages *images = x11_pipe->_XcursorXcFileLoadImages(&xcfile, x11_pipe->_xcursor_size);
2170 if (images !=
nullptr) {
2171 h = x11_pipe->_XcursorImagesLoadCursor(_display, images);
2172 x11_pipe->_XcursorImagesDestroy(images);
2175 }
else if (memcmp(magic,
"\0\0\1\0", 4) == 0
2176 || memcmp(magic,
"\0\0\2\0", 4) == 0) {
2178 x11display_cat.debug()
2179 <<
"Loading Windows cursor " << filename <<
"\n";
2187 x11display_cat.warning()
2188 <<
"X11 cursor filename '" << resolved <<
"' could not be loaded!\n";
2191 _cursor_filenames[resolved] = h;
2199 X11_Cursor x11GraphicsWindow::
2200 read_ico(istream &ico) {
2202 DCAST_INTO_R(x11_pipe, _pipe, None);
2206 uint16_t reserved, type, count;
2210 uint8_t width, height, colorCount, reserved;
2211 uint16_t xhot, yhot;
2212 uint32_t bitmapSize, offset;
2216 uint32_t headerSize, width, height;
2217 uint16_t planes, bitsPerPixel;
2218 uint32_t compression, imageSize, xPixelsPerM, yPixelsPerM, colorsUsed, colorsImportant;
2222 uint8_t blue, green, red, reserved;
2226 unsigned int j, k, mask, shift;
2227 size_t colorCount, bitsPerPixel;
2229 IcoInfoHeader infoHeader;
2230 IcoEntry *entries =
nullptr;
2231 IcoColor color, *palette =
nullptr;
2233 size_t xorBmpSize, andBmpSize;
2234 char *curXor, *curAnd;
2235 char *xorBmp =
nullptr, *andBmp =
nullptr;
2236 XcursorImage *image =
nullptr;
2237 X11_Cursor ret = None;
2239 int def_size = x11_pipe->_xcursor_size;
2242 ico.read(
reinterpret_cast<char *
>(&header),
sizeof(IcoHeader));
2243 if (!ico.good())
goto cleanup;
2244 if (header.type != 1 && header.type != 2)
goto cleanup;
2245 if (header.count < 1)
goto cleanup;
2248 entries =
new IcoEntry[header.count];
2249 ico.read(
reinterpret_cast<char *
>(entries), header.count *
sizeof(IcoEntry));
2250 if (!ico.good())
goto cleanup;
2251 for (i = 1; i < header.count; i++) {
2252 if (entries[i].width == def_size && entries[i].height == def_size) {
2257 if (entries[i].width > entries[entry].width ||
2258 entries[i].height > entries[entry].height)
2263 ico.seekg(entries[entry].offset);
2264 if (!ico.good())
goto cleanup;
2266 if (ico.peek() == 0x89) {
2280 unsigned int *dest = image->pixels;
2282 if (alpha !=
nullptr) {
2283 for (
size_t p = 0; p < num_pixels; ++p) {
2284 *dest++ = (*alpha << 24U) | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2289 for (
size_t p = 0; p < num_pixels; ++p) {
2290 *dest++ = 0xff000000U | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2296 ico.read(
reinterpret_cast<char *
>(&infoHeader),
sizeof(IcoInfoHeader));
2297 if (!ico.good())
goto cleanup;
2298 bitsPerPixel = infoHeader.bitsPerPixel;
2300 if (infoHeader.compression != 0)
goto cleanup;
2303 if (bitsPerPixel != 24 && bitsPerPixel != 32) {
2304 colorCount = 1 << bitsPerPixel;
2305 palette =
new IcoColor[colorCount];
2306 ico.read(
reinterpret_cast<char *
>(palette), colorCount *
sizeof(IcoColor));
2307 if (!ico.good())
goto cleanup;
2310 int and_stride = ((infoHeader.width >> 3) + 3) & ~0x03;
2313 xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8;
2314 andBmpSize = and_stride * (infoHeader.height / 2);
2315 curXor = xorBmp =
new char[xorBmpSize];
2316 curAnd = andBmp =
new char[andBmpSize];
2317 ico.read(xorBmp, xorBmpSize);
2318 if (!ico.good())
goto cleanup;
2319 ico.read(andBmp, andBmpSize);
2320 if (!ico.good())
goto cleanup;
2322 image = x11_pipe->_XcursorImageCreate(infoHeader.width, infoHeader.height / 2);
2325 switch (bitsPerPixel) {
2331 mask = ((1 << bitsPerPixel) - 1);
2332 for (i = image->height - 1; i >= 0; i--) {
2333 for (j = 0; j < image->width; j += 8 / bitsPerPixel) {
2334 for (k = 0; k < 8 / bitsPerPixel; k++) {
2335 shift = 8 - ((k + 1) * bitsPerPixel);
2336 color = palette[(*curXor & (mask << shift)) >> shift];
2337 image->pixels[(i * image->width) + j + k] = (color.red << 16) +
2338 (color.green << 8) +
2346 for (j = 0; j < image->width; j += 8) {
2347 for (k = 0; k < 8; k++) {
2349 image->pixels[(i * image->width) + j + k] |=
2350 ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24);
2360 for (i = image->height - 1; i >= 0; i--) {
2361 for (j = 0; j < image->width; j++) {
2362 shift = 7 - (j & 0x7);
2363 uint32_t alpha = (curAnd[j >> 3] & (1 << shift)) ? 0 : 0xff000000U;
2364 image->pixels[(i * image->width) + j] = (uint8_t)curXor[0]
2365 | ((uint8_t)curXor[1] << 8u)
2366 | ((uint8_t)curXor[2] << 16u)
2370 curAnd += and_stride;
2376 for (i = image->height - 1; i >= 0; i--) {
2377 for (j = 0; j < image->width; j++) {
2378 image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) +
2379 (*(curXor + 2) << 16) +
2380 (*(curXor + 1) << 8) +
2393 if (header.type == 2) {
2394 image->xhot = entries[entry].xhot;
2395 image->yhot = entries[entry].yhot;
2401 ret = x11_pipe->_XcursorImageLoadCursor(_display, image);
2404 x11_pipe->_XcursorImageDestroy(image);
get_real_time
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
virtual bool is_any_clear_active() const
Returns true if any of the clear types (so far there are just color or depth) have been set active,...
The name of a file, such as a texture file or an Egg file.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
virtual void clear(Thread *current_thread)
Clears the entire framebuffer before rendering, according to the settings of get_color_clear_active()...
An object to create GraphicsOutputs that share a particular 3-D API.
get_display_width
Returns the width of the entire display, if it is known.
get_display_height
Returns the height of the entire display, if it is known.
Encapsulates all the communication with a particular instance of a given rendering backend.
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
get_close_request_event
Returns the name of the event set via set_close_request_event().
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
Similar to MutexHolder, but for a light mutex.
bool try_lock()
Alias for try_acquire() to match C++11 semantics.
void release() const
Releases the lightReMutex.
Similar to MutexHolder, but for a light reentrant mutex.
This class maintains the set of all known PNMFileTypes in the universe.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
PNMFileType * get_type_from_extension(const std::string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
void set_maxval(xelval maxval)
Rescales the image to the indicated maxval.
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
xel * get_array()
Directly access the underlying PNMImage array.
xelval * get_alpha_array()
Directly access the underlying PNMImage array of alpha values.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Holds the data that might be generated by a 2-d pointer input device, such as the mouse in the Graphi...
get_in_window
If this returns false, the pointer is not currently present in the window and the values returned by ...
A thread; that is, a lightweight process.
TypeHandle is the identifier used to differentiate C++ class types.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
A hierarchy of directories and files that appears to be one continuous file system,...
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
std::istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read,...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
This object represents a window on the desktop, not necessarily a Panda window.
get_os_handle
Returns the OS-specific handle stored internally to the WindowHandle wrapper.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
clear_cursor_filename
Removes the cursor_filename specification from the properties.
has_cursor_filename
Returns true if set_cursor_filename() has been specified.
get_title
Returns the window's title.
get_undecorated
Returns true if the window has no border.
clear_cursor_hidden
Removes the cursor_hidden specification from the properties.
int get_y_size() const
Returns size in pixels in the y dimension of the useful part of the window, not including decorations...
set_mouse_mode
Specifies the mode in which the window is to operate its mouse pointer.
int get_x_size() const
Returns size in pixels in the x dimension of the useful part of the window, not including decorations...
int get_y_origin() const
Returns the y coordinate of the window's top-left corner, not including decorations.
clear_z_order
Removes the z_order specification from the properties.
get_minimized
Returns true if the window is minimized.
clear_mouse_mode
Removes the mouse_mode specification from the properties.
has_fullscreen
Returns true if set_fullscreen() has been specified.
has_size
Returns true if the window size has been specified, false otherwise.
clear_title
Removes the title specification from the properties.
get_size
Returns size in pixels of the useful part of the window, not including decorations.
clear_origin
Removes the origin specification from the properties.
has_minimized
Returns true if set_minimized() has been specified.
set_size
Specifies the requested size of the window, in pixels.
get_foreground
Returns true if the window is in the foreground.
has_fixed_size
Returns true if set_fixed_size() has been specified.
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
clear_fixed_size
Removes the fixed_size specification from the properties.
clear_fullscreen
Removes the fullscreen specification from the properties.
set_foreground
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
clear_size
Removes the size specification from the properties.
set_open
Specifies whether the window should be open.
get_z_order
Returns the window's z_order.
get_fullscreen
Returns true if the window is in fullscreen mode.
has_title
Returns true if the window title has been specified, false otherwise.
get_mouse_mode
See set_mouse_mode().
has_origin
Returns true if the window origin has been specified, false otherwise.
has_foreground
Returns true if set_foreground() has been specified.
clear_foreground
Removes the foreground specification from the properties.
get_cursor_filename
Returns the icon filename associated with the mouse cursor.
get_cursor_hidden
Returns true if the mouse cursor is invisible.
has_cursor_hidden
Returns true if set_cursor_hidden() has been specified.
set_minimized
Specifies whether the window should be created minimized (true), or normal (false).
has_z_order
Returns true if the window z_order has been specified, false otherwise.
get_fixed_size
Returns true if the window cannot be resized by the user, false otherwise.
int get_x_origin() const
Returns the x coordinate of the window's top-left corner, not including decorations.
set_origin
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
This is our own Panda specialization on the default STL map.
This graphics pipe represents the interface for creating graphics windows on an X-based client.
X11_Window get_root() const
Returns the handle to the root window on the pipe's display.
X11_Display * get_display() const
Returns a pointer to the X display associated with the pipe: the display on which to create the windo...
RRCrtc find_fullscreen_crtc(const LPoint2i &point, int &x, int &y, int &width, int &height)
Finds a CRTC for going fullscreen to, at the given origin.
int get_screen() const
Returns the X screen number associated with the pipe.
XIM get_im() const
Returns the input method opened for the pipe, or NULL if the input method could not be opened for som...
bool supports_relative_mouse() const
Returns true if relative mouse mode is supported on this display.
bool enable_relative_mouse()
Enables relative mouse mode for this display.
X11_Cursor get_hidden_cursor()
Returns an invisible Cursor suitable for assigning to windows that have the cursor_hidden property se...
void disable_relative_mouse()
Disables relative mouse mode for this display.
Interfaces to the X11 window system.
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame.
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
virtual void clear(Thread *current_thread)
Clears the entire framebuffer before rendering, according to the settings of get_color_clear_active()...
virtual bool move_pointer(int device, int x, int y)
Forces the pointer to the indicated position within the window, if possible.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
virtual MouseData get_pointer(int device) const
Returns the MouseData associated with the nth input device's pointer.
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BEGIN_PUBLISH typedef PointerData MouseData
Deprecated alias for PointerData.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.