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