1 //
2 // X11Util.cc for pekwm
3 // Copyright (C) 2021 Claes Nästén <pekdon@gmail.com>
4 //
5 // This program is licensed under the GNU GPL.
6 // See the LICENSE file for more information.
7 //
8 
9 #include "PWinObj.hh"
10 #include "X11Util.hh"
11 #include "Util.hh"
12 
NetWMStates(void)13 NetWMStates::NetWMStates(void)
14 	: modal(false),
15 	  sticky(false),
16 	  max_vert(false),
17 	  max_horz(false), shaded(false),
18 	  skip_taskbar(false),
19 	  skip_pager(false),
20 	  hidden(false),
21 	  fullscreen(false),
22 	  above(false),
23 	  below(false),
24 	  demands_attention(false)
25 {
26 }
27 
~NetWMStates(void)28 NetWMStates::~NetWMStates(void)
29 {
30 }
31 
32 namespace X11Util {
33 
34 	/**
35 	 * Get geometry for the given head, -1 will return the screen
36 	 * geometry.
37 	 */
getHeadGeometry(int head)38 	Geometry getHeadGeometry(int head)
39 	{
40 		if (head < 0) {
41 			return X11::getScreenGeometry();
42 		}
43 		return X11::getHeadGeometry(head);
44 	}
45 
46 	/**
47 	 * Get current head, depending on configuration it is the same
48 	 * head as the cursor is on OR the head where the focused window
49 	 * is on.
50 	 */
getCurrHead(CurrHeadSelector chs)51 	uint getCurrHead(CurrHeadSelector chs)
52 	{
53 		PWinObj *wo;
54 		switch (chs) {
55 		case CURR_HEAD_SELECTOR_FOCUSED_WINDOW:
56 			wo = PWinObj::getFocusedPWinObj();
57 			if (wo != nullptr) {
58 				return X11::getNearestHead(wo->getX() + (wo->getWidth() / 2),
59 							   wo->getY() + (wo->getHeight() / 2));
60 			}
61 		case CURR_HEAD_SELECTOR_CURSOR:
62 		case CURR_HEAD_SELECTOR_NO:
63 			return X11::getCursorHead();
64 		}
65 
66 		return 0;
67 	}
68 
69 	/**
70 	 * Get head closest to center of provided PWinObj.
71 	 */
getNearestHead(const PWinObj & wo)72 	uint getNearestHead(const PWinObj& wo)
73 	{
74 		return X11::getNearestHead(wo.getX() + (wo.getWidth() / 2),
75 					   wo.getY() + (wo.getHeight() / 2));
76 	}
77 
78 	/**
79 	 * Grabs the button button, with the mod mod and mask mask on the
80 	 * window win and cursor curs with "all" possible extra modifiers
81 	 */
82 	void
grabButton(int button,int mod,int mask,Window win,int mode)83 	grabButton(int button, int mod, int mask, Window win, int mode)
84 	{
85 		uint num_lock = X11::getNumLock();
86 		uint scroll_lock = X11::getScrollLock();
87 
88 		X11::grabButton(button, mod, win, mask, mode);
89 		X11::grabButton(button, mod|LockMask, win, mask, mode);
90 
91 		if (num_lock) {
92 			X11::grabButton(button, mod|num_lock, win, mask, mode);
93 			X11::grabButton(button, mod|num_lock|LockMask, win, mask, mode);
94 		}
95 		if (scroll_lock) {
96 			X11::grabButton(button, mod|scroll_lock, win, mask, mode);
97 			X11::grabButton(button, mod|scroll_lock|LockMask, win, mask, mode);
98 		}
99 		if (num_lock && scroll_lock) {
100 			X11::grabButton(button, mod|num_lock|scroll_lock, win, mask, mode);
101 			X11::grabButton(button, mod|num_lock|scroll_lock|LockMask,
102 					win, mask, mode);
103 		}
104 	}
105 
106 	/**
107 	 * Reads MWM hints from a client.
108 	 *
109 	 * @return true if the hint was read succesfully.
110 	 */
111 	bool
readMwmHints(Window win,MwmHints & hints)112 	readMwmHints(Window win, MwmHints &hints)
113 	{
114 		Atom atom = X11::getAtom(MOTIF_WM_HINTS);
115 		uchar *data;
116 		ulong items_read;
117 		if (! X11::getProperty(win, atom, atom, 20L, &data, &items_read)) {
118 			return false;
119 		}
120 
121 		if (items_read >= MWM_HINTS_NUM) {
122 			hints = *reinterpret_cast<MwmHints*>(data);
123 		}
124 
125 		X11::free(data);
126 		return items_read >= MWM_HINTS_NUM;
127 	}
128 
129 	/**
130 	 * Read EWMH state atoms on window.
131 	 */
132 	bool
readEwmhStates(Window win,NetWMStates & win_states)133 	readEwmhStates(Window win, NetWMStates &win_states)
134 	{
135 		int num = 0;
136 		Atom *states = static_cast<Atom*>(X11::getEwmhPropData(win, STATE,
137 								       XA_ATOM, num));
138 		if (! states) {
139 			return false;
140 		}
141 
142 		for (int i = 0; i < num; ++i) {
143 			if (states[i] == X11::getAtom(STATE_MODAL)) {
144 				win_states.modal = true;
145 			} else if (states[i] == X11::getAtom(STATE_STICKY)) {
146 				win_states.sticky = true;
147 			} else if (states[i] == X11::getAtom(STATE_MAXIMIZED_VERT)) {
148 				win_states.max_vert = true;
149 			} else if (states[i] == X11::getAtom(STATE_MAXIMIZED_HORZ)) {
150 				win_states.max_horz = true;
151 			} else if (states[i] == X11::getAtom(STATE_SHADED)) {
152 				win_states.shaded = true;
153 			} else if (states[i] == X11::getAtom(STATE_SKIP_TASKBAR)) {
154 				win_states.skip_taskbar = true;
155 			} else if (states[i] == X11::getAtom(STATE_SKIP_PAGER)) {
156 				win_states.skip_pager = true;
157 			} else if (states[i] == X11::getAtom(STATE_DEMANDS_ATTENTION)) {
158 				win_states.demands_attention = true;
159 			} else if (states[i] == X11::getAtom(STATE_HIDDEN)) {
160 				win_states.hidden = true;
161 			} else if (states[i] == X11::getAtom(STATE_FULLSCREEN)) {
162 				win_states.fullscreen = true;
163 			} else if (states[i] == X11::getAtom(STATE_ABOVE)) {
164 				win_states.above = true;
165 			} else if (states[i] == X11::getAtom(STATE_BELOW)) {
166 				win_states.below = true;
167 			}
168 		}
169 
170 		X11::free(states);
171 
172 		return true;
173 	}
174 
175 }
176 
177 #ifndef PEKWM_HAVE_XUTF8
178 
179 void
Xutf8SetWMProperties(Display * dpy,Window win,const char * window_name,const char * icon_name,char ** argv,int argc,XSizeHints * normal_hints,XWMHints * wm_hints,XClassHint * class_hints)180 Xutf8SetWMProperties(Display *dpy, Window win,
181                      const char* window_name, const char* icon_name,
182                      char** argv, int argc,
183                      XSizeHints* normal_hints, XWMHints* wm_hints,
184                      XClassHint* class_hints)
185 {
186 	X11::setUtf8String(win, WM_CLIENT_MACHINE, Util::getHostname());
187 	X11::setUtf8String(win, WM_NAME, window_name);
188 	X11::setUtf8String(win, WM_ICON_NAME, icon_name);
189 
190 	if (normal_hints) {
191 		XSetNormalHints(dpy, win, normal_hints);
192 	}
193 	if (wm_hints) {
194 		XSetWMHints(dpy, win, wm_hints);
195 	}
196 	if (class_hints) {
197 		XSetClassHint(dpy, win, class_hints);
198 	}
199 }
200 
201 #endif // PEKWM_HAVE_XUTF8
202