This forum has been archived. All content is frozen. Please use KDE Discuss instead.

X11 - Detect whether using the K DE/WM?

Tags: None
(comma "," separated)
samuelvenable
Registered Member
Posts
9
Karma
0
I created a borderless toggle extension for GameMaker Studio, and a requirement of this software is that is can only make use of exported functions with double's and pointers for the arguments and return values, just to give some background on why I did that, beforehand. I am using similar code for another game engine known as ENIGMA. This code can be used on virtually any X11 application simply by either in the form of a dynamic or static library, as well as just including the header.

I noticed KDE responds to the code I am using to measure the title bar and window border than most other desktop environments I've tried - this includes KDE (ofc), GNOME, XFCE, and LXDE. GNOME, XFCE, and LXDE all responded the same to the code. The client area of the application positioned to the same coordinates specified by the clientx and clienty arguments, however, in KDE the window moved to the wrong positon with the same code used. So then, I had to detect whether the current Desktop Environment was running KWin, which is KDE's native Window Manager, if I remember correctly. I'm not sure if it is the the desktop environment at fault, or the Window Manager that is responsible for this oddity and inconsistency among the other Linux distributions I've tried, but I assume it is the WM, as my best guess.

Long story short, I need to know for certain which is causing the issue, the DE, or the WM, and then, I need to be able to check that accurately in code, because right now I'm just checking for the environment variable XDG_CURRENT_DESKTOP and if it has a value of KDE then use KDE specific code, otherwise use GNOME/XFCE/LXDE code. As you can see, I managed to eventually get it working in KDE as well as non-KDE DE's, in the GIF's below, but this is only done by sheer luck of the XDG_CURRENT_DESKTOP environment variable both existing on KDE neon, as well as equaling the exact value of KDE. That said, it doesn't work anymore if I delete or change the value of XDG_CURRENT_DESKTOP, and it will also not work if I happen to not be using KDE as my desktop environment, but am using the KWin Window Manager. Please help.

ShowBorder.h (C++ Header):

Code: Select all
/******************************************************************************

 MIT License

 Copyright © 2019 Samuel Venable

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

******************************************************************************/

#ifdef _WIN32
#define EXPORTED_FUNCTION extern "C" __declspec(dllexport)
#else /* macOS and Linux */
#define EXPORTED_FUNCTION extern "C" __attribute__((visibility("default")))
#endif

EXPORTED_FUNCTION double window_get_showborder(void *hwnd);
EXPORTED_FUNCTION double window_set_showborder(void *hwnd, double show, double clientx, double clienty);


ShowBorder.cpp (C++ Source):

Code: Select all
/******************************************************************************

 MIT License

 Copyright © 2019 Samuel Venable

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

******************************************************************************/

#include "ShowBorder.h"
#include <X11/Xlib.h>
#include <climits>

typedef struct {
  unsigned long flags;
  unsigned long functions;
  unsigned long decorations;
  long inputMode;
  unsigned long status;
} Hints;

double window_get_showborder(void *hwnd) {
  Atom type;
  int format;
  unsigned long bytes;
  unsigned long items;
  unsigned char *data = NULL;
  bool ret = true;
  Display *d = XOpenDisplay(NULL);
  Window w = (Window)hwnd;
  Atom property = XInternAtom(d, "_MOTIF_WM_HINTS", False);
  if (XGetWindowProperty(d, w, property, 0, LONG_MAX, False, AnyPropertyType, &type, &format, &items, &bytes, &data) == Success && data != NULL) {
    Hints *hints = (Hints *)data;
    ret = hints->decorations;
    XFree(data);
  }
  XCloseDisplay(d);
  return ret;
}

double window_set_showborder(void *hwnd, double show, double clientx, double clienty) {
  Display *d = XOpenDisplay(NULL);
  Window w = (Window)hwnd;
  Atom aKWinRunning = XInternAtom(d, "KWIN_RUNNING", True);
  bool bKWinRunning = (aKWinRunning != None);
  XWindowAttributes wa;
  Window root, parent, *child; uint children;
  XWindowAttributes pwa;
  for (;;) {
    XGetWindowAttributes(d, w, &wa);
    XQueryTree(d, w, &root, &parent, &child, &children);
    XGetWindowAttributes(d, parent, &pwa);
    if ((bKWinRunning ? pwa.x : wa.x) || (bKWinRunning ? pwa.y : wa.y) || !window_get_showborder(hwnd))
      break;
  }
  static const int xoffset = bKWinRunning ? pwa.x : wa.x;
  static const int yoffset = bKWinRunning ? pwa.y : wa.y;
  Hints hints;
  Atom property = XInternAtom(d, "_MOTIF_WM_HINTS", False);
  hints.flags = 2;
  hints.decorations = show;
  XChangeProperty(d, w, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
  int xpos = show ? clientx - xoffset : clientx;
  int ypos = show ? clienty - yoffset : clienty;
  XMoveResizeWindow(d, w, xpos, ypos, bKWinRunning ? wa.width : wa.width + xoffset, bKWinRunning ? wa.height : wa.height + yoffset);
  XCloseDisplay(d);
  return 0;
}


GameMaker Studio 2 Usage:

Code: Select all
/// @desc Global Mouse Left Pressed Event:
var hwnd = window_handle(); // Get GameMaker's Runner Window ID
var show = !window_get_showborder(hwnd); // Get Destination Border State
var clientx = window_get_x(); // Get the Current Window X Position
var clienty = window_get_y(); // Get the Current Window Y Position
window_set_showborder(hwnd, show, clientx, clienty); // Set Border State


GameMaker Studo 2 Result:

https://i.imgur.com/CTV3A6b.gif (KDE neon 5.16.4)
https://i.imgur.com/rwpD476.gif (Lubuntu 18.04.2 LTS)
https://i.imgur.com/eB4OUfk.gif (Xubuntu 18.04.2 LTS)
https://i.imgur.com/REAFb9B.gif (Ubuntu 18.04.2 LTS)

Needless to say, it also worked in Kubuntu 18.04.2 LTS, but I don't have screenshots for that.

Thanks,
Samuel

Last edited by samuelvenable on Thu Aug 08, 2019 9:05 pm, edited 5 times in total.
kde-cfeck
Registered Member
Posts
93
Karma
0
There are multiple ways to check if KWin is running.

* Use D-Bus. KWin registers the 'org.kde.KWin' namespace there.

* Check https://cgit.kde.org/kwin.git/tree/atoms.cpp for X11 Atoms KWin uses.

But I suggest to report your issue to bugs.kde.org. KWin developers might check if KWin is wrong or your code is wrong.
samuelvenable
Registered Member
Posts
9
Karma
0
That's perfect! Thank you! I will update my code in the OP with the changes I've made. It works great!


Bookmarks



Who is online

Registered users: Bing [Bot], Evergrowing, Google [Bot], rblackwell