|
|
@ -613,46 +613,41 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, |
|
|
|
|
|
|
|
window->x11.transparent = _glfwIsVisualTransparentX11(visual); |
|
|
|
|
|
|
|
// Create the actual window |
|
|
|
{ |
|
|
|
XSetWindowAttributes wa; |
|
|
|
const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; |
|
|
|
|
|
|
|
wa.colormap = window->x11.colormap; |
|
|
|
wa.border_pixel = 0; |
|
|
|
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | |
|
|
|
PointerMotionMask | ButtonPressMask | ButtonReleaseMask | |
|
|
|
ExposureMask | FocusChangeMask | VisibilityChangeMask | |
|
|
|
EnterWindowMask | LeaveWindowMask | PropertyChangeMask; |
|
|
|
|
|
|
|
_glfwGrabErrorHandlerX11(); |
|
|
|
|
|
|
|
window->x11.handle = XCreateWindow(_glfw.x11.display, |
|
|
|
_glfw.x11.root, |
|
|
|
0, 0, |
|
|
|
width, height, |
|
|
|
0, // Border width |
|
|
|
depth, // Color depth |
|
|
|
InputOutput, |
|
|
|
visual, |
|
|
|
wamask, |
|
|
|
&wa); |
|
|
|
|
|
|
|
_glfwReleaseErrorHandlerX11(); |
|
|
|
|
|
|
|
if (!window->x11.handle) |
|
|
|
{ |
|
|
|
_glfwInputErrorX11(GLFW_PLATFORM_ERROR, |
|
|
|
"X11: Failed to create window"); |
|
|
|
return GLFW_FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
XSaveContext(_glfw.x11.display, |
|
|
|
window->x11.handle, |
|
|
|
_glfw.x11.context, |
|
|
|
(XPointer) window); |
|
|
|
XSetWindowAttributes wa = { 0 }; |
|
|
|
wa.colormap = window->x11.colormap; |
|
|
|
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | |
|
|
|
PointerMotionMask | ButtonPressMask | ButtonReleaseMask | |
|
|
|
ExposureMask | FocusChangeMask | VisibilityChangeMask | |
|
|
|
EnterWindowMask | LeaveWindowMask | PropertyChangeMask; |
|
|
|
|
|
|
|
_glfwGrabErrorHandlerX11(); |
|
|
|
|
|
|
|
window->x11.parent = _glfw.x11.root; |
|
|
|
window->x11.handle = XCreateWindow(_glfw.x11.display, |
|
|
|
_glfw.x11.root, |
|
|
|
0, 0, // Position |
|
|
|
width, height, |
|
|
|
0, // Border width |
|
|
|
depth, // Color depth |
|
|
|
InputOutput, |
|
|
|
visual, |
|
|
|
CWBorderPixel | CWColormap | CWEventMask, |
|
|
|
&wa); |
|
|
|
|
|
|
|
_glfwReleaseErrorHandlerX11(); |
|
|
|
|
|
|
|
if (!window->x11.handle) |
|
|
|
{ |
|
|
|
_glfwInputErrorX11(GLFW_PLATFORM_ERROR, |
|
|
|
"X11: Failed to create window"); |
|
|
|
return GLFW_FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
XSaveContext(_glfw.x11.display, |
|
|
|
window->x11.handle, |
|
|
|
_glfw.x11.context, |
|
|
|
(XPointer) window); |
|
|
|
|
|
|
|
if (!wndconfig->decorated) |
|
|
|
_glfwPlatformSetWindowDecorated(window, GLFW_FALSE); |
|
|
|
|
|
|
@ -682,7 +677,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, |
|
|
|
{ |
|
|
|
XChangeProperty(_glfw.x11.display, window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, |
|
|
|
PropModeReplace, (unsigned char*) o">&states, count); |
|
|
|
PropModeReplace, (unsigned char*) states, count); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -787,6 +782,13 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, |
|
|
|
NULL); |
|
|
|
} |
|
|
|
|
|
|
|
if (window->x11.ic) |
|
|
|
{ |
|
|
|
unsigned long filter = 0; |
|
|
|
if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL) |
|
|
|
XSelectInput(_glfw.x11.display, window->x11.handle, wa.event_mask | filter); |
|
|
|
} |
|
|
|
|
|
|
|
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); |
|
|
|
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); |
|
|
|
|
|
|
@ -1257,6 +1259,12 @@ static void processEvent(XEvent *event) |
|
|
|
|
|
|
|
switch (event->type) |
|
|
|
{ |
|
|
|
case ReparentNotify: |
|
|
|
{ |
|
|
|
window->x11.parent = event->xreparent.parent; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
case KeyPress: |
|
|
|
{ |
|
|
|
const int key = translateKey(keycode); |
|
|
@ -1541,18 +1549,28 @@ static void processEvent(XEvent *event) |
|
|
|
window->x11.height = event->xconfigure.height; |
|
|
|
} |
|
|
|
|
|
|
|
if (event->xconfigure.x != window->x11.xpos || |
|
|
|
event->xconfigure.y != window->x11.ypos) |
|
|
|
int xpos = event->xconfigure.x; |
|
|
|
int ypos = event->xconfigure.y; |
|
|
|
|
|
|
|
// NOTE: ConfigureNotify events from the server are in local |
|
|
|
// coordinates, so if we are reparented we need to translate |
|
|
|
// the position into root (screen) coordinates |
|
|
|
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) |
|
|
|
{ |
|
|
|
if (window->x11.overrideRedirect || event->xany.send_event) |
|
|
|
{ |
|
|
|
_glfwInputWindowPos(window, |
|
|
|
event->xconfigure.x, |
|
|
|
event->xconfigure.y); |
|
|
|
Window dummy; |
|
|
|
XTranslateCoordinates(_glfw.x11.display, |
|
|
|
window->x11.parent, |
|
|
|
_glfw.x11.root, |
|
|
|
xpos, ypos, |
|
|
|
&xpos, &ypos, |
|
|
|
&dummy); |
|
|
|
} |
|
|
|
|
|
|
|
window->x11.xpos = event->xconfigure.x; |
|
|
|
window->x11.ypos = event->xconfigure.y; |
|
|
|
} |
|
|
|
if (xpos != window->x11.xpos || ypos != window->x11.ypos) |
|
|
|
{ |
|
|
|
_glfwInputWindowPos(window, xpos, ypos); |
|
|
|
window->x11.xpos = xpos; |
|
|
|
window->x11.ypos = ypos; |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
@ -2340,18 +2358,67 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) |
|
|
|
|
|
|
|
void _glfwPlatformMaximizeWindow(_GLFWwindow* window) |
|
|
|
{ |
|
|
|
if (_glfw.x11.NET_WM_STATE && |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) |
|
|
|
if (!_glfw.x11.NET_WM_STATE || |
|
|
|
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || |
|
|
|
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (_glfwPlatformWindowVisible(window)) |
|
|
|
{ |
|
|
|
sendEventToWM(window, |
|
|
|
_glfw.x11.NET_WM_STATE, |
|
|
|
_NET_WM_STATE_ADD, |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, |
|
|
|
1, 0); |
|
|
|
XFlush(_glfw.x11.display); |
|
|
|
_glfw.x11.NET_WM_STATE, |
|
|
|
_NET_WM_STATE_ADD, |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, |
|
|
|
1, 0); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Atom* states = NULL; |
|
|
|
unsigned long count = |
|
|
|
_glfwGetWindowPropertyX11(window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, |
|
|
|
XA_ATOM, |
|
|
|
(unsigned char**) &states); |
|
|
|
|
|
|
|
// NOTE: We don't check for failure as this property may not exist yet |
|
|
|
// and that's fine (and we'll create it implicitly with append) |
|
|
|
|
|
|
|
Atom missing[2] = |
|
|
|
{ |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, |
|
|
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ |
|
|
|
}; |
|
|
|
unsigned long missingCount = 2; |
|
|
|
|
|
|
|
for (unsigned long i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
for (unsigned long j = 0; j < missingCount; j++) |
|
|
|
{ |
|
|
|
if (states[i] == missing[j]) |
|
|
|
{ |
|
|
|
missing[j] = missing[missingCount - 1]; |
|
|
|
missingCount--; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (states) |
|
|
|
XFree(states); |
|
|
|
|
|
|
|
if (!missingCount) |
|
|
|
return; |
|
|
|
|
|
|
|
XChangeProperty(_glfw.x11.display, window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, |
|
|
|
PropModeAppend, |
|
|
|
(unsigned char*) missing, |
|
|
|
missingCount); |
|
|
|
} |
|
|
|
|
|
|
|
XFlush(_glfw.x11.display); |
|
|
|
} |
|
|
|
|
|
|
|
void _glfwPlatformShowWindow(_GLFWwindow* window) |
|
|
@ -2371,6 +2438,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) |
|
|
|
|
|
|
|
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) |
|
|
|
{ |
|
|
|
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) |
|
|
|
return; |
|
|
|
|
|
|
|
sendEventToWM(window, |
|
|
|
_glfw.x11.NET_WM_STATE, |
|
|
|
_NET_WM_STATE_ADD, |
|
|
@ -2382,7 +2452,7 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) |
|
|
|
{ |
|
|
|
if (_glfw.x11.NET_ACTIVE_WINDOW) |
|
|
|
sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); |
|
|
|
else |
|
|
|
else if (_glfwPlatformWindowVisible(window)) |
|
|
|
{ |
|
|
|
XRaiseWindow(_glfw.x11.display, window->x11.handle); |
|
|
|
XSetInputFocus(_glfw.x11.display, window->x11.handle, |
|
|
@ -2567,7 +2637,7 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) |
|
|
|
|
|
|
|
if (_glfwPlatformWindowVisible(window)) |
|
|
|
{ |
|
|
|
const n">Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; |
|
|
|
const kt">long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; |
|
|
|
sendEventToWM(window, |
|
|
|
_glfw.x11.NET_WM_STATE, |
|
|
|
action, |
|
|
@ -2576,15 +2646,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Atom* states; |
|
|
|
Atom* states = NULL; |
|
|
|
unsigned long i, count; |
|
|
|
|
|
|
|
count = _glfwGetWindowPropertyX11(window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, |
|
|
|
XA_ATOM, |
|
|
|
(unsigned char**) &states); |
|
|
|
if (!states) |
|
|
|
return; |
|
|
|
|
|
|
|
// NOTE: We don't check for failure as this property may not exist yet |
|
|
|
// and that's fine (and we'll create it implicitly with append) |
|
|
|
|
|
|
|
if (enabled) |
|
|
|
{ |
|
|
@ -2594,32 +2665,36 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (i == count) |
|
|
|
{ |
|
|
|
XChangeProperty(_glfw.x11.display, window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, |
|
|
|
PropModeAppend, |
|
|
|
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, |
|
|
|
1); |
|
|
|
} |
|
|
|
if (i < count) |
|
|
|
return; |
|
|
|
|
|
|
|
XChangeProperty(_glfw.x11.display, window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, |
|
|
|
PropModeAppend, |
|
|
|
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, |
|
|
|
1); |
|
|
|
} |
|
|
|
else |
|
|
|
else if (states) |
|
|
|
{ |
|
|
|
for (i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) |
|
|
|
{ |
|
|
|
states[i] = states[count - 1]; |
|
|
|
count--; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (i == count) |
|
|
|
return; |
|
|
|
|
|
|
|
states[i] = states[count - 1]; |
|
|
|
count--; |
|
|
|
|
|
|
|
XChangeProperty(_glfw.x11.display, window->x11.handle, |
|
|
|
_glfw.x11.NET_WM_STATE, XA_ATOM, 32, |
|
|
|
PropModeReplace, (unsigned char*) &states, count); |
|
|
|
PropModeReplace, (unsigned char*) states, count); |
|
|
|
} |
|
|
|
|
|
|
|
XFree(states); |
|
|
|
if (states) |
|
|
|
XFree(states); |
|
|
|
} |
|
|
|
|
|
|
|
XFlush(_glfw.x11.display); |
|
|
@ -2787,6 +2862,13 @@ const char* _glfwPlatformGetScancodeName(int scancode) |
|
|
|
if (!_glfw.x11.xkb.available) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (scancode < 0 || scancode > 0xff || |
|
|
|
_glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN) |
|
|
|
{ |
|
|
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode"); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
const int key = _glfw.x11.keycodes[scancode]; |
|
|
|
const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, |
|
|
|
scancode, _glfw.x11.xkb.group, 0); |
|
|
|