1 //
2 // X11.hh for pekwm
3 // Copyright (C) 2003-2020 the pekwm development team
4 //
5 // This program is licensed under the GNU GPL.
6 // See the LICENSE file for more information.
7 //
8 
9 #ifndef _PEKWM_X11_HH_
10 #define _PEKWM_X11_HH_
11 
12 #include "config.h"
13 
14 #include "Compat.hh"
15 #include "Types.hh"
16 
17 #include <iostream>
18 #include <string>
19 #include <vector>
20 
21 extern "C" {
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24 #include <X11/Xatom.h>
25 #include <X11/keysym.h>
26 #include <X11/keysymdef.h>
27 #ifdef PEKWM_HAVE_XINERAMA
28 #include <X11/extensions/Xinerama.h>
29 #endif // PEKWM_HAVE_XINERAMA
30 #ifdef PEKWM_HAVE_SHAPE
31 #include <X11/extensions/shape.h>
32 #else // ! PEKWM_HAVE_SHAPE
33 #define ShapeSet 0
34 #define ShapeIntersect 2
35 
36 #define ShapeBounding 0
37 #define ShapeInput 2
38 
39 #define ShapeNotifyMask 1
40 #endif // PEKWM_HAVE_SHAPE
41 
42 	extern bool xerrors_ignore; /**< If true, ignore X errors. */
43 	extern unsigned int xerrors_count; /**< Number of X errors occured. */
44 
45 #define setXErrorsIgnore(X) xerrors_ignore = (X)
46 
47 }
48 
49 typedef long Cardinal;
50 
51 enum AtomName {
52 	// Ewmh Atom Names
53 	NET_SUPPORTED,
54 	NET_CLIENT_LIST, NET_CLIENT_LIST_STACKING,
55 	NET_NUMBER_OF_DESKTOPS,
56 	NET_DESKTOP_GEOMETRY, NET_DESKTOP_VIEWPORT,
57 	NET_CURRENT_DESKTOP, NET_DESKTOP_NAMES,
58 	NET_ACTIVE_WINDOW, NET_WORKAREA,
59 	NET_DESKTOP_LAYOUT, NET_SUPPORTING_WM_CHECK,
60 	NET_CLOSE_WINDOW,
61 	NET_WM_MOVERESIZE,
62 	NET_REQUEST_FRAME_EXTENTS,
63 	NET_WM_NAME, NET_WM_VISIBLE_NAME,
64 	NET_WM_ICON_NAME, NET_WM_VISIBLE_ICON_NAME,
65 	NET_WM_ICON, NET_WM_DESKTOP,
66 	NET_WM_STRUT, NET_WM_PID,
67 	NET_WM_USER_TIME,
68 	NET_FRAME_EXTENTS,
69 	NET_WM_WINDOW_OPACITY,
70 
71 	WINDOW_TYPE,
72 	WINDOW_TYPE_DESKTOP,
73 	WINDOW_TYPE_DOCK,
74 	WINDOW_TYPE_TOOLBAR,
75 	WINDOW_TYPE_MENU,
76 	WINDOW_TYPE_UTILITY,
77 	WINDOW_TYPE_SPLASH,
78 	WINDOW_TYPE_DIALOG,
79 	WINDOW_TYPE_DROPDOWN_MENU,
80 	WINDOW_TYPE_POPUP_MENU,
81 	WINDOW_TYPE_TOOLTIP,
82 	WINDOW_TYPE_NOTIFICATION,
83 	WINDOW_TYPE_COMBO,
84 	WINDOW_TYPE_DND,
85 	WINDOW_TYPE_NORMAL,
86 
87 	STATE,
88 	STATE_MODAL, STATE_STICKY,
89 	STATE_MAXIMIZED_VERT, STATE_MAXIMIZED_HORZ,
90 	STATE_SHADED,
91 	STATE_SKIP_TASKBAR, STATE_SKIP_PAGER,
92 	STATE_HIDDEN, STATE_FULLSCREEN,
93 	STATE_ABOVE, STATE_BELOW,
94 	STATE_DEMANDS_ATTENTION,
95 
96 	EWMH_ALLOWED_ACTIONS,
97 	EWMH_ACTION_MOVE, EWMH_ACTION_RESIZE,
98 	EWMH_ACTION_MINIMIZE, EWMH_ACTION_SHADE,
99 	EWMH_ACTION_STICK,
100 	EWHM_ACTION_MAXIMIZE_VERT, EWMH_ACTION_MAXIMIZE_HORZ,
101 	EWMH_ACTION_FULLSCREEN, ACTION_CHANGE_DESKTOP,
102 	EWMH_ACTION_CLOSE,
103 
104 	// all EWMH atoms must be before this, see x11::setEwmhAtomsSupport
105 	UTF8_STRING,
106 
107 	STRING, MANAGER,
108 
109 	// pekwm atom names
110 	PEKWM_FRAME_ID,
111 	PEKWM_FRAME_ORDER,
112 	PEKWM_FRAME_ACTIVE,
113 	PEKWM_FRAME_DECOR,
114 	PEKWM_FRAME_SKIP,
115 	PEKWM_TITLE,
116 	PEKWM_BG_PID,
117 	PEKWM_CMD,
118 	PEKWM_THEME,
119 
120 	// ICCCM Atom Names
121 	WM_NAME,
122 	WM_ICON_NAME,
123 	WM_HINTS,
124 	WM_CLASS,
125 	WM_STATE,
126 	WM_CHANGE_STATE,
127 	WM_PROTOCOLS,
128 	WM_DELETE_WINDOW,
129 	WM_COLORMAP_WINDOWS,
130 	WM_TAKE_FOCUS,
131 	WM_WINDOW_ROLE,
132 	WM_CLIENT_MACHINE,
133 
134 	// List of non PEKWM, ICCCM and EWMH atoms.
135 	MOTIF_WM_HINTS,
136 
137 	XROOTPMAP_ID,
138 	XSETROOT_ID,
139 
140 	MAX_NR_ATOMS
141 };
142 
143 enum ButtonNum {
144 	BUTTON_ANY = 0,
145 	BUTTON1 = Button1,
146 	BUTTON2,
147 	BUTTON3,
148 	BUTTON4,
149 	BUTTON5,
150 	BUTTON6,
151 	BUTTON7,
152 	BUTTON8,
153 	BUTTON9,
154 	BUTTON10,
155 	BUTTON11,
156 	BUTTON12,
157 	BUTTON_NO
158 };
159 
160 /**
161  * Keep in sync with BorderPosition in pekwm.hh
162  */
163 enum CursorType {
164 	CURSOR_0 = 0,
165 	CURSOR_TOP_LEFT = 0,
166 	CURSOR_TOP_RIGHT,
167 	CURSOR_BOTTOM_LEFT,
168 	CURSOR_BOTTOM_RIGHT,
169 	CURSOR_TOP,
170 	CURSOR_LEFT,
171 	CURSOR_RIGHT,
172 	CURSOR_BOTTOM,
173 
174 	CURSOR_ARROW,
175 	CURSOR_MOVE,
176 	CURSOR_RESIZE,
177 	CURSOR_NONE
178 };
179 
180 /**
181  * Bitmask values for parseGeometry result.
182  */
183 enum XGeometryMask {
184 	NO_VALUE = 0,
185 	X_VALUE = 1 << 0,
186 	Y_VALUE = 1 << 1,
187 	WIDTH_VALUE = 1 << 2,
188 	HEIGHT_VALUE = 1 << 3,
189 	ALL_VALUES = 1 << 4,
190 	X_NEGATIVE = 1 << 5,
191 	Y_NEGATIVE = 1 << 6,
192 	X_PERCENT = 1 << 7,
193 	Y_PERCENT = 1 << 8,
194 	WIDTH_PERCENT = 1 << 9,
195 	HEIGHT_PERCENT = 1 << 10
196 };
197 
198 class Geometry {
199 public:
200 	Geometry(void);
201 	Geometry(int _x, int _y, unsigned int _width, unsigned int _height);
202 	Geometry(const Geometry &gm);
203 	~Geometry(void);
204 
205 	int x, y;
206 	unsigned int width, height;
207 
208 	Geometry& operator=(const Geometry& gm);
209 	bool operator==(const Geometry& gm);
210 	bool operator != (const Geometry& gm);
211 	int diffMask(const Geometry &old_gm);
212 
213 	friend std::ostream& operator<<(std::ostream& os, const Geometry& gm);
214 };
215 
216 /**
217  * Class holding information about screen edge allocation.
218  */
219 class Strut {
220 public:
221 	Strut(long l=0, long r=0, long t=0, long b=0, int nhead=-1);
222 	~Strut(void);
223 
224 	bool isSet(void) const;
225 	void clear(void);
226 
227 public: // member variables
228 	long left; /**< Pixels allocated on the left of the head. */
229 	long right; /**<Pixels allocated on the right of the head. */
230 	long top; /**< Pixels allocated on the top of the head.*/
231 	long bottom; /**< Pixels allocated on the bottom of the head.*/
232 	int head; /**< Which head is the strut valid for */
233 
234 	void operator=(const long *s);
235 	bool operator==(const Strut& rhs) const;
236 	bool operator!=(const Strut& rhs) const;
237 
238 	friend std::ostream &operator<<(std::ostream &stream, const Strut &strut);
239 };
240 
241 //! Output head, used to share same code with Xinerama and RandR
242 class Head {
243 public:
Head(int nx,int ny,uint nwidth,uint nheight)244 	Head(int nx, int ny, uint nwidth, uint nheight)
245 		: x(nx),
246 		  y(ny),
247 		  width(nwidth),
248 		  height(nheight)
249 	{
250 	};
251 
252 public:
253 	int x;
254 	int y;
255 	uint width;
256 	uint height;
257 };
258 
259 /**
260  * Wrapper for XRRScreenChangeNotifyEvent.
261  */
262 struct ScreenChangeNotification
263 {
264 	uint width;
265 	uint height;
266 };
267 
268 //! @brief Display information class.
269 class X11
270 {
271 	/** Bits 1-15 are modifier masks, but bits 13 and 14 aren't
272 	    named in X11/X.h. */
273 	static const unsigned KbdLayoutMask1 = 1<<13;
274 	static const unsigned KbdLayoutMask2 = 1<<14;
275 
276 public:
277 	static void init(Display *dpy,
278 			 bool synchronous = false,
279 			 bool honour_randr = true);
280 	static void destruct(void);
281 
getDpy(void)282 	static Display* getDpy(void) { return _dpy; }
getScreenNum(void)283 	static int getScreenNum(void) { return _screen; }
getRoot(void)284 	static Window getRoot(void) { return _root; }
getScreenGeometry(void)285 	static const Geometry &getScreenGeometry(void) { return _screen_gm; }
getWidth(void)286 	static uint getWidth(void)  { return _screen_gm.width; }
getHeight(void)287 	static uint getHeight(void) { return _screen_gm.height; }
getDepth(void)288 	static int getDepth(void) { return _depth; }
getVisual(void)289 	static Visual *getVisual(void) { return _visual; }
getGC(void)290 	static GC getGC(void) { return _gc; }
getColormap(void)291 	static Colormap getColormap(void) { return _colormap; }
getNumLock(void)292 	static uint getNumLock(void) { return _num_lock; }
getScrollLock(void)293 	static uint getScrollLock(void) { return _scroll_lock; }
hasExtensionShape(void)294 	static bool hasExtensionShape(void) { return _has_extension_shape; }
getEventShape(void)295 	static int getEventShape(void) { return _event_shape; }
296 	static bool updateGeometry(uint width, uint height);
getCursor(CursorType type)297 	static Cursor getCursor(CursorType type) { return _cursor_map[type]; }
298 
getLastEventTime(void)299 	static Time getLastEventTime(void) { return _last_event_time; }
setLastEventTime(Time t)300 	static void setLastEventTime(Time t) { _last_event_time = t; }
301 
getLastClickID(void)302 	static Window getLastClickID(void) { return _last_click_id; }
setLastClickID(Window id)303 	static void setLastClickID(Window id) { _last_click_id = id; }
getLastClickTime(uint button)304 	static Time getLastClickTime(uint button) {
305 		if (button < BUTTON_NO) {
306 			return _last_click_time[button];
307 		}
308 		return 0;
309 	}
setLastClickTime(uint button,Time time)310 	static void setLastClickTime(uint button, Time time) {
311 		if (button < BUTTON_NO) {
312 			_last_click_time[button] = time;
313 		}
314 	}
isDoubleClick(Window id,uint button,Time time,Time dc_time)315 	static bool isDoubleClick(Window id, uint button,
316 				  Time time, Time dc_time) {
317 		if ((_last_click_id == id)
318 		    && ((time - getLastClickTime(button)) < dc_time)) {
319 			return true;
320 		}
321 		return false;
322 	}
323 
324 	static XColor *getColor(const std::string &color);
325 	static void returnColor(XColor*& xc);
326 
327 	static ulong getWhitePixel(void);
328 	static ulong getBlackPixel(void);
329 
330 	static void free(void* data);
331 
332 	static void warpPointer(int x, int y);
333 
334 	static void moveWindow(Window win, int x, int y);
335 	static void resizeWindow(Window win,
336 				 unsigned int width, unsigned int height);
337 	static void moveResizeWindow(Window win, int x, int y,
338 				     unsigned int width, unsigned int height);
339 
340 	static void stripStateModifiers(unsigned int *state);
341 	static void stripButtonModifiers(unsigned int *state);
342 	static void setLockKeys(void);
343 	static bool selectXRandrInput(void);
344 	static bool getScreenChangeNotification(XEvent *ev,
345 						ScreenChangeNotification &scn);
346 
347 	static void flush(void);
348 	static int pending(void);
349 
350 	static bool getNextEvent(XEvent &ev, struct timeval *timeout = nullptr);
351 	static void allowEvents(int event_mode, Time time);
352 	static bool grabServer(void);
353 	static bool ungrabServer(bool sync);
354 	static bool grabKeyboard(Window win);
355 	static bool ungrabKeyboard(void);
356 	static bool grabPointer(Window win, uint event_mask, CursorType cursor);
357 	static bool ungrabPointer(void);
358 
359 	static uint getNearestHead(int x, int y);
360 	static uint getCursorHead(void);
361 	static void addHead(const Head &head);
362 	static bool getHeadInfo(uint head, Geometry &head_info);
363 	static void getHeadInfo(int x, int y, Geometry &head_info);
364 	static Geometry getHeadGeometry(uint head);
365 	static int getNumHeads(void);
366 
getAtom(AtomName name)367 	static Atom getAtom(AtomName name) { return _atoms[name]; }
368 	static const char *getAtomString(AtomName name);
369 	static std::string getAtomIdString(Atom id);
370 	static AtomName getAtomName(Atom id);
371 	static void setAtom(Window win, AtomName aname, AtomName value);
372 	static void setAtoms(Window win, AtomName aname, Atom *values, int size);
373 	static void setEwmhAtomsSupport(Window win);
374 	static bool getWindow(Window win, AtomName aname, Window& value);
375 	static void setWindow(Window win, AtomName aname, Window value);
376 	static void setWindows(Window win, AtomName aname, Window *values,
377 			       int size);
378 	static bool getCardinal(Window win, AtomName aname, Cardinal &value,
379 				long format=XA_CARDINAL);
380 	static void setCardinal(Window win, AtomName aname, Cardinal value,
381 				long format=XA_CARDINAL);
382 	static void setCardinals(Window win, AtomName aname,
383 				 Cardinal *values, int num);
384 	static bool getUtf8String(Window win, AtomName aname, std::string &value);
385 	static bool getUtf8StringId(Window win, Atom id, std::string &value);
386 	static void setUtf8String(Window win, AtomName aname,
387 				  const std::string &value);
388 	static void setUtf8StringArray(Window win, AtomName aname,
389 				       unsigned char *values, uint length);
390 	static bool getString(Window win, AtomName aname, std::string &value);
391 	static bool getStringId(Window win, Atom id, std::string &value);
392 	static void setString(Window win, AtomName aname,
393 			      const std::string &value);
394 
395 	static bool listProperties(Window win, std::vector<Atom>& atoms);
396 
397 	static bool getProperty(Window win, Atom atom, Atom type,
398 				ulong expected, uchar **data, ulong *actual);
399 	static bool getTextProperty(Window win, Atom atom, std::string &value);
400 	static void *getEwmhPropData(Window win, AtomName prop,
401 				     Atom type, int &num);
402 	static void unsetProperty(Window win, AtomName aname);
403 
404 	static void getMousePosition(int &x, int &y);
405 	static uint getButtonFromState(uint state);
406 
407 	static uint getMaskFromKeycode(KeyCode keycode);
408 	static KeyCode getKeycodeFromMask(uint mask);
409 	static KeySym getKeysymFromKeycode(KeyCode keycode);
410 
411 	static void removeMotionEvents(void);
412 
413 	/** Modifier from (XModifierKeymap) to mask table. */
414 	static const uint MODIFIER_TO_MASK[];
415 	/** Number of entries in MODIFIER_TO_MASK. */
416 	static const uint MODIFIER_TO_MASK_NUM;
417 
418 	// helper functions
419 
420 	static int parseGeometry(const std::string& str, Geometry& gm);
421 	static void keepVisible(Geometry &gm);
422 
423 	// X11 function wrappers
424 
425 	static Window createWindow(Window parent,
426 				   int x, int y, uint width, uint height,
427 				   uint border_width, uint depth, uint _class,
428 				   Visual* visual, ulong valuemask,
429 				   XSetWindowAttributes* attrs);
430 	static Window createSimpleWindow(Window parent,
431 					 int x, int y, uint width, uint height,
432 					 uint border_width,
433 					 ulong border, ulong background);
434 	static void destroyWindow(Window win);
435 	static void changeWindowAttributes(Window win, ulong mask,
436 					   XSetWindowAttributes &attrs);
437 	static void grabButton(unsigned b, unsigned int mod, Window win,
438 			       unsigned mask, int mode=GrabModeAsync);
439 
440 	static void mapWindow(Window w);
441 	static void mapRaised(Window w);
442 	static void unmapWindow(Window w);
443 	static void reparentWindow(Window w, Window parent, int x, int y);
444 
445 	static void raiseWindow(Window w);
446 	static void lowerWindow(Window w);
447 
448 	static void ungrabButton(uint button, uint modifiers, Window win);
449 
450 	static void stackWindows(Window *wins, unsigned len);
451 	static bool checkTypedEvent(int type, XEvent *ev);
452 
453 	static void sync(Bool discard);
454 
455 	static int selectInput(Window w, long mask);
456 	static void setInputFocus(Window w);
457 
458 	static int sendEvent(Window dest, Window win, Atom atom, long mask,
459 			     long v1=0l, long v2=0l, long v3=0l,
460 			     long v4=0l, long v5=0l);
461 	static int sendEvent(Window dest, Bool propagate, long mask, XEvent *ev);
462 
463 	static int changeProperty(Window win, Atom prop, Atom type, int format,
464 				  int mode, const unsigned char *data, int num_e);
465 
466 	static int getGeometry(Window win, unsigned *w, unsigned *h, unsigned *bw);
467 
468 	static bool getWindowAttributes(Window win, XWindowAttributes *wa);
469 
470 	static GC createGC(Drawable d, ulong mask, XGCValues *values);
471 	static void freeGC(GC gc);
472 
473 	static Pixmap createPixmapMask(unsigned w, unsigned h);
474 	static Pixmap createPixmap(unsigned w, unsigned h);
475 	static void freePixmap(Pixmap& pixmap);
476 	static XImage *createImage(char *data, uint width, uint height);
477 	static XImage *getImage(Drawable src, int x, int y, uint width, uint height,
478 				unsigned long plane_mask, int format);
479 	static void putImage(Drawable dest, GC gc, XImage *ximage,
480 			     int src_x, int src_y, int dest_x, int dest_y,
481 			     uint width, uint height);
482 	static void destroyImage(XImage *ximage);
483 
484 	static void setWindowBackground(Window window, ulong pixel);
485 	static void setWindowBackgroundPixmap(Window window, Pixmap pixmap);
486 	static void  clearWindow(Window window);
487 	static void clearArea(Window window, int x, int y,
488 			      uint width, uint height);
489 
490 	static void shapeSelectInput(Window window, ulong mask);
491 	static void shapeQuery(Window dst, int *bshaped);
492 	static void shapeCombine(Window dst, int kind, int x, int y,
493 				 Window src, int op);
494 	static void shapeSetRect(Window dst, XRectangle *rect);
495 	static void shapeIntersectRect(Window dst, XRectangle *rect);
496 	static void shapeSetMask(Window dst, int kind, Pixmap pix);
497 	static XRectangle* shapeGetRects(Window win, int kind, int *num);
498 
499 protected:
500 	static int parseGeometryVal(const char *c_str, const char *e_end,
501 				    int &val_ret);
502 
503 private:
504 	static uint calcDistance(int x1, int y1, int x2, int y2);
505 	static uint calcDistance(int p1, int p2);
506 
507 	static void initHeads(void);
508 	static void initHeadsRandr(void);
509 	static void initHeadsXinerama(void);
510 
511 protected:
X11(void)512 	X11(void) {}
~X11(void)513 	~X11(void) {}
514 
515 private:
516 	static Display *_dpy;
517 	static bool _honour_randr; /**< Boolean flag if randr should be honoured. */
518 	static int _fd;
519 
520 	static int _screen, _depth;
521 
522 	static Geometry _screen_gm; /**< Screen geometry, no head information. */
523 
524 	static Window _root;
525 	static Visual *_visual;
526 	static GC _gc;
527 	static Colormap _colormap;
528 	static XModifierKeymap *_modifier_map; /**< Key to modifier mappings. */
529 
530 	static uint _num_lock;
531 	static uint _scroll_lock;
532 
533 	static bool _has_extension_shape;
534 	static int _event_shape;
535 
536 	static bool _has_extension_xkb;
537 
538 	static bool _has_extension_xinerama;
539 
540 	static bool _has_extension_xrandr;
541 	static int _event_xrandr;
542 
543 	static std::vector<Head> _heads; //! Array of head information
544 	static uint _last_head; //! Last accessed head
545 
546 	static uint _server_grabs;
547 
548 	static Time _last_event_time;
549 	// information for dobule clicks
550 	static Window _last_click_id;
551 	static Time _last_click_time[BUTTON_NO - 1];
552 
553 	static Cursor _cursor_map[CURSOR_NONE];
554 
555 	class ColorEntry;
556 	static std::vector<ColorEntry*> _colors;
557 	static XColor _xc_default; // when allocating fails
558 
559 	static Atom _atoms[MAX_NR_ATOMS];
560 };
561 
562 #endif // _PEKWM_X11_HH_
563