38using std::ostringstream;
43 int (*read)(XcursorFile *,
unsigned char *, int);
44 int (*write)(XcursorFile *,
unsigned char *, int);
45 int (*seek)(XcursorFile *, long, int);
48typedef struct _XcursorImage {
59static int xcursor_read(XcursorFile *file,
unsigned char *buf,
int len) {
60 istream* str = (istream*) file->closure;
61 str->read((
char*) buf, len);
65static int xcursor_write(XcursorFile *file,
unsigned char *buf,
int len) {
67 nassertr_always(
false, 0);
71static 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_since = -1;
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() {
145 nassertr(device >= 0 && device < (
int)_input_devices.size(),
MouseData());
151 if (device == 0 && !_dga_mouse_enabled && result._in_window &&
152 x11GraphicsPipe::_x_mutex.
try_lock()) {
154 if (_xwindow != None &&
155 XQueryPointer(_display, _xwindow, &event.xbutton.root,
156 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
157 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state)) {
159 result._xpos =
event.xbutton.x;
160 result._ypos =
event.xbutton.y;
163 x11GraphicsPipe::_x_mutex.
release();
190 if (!md.
get_in_window() || md.get_x() != x || md.get_y() != y) {
191 if (!_dga_mouse_enabled) {
193 XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
229 PStatTimer timer(_make_current_pcollector, current_thread);
231 begin_frame_spam(mode);
232 if (_gsg ==
nullptr) {
235 if (_awaiting_configure_since != -1) {
244 _gsg->reset_if_new();
246 if (mode == FM_render) {
248 clear_cube_map_selection();
252 return _gsg->begin_frame(current_thread);
262 end_frame_spam(mode);
263 nassertv(_gsg !=
nullptr);
265 if (mode == FM_render) {
270 _gsg->end_frame(current_thread);
272 if (mode == FM_render) {
274 clear_cube_map_selection();
291 if (_xwindow == (X11_Window)0) {
296 XKeyEvent keyrelease_event;
297 bool got_keyrelease_event =
false;
299 XConfigureEvent configure_event;
300 bool got_configure_event =
false;
303 bool changed_properties =
false;
305 while (XCheckIfEvent(_display, &event, check_event, (
char *)
this)) {
306 if (got_keyrelease_event) {
311 got_keyrelease_event =
false;
313 if (event.type == KeyPress &&
314 event.xkey.keycode == keyrelease_event.keycode &&
315 (event.xkey.time - keyrelease_event.time <= 1)) {
316 if (!XFilterEvent(&event, None)) {
319 handle_keystroke(event.xkey);
323 handle_keypress(event.xkey);
330 ButtonHandle raw_button = map_raw_button(keyrelease_event.keycode);
331 if (raw_button != ButtonHandle::none()) {
335 handle_keyrelease(keyrelease_event);
341 if (event.type == KeyPress) {
342 ButtonHandle raw_button = map_raw_button(event.xkey.keycode);
343 if (raw_button != ButtonHandle::none()) {
348 if (XFilterEvent(&event, None)) {
354 switch (event.type) {
358 case ConfigureNotify:
361 configure_event =
event.xconfigure;
362 got_configure_event =
true;
367 button = get_mouse_button(event.xbutton);
368 if (!_dga_mouse_enabled) {
375 button = get_mouse_button(event.xbutton);
376 if (!_dga_mouse_enabled) {
383 if (_dga_mouse_enabled) {
392 handle_keystroke(event.xkey);
393 handle_keypress(event.xkey);
400 keyrelease_event =
event.xkey;
401 got_keyrelease_event =
true;
405 if (_dga_mouse_enabled) {
419 changed_properties =
true;
425 changed_properties =
true;
430 changed_properties =
true;
435 changed_properties =
true;
438 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
442 if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
446 if (!close_request_event.empty()) {
449 throw_event(close_request_event);
458 system_changed_properties(properties);
466 x11display_cat.info()
467 <<
"DestroyNotify\n";
471 x11display_cat.warning()
472 <<
"unhandled X event type " <<
event.type <<
"\n";
476 if (got_configure_event) {
478 if (x11display_cat.is_debug() && _awaiting_configure_since != -1) {
479 unsigned long elapsed = (
unsigned long)(clock() - _awaiting_configure_since) / (CLOCKS_PER_SEC / 10000);
480 x11display_cat.debug()
481 <<
"Received ConfigureNotify event after "
482 << (elapsed / 10) <<
"." << (elapsed % 10) <<
" ms\n";
485 _awaiting_configure_since = -1;
492 properties.
set_origin(configure_event.x, configure_event.y);
493 properties.
set_size(configure_event.width, configure_event.height);
495 if (_properties.get_fixed_size()) {
501 if (configure_event.width != _fixed_size.get_x() ||
502 configure_event.height != _fixed_size.get_y()) {
503 XWindowChanges changes;
504 changes.width = _fixed_size.get_x();
505 changes.height = _fixed_size.get_y();
506 int value_mask = (CWWidth | CWHeight);
507 XConfigureWindow(_display, _xwindow, value_mask, &changes);
513 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
514 X11_Cursor cursor = None;
515 if (_properties.get_cursor_hidden()) {
517 DCAST_INTO_V(x11_pipe, _pipe);
521 XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
522 _xwindow, cursor, CurrentTime);
525 changed_properties =
true;
527 else if (_awaiting_configure_since != -1) {
528 unsigned long elapsed = (clock() - _awaiting_configure_since);
529 if (elapsed > CLOCKS_PER_SEC / 10) {
531 if (x11display_cat.is_debug()) {
532 elapsed /= (CLOCKS_PER_SEC / 10000);
533 x11display_cat.debug()
534 <<
"Giving up on waiting for ConfigureNotify event after "
535 << (elapsed / 10) <<
"." << (elapsed % 10) <<
" ms\n";
537 _awaiting_configure_since = -1;
542 _properties.get_mouse_mode() == WindowProperties::M_confined ||
543 _dga_mouse_enabled)) {
545 DCAST_INTO_V(x11_pipe, _pipe);
550 X11_Cursor cursor = None;
551 if (_properties.get_cursor_hidden()) {
555 XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
556 _xwindow, cursor, CurrentTime);
557 if (_dga_mouse_enabled) {
563 if (_dga_mouse_enabled) {
565 }
else if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
566 XUngrabPointer(_display, CurrentTime);
571 if (changed_properties) {
572 system_changed_properties(properties);
575 if (got_keyrelease_event) {
578 ButtonHandle raw_button = map_raw_button(keyrelease_event.keycode);
579 if (raw_button != ButtonHandle::none()) {
583 handle_keyrelease(keyrelease_event);
601 if (_pipe ==
nullptr) {
608 DCAST_INTO_V(x11_pipe, _pipe);
614 bool is_fullscreen = _properties.has_fullscreen() && _properties.get_fullscreen();
617 if (want_fullscreen && properties.
has_origin()) {
623 if (want_fullscreen) {
627 LPoint2i center(0, 0);
628 if (_properties.has_origin()) {
629 center = _properties.get_origin();
630 if (_properties.has_size()) {
631 center += _properties.get_size() / 2;
634 int x, y, width, height;
638 int reqsizex, reqsizey;
642 }
else if (_properties.has_size()) {
643 reqsizex = _properties.get_x_size();
644 reqsizey = _properties.get_y_size();
656 || (width == reqsizex && height == reqsizey)
657 || !x11_pipe->_have_xrandr) {
663 if (x11display_cat.is_debug()) {
664 x11display_cat.debug()
665 <<
"Setting window to fullscreen on CRTC "
666 << width <<
"x" << height <<
"+" << x <<
"+" << y <<
"\n";
672 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, _xwindow ? _xwindow : x11_pipe->
get_root());
673 SizeID old_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation);
674 SizeID new_size_id = (SizeID) -1;
678 xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes);
679 for (
int i = 0; i < num_sizes; ++i) {
680 if (xrrs[i].width == reqsizex &&
681 xrrs[i].height == reqsizey) {
685 if (new_size_id == (SizeID) -1) {
686 x11display_cat.error()
687 <<
"Videocard has no supported display resolutions at specified res ("
688 << reqsizex <<
" x " << reqsizey <<
")\n";
694 if (x11display_cat.is_debug()) {
695 x11display_cat.debug()
696 <<
"Switching to fullscreen with resolution "
697 << reqsizex <<
"x" << reqsizey <<
"\n";
700 if (new_size_id != old_size_id) {
701 _XRRSetScreenConfig(_display, conf, x11_pipe->
get_root(), new_size_id, _orig_rotation, CurrentTime);
702 if (_orig_size_id == (SizeID) -1) {
704 _orig_size_id = old_size_id;
716 if (_orig_size_id != (SizeID) -1) {
717 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, x11_pipe->
get_root());
718 _XRRSetScreenConfig(_display, conf, x11_pipe->
get_root(), _orig_size_id, _orig_rotation, CurrentTime);
719 _orig_size_id = (SizeID) -1;
722 if (!properties.
has_origin() && _properties.has_origin()) {
723 properties.
set_origin(_properties.get_x_origin(), _properties.get_y_origin());
734 if (x_origin == -2) {
737 if (y_origin == -2) {
741 if (x_origin == -2) {
744 if (y_origin == -2) {
762 set_wm_properties(properties,
true);
767 _properties.set_title(properties.
get_title());
781 XWindowChanges changes;
784 if (_properties.get_fullscreen()) {
785 if (_properties.get_x_origin() != 0 ||
786 _properties.get_y_origin() != 0) {
789 value_mask |= CWX | CWY;
796 if (changes.x != -1) value_mask |= CWX;
797 if (changes.y != -1) value_mask |= CWY;
805 _fixed_size = _properties.get_size();
811 value_mask |= (CWWidth | CWHeight);
813 if (_properties.get_fixed_size()) {
814 _fixed_size = properties.
get_size();
825 case WindowProperties::Z_bottom:
826 changes.stack_mode = Below;
829 case WindowProperties::Z_normal:
830 changes.stack_mode = TopIf;
833 case WindowProperties::Z_top:
834 changes.stack_mode = Above;
838 value_mask |= (CWStackMode);
852 _properties.set_cursor_filename(cursor_filename);
856 _properties.set_cursor_filename(filename);
858 if (_properties.get_cursor_hidden()) {
861 }
else if (!cursor_filename.empty()) {
863 X11_Cursor cursor = get_cursor(cursor_filename);
864 XDefineCursor(_display, _xwindow, cursor);
867 XDefineCursor(_display, _xwindow, None);
871 if (!properties.has_mouse_mode() &&
872 _properties.get_mouse_mode() != WindowProperties::M_absolute) {
879 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
881 XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime);
886 if (properties.has_mouse_mode()) {
888 case WindowProperties::M_absolute:
889 XUngrabPointer(_display, CurrentTime);
890 if (_dga_mouse_enabled) {
892 _dga_mouse_enabled =
false;
894 _properties.set_mouse_mode(WindowProperties::M_absolute);
898 case WindowProperties::M_relative:
899 if (!_dga_mouse_enabled) {
901 X11_Cursor cursor = None;
902 if (_properties.get_cursor_hidden()) {
904 DCAST_INTO_V(x11_pipe, _pipe);
908 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
909 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
910 x11display_cat.error() <<
"Failed to grab pointer!\n";
914 _properties.set_mouse_mode(WindowProperties::M_relative);
916 _dga_mouse_enabled =
true;
921 XQueryPointer(_display, _xwindow, &event.xbutton.root,
922 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
923 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
927 x11display_cat.warning()
928 <<
"XF86DGA extension not available, cannot enable relative mouse mode\n";
929 _dga_mouse_enabled =
false;
934 case WindowProperties::M_confined:
937 DCAST_INTO_V(x11_pipe, _pipe);
939 if (_dga_mouse_enabled) {
941 _dga_mouse_enabled =
false;
943 X11_Cursor cursor = None;
944 if (_properties.get_cursor_hidden()) {
948 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
949 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
950 x11display_cat.error() <<
"Failed to grab pointer!\n";
952 _properties.set_mouse_mode(WindowProperties::M_confined);
960 if (value_mask != 0) {
963 XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
966 _awaiting_configure_since = clock();
973void x11GraphicsWindow::
974mouse_mode_absolute() {
981void x11GraphicsWindow::
982mouse_mode_relative() {
989void x11GraphicsWindow::
991 if (_gsg !=
nullptr) {
996 if (_ic != (XIC)
nullptr) {
1001 if (_xwindow != (X11_Window)
nullptr) {
1002 XDestroyWindow(_display, _xwindow);
1003 _xwindow = (X11_Window)
nullptr;
1012 if (_orig_size_id != (SizeID) -1) {
1014 if (_pipe !=
nullptr) {
1016 DCAST_INTO_V(x11_pipe, _pipe);
1021 root = RootWindow(_display, _screen);
1023 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, root);
1024 _XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime);
1028 for (
auto item : _cursor_filenames) {
1029 XFreeCursor(_display, item.second);
1031 _cursor_filenames.clear();
1033 GraphicsWindow::close_window();
1040bool x11GraphicsWindow::
1042 if (_visual_info ==
nullptr) {
1044 x11display_cat.error()
1045 <<
"No X visual: cannot open window.\n";
1050 DCAST_INTO_R(x11_pipe, _pipe,
false);
1052 if (!_properties.has_origin()) {
1053 _properties.set_origin(0, 0);
1055 if (!_properties.has_size()) {
1056 _properties.set_size(100, 100);
1062 X11_Window parent_window = x11_pipe->
get_root();
1063 WindowHandle *window_handle = _properties.get_parent_window();
1064 if (window_handle !=
nullptr) {
1065 x11display_cat.info()
1066 <<
"Got parent_window " << *window_handle <<
"\n";
1068 if (os_handle !=
nullptr) {
1069 x11display_cat.info()
1070 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1072 if (os_handle->
is_of_type(NativeWindowHandle::X11Handle::get_class_type())) {
1073 NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle);
1074 parent_window = x11_handle->get_handle();
1075 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1077 parent_window = (X11_Window)int_handle->get_handle();
1081 _parent_window_handle = window_handle;
1084 ButtonPressMask | ButtonReleaseMask |
1085 KeyPressMask | KeyReleaseMask |
1086 EnterWindowMask | LeaveWindowMask |
1088 FocusChangeMask | StructureNotifyMask;
1091 XSetWindowAttributes wa;
1092 wa.background_pixel = XBlackPixel(_display, _screen);
1093 wa.border_pixel = 0;
1094 wa.colormap = _colormap;
1095 wa.event_mask = _event_mask;
1096 wa.override_redirect = _override_redirect;
1098 unsigned long attrib_mask =
1099 CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
1101 _xwindow = XCreateWindow
1102 (_display, parent_window,
1103 _properties.get_x_origin(), _properties.get_y_origin(),
1104 _properties.get_x_size(), _properties.get_y_size(),
1105 0, _visual_info->depth, InputOutput,
1106 _visual_info->visual, attrib_mask, &wa);
1108 if (_xwindow == (X11_Window)0) {
1109 x11display_cat.error()
1110 <<
"failed to create X window.\n";
1114 if (_properties.get_fixed_size()) {
1115 _fixed_size = _properties.get_size();
1118 set_wm_properties(_properties,
false);
1124 XIM im = x11_pipe->
get_im();
1127 _ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
1128 XNClientWindow, _xwindow,
nullptr);
1129 if (_ic == (XIC)
nullptr) {
1130 x11display_cat.warning()
1131 <<
"Couldn't create input context.\n";
1135 if (_properties.get_cursor_hidden()) {
1138 }
else if (_properties.has_cursor_filename() && !_properties.get_cursor_filename().empty()) {
1140 X11_Cursor cursor = get_cursor(_properties.get_cursor_filename());
1141 XDefineCursor(_display, _xwindow, cursor);
1144 XMapWindow(_display, _xwindow);
1146 if (_properties.get_raw_mice()) {
1149 if (x11display_cat.is_debug()) {
1150 x11display_cat.debug()
1151 <<
"Raw mice not requested.\n";
1156 _window_handle = NativeWindowHandle::make_x11(_xwindow);
1159 if (_parent_window_handle !=
nullptr) {
1160 _parent_window_handle->attach_child(_window_handle);
1178void x11GraphicsWindow::
1179set_wm_properties(
const WindowProperties &properties,
bool already_mapped) {
1181 DCAST_INTO_V(x11_pipe, _pipe);
1184 XTextProperty window_name;
1185 XTextProperty *window_name_p =
nullptr;
1187 const char *name = properties.
get_title().c_str();
1188 if (XStringListToTextProperty((
char **)&name, 1, &window_name) != 0) {
1189 window_name_p = &window_name;
1195 XSizeHints *size_hints_p =
nullptr;
1197 size_hints_p = XAllocSizeHints();
1198 if (size_hints_p !=
nullptr) {
1202 size_hints_p->flags |= USPosition;
1204 LVecBase2i size = _properties.get_size();
1207 size_hints_p->width = size.get_x();
1208 size_hints_p->height = size.get_y();
1209 size_hints_p->flags |= USSize;
1212 size_hints_p->min_width = size.get_x();
1213 size_hints_p->min_height = size.get_y();
1214 size_hints_p->max_width = size.get_x();
1215 size_hints_p->max_height = size.get_y();
1216 size_hints_p->flags |= (PMinSize | PMaxSize);
1223 XWMHints *wm_hints_p =
nullptr;
1224 wm_hints_p = XAllocWMHints();
1225 if (wm_hints_p !=
nullptr) {
1227 wm_hints_p->initial_state = IconicState;
1229 wm_hints_p->initial_state = NormalState;
1231 wm_hints_p->flags = StateHint;
1237 static const int max_type_data = 32;
1238 int32_t type_data[max_type_data];
1239 int next_type_data = 0;
1241 static const int max_state_data = 32;
1242 int32_t state_data[max_state_data];
1243 int next_state_data = 0;
1245 static const int max_set_data = 32;
1248 inline SetAction() { }
1249 inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
1253 SetAction set_data[max_set_data];
1254 int next_set_data = 0;
1260 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_fullscreen;
1263 state_data[next_state_data++] = x11_pipe->_net_wm_state_fullscreen;
1266 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 1);
1269 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 0);
1282 XClassHint *class_hints_p =
nullptr;
1283 if (!x_wm_class.empty()) {
1285 class_hints_p = XAllocClassHint();
1286 class_hints_p->res_class = (
char*) x_wm_class.c_str();
1287 if (!x_wm_class_name.empty()) {
1288 class_hints_p->res_name = (
char*) x_wm_class_name.c_str();
1292 class_hints_p = XAllocClassHint();
1293 class_hints_p->res_class = (
char*)
"Undecorated";
1297 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_splash;
1302 case WindowProperties::Z_bottom:
1303 state_data[next_state_data++] = x11_pipe->_net_wm_state_below;
1304 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1305 x11_pipe->_net_wm_state_add);
1306 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1307 x11_pipe->_net_wm_state_remove);
1310 case WindowProperties::Z_normal:
1311 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1312 x11_pipe->_net_wm_state_remove);
1313 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1314 x11_pipe->_net_wm_state_remove);
1317 case WindowProperties::Z_top:
1318 state_data[next_state_data++] = x11_pipe->_net_wm_state_above;
1319 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1320 x11_pipe->_net_wm_state_remove);
1321 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1322 x11_pipe->_net_wm_state_add);
1327 nassertv(next_type_data < max_type_data);
1328 nassertv(next_state_data < max_state_data);
1329 nassertv(next_set_data < max_set_data);
1332 int32_t pid = getpid();
1333 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_pid,
1334 XA_CARDINAL, 32, PropModeReplace,
1335 (
unsigned char *)&pid, 1);
1340 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_bypass_compositor,
1341 XA_CARDINAL, 32, PropModeReplace,
1342 (
unsigned char *)&compositor, 1);
1345 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_window_type,
1346 XA_ATOM, 32, PropModeReplace,
1347 (
unsigned char *)type_data, next_type_data);
1350 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_state,
1351 XA_ATOM, 32, PropModeReplace,
1352 (
unsigned char *)state_data, next_state_data);
1354 if (already_mapped) {
1360 DCAST_INTO_V(x11_pipe, _pipe);
1362 for (
int i = 0; i < next_set_data; ++i) {
1363 XClientMessageEvent event;
1364 memset(&event, 0,
sizeof(event));
1365 event.type = ClientMessage;
1366 event.send_event = True;
1367 event.display = _display;
1368 event.window = _xwindow;
1369 event.message_type = x11_pipe->_net_wm_state;
1371 event.data.l[0] = set_data[i]._action;
1372 event.data.l[1] = set_data[i]._state;
1373 event.data.l[2] = 0;
1374 event.data.l[3] = 1;
1376 XSendEvent(_display, x11_pipe->
get_root(), True, SubstructureNotifyMask | SubstructureRedirectMask, (XEvent *)&event);
1380 XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
1381 nullptr, 0, size_hints_p, wm_hints_p, class_hints_p);
1383 if (size_hints_p !=
nullptr) {
1384 XFree(size_hints_p);
1386 if (wm_hints_p !=
nullptr) {
1389 if (class_hints_p !=
nullptr) {
1390 XFree(class_hints_p);
1396 Atom protocols[] = {
1400 XSetWMProtocols(_display, _xwindow, protocols,
1401 sizeof(protocols) /
sizeof(Atom));
1408void x11GraphicsWindow::
1409setup_colormap(XVisualInfo *visual) {
1411 DCAST_INTO_V(x11_pipe, _pipe);
1412 X11_Window root_window = x11_pipe->
get_root();
1414 _colormap = XCreateColormap(_display, root_window,
1415 visual->visual, AllocNone);
1422void x11GraphicsWindow::
1424#ifdef PHAVE_LINUX_INPUT_H
1425 bool any_present =
false;
1426 bool any_mice =
false;
1428 for (
int i=0; i<64; i++) {
1430 fnb <<
"/dev/input/event" << i;
1431 string fn = fnb.str();
1432 int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
1434 EvdevInputDevice *device =
new EvdevInputDevice(
nullptr, fd);
1435 nassertd(device != NULL)
continue;
1437 if (device->has_pointer()) {
1438 add_input_device(device);
1440 x11display_cat.info()
1441 <<
"Raw mouse " << _input_devices.size()
1442 <<
" detected: " << device->get_name() <<
"\n";
1448 if (errno == ENOENT || errno == ENOTDIR) {
1452 x11display_cat.error()
1453 <<
"Opening raw mice: " << strerror(errno) <<
" " << fn <<
"\n";
1459 _properties.set_raw_mice(
true);
1461 }
else if (!any_present) {
1462 x11display_cat.error() <<
1463 "Opening raw mice: files not found: /dev/input/event*\n";
1466 x11display_cat.error() <<
1467 "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
1470 x11display_cat.error() <<
1471 "Opening raw mice: panda not compiled with raw mouse support.\n";
1478void x11GraphicsWindow::
1479handle_keystroke(XKeyEvent &event) {
1480 if (!_dga_mouse_enabled) {
1486 static const int buffer_size = 256;
1487 wchar_t buffer[buffer_size];
1489 int len = XwcLookupString(_ic, &event, buffer, buffer_size,
nullptr,
1491 if (status == XBufferOverflow) {
1492 x11display_cat.error()
1493 <<
"Overflowed input buffer.\n";
1497 for (
int i = 0; i < len; i++) {
1513void x11GraphicsWindow::
1514handle_keypress(XKeyEvent &event) {
1515 if (!_dga_mouse_enabled) {
1521 if (button != ButtonHandle::none()) {
1522 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1525 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1528 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1531 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1541void x11GraphicsWindow::
1542handle_keyrelease(XKeyEvent &event) {
1543 if (!_dga_mouse_enabled) {
1549 if (button != ButtonHandle::none()) {
1550 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1551 _input->
button_up(KeyboardButton::control());
1553 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1554 _input->
button_up(KeyboardButton::shift());
1556 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1557 _input->
button_up(KeyboardButton::alt());
1559 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1560 _input->
button_up(KeyboardButton::meta());
1571get_button(XKeyEvent &key_event,
bool allow_shift) {
1572 KeySym key = XLookupKeysym(&key_event, 0);
1574 if ((key_event.state & Mod2Mask) != 0) {
1589 case XK_KP_Multiply:
1591 case XK_KP_Separator:
1592 case XK_KP_Subtract:
1615 k2 = XLookupKeysym(&key_event, 1);
1616 button = map_button(k2);
1617 if (button != ButtonHandle::none()) {
1631 if ((key_event.state & ShiftMask) != 0) {
1632 KeySym k2 = XLookupKeysym(&key_event, 1);
1634 if (button != ButtonHandle::none()) {
1642 if ((key_event.state & (ShiftMask | LockMask)) != 0) {
1643 if (key >= XK_a && key <= XK_z) {
1644 key += (XK_A - XK_a);
1649 return map_button(key);
1657map_button(KeySym key)
const {
1660 return ButtonHandle::none();
1662 return KeyboardButton::backspace();
1665 return KeyboardButton::tab();
1668 return KeyboardButton::enter();
1670 return KeyboardButton::escape();
1673 return KeyboardButton::space();
1694 case XK_KP_Multiply:
1700 case XK_KP_Separator:
1703 case XK_KP_Subtract:
1808 case XK_bracketleft:
1812 case XK_bracketright:
1814 case XK_asciicircum:
1883 return KeyboardButton::f1();
1886 return KeyboardButton::f2();
1889 return KeyboardButton::f3();
1892 return KeyboardButton::f4();
1894 return KeyboardButton::f5();
1896 return KeyboardButton::f6();
1898 return KeyboardButton::f7();
1900 return KeyboardButton::f8();
1902 return KeyboardButton::f9();
1904 return KeyboardButton::f10();
1906 return KeyboardButton::f11();
1908 return KeyboardButton::f12();
1911 return KeyboardButton::left();
1914 return KeyboardButton::up();
1917 return KeyboardButton::right();
1920 return KeyboardButton::down();
1923 return KeyboardButton::page_up();
1926 return KeyboardButton::page_down();
1929 return KeyboardButton::home();
1932 return KeyboardButton::end();
1935 return KeyboardButton::insert();
1938 return KeyboardButton::del();
1940 return KeyboardButton::num_lock();
1941 case XK_Scroll_Lock:
1942 return KeyboardButton::scroll_lock();
1944 return KeyboardButton::print_screen();
1946 return KeyboardButton::pause();
1948 return KeyboardButton::menu();
1950 return KeyboardButton::lshift();
1952 return KeyboardButton::rshift();
1954 return KeyboardButton::lcontrol();
1956 return KeyboardButton::rcontrol();
1958 return KeyboardButton::lalt();
1960 return KeyboardButton::ralt();
1963 return KeyboardButton::lmeta();
1966 return KeyboardButton::rmeta();
1968 return KeyboardButton::caps_lock();
1970 return KeyboardButton::shift_lock();
1972 if (x11display_cat.is_debug()) {
1973 x11display_cat.debug()
1974 <<
"Unrecognized keysym 0x" << std::hex << key << std::dec <<
"\n";
1976 return ButtonHandle::none();
1983map_raw_button(KeyCode key)
const {
1984#ifdef PHAVE_LINUX_INPUT_H
1989 int index = key - 8;
1990 if (index > 0 && index < 128) {
1991 return EvdevInputDevice::map_button(index);
1994 return ButtonHandle::none();
2002get_mouse_button(XButtonEvent &button_event) {
2003 int index = button_event.button;
2004 if (index == x_wheel_up_button) {
2006 }
else if (index == x_wheel_down_button) {
2008 }
else if (index == x_wheel_left_button) {
2010 }
else if (index == x_wheel_right_button) {
2012 }
else if (index >= 8) {
2024get_keyboard_map()
const {
2031 for (
int k = 9; k <= 135; ++k) {
2032 if (k >= 78 && k <= 91) {
2040 if (raw_button == ButtonHandle::none()) {
2044 KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0);
2050 if (sym >= XK_exclam && sym <= XK_asciitilde) {
2051 label = toupper((
char)sym);
2053 else if (sym >= XK_F1 && sym <= XK_F35) {
2054 label =
"F" + format_string(sym - XK_F1 + 1);
2056 else if (sym > 0x1000000 && sym < 0x1110000) {
2058 char32_t ch = sym & 0x0ffffff;
2059 if ((ch & ~0x7f) == 0) {
2060 label = string(1, (
char)ch);
2062 else if ((ch & ~0x7ff) == 0) {
2064 string(1, (
char)((ch >> 6) | 0xc0)) +
2065 string(1, (
char)((ch & 0x3f) | 0x80));
2067 else if ((ch & ~0xffff) == 0) {
2069 string(1, (
char)((ch >> 12) | 0xe0)) +
2070 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2071 string(1, (
char)((ch & 0x3f) | 0x80));
2075 string(1, (
char)((ch >> 18) | 0xf0)) +
2076 string(1, (
char)(((ch >> 12) & 0x3f) | 0x80)) +
2077 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2078 string(1, (
char)((ch & 0x3f) | 0x80));
2081 else if ((sym >= XK_exclamdown && sym <= XK_umacron)
2082 || (sym >= XK_OE && sym <= XK_Ydiaeresis)
2083 || (sym >= XK_Serbian_dje && sym <= XK_Cyrillic_HARDSIGN)
2084 || (sym >= XK_kana_fullstop && sym <= XK_semivoicedsound)
2085 || (sym >= XK_Arabic_comma && sym <= XK_Arabic_sukun)
2086 || (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_omega)
2087 || (sym >= XK_hebrew_doublelowline && sym <= XK_hebrew_taw)
2088 || (sym >= XK_Thai_kokai && sym <= XK_Thai_lekkao)
2089 || (sym >= XK_Hangul_Kiyeog && sym <= XK_Hangul_J_YeorinHieuh)
2090 || sym == XK_EuroSign
2091 || sym == XK_Korean_Won) {
2094 int nbytes = XkbTranslateKeySym(_display, &sym, 0, buffer, 255, 0);
2096 label.assign(buffer, nbytes);
2100 if (button == ButtonHandle::none() && label.empty()) {
2115Bool x11GraphicsWindow::
2116check_event(X11_Display *display, XEvent *event,
char *arg) {
2120 return (event->xany.window == self->_xwindow);
2127X11_Cursor x11GraphicsWindow::
2128get_cursor(
const Filename &filename) {
2130 DCAST_INTO_R(x11_pipe, _pipe, None);
2132 if (x11_pipe->_xcursor_size == -1) {
2133 x11display_cat.info()
2134 <<
"libXcursor.so.1 not available; cannot change mouse cursor.\n";
2140 if (fi != _cursor_filenames.end()) {
2149 x11display_cat.warning()
2150 <<
"Could not find cursor filename " << filename <<
"\n";
2153 fi = _cursor_filenames.find(resolved);
2154 if (fi != _cursor_filenames.end()) {
2160 if (str ==
nullptr) {
2161 x11display_cat.warning()
2162 <<
"Could not open cursor file " << filename <<
"\n";
2168 str->read(magic, 4);
2170 x11display_cat.warning()
2171 <<
"Could not read from cursor file " << filename <<
"\n";
2177 str->putback(magic[3]);
2178 str->putback(magic[2]);
2179 str->putback(magic[1]);
2180 str->putback(magic[0]);
2182 X11_Cursor h = None;
2183 if (memcmp(magic,
"Xcur", 4) == 0) {
2185 x11display_cat.debug()
2186 <<
"Loading X11 cursor " << filename <<
"\n";
2188 xcfile.closure = str;
2189 xcfile.read = &xcursor_read;
2190 xcfile.write = &xcursor_write;
2191 xcfile.seek = &xcursor_seek;
2193 XcursorImages *images = x11_pipe->_XcursorXcFileLoadImages(&xcfile, x11_pipe->_xcursor_size);
2194 if (images !=
nullptr) {
2195 h = x11_pipe->_XcursorImagesLoadCursor(_display, images);
2196 x11_pipe->_XcursorImagesDestroy(images);
2199 }
else if (memcmp(magic,
"\0\0\1\0", 4) == 0
2200 || memcmp(magic,
"\0\0\2\0", 4) == 0) {
2202 x11display_cat.debug()
2203 <<
"Loading Windows cursor " << filename <<
"\n";
2211 x11display_cat.warning()
2212 <<
"X11 cursor filename '" << resolved <<
"' could not be loaded!\n";
2215 _cursor_filenames[resolved] = h;
2223X11_Cursor x11GraphicsWindow::
2224read_ico(istream &ico) {
2226 DCAST_INTO_R(x11_pipe, _pipe, None);
2230 uint16_t reserved, type, count;
2234 uint8_t width, height, colorCount, reserved;
2235 uint16_t xhot, yhot;
2236 uint32_t bitmapSize, offset;
2240 uint32_t headerSize, width, height;
2241 uint16_t planes, bitsPerPixel;
2242 uint32_t compression, imageSize, xPixelsPerM, yPixelsPerM, colorsUsed, colorsImportant;
2246 uint8_t blue, green, red, reserved;
2250 unsigned int j, k, mask, shift;
2251 size_t colorCount, bitsPerPixel;
2253 IcoInfoHeader infoHeader;
2254 IcoEntry *entries =
nullptr;
2255 IcoColor color, *palette =
nullptr;
2257 size_t xorBmpSize, andBmpSize;
2258 char *curXor, *curAnd;
2259 char *xorBmp =
nullptr, *andBmp =
nullptr;
2260 XcursorImage *image =
nullptr;
2261 X11_Cursor ret = None;
2263 int def_size = x11_pipe->_xcursor_size;
2266 ico.read(
reinterpret_cast<char *
>(&header),
sizeof(IcoHeader));
2267 if (!ico.good())
goto cleanup;
2268 if (header.type != 1 && header.type != 2)
goto cleanup;
2269 if (header.count < 1)
goto cleanup;
2272 entries =
new IcoEntry[header.count];
2273 ico.read(
reinterpret_cast<char *
>(entries), header.count *
sizeof(IcoEntry));
2274 if (!ico.good())
goto cleanup;
2275 for (i = 1; i < header.count; i++) {
2276 if (entries[i].width == def_size && entries[i].height == def_size) {
2281 if (entries[i].width > entries[entry].width ||
2282 entries[i].height > entries[entry].height)
2287 ico.seekg(entries[entry].offset);
2288 if (!ico.good())
goto cleanup;
2290 if (ico.peek() == 0x89) {
2304 unsigned int *dest = image->pixels;
2306 if (alpha !=
nullptr) {
2307 for (
size_t p = 0; p < num_pixels; ++p) {
2308 *dest++ = (*alpha << 24U) | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2313 for (
size_t p = 0; p < num_pixels; ++p) {
2314 *dest++ = 0xff000000U | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2320 ico.read(
reinterpret_cast<char *
>(&infoHeader),
sizeof(IcoInfoHeader));
2321 if (!ico.good())
goto cleanup;
2322 bitsPerPixel = infoHeader.bitsPerPixel;
2324 if (infoHeader.compression != 0)
goto cleanup;
2327 if (bitsPerPixel != 24 && bitsPerPixel != 32) {
2328 colorCount = 1 << bitsPerPixel;
2329 palette =
new IcoColor[colorCount];
2330 ico.read(
reinterpret_cast<char *
>(palette), colorCount *
sizeof(IcoColor));
2331 if (!ico.good())
goto cleanup;
2334 int and_stride = ((infoHeader.width >> 3) + 3) & ~0x03;
2337 xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8;
2338 andBmpSize = and_stride * (infoHeader.height / 2);
2339 curXor = xorBmp =
new char[xorBmpSize];
2340 curAnd = andBmp =
new char[andBmpSize];
2341 ico.read(xorBmp, xorBmpSize);
2342 if (!ico.good())
goto cleanup;
2343 ico.read(andBmp, andBmpSize);
2344 if (!ico.good())
goto cleanup;
2346 image = x11_pipe->_XcursorImageCreate(infoHeader.width, infoHeader.height / 2);
2349 switch (bitsPerPixel) {
2355 mask = ((1 << bitsPerPixel) - 1);
2356 for (i = image->height - 1; i >= 0; i--) {
2357 for (j = 0; j < image->width; j += 8 / bitsPerPixel) {
2358 for (k = 0; k < 8 / bitsPerPixel; k++) {
2359 shift = 8 - ((k + 1) * bitsPerPixel);
2360 color = palette[(*curXor & (mask << shift)) >> shift];
2361 image->pixels[(i * image->width) + j + k] = (color.red << 16) +
2362 (color.green << 8) +
2370 for (j = 0; j < image->width; j += 8) {
2371 for (k = 0; k < 8; k++) {
2373 image->pixels[(i * image->width) + j + k] |=
2374 ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24);
2384 for (i = image->height - 1; i >= 0; i--) {
2385 for (j = 0; j < image->width; j++) {
2386 shift = 7 - (j & 0x7);
2387 uint32_t alpha = (curAnd[j >> 3] & (1 << shift)) ? 0 : 0xff000000U;
2388 image->pixels[(i * image->width) + j] = (uint8_t)curXor[0]
2389 | ((uint8_t)curXor[1] << 8u)
2390 | ((uint8_t)curXor[2] << 16u)
2394 curAnd += and_stride;
2400 for (i = image->height - 1; i >= 0; i--) {
2401 for (j = 0; j < image->width; j++) {
2402 image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) +
2403 (*(curXor + 2) << 16) +
2404 (*(curXor + 1) << 8) +
2417 if (header.type == 2) {
2418 image->xhot = entries[entry].xhot;
2419 image->yhot = entries[entry].yhot;
2425 ret = x11_pipe->_XcursorImageLoadCursor(_display, image);
2428 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.