mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
support fullscreen and z-order better on Linux
This commit is contained in:
parent
2527c1bb07
commit
3c2a1d95e0
@ -121,6 +121,12 @@ glxGraphicsPipe(const string &display) {
|
||||
_net_wm_window_type = XInternAtom(_display, "_NET_WM_WINDOW_TYPE", false);
|
||||
_net_wm_window_type_splash = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_SPLASH", false);
|
||||
_net_wm_window_type_fullscreen = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_FULLSCREEN", false);
|
||||
_net_wm_state = XInternAtom(_display, "_NET_WM_STATE", false);
|
||||
_net_wm_state_fullscreen = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", false);
|
||||
_net_wm_state_above = XInternAtom(_display, "_NET_WM_STATE_ABOVE", false);
|
||||
_net_wm_state_below = XInternAtom(_display, "_NET_WM_STATE_BELOW", false);
|
||||
_net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false);
|
||||
_net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -114,6 +114,12 @@ public:
|
||||
Atom _net_wm_window_type;
|
||||
Atom _net_wm_window_type_splash;
|
||||
Atom _net_wm_window_type_fullscreen;
|
||||
Atom _net_wm_state;
|
||||
Atom _net_wm_state_fullscreen;
|
||||
Atom _net_wm_state_above;
|
||||
Atom _net_wm_state_below;
|
||||
Atom _net_wm_state_add;
|
||||
Atom _net_wm_state_remove;
|
||||
|
||||
protected:
|
||||
virtual PT(GraphicsOutput) make_output(const string &name,
|
||||
|
@ -65,6 +65,12 @@ glxGraphicsWindow(GraphicsPipe *pipe,
|
||||
_net_wm_window_type = glx_pipe->_net_wm_window_type;
|
||||
_net_wm_window_type_splash = glx_pipe->_net_wm_window_type_splash;
|
||||
_net_wm_window_type_fullscreen = glx_pipe->_net_wm_window_type_fullscreen;
|
||||
_net_wm_state = glx_pipe->_net_wm_state;
|
||||
_net_wm_state_fullscreen = glx_pipe->_net_wm_state_fullscreen;
|
||||
_net_wm_state_above = glx_pipe->_net_wm_state_above;
|
||||
_net_wm_state_below = glx_pipe->_net_wm_state_below;
|
||||
_net_wm_state_add = glx_pipe->_net_wm_state_add;
|
||||
_net_wm_state_remove = glx_pipe->_net_wm_state_remove;
|
||||
|
||||
GraphicsWindowInputDevice device =
|
||||
GraphicsWindowInputDevice::pointer_and_keyboard("keyboard/mouse");
|
||||
@ -431,16 +437,23 @@ set_properties_now(WindowProperties &properties) {
|
||||
glxGraphicsPipe *glx_pipe;
|
||||
DCAST_INTO_V(glx_pipe, _pipe);
|
||||
|
||||
// We'll pass some property requests on as a window manager hint.
|
||||
WindowProperties wm_properties = _properties;
|
||||
wm_properties.add_properties(properties);
|
||||
|
||||
// The window title may be changed by issuing another hint request.
|
||||
// Assume this will be honored.
|
||||
if (properties.has_title()) {
|
||||
WindowProperties wm_properties;
|
||||
wm_properties.set_title(properties.get_title());
|
||||
_properties.set_title(properties.get_title());
|
||||
set_wm_properties(wm_properties);
|
||||
properties.clear_title();
|
||||
}
|
||||
|
||||
// Ditto for fullscreen.
|
||||
if (properties.has_fullscreen()) {
|
||||
_properties.set_fullscreen(properties.get_fullscreen());
|
||||
properties.clear_fullscreen();
|
||||
}
|
||||
|
||||
// The size and position of an already-open window are changed via
|
||||
// explicit X calls. These may still get intercepted by the window
|
||||
// manager. Rather than changing _properties immediately, we'll
|
||||
@ -460,9 +473,31 @@ set_properties_now(WindowProperties &properties) {
|
||||
value_mask |= (CWWidth | CWHeight);
|
||||
properties.clear_size();
|
||||
}
|
||||
if (properties.has_z_order()) {
|
||||
// We'll send the classing stacking request through the standard
|
||||
// interface, for users of primitive window managers; but we'll
|
||||
// also send it as a window manager hint, for users of modern
|
||||
// window managers.
|
||||
switch (properties.get_z_order()) {
|
||||
case WindowProperties::Z_bottom:
|
||||
changes.stack_mode = Below;
|
||||
break;
|
||||
|
||||
case WindowProperties::Z_normal:
|
||||
changes.stack_mode = TopIf;
|
||||
break;
|
||||
|
||||
case WindowProperties::Z_top:
|
||||
changes.stack_mode = Above;
|
||||
break;
|
||||
}
|
||||
|
||||
value_mask |= (CWStackMode);
|
||||
properties.clear_z_order();
|
||||
}
|
||||
|
||||
if (value_mask != 0) {
|
||||
XConfigureWindow(_display, _xwindow, value_mask, &changes);
|
||||
XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
|
||||
|
||||
// Don't draw anything until this is done reconfiguring.
|
||||
_awaiting_configure = true;
|
||||
@ -478,6 +513,8 @@ set_properties_now(WindowProperties &properties) {
|
||||
}
|
||||
properties.clear_cursor_hidden();
|
||||
}
|
||||
|
||||
set_wm_properties(wm_properties, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -600,7 +637,7 @@ open_window() {
|
||||
<< "failed to create X window.\n";
|
||||
return false;
|
||||
}
|
||||
set_wm_properties(_properties);
|
||||
set_wm_properties(_properties, false);
|
||||
|
||||
// We don't specify any fancy properties of the XIC. It would be
|
||||
// nicer if we could support fancy IM's that want preedit callbacks,
|
||||
@ -645,9 +682,13 @@ open_window() {
|
||||
// specified directly by the application; they must be
|
||||
// requested via the window manager, which may or may
|
||||
// not choose to honor the request.
|
||||
//
|
||||
// If already_mapped is true, the window has already
|
||||
// been mapped (manifested) on the display. This means
|
||||
// we may need to use a different action in some cases.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void glxGraphicsWindow::
|
||||
set_wm_properties(const WindowProperties &properties) {
|
||||
set_wm_properties(const WindowProperties &properties, bool already_mapped) {
|
||||
// Name the window if there is a name
|
||||
XTextProperty window_name;
|
||||
XTextProperty *window_name_p = (XTextProperty *)NULL;
|
||||
@ -698,6 +739,40 @@ set_wm_properties(const WindowProperties &properties) {
|
||||
wm_hints_p->flags = StateHint;
|
||||
}
|
||||
|
||||
// Two competing window manager interfaces have evolved. One of
|
||||
// them allows to set certain properties as a "type"; the other one
|
||||
// as a "state". We'll try to honor both.
|
||||
static const int max_type_data = 32;
|
||||
PN_int32 type_data[max_type_data];
|
||||
int next_type_data = 0;
|
||||
|
||||
static const int max_state_data = 32;
|
||||
PN_int32 state_data[max_state_data];
|
||||
int next_state_data = 0;
|
||||
|
||||
static const int max_set_data = 32;
|
||||
class SetAction {
|
||||
public:
|
||||
inline SetAction() { }
|
||||
inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
|
||||
Atom _state;
|
||||
Atom _action;
|
||||
};
|
||||
SetAction set_data[max_set_data];
|
||||
int next_set_data = 0;
|
||||
|
||||
if (properties.get_fullscreen()) {
|
||||
// For a "fullscreen" request, we pass this through, hoping the
|
||||
// window manager will support EWMH.
|
||||
type_data[next_type_data++] = _net_wm_window_type_fullscreen;
|
||||
|
||||
// We also request it as a state.
|
||||
state_data[next_state_data++] = _net_wm_state_fullscreen;
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, _net_wm_state_add);
|
||||
} else {
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, _net_wm_state_remove);
|
||||
}
|
||||
|
||||
// If we asked for a window without a border, there's no excellent
|
||||
// way to arrange that. For users whose window managers follow the
|
||||
// EWMH specification, we can ask for a "splash" screen, which is
|
||||
@ -712,25 +787,77 @@ set_wm_properties(const WindowProperties &properties) {
|
||||
class_hints_p = XAllocClassHint();
|
||||
class_hints_p->res_class = "Undecorated";
|
||||
|
||||
long data[2];
|
||||
data[0] = _net_wm_window_type_splash;
|
||||
data[1] = None;
|
||||
|
||||
XChangeProperty(_display, _xwindow, _net_wm_window_type,
|
||||
XA_ATOM, 32, PropModeReplace,
|
||||
(unsigned char *)data, 1);
|
||||
if (!properties.get_fullscreen()) {
|
||||
type_data[next_type_data++] = _net_wm_window_type_splash;
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.get_fullscreen()) {
|
||||
// For a "fullscreen" request, we pass this through, hoping the
|
||||
// window manager will support EWMH.
|
||||
long data[2];
|
||||
data[0] = _net_wm_window_type_fullscreen;
|
||||
data[1] = None;
|
||||
if (properties.has_z_order()) {
|
||||
switch (properties.get_z_order()) {
|
||||
case WindowProperties::Z_bottom:
|
||||
state_data[next_state_data++] = _net_wm_state_below;
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_add);
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove);
|
||||
break;
|
||||
|
||||
case WindowProperties::Z_normal:
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove);
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove);
|
||||
break;
|
||||
|
||||
case WindowProperties::Z_top:
|
||||
state_data[next_state_data++] = _net_wm_state_above;
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove);
|
||||
set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_add);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nassertv(next_type_data < max_type_data);
|
||||
nassertv(next_state_data < max_state_data);
|
||||
nassertv(next_set_data < max_set_data);
|
||||
|
||||
XChangeProperty(_display, _xwindow, _net_wm_window_type,
|
||||
XA_ATOM, 32, PropModeReplace,
|
||||
(unsigned char *)data, 1);
|
||||
(unsigned char *)type_data, next_type_data);
|
||||
|
||||
// Request the state properties all at once.
|
||||
XChangeProperty(_display, _xwindow, _net_wm_state,
|
||||
XA_ATOM, 32, PropModeReplace,
|
||||
(unsigned char *)state_data, next_state_data);
|
||||
|
||||
if (!already_mapped) {
|
||||
// We have to request state changes differently when the window
|
||||
// has been mapped. To do this, we need to send a client message
|
||||
// to the root window for each change.
|
||||
|
||||
// This doesn't appear to be working for me, though I think I'm
|
||||
// doing everything right. There's no feedback mechanism,
|
||||
// however, so it's impossible to tell whether I'm actually doing
|
||||
// something wrong, or whether this feature is simply not
|
||||
// supported in my current window manager. I'll leave it here for
|
||||
// now.
|
||||
|
||||
glxGraphicsPipe *glx_pipe;
|
||||
DCAST_INTO_V(glx_pipe, _pipe);
|
||||
|
||||
for (int i = 0; i < next_set_data; ++i) {
|
||||
XClientMessageEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
event.type = ClientMessage;
|
||||
event.send_event = True;
|
||||
event.display = _display;
|
||||
event.window = _xwindow;
|
||||
event.message_type = _net_wm_state;
|
||||
event.format = 32;
|
||||
event.data.l[0] = set_data[i]._action;
|
||||
event.data.l[1] = set_data[i]._state;
|
||||
event.data.l[2] = 0;
|
||||
event.data.l[3] = 1;
|
||||
|
||||
XSendEvent(_display, glx_pipe->get_root(), True, 0, (XEvent *)&event);
|
||||
}
|
||||
}
|
||||
|
||||
XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
|
||||
|
@ -54,7 +54,8 @@ protected:
|
||||
virtual bool open_window();
|
||||
|
||||
private:
|
||||
void set_wm_properties(const WindowProperties &properties);
|
||||
void set_wm_properties(const WindowProperties &properties,
|
||||
bool already_mapped);
|
||||
|
||||
#ifdef HAVE_GLXFBCONFIG
|
||||
void setup_colormap(GLXFBConfig fbconfig);
|
||||
@ -82,6 +83,12 @@ private:
|
||||
Atom _net_wm_window_type;
|
||||
Atom _net_wm_window_type_splash;
|
||||
Atom _net_wm_window_type_fullscreen;
|
||||
Atom _net_wm_state;
|
||||
Atom _net_wm_state_fullscreen;
|
||||
Atom _net_wm_state_above;
|
||||
Atom _net_wm_state_below;
|
||||
Atom _net_wm_state_add;
|
||||
Atom _net_wm_state_remove;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user