#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include <X11/keysym.h>
+#include <X11/cursorfont.h>
#include <fcntl.h>
#if !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
#include <GL/glx.h>
static XEvent xEvent;
static int joystickFD[4];
static X11Window activeWindow;
+static X11Cursor systemCursors[SystemCursor];
+
+static enum NETWMStateAction { remove = 0, add = 1, toggle = 2 };
static enum AtomIdents
{
_net_wm_window_type_desktop, _net_wm_window_type_dialog, _net_wm_window_type_dock, _net_wm_window_type_dropdown_menu,
_net_wm_window_type_menu, _net_wm_window_type_normal, _net_wm_window_type_popup_menu, _net_wm_window_type_splash,
_net_wm_window_type_toolbar, _net_wm_window_type_utility, _net_workarea, _net_frame_extents, _net_request_frame_extents,
- _net_wm_state_maximized_vert, _net_wm_state_maximized_horz, _net_wm_state_modal, app_selection
+ _net_wm_state_maximized_vert, _net_wm_state_maximized_horz, _net_wm_state_modal, app_selection, _net_supported
};
static Atom atoms[AtomIdents];
+static bool atomsSupported[AtomIdents];
static const char *atomNames[AtomIdents] = {
"CLIPBOARD", //clipboard
"_NET_WM_STATE_MAXIMIZED_VERT", // _net_wm_state_maximized_vert
"_NET_WM_STATE_MAXIMIZED_HORZ", // _net_wm_state_maximized_horz
"_NET_WM_STATE_MODAL", // _net_wm_state_modal
- "APP_SELECTION"
+ "APP_SELECTION",
+ "_NET_SUPPORTED"
};
/*
_NET_WM_STATE_STICKY, ATOM
Visual * xSystemVisual;
bool xSharedMemory;
+static void SetNETWMState(X11Window windowHandle, bool throughRoot, NETWMStateAction action, Atom atom1, Atom atom2)
+{
+ if(atomsSupported[_net_wm_state])
+ {
+ int format;
+ unsigned long count, fill;
+ Atom type;
+ char * data = null;
+ uint state = WithdrawnState;
+
+ /*if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[wm_state], 0, 3, False,
+ atoms[wm_state], &type, &format, &count, &fill, &data) == Success && count)
+ {
+ state = *(uint *)data;
+ XFree(data);
+ } */
+ if(!throughRoot) //state == WithdrawnState)
+ {
+ // We need to handle modifying these ourselves for withdrawn windows...
+ if(action == add)
+ {
+ Atom values[2] = { atom1, atom2 };
+ XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM,
+ 32, PropModeAppend, (byte *)values, atom2 ? 2 : 1);
+ }
+ else if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], 0, 32, False,
+ XA_ATOM, &type, &format, &count, &fill, &data) == Success)
+ {
+ Atom * values = (Atom *) data;
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ if(values[i] == atom1 || (atom2 && values[i] == atom2))
+ {
+ if(i < count - 1)
+ memmove(values + i, values + i + 1, sizeof(Atom) * (count - i - 1));
+ count--;
+ i--;
+ }
+ }
+ XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM, 32, PropModeReplace, (byte *)values, (int)count);
+ XFree(data);
+ }
+ }
+ else
+ {
+ XClientMessageEvent event = { 0 };
+ event.type = ClientMessage;
+ event.message_type = atoms[_net_wm_state];
+ event.display = xGlobalDisplay;
+ event.serial = 0;
+ event.window = windowHandle;
+ event.send_event = 1;
+ event.format = 32;
+ event.data.l[0] = action;
+ event.data.l[1] = atom1;
+ event.data.l[2] = atom2;
+ XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
+ SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+ }
+ }
+
+}
+
static Time timeStamp;
class XWindowData : struct
h = XDisplayHeight(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
x_root = XRootWindowOfScreen(x_screen);
- if(atoms[_net_number_of_desktops] != None)
+ if(atomsSupported[_net_number_of_desktops])
{
if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_number_of_desktops], 0, 1, False,
XA_CARDINAL, &type, &format, &len, &fill,
}
}
- if(atoms[_net_current_desktop] != None)
+ if(atomsSupported[_net_current_desktop])
{
if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_current_desktop], 0, 1, False,
XA_CARDINAL, &type, &format, &len, &fill,
//printf("_NET_CURRENT_DESKTOP is %d\n", current);
}
}
- if(atoms[_net_workarea] != None)
+ if(atomsSupported[_net_workarea])
{
long *workareas;
char buffer[1024];
if(xGlobalDisplay)
XGetErrorText(xGlobalDisplay, event->error_code, buffer, sizeof(buffer));
+#ifdef _DEBUG
Logf("X Error: %s\n", buffer);
+#endif
return 0;
}
}
}
+static bool RequestFrameExtents(Window window)
+{
+ if(window.nativeDecorations && frameExtentSupported != broken)
+ {
+ // Request decoration frame extents
+ XClientMessageEvent event = { 0 };
+ event.type = ClientMessage;
+ event.message_type = atoms[_net_request_frame_extents];
+ event.display = xGlobalDisplay;
+ event.serial = 0;
+ event.window = (X11Window)window.windowHandle;
+ event.send_event = 1;
+ window.windowHandle = (void *)window.windowHandle;
+ event.format = 32;
+
+ if(frameExtentSupported == unknown && !frameExtentRequest)
+ {
+ frameExtentRequest = GetTime();
+ frameExtentWindow = (X11Window)window.windowHandle;
+ }
+
+ XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
+ SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+ }
+}
+
+static bool GetFrameExtents(Window window, bool update)
+{
+ XWindowData windowData = window.windowData;
+ bool result = false;
+ int format;
+ unsigned long len, fill;
+ Atom type;
+ char * data = null;
+
+ if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
+ atoms[_net_frame_extents], 0, 4,
+ False, XA_CARDINAL, &type, &format, &len,
+ &fill, &data) == Success && data)
+ {
+ long *extents = (long *)data;
+ bool change = extents[0] != windowData.decor.left ||
+ extents[1] != windowData.decor.right ||
+ extents[2] != windowData.decor.top ||
+ extents[3] != windowData.decor.bottom;
+
+ bool hadFrameExtents = windowData.gotFrameExtents;
+ Box oldDecor = windowData.decor;
+
+ frameExtentSupported = working;
+ frameExtentWindow = 0;
+ frameExtentRequest = 0;
+
+ if(!hadFrameExtents || extents[0] || extents[1] || extents[2] || extents[3])
+ {
+ windowData.decor =
+ {
+ left = (int)extents[0], right = (int)extents[1],
+ top = (int)extents[2], bottom = (int)extents[3]
+ };
+ windowData.gotFrameExtents = true;
+ if(update && change && ((Window)window).clientSize.w > 0)
+ {
+ int x = window.position.x, y = window.position.y, w = window.size.w, h = window.size.h;
+ if(!hadFrameExtents && window.state != maximized)
+ {
+ window.ComputeAnchors(
+ window.normalAnchor,
+ window.normalSizeAnchor,
+ &x, &y, &w, &h);
+ }
+ else
+ {
+ x += windowData.decor.left - oldDecor.left;
+ y += windowData.decor.top - oldDecor.top;
+
+ w += windowData.decor.left - oldDecor.left + windowData.decor.right - oldDecor.right;
+ h += windowData.decor.top - oldDecor.top + windowData.decor.bottom - oldDecor.bottom;
+ }
+
+ if(window.state != maximized)
+ {
+ window.Position(x, y, w, h, true, true, true, true, false, !hadFrameExtents && window.state != maximized);
+ XInterface::UpdateRootWindow(window);
+ }
+ }
+ result = true;
+ }
+ XFree(data);
+ }
+ return result;
+}
+
+static bool WaitForFrameExtents(Window window)
+{
+ int attempts = 0;
+ //XFlush(xGlobalDisplay);
+ while(attempts++ < 10)
+ {
+ if(GetFrameExtents(window, false)) return true;
+ Sleep(1.0 / RESOLUTION);
+ }
+ return false;
+}
+
/****************************************************************************
/// DRIVER IMPLEMENTATION /////////////
****************************************************************************/
}
/*
struct shmid_ds info;
- int maxid = shmctl (0, SHM_INFO, &info);
+ int maxid = shmctl (0, SHM_INFO, &info);
int pid = getpgrp();
int thisPid = getpid();
//if(thisPid == pid)
if(maxid >= 0)
{
int id;
- for(id = 0; id <= maxid; id++)
+ for(id = 0; id <= maxid; id++)
{
- struct shmid_ds shmseg;
+ struct shmid_ds shmseg;
int shmid;
- if((shmid = shmctl(id, SHM_STAT, &shmseg)) >= 0)
+ if((shmid = shmctl(id, SHM_STAT, &shmseg)) >= 0)
{
if(shmseg.shm_cpid == pid || shmseg.shm_cpid == thisPid)
{
xGlobalDisplay = XOpenDisplay(null);
frameExtentSupported = unknown;
- joystickFD[0] = open("/dev/js0", O_RDONLY);
+ joystickFD[0] = open("/dev/js0", O_RDONLY);
joystickFD[1] = open("/dev/js1", O_RDONLY);
joystickFD[2] = open("/dev/js2", O_RDONLY);
joystickFD[3] = open("/dev/js3", O_RDONLY);
+ systemCursors[iBeam] = XCreateFontCursor(xGlobalDisplay, XC_xterm);
+ systemCursors[cross] = XCreateFontCursor(xGlobalDisplay, XC_tcross);
+ systemCursors[moving] = XCreateFontCursor(xGlobalDisplay, XC_fleur);
+ systemCursors[sizeNESW] = XCreateFontCursor(xGlobalDisplay, XC_bottom_left_corner);
+ systemCursors[sizeNS] = XCreateFontCursor(xGlobalDisplay, XC_sb_v_double_arrow);
+ systemCursors[sizeNWSE] = XCreateFontCursor(xGlobalDisplay, XC_bottom_right_corner);
+ systemCursors[sizeWE] = XCreateFontCursor(xGlobalDisplay, XC_sb_h_double_arrow);
+ systemCursors[hand] = XCreateFontCursor(xGlobalDisplay, XC_hand2);
+ systemCursors[arrow] = XCreateFontCursor(xGlobalDisplay, XC_left_ptr);
+
if(xGlobalDisplay)
{
XWindowAttributes attributes = { 0 };
XInternAtoms(xGlobalDisplay, (char**)atomNames, AtomIdents::enumSize, False, atoms);
+ // Check which atoms are supported by the WM
+ {
+ int format;
+ unsigned long count, fill;
+ Atom type;
+ Atom * data;
+
+ if(XGetWindowProperty(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), atoms[_net_supported],
+ 0, 10000, False, XA_ATOM, &type, &format, &count, &fill, (void *)&data) == Success)
+ {
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ AtomIdents j;
+ for(j = 0; j < AtomIdents::enumSize; j++)
+ {
+ if(atoms[j] == data[i])
+ {
+ atomsSupported[j] = true;
+ break;
+ }
+ }
+ }
+ XFree(data);
+ }
+ }
+
{
Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
}
/*
- if(atoms[_net_workarea] == None)
+ if(atomsSupported[_net_workarea])
printf("Warning: _NET_WORKAREA extension not supported\n");
*/
delete timerThread;
hiResTimer.Stop();
+ XFreeCursor(xGlobalDisplay, systemCursors[iBeam]);
+ XFreeCursor(xGlobalDisplay, systemCursors[cross]);
+ XFreeCursor(xGlobalDisplay, systemCursors[moving]);
+ XFreeCursor(xGlobalDisplay, systemCursors[sizeNESW]);
+ XFreeCursor(xGlobalDisplay, systemCursors[sizeNS]);
+ XFreeCursor(xGlobalDisplay, systemCursors[sizeNWSE]);
+ XFreeCursor(xGlobalDisplay, systemCursors[sizeWE]);
+ XFreeCursor(xGlobalDisplay, systemCursors[hand]);
+ XFreeCursor(xGlobalDisplay, systemCursors[arrow]);
+
//XPutBackEvent(xGlobalDisplay, &e);
// xThread.Wait();
// delete xThread;
if(event->button == Button1)
{
+ // Force a raise on click here to deal with confused active state preventing to bring the window up
+ if(!atomsSupported[_net_active_window] && !window.isRemote)
+ {
+ XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+ XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
+ }
button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
whichButton = 0;
}
case SelectionRequest:
{
- XSelectionRequestEvent *req = (XSelectionRequestEvent *) thisEvent;
- XEvent respond;
- if(req->target == atoms[targets] && clipBoardData)
+ XSelectionRequestEvent *req = (XSelectionRequestEvent *) thisEvent;
+ XEvent respond;
+ if(req->target == atoms[targets] && clipBoardData)
{
Atom * supportedTargets = new Atom[4];
supportedTargets[0] = atoms[targets];
supportedTargets[2] = XA_STRING;
supportedTargets[3] = atoms[utf8_string];
XChangeProperty(xGlobalDisplay,req->requestor, req->_property,
- XA_ATOM,32,PropModeReplace, (byte *) supportedTargets, 4*sizeof(Atom));
+ XA_ATOM,32,PropModeReplace, (byte *) supportedTargets, 4*sizeof(Atom));
respond.xselection._property = req->_property;
delete supportedTargets;
}
else if((req->target == XA_STRING || req->target == atoms[utf8_string]) && clipBoardData)
- {
+ {
Atom _property = (req->_property == None) ? req->target : req->_property;
- XChangeProperty(xGlobalDisplay,req->requestor, _property,
- req->target/*req->_property*/,8,PropModeReplace, (byte *) clipBoardData, strlen(clipBoardData));
- respond.xselection._property = _property;
- }
+ XChangeProperty(xGlobalDisplay,req->requestor, _property,
+ req->target/*req->_property*/,8,PropModeReplace, (byte *) clipBoardData, strlen(clipBoardData));
+ respond.xselection._property = _property;
+ }
else
- respond.xselection._property = None;
+ respond.xselection._property = None;
respond.xselection.type = SelectionNotify;
- respond.xselection.display = req->display;
- respond.xselection.requestor = req->requestor;
- respond.xselection.selection =req->selection;
- respond.xselection.target = req->target;
- respond.xselection.time = CurrentTime;
- XSendEvent(xGlobalDisplay, req->requestor,0,0,&respond);
+ respond.xselection.display = req->display;
+ respond.xselection.requestor = req->requestor;
+ respond.xselection.selection =req->selection;
+ respond.xselection.target = req->target;
+ respond.xselection.time = CurrentTime;
+ XSendEvent(xGlobalDisplay, req->requestor,0,0,&respond);
break;
}
case SelectionClear:
case ConfigureNotify:
{
XConfigureEvent * event = (XConfigureEvent *) thisEvent;
+ bool unmaximized = false;
while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, (void *)ConfigureNotifyChecker, (void *)window.windowHandle));
//if(event->x - desktopX != window.position.x || event->y - desktopY != window.position.y || event->width != window.size.w || event->height != window.size.h)
- // TODO: Support _NET_REQUEST_FRAME_EXTENTS message / _NET_FRAME_EXTENTS property for decoration size awareness
- if(window.nativeDecorations)
+ if(atomsSupported[_net_wm_state]) //window.nativeDecorations)
{
int format;
unsigned long len, fill;
if(maxVert && maxHorz)
{
if(window.state != maximized)
+ {
*&window.state = maximized;
+ if(!window.nativeDecorations)
+ window.CreateSystemChildren();
+ }
}
else if(isMinimized)
{
if(window.state != minimized)
+ {
*&window.state = minimized;
+ if(!window.nativeDecorations)
+ window.CreateSystemChildren();
+ }
}
else if(window.state != normal)
+ {
+ if(window.state == maximized)
+ unmaximized = true;
*&window.state = normal;
+ if(!window.nativeDecorations)
+ window.CreateSystemChildren();
+ }
}
}
{
- int x = event->x;
- int y = event->y;
- int w = event->width, h = event->height;
-
- //if(event->send_event)
+ int x, y, w, h;
+ if(unmaximized)
{
- X11Window rootChild;
- int rootX, rootY;
- XTranslateCoordinates(xGlobalDisplay, event->window,
- RootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 0, 0,
- &rootX, &rootY, &rootChild);
- x = rootX;
- y = rootY;
+ // Ensure we set the normal size anchor when un-maximizing
+ if(window.nativeDecorations && RequestFrameExtents(window))
+ WaitForFrameExtents(window);
+ x = window.position.x, y = window.position.y, w = window.size.w, h = window.size.h;
+ window.ComputeAnchors(window.normalAnchor, window.normalSizeAnchor, &x, &y, &w, &h);
}
+ else
+ {
+ x = event->x;
+ y = event->y;
+ w = event->width, h = event->height;
+
+ //if(event->send_event)
+ {
+ X11Window rootChild;
+ int rootX, rootY;
+ XTranslateCoordinates(xGlobalDisplay, event->window,
+ RootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 0, 0,
+ &rootX, &rootY, &rootChild);
+ x = rootX;
+ y = rootY;
+ }
- x -= desktopX;
- y -= desktopY;
+ x -= desktopX;
+ y -= desktopY;
- if(window.nativeDecorations && window.state != maximized)
+ if(window.nativeDecorations && window.state != maximized)
+ {
+ x -= windowData.decor.left;
+ y -= windowData.decor.top;
+ w += windowData.decor.left + windowData.decor.right;
+ h += windowData.decor.top + windowData.decor.bottom;
+ /*
+ x -= window.clientStart.x;
+ y -= window.clientStart.y - (window.hasMenuBar ? skinMenuHeight : 0);
+ w += window.size.w - window.clientSize.w;
+ h += window.size.h - window.clientSize.h;
+ */
+ }
+ }
+
+ // Break the anchors for moveable/resizable windows
+ if(window.style.fixed && window.state == normal)
{
- x -= windowData.decor.left;
- y -= windowData.decor.top;
- w += windowData.decor.left + windowData.decor.right;
- h += windowData.decor.top + windowData.decor.bottom;
- /*
- x -= window.clientStart.x;
- y -= window.clientStart.y - (window.hasMenuBar ? skinMenuHeight : 0);
- w += window.size.w - window.clientSize.w;
- h += window.size.h - window.clientSize.h;
- */
+ window.normalAnchor = Anchor { left = x, top = y };
+ window.normalSizeAnchor = SizeAnchor { { w, h } };
+ window.anchored = false;
+ }
+
+ // Break the anchors for moveable/resizable windows
+ if(window.style.fixed && window.state == normal)
+ {
+ window.normalAnchor = Anchor { left = x, top = y };
+ window.normalSizeAnchor = SizeAnchor { { w, h } };
+ window.anchored = false;
}
- window.Position(x, y, w, h, true, true, true, true, false, false);
+
+ window.Position(x, y, w, h, true, true, true, true, false, unmaximized);
}
break;
}
{
XRaiseWindow(xGlobalDisplay, (X11Window)modalRoot.windowHandle);
WaitForViewableWindow(modalRoot);
- if(atoms[_net_active_window])
+ if(atomsSupported[_net_active_window])
{
XClientMessageEvent event = { 0 };
event.type = ClientMessage;
if(event->atom == atoms[_net_frame_extents] &&
event->state == PropertyNewValue && windowData)
{
- int format;
- unsigned long len, fill;
- Atom type;
- char * data = null;
-
- if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
- atoms[_net_frame_extents], 0, 4,
- False, XA_CARDINAL, &type, &format, &len,
- &fill, &data) == Success && data)
- {
- long *extents = (long *)data;
- bool change = extents[0] != windowData.decor.left ||
- extents[1] != windowData.decor.right ||
- extents[2] != windowData.decor.top ||
- extents[3] != windowData.decor.bottom;
-
- bool hadFrameExtents = windowData.gotFrameExtents;
- Box oldDecor = windowData.decor;
-
- frameExtentSupported = working;
- frameExtentWindow = 0;
- frameExtentRequest = 0;
-
- if(!hadFrameExtents || extents[0] || extents[1] || extents[2] || extents[3])
- {
- windowData.decor =
- {
- left = (int)extents[0], right = (int)extents[1],
- top = (int)extents[2], bottom = (int)extents[3]
- };
- windowData.gotFrameExtents = true;
- if(change && ((Window)window).clientSize.w > 0)
- {
- int x = window.position.x, y = window.position.y, w = window.size.w, h = window.size.h;
- if(!hadFrameExtents && window.state != maximized)
- {
- window.ComputeAnchors(
- window.normalAnchor,
- window.normalSizeAnchor,
- &x, &y, &w, &h);
- }
- else
- {
- x += windowData.decor.left - oldDecor.left;
- y += windowData.decor.top - oldDecor.top;
-
- w += windowData.decor.left - oldDecor.left + windowData.decor.right - oldDecor.right;
- h += windowData.decor.top - oldDecor.top + windowData.decor.bottom - oldDecor.bottom;
- }
-
- if(window.state != maximized)
- {
- window.Position(x, y, w, h, true, true, true, true, false, !hadFrameExtents && window.state != maximized);
- UpdateRootWindow(window);
- }
- }
- }
- XFree(data);
- }
- else
+ if(!GetFrameExtents(window, true))
windowData.gotFrameExtents = true; // Unsupported?
}
break;
XIC ic = null;
unsigned long mask = EVENT_MASK;
- attributes.override_redirect = window.interim ? True : False;
+ // Old WM (e.g. TWM), use built-in decorations
+ if(!atomsSupported[_net_wm_state])
+ window.nativeDecorations = false;
+ attributes.override_redirect = (window.interim || (!atomsSupported[_net_wm_state] && !window.nativeDecorations)) ? True : False;
attributes.event_mask = EVENT_MASK;
//printf("%s\n", guiApp.defaultDisplayDriver);
#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
else
{
X11Window parentWindow = (X11Window)null;
+ int x = window.position.x + desktopX, y = window.position.y + desktopY;
+ int w = window.state == normal ? Max(1, window.size.w) : Max(1, window.normalSizeAnchor.size.w);
+ int h = window.state == normal ? Max(1, window.size.h) : Max(1, window.normalSizeAnchor.size.h);
+ if(!window.nativeDecorations && window.state != normal)
+ {
+ w += window.size.w - window.clientSize.w;
+ h += window.size.h - window.clientSize.h;
+ }
if(window.master.rootWindow && window.master.rootWindow != guiApp.desktop && (window._isModal || window.style.interim))
{
parentWindow = (X11Window)null;
windowHandle = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay),
- 0,0,1,1,0, depth, InputOutput, visual ? visual : CopyFromParent,
+ x, y, w, h,
+ 0, depth, InputOutput, visual ? visual : CopyFromParent,
CWEventMask | CWOverrideRedirect | (visual ? (CWColormap | CWBorderPixel) : 0), &attributes);
if(parentWindow && (window.interim || window.isModal))
//printf("Done.\n");
//XChangeProperty(xGlobalDisplay, windowHandle, atoms[wm_transient_for], XA_WINDOW, 32, PropModeReplace, (unsigned char*)&parentWindow, 1);
if(window.isModal)
- {
- Atom hints[1] = { atoms[_net_wm_state_modal] };
- XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM, 32, PropModeReplace, (unsigned char*)&hints, 1);
- }
+ SetNETWMState(windowHandle, false, add, atoms[_net_wm_state_modal], 0);
}
{
}
// Set Normal hints for minimum/maximum size
- if(window.minSize.w || window.minSize.h || window.maxSize.w < MAXINT || window.maxSize.h < MAXINT)
+ if(true) //window.minSize.w || window.minSize.h || window.maxSize.w < MAXINT || window.maxSize.h < MAXINT)
{
XSizeHints hints = { 0 };
+ MinMaxValue mw, mh;
+ window.SetWindowMinimum(&mw, &mh);
if(window.minSize.w || window.minSize.h)
{
- hints.min_width = window.minSize.w;
- hints.min_height = window.minSize.h;
+ hints.min_width = Max(window.minSize.w, mw);
+ hints.min_height = Max(window.minSize.h, mh);
hints.flags |= PMinSize;
}
if(window.maxSize.w < MAXINT || window.minSize.h < MAXINT)
hints.max_height = window.maxSize.h;
hints.flags |= PMaxSize;
}
+ hints.x = x;
+ hints.y = y;
+ hints.flags |= PPosition;
+
+ hints.width = w;
+ hints.height = h;
+ hints.flags |= PSize;
+
XSetWMNormalHints(xGlobalDisplay, windowHandle, &hints);
}
}
}
if(ic)
{
- XGetICValues(ic, XNFilterEvents, &mask, NULL);
- mask |= EVENT_MASK;
+ XGetICValues(ic, XNFilterEvents, &mask, NULL);
+ mask |= EVENT_MASK;
}
/*
XSelectInput(xGlobalDisplay, windowHandle, mask);
XChangeProperty(xGlobalDisplay, windowHandle, atoms[_motif_wm_hints], atoms[_motif_wm_hints], 32,
PropModeReplace, (unsigned char*)&hints, 5);
}
- if(atoms[_net_wm_pid] != None)
+
+ // *** We set this for ourselves, so don't check atomsSupported !!! ***
+ if(atoms[_net_wm_pid])
{
int pid = getpid();
// printf("Setting _NET_WM_PID to %d\n", pid);
XUngrabPointer(xGlobalDisplay, CurrentTime);
}
- if(window.nativeDecorations && frameExtentSupported != broken)
- {
- // Request decoration frame extents
- XClientMessageEvent event = { 0 };
- event.type = ClientMessage;
- event.message_type = atoms[_net_request_frame_extents];
- event.display = xGlobalDisplay;
- event.serial = 0;
- event.window = (X11Window)windowHandle;
- event.send_event = 1;
- window.windowHandle = (void *)windowHandle;
- event.format = 32;
-
- if(frameExtentSupported == unknown && !frameExtentRequest)
- {
- frameExtentRequest = GetTime();
- frameExtentWindow = windowHandle;
- }
-
- XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
- SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
- }
- else
+ if(!window.nativeDecorations || !RequestFrameExtents(window))
((XWindowData)window.windowData).gotFrameExtents = true;
return (void *)windowHandle;
}
bool visible = window.visible;
if(window.visible && window.created)
XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
- if(window.state == minimized) return;
+ if(window.state == minimized && atomsSupported[_net_wm_state]) return;
if(window.nativeDecorations)
{
// Was commenting this out was part of #700/#795 fix, but this causes jumping of e.g. About box after getting frame extents PropertyNotify
// && window.state != maximized -- required for Cinnamon on Mint 14/15
- if(!windowData.gotFrameExtents && window.state != maximized) return;
+ if(!windowData.gotFrameExtents && window.state != maximized)
+ {
+ if(WaitForFrameExtents(window))
+ {
+ x += windowData.decor.left;
+ y += windowData.decor.top ;
+
+ w += windowData.decor.left + windowData.decor.right;
+ h += windowData.decor.top + windowData.decor.bottom;
+ }
+ }
x -= windowData.decor.left;
y -= windowData.decor.top;
h -= windowData.decor.top + windowData.decor.bottom;
// Tweak for first unmaximize on Unity on Ubuntu 11.10
- if(window.state == maximized && (desktopX + w > desktopW || desktopY + h > desktopH))
+ /*if(window.state == maximized && (desktopX + w > desktopW || desktopY + h > desktopH))
{
w -= 40;
h -= 40;
- }
+ }*/
}
x += desktopX;
y += desktopY;
- if(move && resize)
- XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y, w, h);
- else if(move)
- XMoveWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y);
- else if(resize)
- XResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, w, h);
+ if(!atomsSupported[_net_wm_state] || window.state != maximized)
+ {
+ if(move && resize)
+ XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y, w, h);
+ else if(move)
+ XMoveWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y);
+ else if(resize)
+ XResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, w, h);
+ }
#if defined(__APPLE__)
// if(window.created && !visible)
// XUnmapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
}
}
-
void SetRootWindowState(Window window, WindowState state, bool visible)
{
+ // Old WM (e.g. TWM), use built-in decorations
+ if(!atomsSupported[_net_wm_state])
+ window.nativeDecorations = false;
if(!window.parent || !window.parent.display)
{
//Logf("Set root window state %d %s\n", state, window.name);
if(window.creationActivation == activate && state != minimized)
ActivateRootWindow(window);
- if(state == minimized)
+ if(state == minimized && atomsSupported[_net_wm_state])
{
uint iconic = IconicState;
- /*
- XChangeProperty(xGlobalDisplay, window.windowHandle, atoms[_net_wm_state], XA_ATOM, 32,
- PropModeReplace, (unsigned char*)&atoms[_net_wm_state_hidden], 1);
- */
+
+ // SetNETWMState(window.windowHandle, true, add, atoms[_net_wm_state_hidden], null);
/*
XChangeProperty(xGlobalDisplay, window.windowHandle, atoms[wm_state], XA_CARDINAL, 32,
PropModeReplace, &iconic, 1);
/*
XClientMessageEvent event = { 0 };
event.type = ClientMessage;
- event.message_type = atoms[_net_wm_state];
- event.display = xGlobalDisplay;
- event.serial = 0;
- event.window = window.windowHandle;
- event.send_event = 1;
- event.format = 32;
- event.data.l[0] = 2; // 1;
- event.data.l[1] = atoms[_net_wm_state_hidden];
- XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, &event);
- */
- /*
- XClientMessageEvent event = { 0 };
- event.type = ClientMessage;
event.message_type = atoms[wm_state];
event.display = xGlobalDisplay;
event.window = window.windowHandle;
}
else
{
- if(!window.nativeDecorations || (!((XWindowData)window.windowData).gotFrameExtents && window.state == maximized)) //((XWindowData)window.windowData).gotFrameExtents && (!window.nativeDecorations || window.state == state))
+ //((XWindowData)window.windowData).gotFrameExtents && (!window.nativeDecorations || window.state == state))
+ if(!atomsSupported[_net_wm_state] || (!((XWindowData)window.windowData).gotFrameExtents && window.state == maximized))
{
- int x = window.position.x;
- int y = window.position.y;
- int w = window.size.w;
- int h = window.size.h;
-
- if(window.nativeDecorations)
+ // Running this block avoids the initial IDE maximized->unmaximized flicker
+ //if(window.state != maximized || !atomsSupported[_net_wm_state] || window.nativeDecorations)
{
- XWindowData windowData = window.windowData;
- x -= windowData.decor.left;
- y -= windowData.decor.top;
+ int x = window.position.x;
+ int y = window.position.y;
+ int w = window.size.w;
+ int h = window.size.h;
+
+ if(window.nativeDecorations)
+ {
+ XWindowData windowData = window.windowData;
+ x -= windowData.decor.left;
+ y -= windowData.decor.top;
+
+ w -= windowData.decor.left + windowData.decor.right;
+ h -= windowData.decor.top + windowData.decor.bottom;
+ }
+ x += desktopX;
+ y += desktopY;
- w -= windowData.decor.left + windowData.decor.right;
- h -= windowData.decor.top + windowData.decor.bottom;
+ XMoveResizeWindow(xGlobalDisplay,
+ (X11Window)window.windowHandle,
+ x, y, w, h);
}
- x += desktopX;
- y += desktopY;
-
- // With native decorations, we do it the first time
- // or the WM (Gnome) is sticking it to the top/right!
- XMoveResizeWindow(xGlobalDisplay,
- (X11Window)window.windowHandle,
- x, y, w, h);
UpdateRootWindow(window);
}
- if(window.nativeDecorations)
+ if(atomsSupported[_net_wm_state])
{
// Maximize / Restore the window
- XClientMessageEvent event = { 0 };
- event.type = ClientMessage;
- event.message_type = atoms[_net_wm_state];
- event.display = xGlobalDisplay;
- event.serial = 0;
- event.window = (X11Window)window.windowHandle;
- event.send_event = 1;
- event.format = 32;
- event.data.l[0] = (state == maximized) ? 1 : 0;
- event.data.l[1] = atoms[_net_wm_state_maximized_vert];
- event.data.l[2] = atoms[_net_wm_state_maximized_horz];
- XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
- SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+ SetNETWMState((X11Window)window.windowHandle, true, state == maximized ? add: remove,
+ atoms[_net_wm_state_maximized_vert], atoms[_net_wm_state_maximized_horz]);
+ if(state == maximized)
+ {
+ // Prevent the code in ConfigureNotify to think the window has been unmaximized
+ // if the Window Manager hasn't set the hints yet.
+ XFlush(xGlobalDisplay);
+ Sleep(0.01);
+ }
}
}
}
void FlashRootWindow(Window window)
{
- XClientMessageEvent event = { 0 };
// printf("Attempting to flash root window\n");
- event.type = ClientMessage;
- event.message_type = atoms[_net_wm_state];
- event.display = xGlobalDisplay;
- event.serial = 0;
- event.window = (X11Window)window.windowHandle;
- event.send_event = 1;
- event.format = 32;
- event.data.l[0] = 1;
- event.data.l[1] = atoms[_net_wm_state_demands_attention];
- XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+ SetNETWMState((X11Window)window.windowHandle, true, add, atoms[_net_wm_state_demands_attention], 0);
}
void ActivateRootWindow(Window window)
XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
WaitForViewableWindow(window);
- if(atoms[_net_active_window])
+ if(atomsSupported[_net_active_window])
{
XClientMessageEvent event = { 0 };
event.type = ClientMessage;
// -- Mouse cursor ---
- void SetMouseCursor(int cursor)
+ void SetMouseCursor(Window window, int cursor)
{
- //*XLockDisplay(xGlobalDisplay);
- if(cursor == -1)
- {
- XDefineCursor(xGlobalDisplay, (X11Window) guiApp.desktop.windowHandle, nullCursor);
- }
- //*XUnlockDisplay(xGlobalDisplay);
+ XDefineCursor(xGlobalDisplay, (X11Window) window.rootWindow.windowHandle,
+ cursor == -1 ? (X11Cursor)0 : systemCursors[(SystemCursor)cursor]);
}
// --- Caret ---
if(clipBoardData)
{
delete clipBoardData;
- XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
+ XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
}
//*XUnlockDisplay(xGlobalDisplay);
}
else
memcpy(icon + 2, bitmap.picture, bitmap.width * bitmap.height * sizeof(uint32));
XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_icon],
- XA_CARDINAL,32,PropModeReplace, (byte *)icon, 2+bitmap.width*bitmap.height);
- delete icon;
+ XA_CARDINAL,32,PropModeReplace, (byte *)icon, 2+bitmap.width*bitmap.height);
+ delete icon;
}
delete bitmap;
}