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()) {
771 if (_properties.get_x_origin() != 0 ||
772 _properties.get_y_origin() != 0) {
775 value_mask |= CWX | CWY;
782 if (changes.x != -1) value_mask |= CWX;
783 if (changes.y != -1) value_mask |= CWY;
791 _fixed_size = _properties.get_size();
797 value_mask |= (CWWidth | CWHeight);
799 if (_properties.get_fixed_size()) {
800 _fixed_size = properties.
get_size();
811 case WindowProperties::Z_bottom:
812 changes.stack_mode = Below;
815 case WindowProperties::Z_normal:
816 changes.stack_mode = TopIf;
819 case WindowProperties::Z_top:
820 changes.stack_mode = Above;
824 value_mask |= (CWStackMode);
838 _properties.set_cursor_filename(cursor_filename);
842 _properties.set_cursor_filename(filename);
844 if (_properties.get_cursor_hidden()) {
847 }
else if (!cursor_filename.empty()) {
849 X11_Cursor cursor = get_cursor(cursor_filename);
850 XDefineCursor(_display, _xwindow, cursor);
853 XDefineCursor(_display, _xwindow, None);
857 if (!properties.has_mouse_mode() &&
858 _properties.get_mouse_mode() != WindowProperties::M_absolute) {
865 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
867 XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime);
872 if (properties.has_mouse_mode()) {
874 case WindowProperties::M_absolute:
875 XUngrabPointer(_display, CurrentTime);
876 if (_dga_mouse_enabled) {
878 _dga_mouse_enabled =
false;
880 _properties.set_mouse_mode(WindowProperties::M_absolute);
884 case WindowProperties::M_relative:
885 if (!_dga_mouse_enabled) {
887 X11_Cursor cursor = None;
888 if (_properties.get_cursor_hidden()) {
890 DCAST_INTO_V(x11_pipe, _pipe);
894 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
895 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
896 x11display_cat.error() <<
"Failed to grab pointer!\n";
900 _properties.set_mouse_mode(WindowProperties::M_relative);
902 _dga_mouse_enabled =
true;
907 XQueryPointer(_display, _xwindow, &event.xbutton.root,
908 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
909 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
913 x11display_cat.warning()
914 <<
"XF86DGA extension not available, cannot enable relative mouse mode\n";
915 _dga_mouse_enabled =
false;
920 case WindowProperties::M_confined:
923 DCAST_INTO_V(x11_pipe, _pipe);
925 if (_dga_mouse_enabled) {
927 _dga_mouse_enabled =
false;
929 X11_Cursor cursor = None;
930 if (_properties.get_cursor_hidden()) {
934 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
935 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
936 x11display_cat.error() <<
"Failed to grab pointer!\n";
938 _properties.set_mouse_mode(WindowProperties::M_confined);
946 if (value_mask != 0) {
949 XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
952 _awaiting_configure =
true;
959 void x11GraphicsWindow::
960 mouse_mode_absolute() {
967 void x11GraphicsWindow::
968 mouse_mode_relative() {
975 void x11GraphicsWindow::
977 if (_gsg !=
nullptr) {
982 if (_ic != (XIC)
nullptr) {
987 if (_xwindow != (X11_Window)
nullptr) {
988 XDestroyWindow(_display, _xwindow);
989 _xwindow = (X11_Window)
nullptr;
998 if (_orig_size_id != (SizeID) -1) {
1000 if (_pipe !=
nullptr) {
1002 DCAST_INTO_V(x11_pipe, _pipe);
1007 root = RootWindow(_display, _screen);
1009 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, root);
1010 _XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime);
1014 GraphicsWindow::close_window();
1021 bool x11GraphicsWindow::
1023 if (_visual_info ==
nullptr) {
1025 x11display_cat.error()
1026 <<
"No X visual: cannot open window.\n";
1031 DCAST_INTO_R(x11_pipe, _pipe,
false);
1033 if (!_properties.has_origin()) {
1034 _properties.set_origin(0, 0);
1036 if (!_properties.has_size()) {
1037 _properties.set_size(100, 100);
1043 X11_Window parent_window = x11_pipe->
get_root();
1044 WindowHandle *window_handle = _properties.get_parent_window();
1045 if (window_handle !=
nullptr) {
1046 x11display_cat.info()
1047 <<
"Got parent_window " << *window_handle <<
"\n";
1049 if (os_handle !=
nullptr) {
1050 x11display_cat.info()
1051 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1053 if (os_handle->
is_of_type(NativeWindowHandle::X11Handle::get_class_type())) {
1054 NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle);
1055 parent_window = x11_handle->get_handle();
1056 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1058 parent_window = (X11_Window)int_handle->get_handle();
1062 _parent_window_handle = window_handle;
1065 ButtonPressMask | ButtonReleaseMask |
1066 KeyPressMask | KeyReleaseMask |
1067 EnterWindowMask | LeaveWindowMask |
1069 FocusChangeMask | StructureNotifyMask;
1072 XSetWindowAttributes wa;
1073 wa.background_pixel = XBlackPixel(_display, _screen);
1074 wa.border_pixel = 0;
1075 wa.colormap = _colormap;
1076 wa.event_mask = _event_mask;
1077 wa.override_redirect = _override_redirect;
1079 unsigned long attrib_mask =
1080 CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
1082 _xwindow = XCreateWindow
1083 (_display, parent_window,
1084 _properties.get_x_origin(), _properties.get_y_origin(),
1085 _properties.get_x_size(), _properties.get_y_size(),
1086 0, _visual_info->depth, InputOutput,
1087 _visual_info->visual, attrib_mask, &wa);
1089 if (_xwindow == (X11_Window)0) {
1090 x11display_cat.error()
1091 <<
"failed to create X window.\n";
1095 if (_properties.get_fixed_size()) {
1096 _fixed_size = _properties.get_size();
1099 set_wm_properties(_properties,
false);
1105 XIM im = x11_pipe->
get_im();
1108 _ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
1109 XNClientWindow, _xwindow,
nullptr);
1110 if (_ic == (XIC)
nullptr) {
1111 x11display_cat.warning()
1112 <<
"Couldn't create input context.\n";
1116 if (_properties.get_cursor_hidden()) {
1119 }
else if (_properties.has_cursor_filename() && !_properties.get_cursor_filename().empty()) {
1121 X11_Cursor cursor = get_cursor(_properties.get_cursor_filename());
1122 XDefineCursor(_display, _xwindow, cursor);
1125 XMapWindow(_display, _xwindow);
1127 if (_properties.get_raw_mice()) {
1130 if (x11display_cat.is_debug()) {
1131 x11display_cat.debug()
1132 <<
"Raw mice not requested.\n";
1137 _window_handle = NativeWindowHandle::make_x11(_xwindow);
1140 if (_parent_window_handle !=
nullptr) {
1141 _parent_window_handle->attach_child(_window_handle);
1159 void x11GraphicsWindow::
1160 set_wm_properties(
const WindowProperties &properties,
bool already_mapped) {
1162 DCAST_INTO_V(x11_pipe, _pipe);
1165 XTextProperty window_name;
1166 XTextProperty *window_name_p =
nullptr;
1168 const char *name = properties.
get_title().c_str();
1169 if (XStringListToTextProperty((
char **)&name, 1, &window_name) != 0) {
1170 window_name_p = &window_name;
1176 XSizeHints *size_hints_p =
nullptr;
1178 size_hints_p = XAllocSizeHints();
1179 if (size_hints_p !=
nullptr) {
1183 size_hints_p->flags |= USPosition;
1185 LVecBase2i size = _properties.get_size();
1188 size_hints_p->width = size.get_x();
1189 size_hints_p->height = size.get_y();
1190 size_hints_p->flags |= USSize;
1193 size_hints_p->min_width = size.get_x();
1194 size_hints_p->min_height = size.get_y();
1195 size_hints_p->max_width = size.get_x();
1196 size_hints_p->max_height = size.get_y();
1197 size_hints_p->flags |= (PMinSize | PMaxSize);
1204 XWMHints *wm_hints_p =
nullptr;
1205 wm_hints_p = XAllocWMHints();
1206 if (wm_hints_p !=
nullptr) {
1208 wm_hints_p->initial_state = IconicState;
1210 wm_hints_p->initial_state = NormalState;
1212 wm_hints_p->flags = StateHint;
1218 static const int max_type_data = 32;
1219 int32_t type_data[max_type_data];
1220 int next_type_data = 0;
1222 static const int max_state_data = 32;
1223 int32_t state_data[max_state_data];
1224 int next_state_data = 0;
1226 static const int max_set_data = 32;
1229 inline SetAction() { }
1230 inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
1234 SetAction set_data[max_set_data];
1235 int next_set_data = 0;
1241 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_fullscreen;
1244 state_data[next_state_data++] = x11_pipe->_net_wm_state_fullscreen;
1247 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 1);
1250 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 0);
1263 XClassHint *class_hints_p =
nullptr;
1264 if (!x_wm_class.empty()) {
1266 class_hints_p = XAllocClassHint();
1267 class_hints_p->res_class = (
char*) x_wm_class.c_str();
1268 if (!x_wm_class_name.empty()) {
1269 class_hints_p->res_name = (
char*) x_wm_class_name.c_str();
1273 class_hints_p = XAllocClassHint();
1274 class_hints_p->res_class = (
char*)
"Undecorated";
1278 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_splash;
1283 case WindowProperties::Z_bottom:
1284 state_data[next_state_data++] = x11_pipe->_net_wm_state_below;
1285 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1286 x11_pipe->_net_wm_state_add);
1287 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1288 x11_pipe->_net_wm_state_remove);
1291 case WindowProperties::Z_normal:
1292 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1293 x11_pipe->_net_wm_state_remove);
1294 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1295 x11_pipe->_net_wm_state_remove);
1298 case WindowProperties::Z_top:
1299 state_data[next_state_data++] = x11_pipe->_net_wm_state_above;
1300 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1301 x11_pipe->_net_wm_state_remove);
1302 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1303 x11_pipe->_net_wm_state_add);
1308 nassertv(next_type_data < max_type_data);
1309 nassertv(next_state_data < max_state_data);
1310 nassertv(next_set_data < max_set_data);
1313 int32_t pid = getpid();
1314 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_pid,
1315 XA_CARDINAL, 32, PropModeReplace,
1316 (
unsigned char *)&pid, 1);
1321 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_bypass_compositor,
1322 XA_CARDINAL, 32, PropModeReplace,
1323 (
unsigned char *)&compositor, 1);
1326 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_window_type,
1327 XA_ATOM, 32, PropModeReplace,
1328 (
unsigned char *)type_data, next_type_data);
1331 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_state,
1332 XA_ATOM, 32, PropModeReplace,
1333 (
unsigned char *)state_data, next_state_data);
1335 if (already_mapped) {
1341 DCAST_INTO_V(x11_pipe, _pipe);
1343 for (
int i = 0; i < next_set_data; ++i) {
1344 XClientMessageEvent event;
1345 memset(&event, 0,
sizeof(event));
1346 event.type = ClientMessage;
1347 event.send_event = True;
1348 event.display = _display;
1349 event.window = _xwindow;
1350 event.message_type = x11_pipe->_net_wm_state;
1352 event.data.l[0] = set_data[i]._action;
1353 event.data.l[1] = set_data[i]._state;
1354 event.data.l[2] = 0;
1355 event.data.l[3] = 1;
1357 XSendEvent(_display, x11_pipe->
get_root(), True, SubstructureNotifyMask | SubstructureRedirectMask, (XEvent *)&event);
1361 XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
1362 nullptr, 0, size_hints_p, wm_hints_p, class_hints_p);
1364 if (size_hints_p !=
nullptr) {
1365 XFree(size_hints_p);
1367 if (wm_hints_p !=
nullptr) {
1370 if (class_hints_p !=
nullptr) {
1371 XFree(class_hints_p);
1377 Atom protocols[] = {
1381 XSetWMProtocols(_display, _xwindow, protocols,
1382 sizeof(protocols) /
sizeof(Atom));
1389 void x11GraphicsWindow::
1390 setup_colormap(XVisualInfo *visual) {
1392 DCAST_INTO_V(x11_pipe, _pipe);
1393 X11_Window root_window = x11_pipe->
get_root();
1395 _colormap = XCreateColormap(_display, root_window,
1396 visual->visual, AllocNone);
1403 void x11GraphicsWindow::
1405 #ifdef PHAVE_LINUX_INPUT_H
1406 bool any_present =
false;
1407 bool any_mice =
false;
1409 for (
int i=0; i<64; i++) {
1411 fnb <<
"/dev/input/event" << i;
1412 string fn = fnb.str();
1413 int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
1415 EvdevInputDevice *device =
new EvdevInputDevice(
nullptr, fd);
1416 nassertd(device != NULL)
continue;
1418 if (device->has_pointer()) {
1419 add_input_device(device);
1421 x11display_cat.info()
1422 <<
"Raw mouse " << _input_devices.size()
1423 <<
" detected: " << device->get_name() <<
"\n";
1429 if (errno == ENOENT || errno == ENOTDIR) {
1433 x11display_cat.error()
1434 <<
"Opening raw mice: " << strerror(errno) <<
" " << fn <<
"\n";
1440 _properties.set_raw_mice(
true);
1442 }
else if (!any_present) {
1443 x11display_cat.error() <<
1444 "Opening raw mice: files not found: /dev/input/event*\n";
1447 x11display_cat.error() <<
1448 "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
1451 x11display_cat.error() <<
1452 "Opening raw mice: panda not compiled with raw mouse support.\n";
1459 void x11GraphicsWindow::
1460 handle_keystroke(XKeyEvent &event) {
1461 if (!_dga_mouse_enabled) {
1467 static const int buffer_size = 256;
1468 wchar_t buffer[buffer_size];
1470 int len = XwcLookupString(_ic, &event, buffer, buffer_size,
nullptr,
1472 if (status == XBufferOverflow) {
1473 x11display_cat.error()
1474 <<
"Overflowed input buffer.\n";
1478 for (
int i = 0; i < len; i++) {
1494 void x11GraphicsWindow::
1495 handle_keypress(XKeyEvent &event) {
1496 if (!_dga_mouse_enabled) {
1502 if (button != ButtonHandle::none()) {
1503 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1506 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1509 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1512 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1522 void x11GraphicsWindow::
1523 handle_keyrelease(XKeyEvent &event) {
1524 if (!_dga_mouse_enabled) {
1530 if (button != ButtonHandle::none()) {
1531 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1532 _input->
button_up(KeyboardButton::control());
1534 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1535 _input->
button_up(KeyboardButton::shift());
1537 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1538 _input->
button_up(KeyboardButton::alt());
1540 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1541 _input->
button_up(KeyboardButton::meta());
1552 get_button(XKeyEvent &key_event,
bool allow_shift) {
1553 KeySym key = XLookupKeysym(&key_event, 0);
1555 if ((key_event.state & Mod2Mask) != 0) {
1570 case XK_KP_Multiply:
1572 case XK_KP_Separator:
1573 case XK_KP_Subtract:
1596 k2 = XLookupKeysym(&key_event, 1);
1597 button = map_button(k2);
1598 if (button != ButtonHandle::none()) {
1612 if ((key_event.state & ShiftMask) != 0) {
1613 KeySym k2 = XLookupKeysym(&key_event, 1);
1615 if (button != ButtonHandle::none()) {
1623 if ((key_event.state & (ShiftMask | LockMask)) != 0) {
1624 if (key >= XK_a && key <= XK_z) {
1625 key += (XK_A - XK_a);
1630 return map_button(key);
1638 map_button(KeySym key)
const {
1641 return ButtonHandle::none();
1643 return KeyboardButton::backspace();
1646 return KeyboardButton::tab();
1649 return KeyboardButton::enter();
1651 return KeyboardButton::escape();
1654 return KeyboardButton::space();
1675 case XK_KP_Multiply:
1681 case XK_KP_Separator:
1684 case XK_KP_Subtract:
1789 case XK_bracketleft:
1793 case XK_bracketright:
1795 case XK_asciicircum:
1864 return KeyboardButton::f1();
1867 return KeyboardButton::f2();
1870 return KeyboardButton::f3();
1873 return KeyboardButton::f4();
1875 return KeyboardButton::f5();
1877 return KeyboardButton::f6();
1879 return KeyboardButton::f7();
1881 return KeyboardButton::f8();
1883 return KeyboardButton::f9();
1885 return KeyboardButton::f10();
1887 return KeyboardButton::f11();
1889 return KeyboardButton::f12();
1892 return KeyboardButton::left();
1895 return KeyboardButton::up();
1898 return KeyboardButton::right();
1901 return KeyboardButton::down();
1904 return KeyboardButton::page_up();
1907 return KeyboardButton::page_down();
1910 return KeyboardButton::home();
1913 return KeyboardButton::end();
1916 return KeyboardButton::insert();
1919 return KeyboardButton::del();
1921 return KeyboardButton::num_lock();
1922 case XK_Scroll_Lock:
1923 return KeyboardButton::scroll_lock();
1925 return KeyboardButton::print_screen();
1927 return KeyboardButton::pause();
1929 return KeyboardButton::menu();
1931 return KeyboardButton::lshift();
1933 return KeyboardButton::rshift();
1935 return KeyboardButton::lcontrol();
1937 return KeyboardButton::rcontrol();
1939 return KeyboardButton::lalt();
1941 return KeyboardButton::ralt();
1944 return KeyboardButton::lmeta();
1947 return KeyboardButton::rmeta();
1949 return KeyboardButton::caps_lock();
1951 return KeyboardButton::shift_lock();
1953 if (x11display_cat.is_debug()) {
1954 x11display_cat.debug()
1955 <<
"Unrecognized keysym 0x" << std::hex << key << std::dec <<
"\n";
1957 return ButtonHandle::none();
1964 map_raw_button(KeyCode key)
const {
1965 #ifdef PHAVE_LINUX_INPUT_H
1970 int index = key - 8;
1971 if (index > 0 && index < 128) {
1972 return EvdevInputDevice::map_button(index);
1975 return ButtonHandle::none();
1983 get_mouse_button(XButtonEvent &button_event) {
1984 int index = button_event.button;
1985 if (index == x_wheel_up_button) {
1987 }
else if (index == x_wheel_down_button) {
1989 }
else if (index == x_wheel_left_button) {
1991 }
else if (index == x_wheel_right_button) {
2003 get_keyboard_map()
const {
2010 for (
int k = 9; k <= 135; ++k) {
2011 if (k >= 78 && k <= 91) {
2019 if (raw_button == ButtonHandle::none()) {
2023 KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0);
2029 if (sym >= XK_exclam && sym <= XK_asciitilde) {
2030 label = toupper((
char)sym);
2032 else if (sym >= XK_F1 && sym <= XK_F35) {
2033 label =
"F" + format_string(sym - XK_F1 + 1);
2035 else if (sym > 0x1000000 && sym < 0x1110000) {
2037 char32_t ch = sym & 0x0ffffff;
2038 if ((ch & ~0x7f) == 0) {
2039 label = string(1, (
char)ch);
2041 else if ((ch & ~0x7ff) == 0) {
2043 string(1, (
char)((ch >> 6) | 0xc0)) +
2044 string(1, (
char)((ch & 0x3f) | 0x80));
2046 else if ((ch & ~0xffff) == 0) {
2048 string(1, (
char)((ch >> 12) | 0xe0)) +
2049 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2050 string(1, (
char)((ch & 0x3f) | 0x80));
2054 string(1, (
char)((ch >> 18) | 0xf0)) +
2055 string(1, (
char)(((ch >> 12) & 0x3f) | 0x80)) +
2056 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2057 string(1, (
char)((ch & 0x3f) | 0x80));
2060 else if ((sym >= XK_exclamdown && sym <= XK_umacron)
2061 || (sym >= XK_OE && sym <= XK_Ydiaeresis)
2062 || (sym >= XK_Serbian_dje && sym <= XK_Cyrillic_HARDSIGN)
2063 || (sym >= XK_kana_fullstop && sym <= XK_semivoicedsound)
2064 || (sym >= XK_Arabic_comma && sym <= XK_Arabic_sukun)
2065 || (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_omega)
2066 || (sym >= XK_hebrew_doublelowline && sym <= XK_hebrew_taw)
2067 || (sym >= XK_Thai_kokai && sym <= XK_Thai_lekkao)
2068 || (sym >= XK_Hangul_Kiyeog && sym <= XK_Hangul_J_YeorinHieuh)
2069 || sym == XK_EuroSign
2070 || sym == XK_Korean_Won) {
2073 int nbytes = XkbTranslateKeySym(_display, &sym, 0, buffer, 255, 0);
2075 label.assign(buffer, nbytes);
2079 if (button == ButtonHandle::none() && label.empty()) {
2094 Bool x11GraphicsWindow::
2095 check_event(X11_Display *display, XEvent *event,
char *arg) {
2099 return (event->xany.window == self->_xwindow);
2106 X11_Cursor x11GraphicsWindow::
2107 get_cursor(
const Filename &filename) {
2109 DCAST_INTO_R(x11_pipe, _pipe, None);
2111 if (x11_pipe->_xcursor_size == -1) {
2112 x11display_cat.info()
2113 <<
"libXcursor.so.1 not available; cannot change mouse cursor.\n";
2119 if (fi != _cursor_filenames.end()) {
2128 x11display_cat.warning()
2129 <<
"Could not find cursor filename " << filename <<
"\n";
2132 fi = _cursor_filenames.find(resolved);
2133 if (fi != _cursor_filenames.end()) {
2139 if (str ==
nullptr) {
2140 x11display_cat.warning()
2141 <<
"Could not open cursor file " << filename <<
"\n";
2147 str->read(magic, 4);
2149 x11display_cat.warning()
2150 <<
"Could not read from cursor file " << filename <<
"\n";
2156 str->putback(magic[3]);
2157 str->putback(magic[2]);
2158 str->putback(magic[1]);
2159 str->putback(magic[0]);
2161 X11_Cursor h = None;
2162 if (memcmp(magic,
"Xcur", 4) == 0) {
2164 x11display_cat.debug()
2165 <<
"Loading X11 cursor " << filename <<
"\n";
2167 xcfile.closure = str;
2168 xcfile.read = &xcursor_read;
2169 xcfile.write = &xcursor_write;
2170 xcfile.seek = &xcursor_seek;
2172 XcursorImages *images = x11_pipe->_XcursorXcFileLoadImages(&xcfile, x11_pipe->_xcursor_size);
2173 if (images !=
nullptr) {
2174 h = x11_pipe->_XcursorImagesLoadCursor(_display, images);
2175 x11_pipe->_XcursorImagesDestroy(images);
2178 }
else if (memcmp(magic,
"\0\0\1\0", 4) == 0
2179 || memcmp(magic,
"\0\0\2\0", 4) == 0) {
2181 x11display_cat.debug()
2182 <<
"Loading Windows cursor " << filename <<
"\n";
2190 x11display_cat.warning()
2191 <<
"X11 cursor filename '" << resolved <<
"' could not be loaded!\n";
2194 _cursor_filenames[resolved] = h;
2202 X11_Cursor x11GraphicsWindow::
2203 read_ico(istream &ico) {
2205 DCAST_INTO_R(x11_pipe, _pipe, None);
2209 uint16_t reserved, type, count;
2213 uint8_t width, height, colorCount, reserved;
2214 uint16_t xhot, yhot;
2215 uint32_t bitmapSize, offset;
2219 uint32_t headerSize, width, height;
2220 uint16_t planes, bitsPerPixel;
2221 uint32_t compression, imageSize, xPixelsPerM, yPixelsPerM, colorsUsed, colorsImportant;
2225 uint8_t blue, green, red, reserved;
2229 unsigned int j, k, mask, shift;
2230 size_t colorCount, bitsPerPixel;
2232 IcoInfoHeader infoHeader;
2233 IcoEntry *entries =
nullptr;
2234 IcoColor color, *palette =
nullptr;
2236 size_t xorBmpSize, andBmpSize;
2237 char *curXor, *curAnd;
2238 char *xorBmp =
nullptr, *andBmp =
nullptr;
2239 XcursorImage *image =
nullptr;
2240 X11_Cursor ret = None;
2242 int def_size = x11_pipe->_xcursor_size;
2245 ico.read(
reinterpret_cast<char *
>(&header),
sizeof(IcoHeader));
2246 if (!ico.good())
goto cleanup;
2247 if (header.type != 1 && header.type != 2)
goto cleanup;
2248 if (header.count < 1)
goto cleanup;
2251 entries =
new IcoEntry[header.count];
2252 ico.read(
reinterpret_cast<char *
>(entries), header.count *
sizeof(IcoEntry));
2253 if (!ico.good())
goto cleanup;
2254 for (i = 1; i < header.count; i++) {
2255 if (entries[i].width == def_size && entries[i].height == def_size) {
2260 if (entries[i].width > entries[entry].width ||
2261 entries[i].height > entries[entry].height)
2266 ico.seekg(entries[entry].offset);
2267 if (!ico.good())
goto cleanup;
2269 if (ico.peek() == 0x89) {
2283 unsigned int *dest = image->pixels;
2285 if (alpha !=
nullptr) {
2286 for (
size_t p = 0; p < num_pixels; ++p) {
2287 *dest++ = (*alpha << 24U) | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2292 for (
size_t p = 0; p < num_pixels; ++p) {
2293 *dest++ = 0xff000000U | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2299 ico.read(
reinterpret_cast<char *
>(&infoHeader),
sizeof(IcoInfoHeader));
2300 if (!ico.good())
goto cleanup;
2301 bitsPerPixel = infoHeader.bitsPerPixel;
2303 if (infoHeader.compression != 0)
goto cleanup;
2306 if (bitsPerPixel != 24 && bitsPerPixel != 32) {
2307 colorCount = 1 << bitsPerPixel;
2308 palette =
new IcoColor[colorCount];
2309 ico.read(
reinterpret_cast<char *
>(palette), colorCount *
sizeof(IcoColor));
2310 if (!ico.good())
goto cleanup;
2313 int and_stride = ((infoHeader.width >> 3) + 3) & ~0x03;
2316 xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8;
2317 andBmpSize = and_stride * (infoHeader.height / 2);
2318 curXor = xorBmp =
new char[xorBmpSize];
2319 curAnd = andBmp =
new char[andBmpSize];
2320 ico.read(xorBmp, xorBmpSize);
2321 if (!ico.good())
goto cleanup;
2322 ico.read(andBmp, andBmpSize);
2323 if (!ico.good())
goto cleanup;
2325 image = x11_pipe->_XcursorImageCreate(infoHeader.width, infoHeader.height / 2);
2328 switch (bitsPerPixel) {
2334 mask = ((1 << bitsPerPixel) - 1);
2335 for (i = image->height - 1; i >= 0; i--) {
2336 for (j = 0; j < image->width; j += 8 / bitsPerPixel) {
2337 for (k = 0; k < 8 / bitsPerPixel; k++) {
2338 shift = 8 - ((k + 1) * bitsPerPixel);
2339 color = palette[(*curXor & (mask << shift)) >> shift];
2340 image->pixels[(i * image->width) + j + k] = (color.red << 16) +
2341 (color.green << 8) +
2349 for (j = 0; j < image->width; j += 8) {
2350 for (k = 0; k < 8; k++) {
2352 image->pixels[(i * image->width) + j + k] |=
2353 ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24);
2363 for (i = image->height - 1; i >= 0; i--) {
2364 for (j = 0; j < image->width; j++) {
2365 shift = 7 - (j & 0x7);
2366 uint32_t alpha = (curAnd[j >> 3] & (1 << shift)) ? 0 : 0xff000000U;
2367 image->pixels[(i * image->width) + j] = (uint8_t)curXor[0]
2368 | ((uint8_t)curXor[1] << 8u)
2369 | ((uint8_t)curXor[2] << 16u)
2373 curAnd += and_stride;
2379 for (i = image->height - 1; i >= 0; i--) {
2380 for (j = 0; j < image->width; j++) {
2381 image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) +
2382 (*(curXor + 2) << 16) +
2383 (*(curXor + 1) << 8) +
2396 if (header.type == 2) {
2397 image->xhot = entries[entry].xhot;
2398 image->yhot = entries[entry].yhot;
2404 ret = x11_pipe->_XcursorImageLoadCursor(_display, image);
2407 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.