Skip to content

Instantly share code, notes, and snippets.

@tom-seddon
Created April 16, 2017 18:22
Show Gist options
  • Save tom-seddon/988cb157b09b3dccaeab7b3374361af1 to your computer and use it in GitHub Desktop.
Save tom-seddon/988cb157b09b3dccaeab7b3374361af1 to your computer and use it in GitHub Desktop.
Some Xlib junk, vaguely along the lines of GetWindowPlacement/SetWindowPlacement
#include <shared/system.h>
#include "x11.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xinerama.h>
#include <string.h>
#include <shared/log.h>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static const char NET_WM_STATE[]="_NET_WM_STATE";
static const char NET_WM_STATE_MAXIMIZED_HORZ[]="_NET_WM_STATE_MAXIMIZED_HORZ";
static const char NET_WM_STATE_MAXIMIZED_VERT[]="_NET_WM_STATE_MAXIMIZED_VERT";
enum {
_NET_WM_STATE_REMOVE=0, // remove/unset property
_NET_WM_STATE_ADD=1, // add/set property
_NET_WM_STATE_TOGGLE=2, // toggle property
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
template<class T>
static void Free(T **p_ptr) {
if(*p_ptr) {
XFree(*p_ptr);
*p_ptr=nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static void *GetWindowProperty(unsigned long *num_items,
Display *display,
Window window,
Atom property)
{
Atom actual_type;
int actual_format;
unsigned long tmp_num_items,bytes_after;
unsigned char *prop;
int result=XGetWindowProperty(display, /* display */
window, /* window */
property, /* property */
0, /* long_offset */
~0L, /* long_length */
False, /* delete */
AnyPropertyType, /* req_type */
&actual_type, /* actual_type_return */
&actual_format, /* actual_format_return */
&tmp_num_items, /* nitems_return */
&bytes_after, /* bytes_after_return */
&prop); /* prop_return */
if(result==Success) {
/* char *n=XGetAtomName(display,property); */
/* printf("Property %s, actual format=%d\n",n,actual_format); */
/* XFree(n); */
} else {
tmp_num_items=0;
prop=NULL;
}
if(num_items) {
*num_items=tmp_num_items;
}
return prop;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static bool IsWindowManagerStateSet(Display *display,
Window window,
const char *atom_name)
{
Atom net_wm_state=XInternAtom(display,NET_WM_STATE,False);
if(net_wm_state==None) {
return false;
}
Atom atom=XInternAtom(display,atom_name,False);
if(atom==None) {
return false;
}
bool set=false;
unsigned long num_ws;
if(auto ws=(Atom *)GetWindowProperty(&num_ws,
display,
window,
net_wm_state))
{
for(unsigned long ws_idx=0;ws_idx<num_ws;++ws_idx) {
if(ws[ws_idx]==atom) {
set=true;
break;
}
}
Free(&ws);
}
return set;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
bool GetXWindowPlacement(XWindowPlacement *placement,
Display *display,
uint64_t window)
{
if(!display||window==0) {
return false;
}
XWindowAttributes xwa;
if(!XGetWindowAttributes(display,window,&xwa)) {
return false;
}
Window child;
if(!XTranslateCoordinates(display,window,xwa.root,0,0,&xwa.x,&xwa.y,&child)) {
return false;
}
if(xwa.width<0||xwa.height<0) {
return false;
}
placement->valid=1;
placement->hmax=IsWindowManagerStateSet(display,window,NET_WM_STATE_MAXIMIZED_HORZ);
placement->vmax=IsWindowManagerStateSet(display,window,NET_WM_STATE_MAXIMIZED_VERT);
if(!placement->hmax) {
placement->x=xwa.x;
placement->w=(unsigned)xwa.width;
}
if(!placement->vmax) {
placement->y=xwa.y;
placement->h=(unsigned)xwa.height;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static void SetWindowMaximizedFlag(Display *display,
Window window,
const char *name,
bool state)
{
Atom net_wm_state=XInternAtom(display,NET_WM_STATE,False);
if(net_wm_state==None) {
return;
}
Atom atom=XInternAtom(display,name,False);
if(atom==None) {
return;
}
XEvent e;
memset(&e,0,sizeof e);
e.xany.type=ClientMessage;
e.xclient.message_type=net_wm_state;
e.xclient.format=32;
e.xclient.window=window;
e.xclient.data.l[0]=state?_NET_WM_STATE_ADD:_NET_WM_STATE_REMOVE;
e.xclient.data.l[1]=(long)atom;
// http://standards.freedesktop.org/wm-spec/1.3/ar01s07.html#sourceindication
e.xclient.data.l[3]=2; /* "pagers and other Clients that
* represent direct user actions" */
XSendEvent(display,
XDefaultRootWindow(display),
True,
SubstructureNotifyMask|SubstructureRedirectMask,
&e);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void SetXWindowPlacement(Display *display,
uint64_t window,
const XWindowPlacement &placement)
{
if(!placement.valid) {
return;
}
//OU_LOG(OUTPUT,"%s: x=%d y=%d w=%d h=%d\n",__func__,placement.x,placement.y,placement.w,placement.h);
SetWindowMaximizedFlag(display,window,NET_WM_STATE_MAXIMIZED_HORZ,false);
SetWindowMaximizedFlag(display,window,NET_WM_STATE_MAXIMIZED_VERT,false);
if(placement.x!=INT_MIN&&placement.y!=INT_MIN) {
XMoveWindow(display,window,placement.x,placement.y);
}
if(placement.w>0&&placement.h>0) {
XResizeWindow(display,window,placement.w,placement.h);
}
if(placement.hmax) {
SetWindowMaximizedFlag(display,window,NET_WM_STATE_MAXIMIZED_HORZ,true);
}
if(placement.vmax) {
SetWindowMaximizedFlag(display,window,NET_WM_STATE_MAXIMIZED_VERT,true);
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#ifndef HEADER_710C85347C9F4264A30F6361CB5DB1F7// -*- mode:c++ -*-
#define HEADER_710C85347C9F4264A30F6361CB5DB1F7
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#include <limits.h>
struct _XDisplay;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// X11 analogue of WINDOWPLACEMENT. This just gets stuffed in the
// BeebWindows placementdata bit. Probably needs some better
// mechanism...
#include <shared/pshpack1.h>
struct XWindowPlacement {
// if false, the Set operation is a no-op.
int8_t valid=false;
// horizontally/vertically maximized flags
uint8_t hmax=0;
uint8_t vmax=0;
// Window rect in display coordinates.
//
// If x or y is INT_MIN, the position isn't set; if width or
// height is 0, the size isn't set.
int32_t x=INT_MIN,y=INT_MIN;
unsigned w=0,h=0;
};
#include <shared/poppack.h>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// If the window is in one axis, the coordinate and size on that axis
// is not set, as there doesn't seem to be any way to get the
// unmaximized size of an X window. So this grabs that info if it's
// available, and leaves the old values in place if it isn't.
bool GetXWindowPlacement(XWindowPlacement *placement,
_XDisplay *display,
uint64_t window);
void SetXWindowPlacement(_XDisplay *display,
uint64_t window,
const XWindowPlacement &placement);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment