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) {
102 DCAST_INTO_V(x11_pipe, _pipe);
105 _xwindow = (X11_Window)
nullptr;
107 _visual_info =
nullptr;
110 if (x11_pipe->_have_xrandr) {
113 _XRRGetScreenInfo = x11_pipe->_XRRGetScreenInfo;
114 _XRRSetScreenConfig = x11_pipe->_XRRSetScreenConfig;
117 _awaiting_configure_since = -1;
118 _dga_mouse_enabled =
false;
119 _override_redirect = False;
120 _wm_delete_window = x11_pipe->_wm_delete_window;
123 add_input_device(device);
126 enable_detectable_auto_repeat();
133~x11GraphicsWindow() {
146 nassertr(device >= 0 && device < (
int)_input_devices.size(),
MouseData());
152 if (device == 0 && !_dga_mouse_enabled && result._in_window &&
153 x11GraphicsPipe::_x_mutex.try_lock()) {
155 if (_xwindow != None &&
156 XQueryPointer(_display, _xwindow, &event.xbutton.root,
157 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
158 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state)) {
160 result._xpos =
event.xbutton.x;
161 result._ypos =
event.xbutton.y;
164 x11GraphicsPipe::_x_mutex.release();
191 if (!md.
get_in_window() || md.get_x() != x || md.get_y() != y) {
192 if (!_dga_mouse_enabled) {
194 XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
196 _input->set_pointer_in_window(x, y);
230 PStatTimer timer(_make_current_pcollector, current_thread);
232 begin_frame_spam(mode);
233 if (_gsg ==
nullptr) {
236 if (_awaiting_configure_since != -1) {
245 _gsg->reset_if_new();
247 if (mode == FM_render) {
249 clear_cube_map_selection();
253 return _gsg->begin_frame(current_thread);
263 end_frame_spam(mode);
264 nassertv(_gsg !=
nullptr);
266 if (mode == FM_render) {
271 _gsg->end_frame(current_thread);
273 if (mode == FM_render) {
275 clear_cube_map_selection();
292 if (_xwindow == (X11_Window)0) {
297 XKeyEvent keyrelease_event;
298 bool got_keyrelease_event =
false;
300 XConfigureEvent configure_event;
301 bool got_configure_event =
false;
304 bool changed_properties =
false;
306 while (XCheckIfEvent(_display, &event, check_event, (
char *)
this)) {
307 if (got_keyrelease_event) {
312 got_keyrelease_event =
false;
314 if (event.type == KeyPress &&
315 event.xkey.keycode == keyrelease_event.keycode &&
316 (event.xkey.time - keyrelease_event.time <= 1)) {
317 if (!XFilterEvent(&event, None)) {
320 handle_keystroke(event.xkey);
324 handle_keypress(event.xkey);
331 ButtonHandle raw_button = map_raw_button(keyrelease_event.keycode);
332 if (raw_button != ButtonHandle::none()) {
333 _input->raw_button_up(raw_button);
336 handle_keyrelease(keyrelease_event);
342 if (event.type == KeyPress) {
343 ButtonHandle raw_button = map_raw_button(event.xkey.keycode);
344 if (raw_button != ButtonHandle::none()) {
345 _input->raw_button_down(raw_button);
349 if (XFilterEvent(&event, None)) {
355 switch (event.type) {
359 case ConfigureNotify:
362 configure_event =
event.xconfigure;
363 got_configure_event =
true;
368 button = get_mouse_button(event.xbutton);
369 if (!_dga_mouse_enabled) {
370 _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
372 _input->button_down(button);
376 button = get_mouse_button(event.xbutton);
377 if (!_dga_mouse_enabled) {
378 _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
380 _input->button_up(button);
384 if (_dga_mouse_enabled) {
386 _input->set_pointer_in_window(md.get_x() + event.xmotion.x_root, md.get_y() + event.xmotion.y_root);
388 _input->set_pointer_in_window(event.xmotion.x, event.xmotion.y);
393 handle_keystroke(event.xkey);
394 handle_keypress(event.xkey);
401 keyrelease_event =
event.xkey;
402 got_keyrelease_event =
true;
406 if (_dga_mouse_enabled) {
408 _input->set_pointer_in_window(md.get_x(), md.get_y());
410 _input->set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
415 _input->set_pointer_out_of_window();
420 changed_properties =
true;
424 _input->focus_lost();
426 changed_properties =
true;
431 changed_properties =
true;
436 changed_properties =
true;
439 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
443 if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
447 if (!close_request_event.empty()) {
450 throw_event(close_request_event);
459 system_changed_properties(properties);
467 x11display_cat.info()
468 <<
"DestroyNotify\n";
472 x11display_cat.warning()
473 <<
"unhandled X event type " <<
event.type <<
"\n";
477 if (got_configure_event) {
479 if (x11display_cat.is_debug() && _awaiting_configure_since != -1) {
480 unsigned long elapsed = (
unsigned long)(clock() - _awaiting_configure_since) / (CLOCKS_PER_SEC / 10000);
481 x11display_cat.debug()
482 <<
"Received ConfigureNotify event after "
483 << (elapsed / 10) <<
"." << (elapsed % 10) <<
" ms\n";
486 _awaiting_configure_since = -1;
493 properties.
set_origin(configure_event.x, configure_event.y);
494 properties.
set_size(configure_event.width, configure_event.height);
496 if (_properties.get_fixed_size()) {
502 if (configure_event.width != _fixed_size.get_x() ||
503 configure_event.height != _fixed_size.get_y()) {
504 XWindowChanges changes;
505 changes.width = _fixed_size.get_x();
506 changes.height = _fixed_size.get_y();
507 int value_mask = (CWWidth | CWHeight);
508 XConfigureWindow(_display, _xwindow, value_mask, &changes);
514 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
515 X11_Cursor cursor = None;
516 if (_properties.get_cursor_hidden()) {
518 DCAST_INTO_V(x11_pipe, _pipe);
522 XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
523 _xwindow, cursor, CurrentTime);
526 changed_properties =
true;
528 else if (_awaiting_configure_since != -1) {
529 unsigned long elapsed = (clock() - _awaiting_configure_since);
530 if (elapsed > CLOCKS_PER_SEC / 10) {
532 if (x11display_cat.is_debug()) {
533 elapsed /= (CLOCKS_PER_SEC / 10000);
534 x11display_cat.debug()
535 <<
"Giving up on waiting for ConfigureNotify event after "
536 << (elapsed / 10) <<
"." << (elapsed % 10) <<
" ms\n";
538 _awaiting_configure_since = -1;
543 _properties.get_mouse_mode() == WindowProperties::M_confined ||
544 _dga_mouse_enabled)) {
546 DCAST_INTO_V(x11_pipe, _pipe);
551 X11_Cursor cursor = None;
552 if (_properties.get_cursor_hidden()) {
556 XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
557 _xwindow, cursor, CurrentTime);
558 if (_dga_mouse_enabled) {
564 if (_dga_mouse_enabled) {
566 }
else if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
567 XUngrabPointer(_display, CurrentTime);
572 if (changed_properties) {
573 system_changed_properties(properties);
576 if (got_keyrelease_event) {
579 ButtonHandle raw_button = map_raw_button(keyrelease_event.keycode);
580 if (raw_button != ButtonHandle::none()) {
581 _input->raw_button_up(raw_button);
584 handle_keyrelease(keyrelease_event);
602 if (_pipe ==
nullptr) {
609 DCAST_INTO_V(x11_pipe, _pipe);
615 bool is_fullscreen = _properties.has_fullscreen() && _properties.get_fullscreen();
618 if (want_fullscreen && properties.
has_origin()) {
624 if (want_fullscreen) {
628 LPoint2i center(0, 0);
629 if (_properties.has_origin()) {
630 center = _properties.get_origin();
631 if (_properties.has_size()) {
632 center += _properties.get_size() / 2;
635 int x, y, width, height;
639 int reqsizex, reqsizey;
643 }
else if (_properties.has_size()) {
644 reqsizex = _properties.get_x_size();
645 reqsizey = _properties.get_y_size();
657 || (width == reqsizex && height == reqsizey)
658 || !x11_pipe->_have_xrandr) {
664 if (x11display_cat.is_debug()) {
665 x11display_cat.debug()
666 <<
"Setting window to fullscreen on CRTC "
667 << width <<
"x" << height <<
"+" << x <<
"+" << y <<
"\n";
673 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, _xwindow ? _xwindow : x11_pipe->
get_root());
674 SizeID old_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation);
675 SizeID new_size_id = (SizeID) -1;
679 xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes);
680 for (
int i = 0; i < num_sizes; ++i) {
681 if (xrrs[i].width == reqsizex &&
682 xrrs[i].height == reqsizey) {
686 if (new_size_id == (SizeID) -1) {
687 x11display_cat.error()
688 <<
"Videocard has no supported display resolutions at specified res ("
689 << reqsizex <<
" x " << reqsizey <<
")\n";
695 if (x11display_cat.is_debug()) {
696 x11display_cat.debug()
697 <<
"Switching to fullscreen with resolution "
698 << reqsizex <<
"x" << reqsizey <<
"\n";
701 if (new_size_id != old_size_id) {
702 _XRRSetScreenConfig(_display, conf, x11_pipe->
get_root(), new_size_id, _orig_rotation, CurrentTime);
703 if (_orig_size_id == (SizeID) -1) {
705 _orig_size_id = old_size_id;
717 if (_orig_size_id != (SizeID) -1) {
718 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, x11_pipe->
get_root());
719 _XRRSetScreenConfig(_display, conf, x11_pipe->
get_root(), _orig_size_id, _orig_rotation, CurrentTime);
720 _orig_size_id = (SizeID) -1;
723 if (!properties.
has_origin() && _properties.has_origin()) {
724 properties.
set_origin(_properties.get_x_origin(), _properties.get_y_origin());
735 if (x_origin == -2) {
738 if (y_origin == -2) {
742 if (x_origin == -2) {
745 if (y_origin == -2) {
763 set_wm_properties(properties,
true);
768 _properties.set_title(properties.
get_title());
782 XWindowChanges changes;
785 if (_properties.get_fullscreen()) {
786 if (_properties.get_x_origin() != 0 ||
787 _properties.get_y_origin() != 0) {
790 value_mask |= CWX | CWY;
797 if (changes.x != -1) value_mask |= CWX;
798 if (changes.y != -1) value_mask |= CWY;
806 _fixed_size = _properties.get_size();
812 value_mask |= (CWWidth | CWHeight);
814 if (_properties.get_fixed_size()) {
815 _fixed_size = properties.
get_size();
826 case WindowProperties::Z_bottom:
827 changes.stack_mode = Below;
830 case WindowProperties::Z_normal:
831 changes.stack_mode = TopIf;
834 case WindowProperties::Z_top:
835 changes.stack_mode = Above;
839 value_mask |= (CWStackMode);
853 _properties.set_cursor_filename(cursor_filename);
857 _properties.set_cursor_filename(filename);
859 if (_properties.get_cursor_hidden()) {
862 }
else if (!cursor_filename.empty()) {
864 X11_Cursor cursor = get_cursor(cursor_filename);
865 XDefineCursor(_display, _xwindow, cursor);
868 XDefineCursor(_display, _xwindow, None);
872 if (!properties.has_mouse_mode() &&
873 _properties.get_mouse_mode() != WindowProperties::M_absolute) {
880 XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
882 XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime);
887 if (properties.has_mouse_mode()) {
889 case WindowProperties::M_absolute:
890 XUngrabPointer(_display, CurrentTime);
891 if (_dga_mouse_enabled) {
893 _dga_mouse_enabled =
false;
895 _properties.set_mouse_mode(WindowProperties::M_absolute);
899 case WindowProperties::M_relative:
900 if (!_dga_mouse_enabled) {
902 X11_Cursor cursor = None;
903 if (_properties.get_cursor_hidden()) {
905 DCAST_INTO_V(x11_pipe, _pipe);
909 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
910 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
911 x11display_cat.error() <<
"Failed to grab pointer!\n";
915 _properties.set_mouse_mode(WindowProperties::M_relative);
917 _dga_mouse_enabled =
true;
922 XQueryPointer(_display, _xwindow, &event.xbutton.root,
923 &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root,
924 &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
925 _input->set_pointer_in_window(event.xbutton.x, event.xbutton.y);
928 x11display_cat.warning()
929 <<
"XF86DGA extension not available, cannot enable relative mouse mode\n";
930 _dga_mouse_enabled =
false;
935 case WindowProperties::M_confined:
938 DCAST_INTO_V(x11_pipe, _pipe);
940 if (_dga_mouse_enabled) {
942 _dga_mouse_enabled =
false;
944 X11_Cursor cursor = None;
945 if (_properties.get_cursor_hidden()) {
949 if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync,
950 GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) {
951 x11display_cat.error() <<
"Failed to grab pointer!\n";
953 _properties.set_mouse_mode(WindowProperties::M_confined);
961 if (value_mask != 0) {
964 XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
967 _awaiting_configure_since = clock();
974void x11GraphicsWindow::
975mouse_mode_absolute() {
982void x11GraphicsWindow::
983mouse_mode_relative() {
990void x11GraphicsWindow::
992 if (_gsg !=
nullptr) {
996 LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
997 if (_ic != (XIC)
nullptr) {
1002 if (_xwindow != (X11_Window)
nullptr) {
1003 XDestroyWindow(_display, _xwindow);
1004 _xwindow = (X11_Window)
nullptr;
1013 if (_orig_size_id != (SizeID) -1) {
1015 if (_pipe !=
nullptr) {
1016 x11GraphicsPipe *x11_pipe;
1017 DCAST_INTO_V(x11_pipe, _pipe);
1022 root = RootWindow(_display, _screen);
1024 XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, root);
1025 _XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime);
1029 for (
auto item : _cursor_filenames) {
1030 XFreeCursor(_display, item.second);
1032 _cursor_filenames.clear();
1034 GraphicsWindow::close_window();
1041bool x11GraphicsWindow::
1043 if (_visual_info ==
nullptr) {
1045 x11display_cat.error()
1046 <<
"No X visual: cannot open window.\n";
1050 x11GraphicsPipe *x11_pipe;
1051 DCAST_INTO_R(x11_pipe, _pipe,
false);
1053 if (!_properties.has_origin()) {
1054 _properties.set_origin(0, 0);
1056 if (!_properties.has_size()) {
1057 _properties.set_size(100, 100);
1061 LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
1063 X11_Window parent_window = x11_pipe->
get_root();
1064 WindowHandle *window_handle = _properties.get_parent_window();
1065 if (window_handle !=
nullptr) {
1066 x11display_cat.info()
1067 <<
"Got parent_window " << *window_handle <<
"\n";
1068 WindowHandle::OSHandle *os_handle = window_handle->
get_os_handle();
1069 if (os_handle !=
nullptr) {
1070 x11display_cat.info()
1071 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1073 if (os_handle->
is_of_type(NativeWindowHandle::X11Handle::get_class_type())) {
1074 NativeWindowHandle::X11Handle *x11_handle = DCAST(NativeWindowHandle::X11Handle, os_handle);
1075 parent_window = x11_handle->get_handle();
1076 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1077 NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle);
1078 parent_window = (X11_Window)int_handle->get_handle();
1082 _parent_window_handle = window_handle;
1085 ButtonPressMask | ButtonReleaseMask |
1086 KeyPressMask | KeyReleaseMask |
1087 EnterWindowMask | LeaveWindowMask |
1089 FocusChangeMask | StructureNotifyMask;
1092 XSetWindowAttributes wa;
1093 wa.background_pixel = XBlackPixel(_display, _screen);
1094 wa.border_pixel = 0;
1095 wa.colormap = _colormap;
1096 wa.event_mask = _event_mask;
1097 wa.override_redirect = _override_redirect;
1099 unsigned long attrib_mask =
1100 CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
1102 _xwindow = XCreateWindow
1103 (_display, parent_window,
1104 _properties.get_x_origin(), _properties.get_y_origin(),
1105 _properties.get_x_size(), _properties.get_y_size(),
1106 0, _visual_info->depth, InputOutput,
1107 _visual_info->visual, attrib_mask, &wa);
1109 if (_xwindow == (X11_Window)0) {
1110 x11display_cat.error()
1111 <<
"failed to create X window.\n";
1115 if (_properties.get_fixed_size()) {
1116 _fixed_size = _properties.get_size();
1119 set_wm_properties(_properties,
false);
1125 XIM im = x11_pipe->
get_im();
1128 _ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
1129 XNClientWindow, _xwindow,
nullptr);
1130 if (_ic == (XIC)
nullptr) {
1131 x11display_cat.warning()
1132 <<
"Couldn't create input context.\n";
1136 if (_properties.get_cursor_hidden()) {
1139 }
else if (_properties.has_cursor_filename() && !_properties.get_cursor_filename().empty()) {
1141 X11_Cursor cursor = get_cursor(_properties.get_cursor_filename());
1142 XDefineCursor(_display, _xwindow, cursor);
1145 XMapWindow(_display, _xwindow);
1147 if (_properties.get_raw_mice()) {
1150 if (x11display_cat.is_debug()) {
1151 x11display_cat.debug()
1152 <<
"Raw mice not requested.\n";
1157 _window_handle = NativeWindowHandle::make_x11(_xwindow);
1160 if (_parent_window_handle !=
nullptr) {
1161 _parent_window_handle->attach_child(_window_handle);
1179void x11GraphicsWindow::
1180set_wm_properties(
const WindowProperties &properties,
bool already_mapped) {
1181 x11GraphicsPipe *x11_pipe;
1182 DCAST_INTO_V(x11_pipe, _pipe);
1185 XTextProperty window_name;
1186 XTextProperty *window_name_p =
nullptr;
1188 const char *name = properties.
get_title().c_str();
1189 if (XStringListToTextProperty((
char **)&name, 1, &window_name) != 0) {
1190 window_name_p = &window_name;
1193#ifdef X_HAVE_UTF8_STRING
1194 XTextProperty wm_name;
1195 if (Xutf8TextListToTextProperty(_display, (
char **)&name, 1,
1196 XUTF8StringStyle, &wm_name) == Success) {
1197 XSetTextProperty(_display, _xwindow, &wm_name, x11_pipe->_net_wm_name);
1198 XFree(wm_name.value);
1205 XSizeHints *size_hints_p =
nullptr;
1207 size_hints_p = XAllocSizeHints();
1208 if (size_hints_p !=
nullptr) {
1212 size_hints_p->flags |= USPosition;
1214 LVecBase2i size = _properties.get_size();
1217 size_hints_p->width = size.get_x();
1218 size_hints_p->height = size.get_y();
1219 size_hints_p->flags |= USSize;
1222 size_hints_p->min_width = size.get_x();
1223 size_hints_p->min_height = size.get_y();
1224 size_hints_p->max_width = size.get_x();
1225 size_hints_p->max_height = size.get_y();
1226 size_hints_p->flags |= (PMinSize | PMaxSize);
1233 XWMHints *wm_hints_p =
nullptr;
1234 wm_hints_p = XAllocWMHints();
1235 if (wm_hints_p !=
nullptr) {
1237 wm_hints_p->initial_state = IconicState;
1239 wm_hints_p->initial_state = NormalState;
1241 wm_hints_p->flags = StateHint;
1247 static const int max_type_data = 32;
1248 int32_t type_data[max_type_data];
1249 int next_type_data = 0;
1251 static const int max_state_data = 32;
1252 int32_t state_data[max_state_data];
1253 int next_state_data = 0;
1255 static const int max_set_data = 32;
1258 inline SetAction() { }
1259 inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
1263 SetAction set_data[max_set_data];
1264 int next_set_data = 0;
1267 if (properties.get_fullscreen()) {
1270 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_fullscreen;
1273 state_data[next_state_data++] = x11_pipe->_net_wm_state_fullscreen;
1276 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 1);
1279 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 0);
1292 XClassHint *class_hints_p =
nullptr;
1293 if (!x_wm_class.empty()) {
1295 class_hints_p = XAllocClassHint();
1296 class_hints_p->res_class = (char*) x_wm_class.c_str();
1297 if (!x_wm_class_name.empty()) {
1298 class_hints_p->res_name = (char*) x_wm_class_name.c_str();
1302 class_hints_p = XAllocClassHint();
1303 class_hints_p->res_class = (char*)
"Undecorated";
1307 type_data[next_type_data++] = x11_pipe->_net_wm_window_type_splash;
1311 switch (properties.get_z_order()) {
1312 case WindowProperties::Z_bottom:
1313 state_data[next_state_data++] = x11_pipe->_net_wm_state_below;
1314 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1315 x11_pipe->_net_wm_state_add);
1316 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1317 x11_pipe->_net_wm_state_remove);
1320 case WindowProperties::Z_normal:
1321 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1322 x11_pipe->_net_wm_state_remove);
1323 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1324 x11_pipe->_net_wm_state_remove);
1327 case WindowProperties::Z_top:
1328 state_data[next_state_data++] = x11_pipe->_net_wm_state_above;
1329 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below,
1330 x11_pipe->_net_wm_state_remove);
1331 set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above,
1332 x11_pipe->_net_wm_state_add);
1337 nassertv(next_type_data < max_type_data);
1338 nassertv(next_state_data < max_state_data);
1339 nassertv(next_set_data < max_set_data);
1342 int32_t pid = getpid();
1343 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_pid,
1344 XA_CARDINAL, 32, PropModeReplace,
1345 (
unsigned char *)&pid, 1);
1350 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_bypass_compositor,
1351 XA_CARDINAL, 32, PropModeReplace,
1352 (
unsigned char *)&compositor, 1);
1355 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_window_type,
1356 XA_ATOM, 32, PropModeReplace,
1357 (
unsigned char *)type_data, next_type_data);
1360 XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_state,
1361 XA_ATOM, 32, PropModeReplace,
1362 (
unsigned char *)state_data, next_state_data);
1364 if (already_mapped) {
1370 DCAST_INTO_V(x11_pipe, _pipe);
1372 for (
int i = 0; i < next_set_data; ++i) {
1373 XClientMessageEvent event;
1374 memset(&event, 0,
sizeof(event));
1375 event.type = ClientMessage;
1376 event.send_event = True;
1377 event.display = _display;
1378 event.window = _xwindow;
1379 event.message_type = x11_pipe->_net_wm_state;
1381 event.data.l[0] = set_data[i]._action;
1382 event.data.l[1] = set_data[i]._state;
1383 event.data.l[2] = 0;
1384 event.data.l[3] = 1;
1386 XSendEvent(_display, x11_pipe->
get_root(), True, SubstructureNotifyMask | SubstructureRedirectMask, (XEvent *)&event);
1390 XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
1391 nullptr, 0, size_hints_p, wm_hints_p, class_hints_p);
1393 if (size_hints_p !=
nullptr) {
1394 XFree(size_hints_p);
1396 if (wm_hints_p !=
nullptr) {
1399 if (class_hints_p !=
nullptr) {
1400 XFree(class_hints_p);
1406 Atom protocols[] = {
1410 XSetWMProtocols(_display, _xwindow, protocols,
1411 sizeof(protocols) /
sizeof(Atom));
1418void x11GraphicsWindow::
1419setup_colormap(XVisualInfo *visual) {
1420 x11GraphicsPipe *x11_pipe;
1421 DCAST_INTO_V(x11_pipe, _pipe);
1422 X11_Window root_window = x11_pipe->
get_root();
1424 _colormap = XCreateColormap(_display, root_window,
1425 visual->visual, AllocNone);
1432void x11GraphicsWindow::
1434#ifdef PHAVE_LINUX_INPUT_H
1435 bool any_present =
false;
1436 bool any_mice =
false;
1438 for (
int i=0; i<64; i++) {
1440 fnb <<
"/dev/input/event" << i;
1441 string fn = fnb.str();
1442 int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
1444 EvdevInputDevice *device =
new EvdevInputDevice(
nullptr, fd);
1445 nassertd(device != NULL)
continue;
1447 if (device->has_pointer()) {
1448 add_input_device(device);
1450 x11display_cat.info()
1451 <<
"Raw mouse " << _input_devices.size()
1452 <<
" detected: " << device->get_name() <<
"\n";
1458 if (errno == ENOENT || errno == ENOTDIR) {
1462 x11display_cat.error()
1463 <<
"Opening raw mice: " << strerror(errno) <<
" " << fn <<
"\n";
1469 _properties.set_raw_mice(
true);
1471 }
else if (!any_present) {
1472 x11display_cat.error() <<
1473 "Opening raw mice: files not found: /dev/input/event*\n";
1476 x11display_cat.error() <<
1477 "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
1480 x11display_cat.error() <<
1481 "Opening raw mice: panda not compiled with raw mouse support.\n";
1488void x11GraphicsWindow::
1489handle_keystroke(XKeyEvent &event) {
1490 if (!_dga_mouse_enabled) {
1491 _input->set_pointer_in_window(event.x, event.y);
1496 static const int buffer_size = 256;
1497 wchar_t buffer[buffer_size];
1499 int len = XwcLookupString(_ic, &event, buffer, buffer_size,
nullptr,
1501 if (status == XBufferOverflow) {
1502 x11display_cat.error()
1503 <<
"Overflowed input buffer.\n";
1507 for (
int i = 0; i < len; i++) {
1508 _input->keystroke(buffer[i]);
1513 ButtonHandle button = get_button(event,
true);
1523void x11GraphicsWindow::
1524handle_keypress(XKeyEvent &event) {
1525 if (!_dga_mouse_enabled) {
1526 _input->set_pointer_in_window(event.x, event.y);
1530 ButtonHandle button = get_button(event,
false);
1531 if (button != ButtonHandle::none()) {
1532 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1533 _input->button_down(KeyboardButton::control());
1535 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1536 _input->button_down(KeyboardButton::shift());
1538 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1539 _input->button_down(KeyboardButton::alt());
1541 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1542 _input->button_down(KeyboardButton::meta());
1544 _input->button_down(button);
1551void x11GraphicsWindow::
1552handle_keyrelease(XKeyEvent &event) {
1553 if (!_dga_mouse_enabled) {
1554 _input->set_pointer_in_window(event.x, event.y);
1558 ButtonHandle button = get_button(event,
false);
1559 if (button != ButtonHandle::none()) {
1560 if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
1561 _input->button_up(KeyboardButton::control());
1563 if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
1564 _input->button_up(KeyboardButton::shift());
1566 if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
1567 _input->button_up(KeyboardButton::alt());
1569 if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
1570 _input->button_up(KeyboardButton::meta());
1572 _input->button_up(button);
1581get_button(XKeyEvent &key_event,
bool allow_shift) {
1582 KeySym key = XLookupKeysym(&key_event, 0);
1584 if ((key_event.state & Mod2Mask) != 0) {
1589 ButtonHandle button;
1599 case XK_KP_Multiply:
1601 case XK_KP_Separator:
1602 case XK_KP_Subtract:
1625 k2 = XLookupKeysym(&key_event, 1);
1626 button = map_button(k2);
1627 if (button != ButtonHandle::none()) {
1641 if ((key_event.state & ShiftMask) != 0) {
1642 KeySym k2 = XLookupKeysym(&key_event, 1);
1643 ButtonHandle button = map_button(k2);
1644 if (button != ButtonHandle::none()) {
1652 if ((key_event.state & (ShiftMask | LockMask)) != 0) {
1653 if (key >= XK_a && key <= XK_z) {
1654 key += (XK_A - XK_a);
1659 return map_button(key);
1667map_button(KeySym key)
const {
1670 return ButtonHandle::none();
1672 return KeyboardButton::backspace();
1675 return KeyboardButton::tab();
1678 return KeyboardButton::enter();
1680 return KeyboardButton::escape();
1683 return KeyboardButton::space();
1704 case XK_KP_Multiply:
1710 case XK_KP_Separator:
1713 case XK_KP_Subtract:
1818 case XK_bracketleft:
1822 case XK_bracketright:
1824 case XK_asciicircum:
1893 return KeyboardButton::f1();
1896 return KeyboardButton::f2();
1899 return KeyboardButton::f3();
1902 return KeyboardButton::f4();
1904 return KeyboardButton::f5();
1906 return KeyboardButton::f6();
1908 return KeyboardButton::f7();
1910 return KeyboardButton::f8();
1912 return KeyboardButton::f9();
1914 return KeyboardButton::f10();
1916 return KeyboardButton::f11();
1918 return KeyboardButton::f12();
1921 return KeyboardButton::left();
1924 return KeyboardButton::up();
1927 return KeyboardButton::right();
1930 return KeyboardButton::down();
1933 return KeyboardButton::page_up();
1936 return KeyboardButton::page_down();
1939 return KeyboardButton::home();
1942 return KeyboardButton::end();
1945 return KeyboardButton::insert();
1948 return KeyboardButton::del();
1950 return KeyboardButton::num_lock();
1951 case XK_Scroll_Lock:
1952 return KeyboardButton::scroll_lock();
1954 return KeyboardButton::print_screen();
1956 return KeyboardButton::pause();
1958 return KeyboardButton::menu();
1960 return KeyboardButton::lshift();
1962 return KeyboardButton::rshift();
1964 return KeyboardButton::lcontrol();
1966 return KeyboardButton::rcontrol();
1968 return KeyboardButton::lalt();
1970 return KeyboardButton::ralt();
1973 return KeyboardButton::lmeta();
1976 return KeyboardButton::rmeta();
1978 return KeyboardButton::caps_lock();
1980 return KeyboardButton::shift_lock();
1982 if (x11display_cat.is_debug()) {
1983 x11display_cat.debug()
1984 <<
"Unrecognized keysym 0x" << std::hex << key << std::dec <<
"\n";
1986 return ButtonHandle::none();
1993map_raw_button(KeyCode key)
const {
1994#ifdef PHAVE_LINUX_INPUT_H
1999 int index = key - 8;
2000 if (index > 0 && index < 128) {
2001 return EvdevInputDevice::map_button(index);
2004 return ButtonHandle::none();
2012get_mouse_button(XButtonEvent &button_event) {
2013 int index = button_event.button;
2014 if (index == x_wheel_up_button) {
2016 }
else if (index == x_wheel_down_button) {
2018 }
else if (index == x_wheel_left_button) {
2020 }
else if (index == x_wheel_right_button) {
2022 }
else if (index >= 8) {
2034get_keyboard_map()
const {
2037 ButtonMap *map =
new ButtonMap;
2039 LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
2041 for (
int k = 9; k <= 135; ++k) {
2042 if (k >= 78 && k <= 91) {
2049 ButtonHandle raw_button = map_raw_button(k);
2050 if (raw_button == ButtonHandle::none()) {
2054 KeySym sym = XkbKeycodeToKeysym(_display, k, 0, 0);
2055 ButtonHandle button = map_button(sym);
2060 if (sym >= XK_exclam && sym <= XK_asciitilde) {
2061 label = toupper((
char)sym);
2063 else if (sym >= XK_F1 && sym <= XK_F35) {
2064 label =
"F" + format_string(sym - XK_F1 + 1);
2066 else if (sym > 0x1000000 && sym < 0x1110000) {
2068 char32_t ch = sym & 0x0ffffff;
2069 if ((ch & ~0x7f) == 0) {
2070 label = string(1, (
char)ch);
2072 else if ((ch & ~0x7ff) == 0) {
2074 string(1, (
char)((ch >> 6) | 0xc0)) +
2075 string(1, (
char)((ch & 0x3f) | 0x80));
2077 else if ((ch & ~0xffff) == 0) {
2079 string(1, (
char)((ch >> 12) | 0xe0)) +
2080 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2081 string(1, (
char)((ch & 0x3f) | 0x80));
2085 string(1, (
char)((ch >> 18) | 0xf0)) +
2086 string(1, (
char)(((ch >> 12) & 0x3f) | 0x80)) +
2087 string(1, (
char)(((ch >> 6) & 0x3f) | 0x80)) +
2088 string(1, (
char)((ch & 0x3f) | 0x80));
2091 else if ((sym >= XK_exclamdown && sym <= XK_umacron)
2092 || (sym >= XK_OE && sym <= XK_Ydiaeresis)
2093 || (sym >= XK_Serbian_dje && sym <= XK_Cyrillic_HARDSIGN)
2094 || (sym >= XK_kana_fullstop && sym <= XK_semivoicedsound)
2095 || (sym >= XK_Arabic_comma && sym <= XK_Arabic_sukun)
2096 || (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_omega)
2097 || (sym >= XK_hebrew_doublelowline && sym <= XK_hebrew_taw)
2098 || (sym >= XK_Thai_kokai && sym <= XK_Thai_lekkao)
2099 || (sym >= XK_Hangul_Kiyeog && sym <= XK_Hangul_J_YeorinHieuh)
2100 || sym == XK_EuroSign
2101 || sym == XK_Korean_Won) {
2104 int nbytes = XkbTranslateKeySym(_display, &sym, 0, buffer, 255, 0);
2106 label.assign(buffer, nbytes);
2110 if (button == ButtonHandle::none() && label.empty()) {
2125Bool x11GraphicsWindow::
2126check_event(X11_Display *display, XEvent *event,
char *arg) {
2127 const x11GraphicsWindow *self = (x11GraphicsWindow *)arg;
2130 return (event->xany.window == self->_xwindow);
2137X11_Cursor x11GraphicsWindow::
2138get_cursor(
const Filename &filename) {
2139 x11GraphicsPipe *x11_pipe;
2140 DCAST_INTO_R(x11_pipe, _pipe, None);
2142 if (x11_pipe->_xcursor_size == -1) {
2143 x11display_cat.info()
2144 <<
"libXcursor.so.1 not available; cannot change mouse cursor.\n";
2149 pmap<Filename, X11_Cursor>::iterator fi = _cursor_filenames.find(filename);
2150 if (fi != _cursor_filenames.end()) {
2156 Filename resolved (filename);
2159 x11display_cat.warning()
2160 <<
"Could not find cursor filename " << filename <<
"\n";
2163 fi = _cursor_filenames.find(resolved);
2164 if (fi != _cursor_filenames.end()) {
2170 if (str ==
nullptr) {
2171 x11display_cat.warning()
2172 <<
"Could not open cursor file " << filename <<
"\n";
2178 str->read(magic, 4);
2180 x11display_cat.warning()
2181 <<
"Could not read from cursor file " << filename <<
"\n";
2187 str->putback(magic[3]);
2188 str->putback(magic[2]);
2189 str->putback(magic[1]);
2190 str->putback(magic[0]);
2192 X11_Cursor h = None;
2193 if (memcmp(magic,
"Xcur", 4) == 0) {
2195 x11display_cat.debug()
2196 <<
"Loading X11 cursor " << filename <<
"\n";
2198 xcfile.closure = str;
2199 xcfile.read = &xcursor_read;
2200 xcfile.write = &xcursor_write;
2201 xcfile.seek = &xcursor_seek;
2203 XcursorImages *images = x11_pipe->_XcursorXcFileLoadImages(&xcfile, x11_pipe->_xcursor_size);
2204 if (images !=
nullptr) {
2205 h = x11_pipe->_XcursorImagesLoadCursor(_display, images);
2206 x11_pipe->_XcursorImagesDestroy(images);
2209 }
else if (memcmp(magic,
"\0\0\1\0", 4) == 0
2210 || memcmp(magic,
"\0\0\2\0", 4) == 0) {
2212 x11display_cat.debug()
2213 <<
"Loading Windows cursor " << filename <<
"\n";
2221 x11display_cat.warning()
2222 <<
"X11 cursor filename '" << resolved <<
"' could not be loaded!\n";
2225 _cursor_filenames[resolved] = h;
2233X11_Cursor x11GraphicsWindow::
2234read_ico(istream &ico) {
2235 x11GraphicsPipe *x11_pipe;
2236 DCAST_INTO_R(x11_pipe, _pipe, None);
2240 uint16_t reserved, type, count;
2244 uint8_t width, height, colorCount, reserved;
2245 uint16_t xhot, yhot;
2246 uint32_t bitmapSize, offset;
2250 uint32_t headerSize, width, height;
2251 uint16_t planes, bitsPerPixel;
2252 uint32_t compression, imageSize, xPixelsPerM, yPixelsPerM, colorsUsed, colorsImportant;
2256 uint8_t blue, green, red, reserved;
2260 unsigned int j, k, mask, shift;
2261 size_t colorCount, bitsPerPixel;
2263 IcoInfoHeader infoHeader;
2264 IcoEntry *entries =
nullptr;
2265 IcoColor color, *palette =
nullptr;
2267 size_t xorBmpSize, andBmpSize;
2268 char *curXor, *curAnd;
2269 char *xorBmp =
nullptr, *andBmp =
nullptr;
2270 XcursorImage *image =
nullptr;
2271 X11_Cursor ret = None;
2273 int def_size = x11_pipe->_xcursor_size;
2276 ico.read(
reinterpret_cast<char *
>(&header),
sizeof(IcoHeader));
2277 if (!ico.good())
goto cleanup;
2278 if (header.type != 1 && header.type != 2)
goto cleanup;
2279 if (header.count < 1)
goto cleanup;
2282 entries =
new IcoEntry[header.count];
2283 ico.read(
reinterpret_cast<char *
>(entries), header.count *
sizeof(IcoEntry));
2284 if (!ico.good())
goto cleanup;
2285 for (i = 1; i < header.count; i++) {
2286 if (entries[i].width == def_size && entries[i].height == def_size) {
2291 if (entries[i].width > entries[entry].width ||
2292 entries[i].height > entries[entry].height)
2297 ico.seekg(entries[entry].offset);
2298 if (!ico.good())
goto cleanup;
2300 if (ico.peek() == 0x89) {
2314 unsigned int *dest = image->pixels;
2316 if (alpha !=
nullptr) {
2317 for (
size_t p = 0; p < num_pixels; ++p) {
2318 *dest++ = (*alpha << 24U) | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2323 for (
size_t p = 0; p < num_pixels; ++p) {
2324 *dest++ = 0xff000000U | (ptr->r << 16U) | (ptr->g << 8U) | (ptr->b);
2330 ico.read(
reinterpret_cast<char *
>(&infoHeader),
sizeof(IcoInfoHeader));
2331 if (!ico.good())
goto cleanup;
2332 bitsPerPixel = infoHeader.bitsPerPixel;
2334 if (infoHeader.compression != 0)
goto cleanup;
2337 if (bitsPerPixel != 24 && bitsPerPixel != 32) {
2338 colorCount = 1 << bitsPerPixel;
2339 palette =
new IcoColor[colorCount];
2340 ico.read(
reinterpret_cast<char *
>(palette), colorCount *
sizeof(IcoColor));
2341 if (!ico.good())
goto cleanup;
2344 int and_stride = ((infoHeader.width >> 3) + 3) & ~0x03;
2347 xorBmpSize = (infoHeader.width * (infoHeader.height / 2) * bitsPerPixel) / 8;
2348 andBmpSize = and_stride * (infoHeader.height / 2);
2349 curXor = xorBmp =
new char[xorBmpSize];
2350 curAnd = andBmp =
new char[andBmpSize];
2351 ico.read(xorBmp, xorBmpSize);
2352 if (!ico.good())
goto cleanup;
2353 ico.read(andBmp, andBmpSize);
2354 if (!ico.good())
goto cleanup;
2356 image = x11_pipe->_XcursorImageCreate(infoHeader.width, infoHeader.height / 2);
2359 switch (bitsPerPixel) {
2365 mask = ((1 << bitsPerPixel) - 1);
2366 for (i = image->height - 1; i >= 0; i--) {
2367 for (j = 0; j < image->width; j += 8 / bitsPerPixel) {
2368 for (k = 0; k < 8 / bitsPerPixel; k++) {
2369 shift = 8 - ((k + 1) * bitsPerPixel);
2370 color = palette[(*curXor & (mask << shift)) >> shift];
2371 image->pixels[(i * image->width) + j + k] = (color.red << 16) +
2372 (color.green << 8) +
2380 for (j = 0; j < image->width; j += 8) {
2381 for (k = 0; k < 8; k++) {
2383 image->pixels[(i * image->width) + j + k] |=
2384 ((*curAnd & (1 << shift)) >> shift) ? 0x0 : (0xff << 24);
2394 for (i = image->height - 1; i >= 0; i--) {
2395 for (j = 0; j < image->width; j++) {
2396 shift = 7 - (j & 0x7);
2397 uint32_t alpha = (curAnd[j >> 3] & (1 << shift)) ? 0 : 0xff000000U;
2398 image->pixels[(i * image->width) + j] = (uint8_t)curXor[0]
2399 | ((uint8_t)curXor[1] << 8u)
2400 | ((uint8_t)curXor[2] << 16u)
2404 curAnd += and_stride;
2410 for (i = image->height - 1; i >= 0; i--) {
2411 for (j = 0; j < image->width; j++) {
2412 image->pixels[(i * image->width) + j] = (*(curXor + 3) << 24) +
2413 (*(curXor + 2) << 16) +
2414 (*(curXor + 1) << 8) +
2427 if (header.type == 2) {
2428 image->xhot = entries[entry].xhot;
2429 image->yhot = entries[entry].yhot;
2435 ret = x11_pipe->_XcursorImageLoadCursor(_display, image);
2438 x11_pipe->_XcursorImageDestroy(image);
2452 if (!x_detectable_auto_repeat) {
2457 if (XkbSetDetectableAutoRepeat(_display, True, &supported)) {
2458 x11display_cat.info() <<
"Detectable auto-repeat enabled.\n";
2459 }
else if (!supported) {
2460 x11display_cat.warning() <<
"Detectable auto-repeat is not supported by the X server.\n";
2462 x11display_cat.error() <<
"Failed to set detectable auto-repeat.\n";
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.
Similar to MutexHolder, but for a light reentrant mutex.
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...
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.
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.
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 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.
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.
void enable_detectable_auto_repeat()
Enables detectable auto-repeat if supported by the X server.
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.