1 #include "config.h"
2 #include "yxapp.h"
3 #include "yfull.h"
4 #include "ymenu.h"
5 #include "wmmgr.h"
6 #include "MwmUtil.h"
7 #include "ypointer.h"
8 #include "yxcontext.h"
9 #include "guievent.h"
10 #include "intl.h"
11 #undef override
12 #include <X11/Xproto.h>
13 #ifdef XINERAMA
14 #include <X11/extensions/Xinerama.h>
15 #endif
16 #include <X11/extensions/Xcomposite.h>
17 #include <X11/extensions/XShm.h>
18
19 YXApplication *xapp = nullptr;
20
21 YDesktop *desktop = nullptr;
22 YContext<YWindow> windowContext;
23
24 bool YXApplication::synchronizeX11;
25 bool YXApplication::alphaBlending;
26 Window YXApplication::ignorable;
27
28 Atom _XA_WM_CHANGE_STATE;
29 Atom _XA_WM_CLASS;
30 Atom _XA_WM_CLIENT_LEADER;
31 Atom _XA_WM_CLIENT_MACHINE;
32 Atom _XA_WM_COLORMAP_NOTIFY;
33 Atom _XA_WM_COLORMAP_WINDOWS;
34 Atom _XA_WM_COMMAND;
35 Atom _XA_WM_DELETE_WINDOW;
36 Atom _XA_WM_DESKTOP;
37 Atom _XA_WM_HINTS;
38 Atom _XA_WM_ICON_NAME;
39 Atom _XA_WM_ICON_SIZE;
40 Atom _XA_WM_LOCALE_NAME;
41 Atom _XA_WM_NAME;
42 Atom _XA_WM_NORMAL_HINTS;
43 Atom _XA_WM_PROTOCOLS;
44 Atom _XA_WM_SIZE_HINTS;
45 Atom _XA_WM_STATE;
46 Atom _XA_WM_TAKE_FOCUS;
47 Atom _XA_WM_TRANSIENT_FOR;
48 Atom _XA_WM_WINDOW_ROLE;
49 Atom _XA_WM_ZOOM_HINTS;
50
51 Atom _XATOM_MWM_HINTS;
52 Atom _XATOM_MWM_INFO;
53 Atom _XA_WINDOW_ROLE;
54 Atom _XA_SM_CLIENT_ID;
55 Atom _XA_ICEWM_ACTION;
56 Atom _XA_ICEWM_GUIEVENT;
57 Atom _XA_ICEWM_HINT;
58 Atom _XA_ICEWM_FONT_PATH;
59 Atom _XA_ICEWMBG_IMAGE;
60 Atom _XA_XROOTPMAP_ID;
61 Atom _XA_XROOTCOLOR_PIXEL;
62 Atom _XA_GDK_TIMESTAMP_PROP;
63 Atom _XA_CLIPBOARD;
64 Atom _XA_MANAGER;
65 Atom _XA_TARGETS;
66 Atom _XA_XEMBED;
67 Atom _XA_XEMBED_INFO;
68 Atom _XA_UTF8_STRING;
69
70 Atom _XA_WIN_ICONS;
71 Atom _XA_WIN_LAYER;
72 Atom _XA_WIN_PROTOCOLS;
73 Atom _XA_WIN_TRAY;
74
75 Atom _XA_NET_ACTIVE_WINDOW;
76 Atom _XA_NET_CLIENT_LIST;
77 Atom _XA_NET_CLIENT_LIST_STACKING;
78 Atom _XA_NET_CLOSE_WINDOW;
79 Atom _XA_NET_CURRENT_DESKTOP;
80 Atom _XA_NET_DESKTOP_GEOMETRY;
81 Atom _XA_NET_DESKTOP_LAYOUT;
82 Atom _XA_NET_DESKTOP_NAMES;
83 Atom _XA_NET_DESKTOP_VIEWPORT;
84 Atom _XA_NET_FRAME_EXTENTS;
85 Atom _XA_NET_MOVERESIZE_WINDOW;
86 Atom _XA_NET_NUMBER_OF_DESKTOPS;
87 Atom _XA_NET_PROPERTIES;
88 Atom _XA_NET_REQUEST_FRAME_EXTENTS;
89 Atom _XA_NET_RESTACK_WINDOW;
90 Atom _XA_NET_SHOWING_DESKTOP;
91 Atom _XA_NET_STARTUP_ID;
92 Atom _XA_NET_STARTUP_INFO_BEGIN;
93 Atom _XA_NET_STARTUP_INFO;
94 Atom _XA_NET_SUPPORTED;
95 Atom _XA_NET_SUPPORTING_WM_CHECK;
96 Atom _XA_NET_SYSTEM_TRAY_MESSAGE_DATA;
97 Atom _XA_NET_SYSTEM_TRAY_OPCODE;
98 Atom _XA_NET_SYSTEM_TRAY_ORIENTATION;
99 Atom _XA_NET_SYSTEM_TRAY_VISUAL;
100 Atom _XA_NET_VIRTUAL_ROOTS;
101 Atom _XA_NET_WM_ACTION_ABOVE;
102 Atom _XA_NET_WM_ACTION_BELOW;
103 Atom _XA_NET_WM_ACTION_CHANGE_DESKTOP;
104 Atom _XA_NET_WM_ACTION_CLOSE;
105 Atom _XA_NET_WM_ACTION_FULLSCREEN;
106 Atom _XA_NET_WM_ACTION_MAXIMIZE_HORZ;
107 Atom _XA_NET_WM_ACTION_MAXIMIZE_VERT;
108 Atom _XA_NET_WM_ACTION_MINIMIZE;
109 Atom _XA_NET_WM_ACTION_MOVE;
110 Atom _XA_NET_WM_ACTION_RESIZE;
111 Atom _XA_NET_WM_ACTION_SHADE;
112 Atom _XA_NET_WM_ACTION_STICK;
113 Atom _XA_NET_WM_ALLOWED_ACTIONS;
114 Atom _XA_NET_WM_BYPASS_COMPOSITOR;
115 Atom _XA_NET_WM_DESKTOP;
116 Atom _XA_NET_WM_FULL_PLACEMENT;
117 Atom _XA_NET_WM_FULLSCREEN_MONITORS;
118 Atom _XA_NET_WM_HANDLED_ICONS;
119 Atom _XA_NET_WM_ICON_GEOMETRY;
120 Atom _XA_NET_WM_ICON_NAME;
121 Atom _XA_NET_WM_ICON;
122 Atom _XA_NET_WM_MOVERESIZE;
123 Atom _XA_NET_WM_NAME;
124 Atom _XA_NET_WM_OPAQUE_REGION;
125 Atom _XA_NET_WM_PID;
126 Atom _XA_NET_WM_PING;
127 Atom _XA_NET_WM_STATE;
128 Atom _XA_NET_WM_STATE_ABOVE;
129 Atom _XA_NET_WM_STATE_BELOW;
130 Atom _XA_NET_WM_STATE_DEMANDS_ATTENTION;
131 Atom _XA_NET_WM_STATE_FOCUSED;
132 Atom _XA_NET_WM_STATE_FULLSCREEN;
133 Atom _XA_NET_WM_STATE_HIDDEN;
134 Atom _XA_NET_WM_STATE_MAXIMIZED_HORZ;
135 Atom _XA_NET_WM_STATE_MAXIMIZED_VERT;
136 Atom _XA_NET_WM_STATE_MODAL;
137 Atom _XA_NET_WM_STATE_SHADED;
138 Atom _XA_NET_WM_STATE_SKIP_PAGER;
139 Atom _XA_NET_WM_STATE_SKIP_TASKBAR;
140 Atom _XA_NET_WM_STATE_STICKY;
141 Atom _XA_NET_WM_STRUT;
142 Atom _XA_NET_WM_STRUT_PARTIAL;
143 Atom _XA_NET_WM_SYNC_REQUEST;
144 Atom _XA_NET_WM_SYNC_REQUEST_COUNTER;
145 Atom _XA_NET_WM_USER_TIME;
146 Atom _XA_NET_WM_USER_TIME_WINDOW;
147 Atom _XA_NET_WM_VISIBLE_ICON_NAME;
148 Atom _XA_NET_WM_VISIBLE_NAME;
149 Atom _XA_NET_WM_WINDOW_OPACITY;
150 Atom _XA_NET_WM_WINDOW_TYPE;
151 Atom _XA_NET_WM_WINDOW_TYPE_COMBO;
152 Atom _XA_NET_WM_WINDOW_TYPE_DESKTOP;
153 Atom _XA_NET_WM_WINDOW_TYPE_DIALOG;
154 Atom _XA_NET_WM_WINDOW_TYPE_DND;
155 Atom _XA_NET_WM_WINDOW_TYPE_DOCK;
156 Atom _XA_NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
157 Atom _XA_NET_WM_WINDOW_TYPE_MENU;
158 Atom _XA_NET_WM_WINDOW_TYPE_NORMAL;
159 Atom _XA_NET_WM_WINDOW_TYPE_NOTIFICATION;
160 Atom _XA_NET_WM_WINDOW_TYPE_POPUP_MENU;
161 Atom _XA_NET_WM_WINDOW_TYPE_SPLASH;
162 Atom _XA_NET_WM_WINDOW_TYPE_TOOLBAR;
163 Atom _XA_NET_WM_WINDOW_TYPE_TOOLTIP;
164 Atom _XA_NET_WM_WINDOW_TYPE_UTILITY;
165 Atom _XA_NET_WORKAREA;
166
167 Atom _XA_KWM_DOCKWINDOW;
168 Atom _XA_KWM_WIN_ICON;
169
170 Atom _XA_KDE_NET_SYSTEM_TRAY_WINDOWS;
171 Atom _XA_KDE_NET_WM_FRAME_STRUT;
172 Atom _XA_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR;
173 Atom _XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE;
174 Atom _XA_KDE_SPLASH_PROGRESS;
175 Atom _XA_KDE_WM_CHANGE_STATE;
176
177 Atom XA_XdndAware;
178 Atom XA_XdndDrop;
179 Atom XA_XdndEnter;
180 Atom XA_XdndFinished;
181 Atom XA_XdndLeave;
182 Atom XA_XdndPosition;
183 Atom XA_XdndProxy;
184 Atom XA_XdndStatus;
185 Atom XA_XdndActionCopy;
186 Atom XA_XdndActionMove;
187 Atom XA_XdndActionLink;
188 Atom XA_XdndActionAsk;
189 Atom XA_XdndActionPrivate;
190
191 YExtension composite;
192 YExtension damage;
193 YExtension fixes;
194 YExtension render;
195 YExtension shapes;
196 YExtension xrandr;
197 YExtension xinerama;
198 YExtension xshm;
199
200 #ifdef DEBUG
201 int xeventcount = 0;
202 #endif
203
204 class YClipboard: public YWindow {
205 public:
setData(mstring data)206 void setData(mstring data) {
207 fData = data;
208 if (length() == 0)
209 clearSelection(false);
210 else
211 acquireSelection(false);
212 }
handleSelectionClear(const XSelectionClearEvent & clear)213 void handleSelectionClear(const XSelectionClearEvent &clear) {
214 if (clear.selection == _XA_CLIPBOARD) {
215 fData = null;
216 }
217 }
handleSelectionRequest(const XSelectionRequestEvent & request)218 void handleSelectionRequest(const XSelectionRequestEvent &request) {
219 if (request.selection == _XA_CLIPBOARD) {
220 XSelectionEvent notify;
221
222 notify.type = SelectionNotify;
223 notify.requestor = request.requestor;
224 notify.selection = request.selection;
225 notify.target = request.target;
226 notify.time = request.time;
227 notify.property = request.property;
228
229 if (request.selection == _XA_CLIPBOARD &&
230 (request.target == XA_STRING ||
231 request.target == _XA_UTF8_STRING) &&
232 length() > 0)
233 {
234 unsigned char *data =
235 reinterpret_cast<unsigned char *>(
236 const_cast<char *>(fData.c_str()));
237 XChangeProperty(xapp->display(),
238 request.requestor,
239 request.property,
240 request.target,
241 8, PropModeReplace,
242 data, length());
243 } else if (request.selection == _XA_CLIPBOARD &&
244 request.target == _XA_TARGETS &&
245 length() > 0)
246 {
247 Atom targets[] = {
248 XA_STRING,
249 _XA_UTF8_STRING,
250 };
251 unsigned char* data =
252 reinterpret_cast<unsigned char *>(targets);
253 const int count = int ACOUNT(targets);
254
255 XChangeProperty(xapp->display(),
256 request.requestor,
257 request.property,
258 request.target,
259 32, PropModeReplace,
260 data, count);
261 } else {
262 notify.property = None;
263 }
264
265 XSendEvent(xapp->display(), notify.requestor, False, None,
266 reinterpret_cast<XEvent *>(¬ify));
267 }
268 }
269
length() const270 int length() const {
271 return fData.length();
272 }
273
274 private:
275 mstring fData;
276 };
277
278 YAtomName YXApplication::atom_info[] = {
279 { &_XA_WM_CHANGE_STATE , "WM_CHANGE_STATE" },
280 { &_XA_WM_CLASS , "WM_CLASS" },
281 { &_XA_WM_CLIENT_LEADER , "WM_CLIENT_LEADER" },
282 { &_XA_WM_CLIENT_MACHINE , "WM_CLIENT_MACHINE" },
283 { &_XA_WM_COLORMAP_NOTIFY , "WM_COLORMAP_NOTIFY" },
284 { &_XA_WM_COLORMAP_WINDOWS , "WM_COLORMAP_WINDOWS" },
285 { &_XA_WM_COMMAND , "WM_COMMAND" },
286 { &_XA_WM_DELETE_WINDOW , "WM_DELETE_WINDOW" },
287 { &_XA_WM_DESKTOP , "WM_DESKTOP" },
288 { &_XA_WM_HINTS , "WM_HINTS" },
289 { &_XA_WM_ICON_NAME , "WM_ICON_NAME" },
290 { &_XA_WM_ICON_SIZE , "WM_ICON_SIZE" },
291 { &_XA_WM_LOCALE_NAME , "WM_LOCALE_NAME" },
292 { &_XA_WM_NAME , "WM_NAME" },
293 { &_XA_WM_NORMAL_HINTS , "WM_NORMAL_HINTS" },
294 { &_XA_WM_PROTOCOLS , "WM_PROTOCOLS" },
295 { &_XA_WM_SIZE_HINTS , "WM_SIZE_HINTS" },
296 { &_XA_WM_STATE , "WM_STATE" },
297 { &_XA_WM_TAKE_FOCUS , "WM_TAKE_FOCUS" },
298 { &_XA_WM_TRANSIENT_FOR , "WM_TRANSIENT_FOR" },
299 { &_XA_WM_WINDOW_ROLE , "WM_WINDOW_ROLE" },
300 { &_XA_WM_ZOOM_HINTS , "WM_ZOOM_HINTS" },
301
302 { &_XA_WINDOW_ROLE , "WINDOW_ROLE" },
303 { &_XA_SM_CLIENT_ID , "SM_CLIENT_ID" },
304 { &_XA_ICEWM_ACTION , "_ICEWM_ACTION" },
305 { &_XA_ICEWM_GUIEVENT , XA_GUI_EVENT_NAME },
306 { &_XA_ICEWM_HINT , "_ICEWM_WINOPTHINT" },
307 { &_XA_ICEWM_FONT_PATH , "ICEWM_FONT_PATH" },
308 { &_XA_ICEWMBG_IMAGE , "_ICEWMBG_IMAGE" },
309 { &_XA_XROOTPMAP_ID , "_XROOTPMAP_ID" },
310 { &_XA_XROOTCOLOR_PIXEL , "_XROOTCOLOR_PIXEL" },
311 { &_XA_GDK_TIMESTAMP_PROP , "GDK_TIMESTAMP_PROP" },
312 { &_XATOM_MWM_HINTS , _XA_MOTIF_WM_HINTS },
313 { &_XATOM_MWM_INFO , _XA_MOTIF_WM_INFO },
314
315 { &_XA_KWM_DOCKWINDOW , "KWM_DOCKWINDOW" },
316 { &_XA_KWM_WIN_ICON , "KWM_WIN_ICON" },
317
318 { &_XA_KDE_NET_SYSTEM_TRAY_WINDOWS , "_KDE_NET_SYSTEM_TRAY_WINDOWS" },
319 { &_XA_KDE_NET_WM_FRAME_STRUT , "_KDE_NET_WM_FRAME_STRUT" },
320 { &_XA_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR" },
321 { &_XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE , "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE" },
322 { &_XA_KDE_SPLASH_PROGRESS , "_KDE_SPLASH_PROGRESS" },
323 { &_XA_KDE_WM_CHANGE_STATE , "_KDE_WM_CHANGE_STATE" },
324
325 { &_XA_WIN_ICONS , XA_WIN_ICONS },
326 { &_XA_WIN_LAYER , XA_WIN_LAYER },
327 { &_XA_WIN_PROTOCOLS , XA_WIN_PROTOCOLS },
328 { &_XA_WIN_TRAY , XA_WIN_TRAY },
329
330 { &_XA_NET_ACTIVE_WINDOW , "_NET_ACTIVE_WINDOW" },
331 { &_XA_NET_CLIENT_LIST , "_NET_CLIENT_LIST" },
332 { &_XA_NET_CLIENT_LIST_STACKING , "_NET_CLIENT_LIST_STACKING" },
333 { &_XA_NET_CLOSE_WINDOW , "_NET_CLOSE_WINDOW" },
334 { &_XA_NET_CURRENT_DESKTOP , "_NET_CURRENT_DESKTOP" },
335 { &_XA_NET_DESKTOP_GEOMETRY , "_NET_DESKTOP_GEOMETRY" },
336 { &_XA_NET_DESKTOP_LAYOUT , "_NET_DESKTOP_LAYOUT" },
337 { &_XA_NET_DESKTOP_NAMES , "_NET_DESKTOP_NAMES" },
338 { &_XA_NET_DESKTOP_VIEWPORT , "_NET_DESKTOP_VIEWPORT" },
339 { &_XA_NET_FRAME_EXTENTS , "_NET_FRAME_EXTENTS" },
340 { &_XA_NET_MOVERESIZE_WINDOW , "_NET_MOVERESIZE_WINDOW" },
341 { &_XA_NET_NUMBER_OF_DESKTOPS , "_NET_NUMBER_OF_DESKTOPS" },
342 { &_XA_NET_PROPERTIES , "_NET_PROPERTIES" },
343 { &_XA_NET_REQUEST_FRAME_EXTENTS , "_NET_REQUEST_FRAME_EXTENTS" },
344 { &_XA_NET_RESTACK_WINDOW , "_NET_RESTACK_WINDOW" },
345 { &_XA_NET_SHOWING_DESKTOP , "_NET_SHOWING_DESKTOP" },
346 { &_XA_NET_STARTUP_ID , "_NET_STARTUP_ID" },
347 { &_XA_NET_STARTUP_INFO , "_NET_STARTUP_INFO" },
348 { &_XA_NET_STARTUP_INFO_BEGIN , "_NET_STARTUP_INFO_BEGIN" },
349 { &_XA_NET_SUPPORTED , "_NET_SUPPORTED" },
350 { &_XA_NET_SUPPORTING_WM_CHECK , "_NET_SUPPORTING_WM_CHECK" },
351 { &_XA_NET_SYSTEM_TRAY_MESSAGE_DATA , "_NET_SYSTEM_TRAY_MESSAGE_DATA" },
352 { &_XA_NET_SYSTEM_TRAY_OPCODE , "_NET_SYSTEM_TRAY_OPCODE" },
353 { &_XA_NET_SYSTEM_TRAY_ORIENTATION , "_NET_SYSTEM_TRAY_ORIENTATION" },
354 { &_XA_NET_SYSTEM_TRAY_VISUAL , "_NET_SYSTEM_TRAY_VISUAL" },
355 { &_XA_NET_VIRTUAL_ROOTS , "_NET_VIRTUAL_ROOTS" },
356 { &_XA_NET_WM_ACTION_ABOVE , "_NET_WM_ACTION_ABOVE" },
357 { &_XA_NET_WM_ACTION_BELOW , "_NET_WM_ACTION_BELOW" },
358 { &_XA_NET_WM_ACTION_CHANGE_DESKTOP , "_NET_WM_ACTION_CHANGE_DESKTOP" },
359 { &_XA_NET_WM_ACTION_CLOSE , "_NET_WM_ACTION_CLOSE" },
360 { &_XA_NET_WM_ACTION_FULLSCREEN , "_NET_WM_ACTION_FULLSCREEN" },
361 { &_XA_NET_WM_ACTION_MAXIMIZE_HORZ , "_NET_WM_ACTION_MAXIMIZE_HORZ" },
362 { &_XA_NET_WM_ACTION_MAXIMIZE_VERT , "_NET_WM_ACTION_MAXIMIZE_VERT" },
363 { &_XA_NET_WM_ACTION_MINIMIZE , "_NET_WM_ACTION_MINIMIZE" },
364 { &_XA_NET_WM_ACTION_MOVE , "_NET_WM_ACTION_MOVE" },
365 { &_XA_NET_WM_ACTION_RESIZE , "_NET_WM_ACTION_RESIZE" },
366 { &_XA_NET_WM_ACTION_SHADE , "_NET_WM_ACTION_SHADE" },
367 { &_XA_NET_WM_ACTION_STICK , "_NET_WM_ACTION_STICK" },
368 { &_XA_NET_WM_ALLOWED_ACTIONS , "_NET_WM_ALLOWED_ACTIONS" },
369 { &_XA_NET_WM_BYPASS_COMPOSITOR , "_NET_WM_BYPASS_COMPOSITOR" },
370 { &_XA_NET_WM_DESKTOP , "_NET_WM_DESKTOP" },
371 { &_XA_NET_WM_FULL_PLACEMENT , "_NET_WM_FULL_PLACEMENT" },
372 { &_XA_NET_WM_FULLSCREEN_MONITORS , "_NET_WM_FULLSCREEN_MONITORS" },
373 { &_XA_NET_WM_HANDLED_ICONS , "_NET_WM_HANDLED_ICONS" },
374 { &_XA_NET_WM_ICON_GEOMETRY , "_NET_WM_ICON_GEOMETRY" },
375 { &_XA_NET_WM_ICON_NAME , "_NET_WM_ICON_NAME" },
376 { &_XA_NET_WM_ICON , "_NET_WM_ICON" },
377 { &_XA_NET_WM_MOVERESIZE , "_NET_WM_MOVERESIZE" },
378 { &_XA_NET_WM_NAME , "_NET_WM_NAME" },
379 { &_XA_NET_WM_OPAQUE_REGION , "_NET_WM_OPAQUE_REGION" },
380 { &_XA_NET_WM_PID , "_NET_WM_PID" },
381 { &_XA_NET_WM_PING , "_NET_WM_PING" },
382 { &_XA_NET_WM_STATE , "_NET_WM_STATE" },
383 { &_XA_NET_WM_STATE_ABOVE , "_NET_WM_STATE_ABOVE" },
384 { &_XA_NET_WM_STATE_BELOW , "_NET_WM_STATE_BELOW" },
385 { &_XA_NET_WM_STATE_DEMANDS_ATTENTION , "_NET_WM_STATE_DEMANDS_ATTENTION" },
386 { &_XA_NET_WM_STATE_FOCUSED , "_NET_WM_STATE_FOCUSED" },
387 { &_XA_NET_WM_STATE_FULLSCREEN , "_NET_WM_STATE_FULLSCREEN" },
388 { &_XA_NET_WM_STATE_HIDDEN , "_NET_WM_STATE_HIDDEN" },
389 { &_XA_NET_WM_STATE_MAXIMIZED_HORZ , "_NET_WM_STATE_MAXIMIZED_HORZ" },
390 { &_XA_NET_WM_STATE_MAXIMIZED_VERT , "_NET_WM_STATE_MAXIMIZED_VERT" },
391 { &_XA_NET_WM_STATE_MODAL , "_NET_WM_STATE_MODAL" },
392 { &_XA_NET_WM_STATE_SHADED , "_NET_WM_STATE_SHADED" },
393 { &_XA_NET_WM_STATE_SKIP_PAGER , "_NET_WM_STATE_SKIP_PAGER" },
394 { &_XA_NET_WM_STATE_SKIP_TASKBAR , "_NET_WM_STATE_SKIP_TASKBAR" },
395 { &_XA_NET_WM_STATE_STICKY , "_NET_WM_STATE_STICKY" },
396 { &_XA_NET_WM_STRUT , "_NET_WM_STRUT" },
397 { &_XA_NET_WM_STRUT_PARTIAL , "_NET_WM_STRUT_PARTIAL" },
398 { &_XA_NET_WM_SYNC_REQUEST , "_NET_WM_SYNC_REQUEST" },
399 { &_XA_NET_WM_SYNC_REQUEST_COUNTER , "_NET_WM_SYNC_REQUEST_COUNTER" },
400 { &_XA_NET_WM_USER_TIME , "_NET_WM_USER_TIME" },
401 { &_XA_NET_WM_USER_TIME_WINDOW , "_NET_WM_USER_TIME_WINDOW" },
402 { &_XA_NET_WM_VISIBLE_ICON_NAME , "_NET_WM_VISIBLE_ICON_NAME" },
403 { &_XA_NET_WM_VISIBLE_NAME , "_NET_WM_VISIBLE_NAME" },
404 { &_XA_NET_WM_WINDOW_OPACITY , "_NET_WM_WINDOW_OPACITY" },
405 { &_XA_NET_WM_WINDOW_TYPE , "_NET_WM_WINDOW_TYPE" },
406 { &_XA_NET_WM_WINDOW_TYPE_COMBO , "_NET_WM_WINDOW_TYPE_COMBO" },
407 { &_XA_NET_WM_WINDOW_TYPE_DESKTOP , "_NET_WM_WINDOW_TYPE_DESKTOP" },
408 { &_XA_NET_WM_WINDOW_TYPE_DIALOG , "_NET_WM_WINDOW_TYPE_DIALOG" },
409 { &_XA_NET_WM_WINDOW_TYPE_DND , "_NET_WM_WINDOW_TYPE_DND" },
410 { &_XA_NET_WM_WINDOW_TYPE_DOCK , "_NET_WM_WINDOW_TYPE_DOCK" },
411 { &_XA_NET_WM_WINDOW_TYPE_DROPDOWN_MENU , "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
412 { &_XA_NET_WM_WINDOW_TYPE_MENU , "_NET_WM_WINDOW_TYPE_MENU" },
413 { &_XA_NET_WM_WINDOW_TYPE_NORMAL , "_NET_WM_WINDOW_TYPE_NORMAL" },
414 { &_XA_NET_WM_WINDOW_TYPE_NOTIFICATION , "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
415 { &_XA_NET_WM_WINDOW_TYPE_POPUP_MENU , "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
416 { &_XA_NET_WM_WINDOW_TYPE_SPLASH , "_NET_WM_WINDOW_TYPE_SPLASH" },
417 { &_XA_NET_WM_WINDOW_TYPE_TOOLBAR , "_NET_WM_WINDOW_TYPE_TOOLBAR" },
418 { &_XA_NET_WM_WINDOW_TYPE_TOOLTIP , "_NET_WM_WINDOW_TYPE_TOOLTIP" },
419 { &_XA_NET_WM_WINDOW_TYPE_UTILITY , "_NET_WM_WINDOW_TYPE_UTILITY" },
420 { &_XA_NET_WORKAREA , "_NET_WORKAREA" },
421
422 { &_XA_CLIPBOARD , "CLIPBOARD" },
423 { &_XA_MANAGER , "MANAGER" },
424 { &_XA_XEMBED , "_XEMBED" },
425 { &_XA_XEMBED_INFO , "_XEMBED_INFO" },
426 { &_XA_TARGETS , "TARGETS" },
427 { &_XA_UTF8_STRING , "UTF8_STRING" },
428
429 { &XA_XdndActionAsk , "XdndActionAsk" },
430 { &XA_XdndActionCopy , "XdndActionCopy" },
431 { &XA_XdndActionLink , "XdndActionLink" },
432 { &XA_XdndActionMove , "XdndActionMove" },
433 { &XA_XdndActionPrivate , "XdndActionPrivate" },
434 { &XA_XdndAware , "XdndAware" },
435 { &XA_XdndDrop , "XdndDrop" },
436 { &XA_XdndEnter , "XdndEnter" },
437 { &XA_XdndFinished , "XdndFinished" },
438 { &XA_XdndLeave , "XdndLeave" },
439 { &XA_XdndPosition , "XdndPosition" },
440 { &XA_XdndProxy , "XdndProxy" },
441 { &XA_XdndStatus , "XdndStatus" },
442 };
443
initAtoms()444 void YXApplication::initAtoms() {
445 const int num_atoms = int ACOUNT(atom_info);
446
447 #ifdef HAVE_XINTERNATOMS
448 char* names[num_atoms];
449 Atom xatoms[num_atoms];
450
451 for (int i = 0; i < num_atoms; i++)
452 names[i] = const_cast<char *>(atom_info[i].name);
453
454 XInternAtoms(xapp->display(), names, num_atoms, False, xatoms);
455
456 for (int i = 0; i < num_atoms; i++)
457 *(atom_info[i].atom) = xatoms[i];
458 #else
459 for (int i = 0; i < num_atoms; i++)
460 *(atom_info[i].atom) = xapp->atom(atom_info[i].name);
461 #endif
462
463 qsort(atom_info, size_t(num_atoms), sizeof(atom_info[0]), sortAtoms);
464 setAtomName(atomName);
465 }
466
sortAtoms(const void * p1,const void * p2)467 int YXApplication::sortAtoms(const void* p1, const void* p2) {
468 const Atom a1 = *static_cast<const YAtomName*>(p1)->atom;
469 const Atom a2 = *static_cast<const YAtomName*>(p2)->atom;
470 return int(long(a1) - long(a2));
471 }
472
atomName(Atom atom)473 const char* YXApplication::atomName(Atom atom) {
474 int lo = 0, hi = int ACOUNT(atom_info);
475 while (lo < hi) {
476 int pv = (lo + hi) / 2;
477 if (atom < *atom_info[pv].atom)
478 hi = pv;
479 else if (atom > *atom_info[pv].atom)
480 lo = pv + 1;
481 else
482 return atom_info[pv].name;
483 }
484 static char buf[32];
485 snprintf(buf, sizeof buf, "Atom(%lu)", atom);
486 return buf;
487 }
488
initModifiers()489 void YXApplication::initModifiers() {
490 XModifierKeymap *xmk = XGetModifierMapping(xapp->display());
491 AltMask = MetaMask = WinMask = SuperMask = HyperMask =
492 NumLockMask = ScrollLockMask = ModeSwitchMask = 0;
493
494 if (xmk) {
495 KeyCode *c = xmk->modifiermap;
496
497 for (int m = 0; m < 8; m++)
498 for (int k = 0; k < xmk->max_keypermod; k++, c++) {
499 if (*c == NoSymbol)
500 continue;
501 KeySym kc = XkbKeycodeToKeysym(xapp->display(), *c, 0, 0);
502 if (kc == NoSymbol)
503 kc = XkbKeycodeToKeysym(xapp->display(), *c, 0, 1);
504 if (kc == XK_Num_Lock && NumLockMask == 0)
505 NumLockMask = (1 << m);
506 if (kc == XK_Scroll_Lock && ScrollLockMask == 0)
507 ScrollLockMask = (1 << m);
508 if ((kc == XK_Alt_L || kc == XK_Alt_R) && AltMask == 0)
509 AltMask = (1 << m);
510 if ((kc == XK_Meta_L || kc == XK_Meta_R) && MetaMask == 0)
511 MetaMask = (1 << m);
512 if ((kc == XK_Super_L || kc == XK_Super_R) && SuperMask == 0)
513 SuperMask = (1 << m);
514 if ((kc == XK_Hyper_L || kc == XK_Hyper_R) && HyperMask == 0)
515 HyperMask = (1 << m);
516 if ((kc == XK_Mode_switch || kc == XK_ISO_Level3_Shift) && ModeSwitchMask == 0)
517 ModeSwitchMask = (1 << m);
518 }
519
520 XFreeModifiermap(xmk);
521 }
522 if (MetaMask == AltMask)
523 MetaMask = 0;
524
525 MSG(("alt:%d meta:%d super:%d hyper:%d win:%d mode:%d num:%d scroll:%d",
526 AltMask, MetaMask, SuperMask, HyperMask, WinMask, ModeSwitchMask,
527 NumLockMask, ScrollLockMask));
528
529 // some hacks for "broken" modifier configurations
530 if (HyperMask == SuperMask)
531 HyperMask = 0;
532
533 // this basically does what <0.9.13 versions did
534 if (AltMask != 0 && MetaMask == Mod1Mask) {
535 MetaMask = AltMask;
536 AltMask = Mod1Mask;
537 }
538
539 if (AltMask == 0 && MetaMask != 0) {
540 if (MetaMask != Mod1Mask) {
541 AltMask = Mod1Mask;
542 }
543 else {
544 AltMask = MetaMask;
545 MetaMask = 0;
546 }
547 }
548
549 if (AltMask == 0)
550 AltMask = Mod1Mask;
551
552 if (ModeSwitchMask & (AltMask | MetaMask | SuperMask | HyperMask))
553 ModeSwitchMask = 0;
554
555 PRECONDITION(xapp->AltMask != 0);
556 PRECONDITION(xapp->AltMask != ShiftMask);
557 PRECONDITION(xapp->AltMask != ControlMask);
558 PRECONDITION(xapp->AltMask != xapp->MetaMask);
559
560 KeyMask =
561 ControlMask |
562 ShiftMask |
563 AltMask |
564 MetaMask |
565 SuperMask |
566 HyperMask |
567 ModeSwitchMask;
568
569 ButtonMask =
570 Button1Mask |
571 Button2Mask |
572 Button3Mask |
573 Button4Mask |
574 Button5Mask;
575
576 ButtonKeyMask = KeyMask | ButtonMask;
577
578 #if 0
579 KeySym wl = XKeycodeToKeysym(app->display(), 115, 0);
580 KeySym wr = XKeycodeToKeysym(app->display(), 116, 0);
581
582 if (wl == XK_Super_L) {
583 } else if (wl == XK_Meta_L) {
584 }
585 #endif
586 // this will do for now, but we should actualy check the keycodes
587 Win_L = Win_R = 0;
588
589 if (SuperMask != 0) {
590 WinMask = SuperMask;
591
592 Win_L = XK_Super_L;
593 Win_R = XK_Super_R;
594 }
595 MSG(("alt:%d meta:%d super:%d hyper:%d win:%d mode:%d num:%d scroll:%d",
596 AltMask, MetaMask, SuperMask, HyperMask, WinMask, ModeSwitchMask,
597 NumLockMask, ScrollLockMask));
598
599 }
600
hasControlAlt(unsigned state) const601 bool YXApplication::hasControlAlt(unsigned state) const {
602 return xapp->AltMask && hasbits((state & KeyMask), ControlMask | AltMask);
603 }
604
hasWinMask(unsigned state) const605 bool YXApplication::hasWinMask(unsigned state) const {
606 return xapp->WinMask && hasbit((state & KeyMask), WinMask);
607 }
608
dispatchEvent(YWindow * win,XEvent & xev)609 void YXApplication::dispatchEvent(YWindow *win, XEvent &xev) {
610 if (xev.type == KeyPress || xev.type == KeyRelease) {
611 YWindow *w = win;
612
613 if (w && (fGrabWindow == nullptr || fGrabTree)) {
614 if (w->toplevel())
615 w = w->toplevel();
616
617 if (w->getFocusWindow())
618 w = w->getFocusWindow();
619 }
620
621 for (; w && (w->handleKey(xev.xkey) == false); w = w->parent()) {
622 if (fGrabTree && w == fXGrabWindow)
623 break;
624 }
625 } else {
626 Window child;
627
628 if (xev.type == MotionNotify) {
629 if (xev.xmotion.window != win->handle()) {
630 if (XTranslateCoordinates(xapp->display(),
631 xev.xany.window, win->handle(),
632 xev.xmotion.x, xev.xmotion.y,
633 &xev.xmotion.x, &xev.xmotion.y, &child) == True)
634 xev.xmotion.window = win->handle();
635 else
636 return ;
637 }
638 } else if (xev.type == ButtonPress || xev.type == ButtonRelease ||
639 xev.type == EnterNotify || xev.type == LeaveNotify)
640 {
641 if (xev.xbutton.window != win->handle()) {
642 if (XTranslateCoordinates(xapp->display(),
643 xev.xany.window, win->handle(),
644 xev.xbutton.x, xev.xbutton.y,
645 &xev.xbutton.x, &xev.xbutton.y, &child) == True)
646 xev.xbutton.window = win->handle();
647 else
648 return ;
649 }
650 } else if (xev.type == KeyPress || xev.type == KeyRelease) {
651 if (xev.xkey.window != win->handle()) {
652 if (XTranslateCoordinates(xapp->display(),
653 xev.xany.window, win->handle(),
654 xev.xkey.x, xev.xkey.y,
655 &xev.xkey.x, &xev.xkey.y, &child) == True)
656 xev.xkey.window = win->handle();
657 else
658 return ;
659 }
660 }
661 win->handleEvent(xev);
662 }
663 }
664
handleGrabEvent(YWindow * winx,XEvent & xev)665 void YXApplication::handleGrabEvent(YWindow *winx, XEvent &xev) {
666 struct {
667 YWindow *ptr;
668 } win = { winx };
669
670 PRECONDITION(win.ptr != 0);
671 if (fGrabTree) {
672 if (xev.xbutton.subwindow != None) {
673 if ( ! windowContext.find(xev.xbutton.subwindow, &win.ptr))
674 {
675 if (xev.type == EnterNotify || xev.type == LeaveNotify)
676 win.ptr = nullptr;
677 else
678 win.ptr = fGrabWindow;
679 }
680 } else {
681 if ( ! windowContext.find(xev.xbutton.window, &win.ptr))
682 {
683 if (xev.type == EnterNotify || xev.type == LeaveNotify)
684 win.ptr = nullptr;
685 else
686 win.ptr = fGrabWindow;
687 }
688 }
689 if (win.ptr == nullptr)
690 return ;
691 {
692 YWindow *p = win.ptr;
693 for (; p; p = p->parent()) {
694 if (p == fXGrabWindow)
695 break;
696 }
697 if (p == nullptr) {
698 if (xev.type == EnterNotify || xev.type == LeaveNotify)
699 return ;
700 else
701 win.ptr = fGrabWindow;
702 }
703 }
704 if (xev.type == EnterNotify || xev.type == LeaveNotify)
705 if (win.ptr != fGrabWindow)
706 return ;
707 if (fGrabWindow != fXGrabWindow)
708 win.ptr = fGrabWindow;
709 }
710 dispatchEvent(win.ptr, xev);
711 }
712
replayEvent()713 void YXApplication::replayEvent() {
714 if (!fReplayEvent) {
715 fReplayEvent = true;
716 XAllowEvents(xapp->display(), ReplayPointer, CurrentTime);
717 }
718 }
719
captureGrabEvents(YWindow * win)720 void YXApplication::captureGrabEvents(YWindow *win) {
721 if (fGrabWindow == fXGrabWindow && fGrabTree) {
722 fGrabWindow = win;
723 }
724 }
725
releaseGrabEvents(YWindow * win)726 void YXApplication::releaseGrabEvents(YWindow *win) {
727 if (win == fGrabWindow && fGrabTree) {
728 fGrabWindow = fXGrabWindow;
729 }
730 }
731
grabEvents(YWindow * win,Cursor ptr,unsigned long eventMask,bool grabMouse,bool grabKeyboard,bool grabTree)732 bool YXApplication::grabEvents(YWindow *win, Cursor ptr,
733 unsigned long eventMask, bool grabMouse, bool grabKeyboard, bool grabTree)
734 {
735 if (fGrabWindow || !win)
736 return false;
737
738 fGrabTree = grabTree;
739 fGrabMouse = grabMouse;
740 if (grabMouse) {
741 int rc = XGrabPointer(display(), win->handle(), grabTree,
742 eventMask, GrabModeSync, GrabModeAsync,
743 None, ptr, CurrentTime);
744 if (rc) {
745 MSG(("grab status = %d\x7", rc));
746 return false;
747 }
748 }
749 else {
750 XChangeActivePointerGrab(display(), eventMask, ptr, CurrentTime);
751 }
752
753 if (grabKeyboard) {
754 int rc = XGrabKeyboard(display(), win->handle(), grabTree,
755 GrabModeSync, GrabModeAsync, CurrentTime);
756 if (rc) {
757 MSG(("grab status = %d\x7", rc));
758 if (grabMouse) {
759 XUngrabPointer(display(), CurrentTime);
760 fGrabMouse = false;
761 }
762 return false;
763 }
764 }
765 XAllowEvents(xapp->display(), SyncPointer, CurrentTime);
766
767 fXGrabWindow = win;
768 fGrabWindow = win;
769 return true;
770 }
771
releaseEvents()772 bool YXApplication::releaseEvents() {
773 if (fGrabWindow == nullptr)
774 return false;
775
776 fGrabWindow = nullptr;
777 fXGrabWindow = nullptr;
778 fGrabTree = false;
779 if (fGrabMouse) {
780 XUngrabPointer(display(), CurrentTime);
781 fGrabMouse = false;
782 }
783 XUngrabKeyboard(display(), CurrentTime);
784
785 return true;
786 }
787
afterWindowEvent(XEvent &)788 void YXApplication::afterWindowEvent(XEvent & /*xev*/) {
789 }
790
filterEvent(const XEvent & xev)791 bool YXApplication::filterEvent(const XEvent &xev) {
792 if (xev.type == MappingNotify) {
793 MSG(("MappingNotify"));
794 XMappingEvent xmapping = xev.xmapping;
795 XRefreshKeyboardMapping(&xmapping);
796
797 while (0 < XPending(display())) {
798 XEvent event;
799 XNextEvent(display(), &event);
800 if (event.type == MappingNotify) {
801 XRefreshKeyboardMapping(&event.xmapping);
802 } else {
803 XPutBackEvent(display(), &event);
804 break;
805 }
806 }
807
808 initModifiers();
809
810 desktop->grabKeys();
811 desktop->kbLayout();
812 return true;
813 }
814 return false;
815 }
816
saveEventTime(const XEvent & xev)817 void YXApplication::saveEventTime(const XEvent &xev) {
818 switch (xev.type) {
819 case ButtonPress:
820 case ButtonRelease:
821 lastEventTime = xev.xbutton.time;
822 break;
823
824 case MotionNotify:
825 lastEventTime = xev.xmotion.time;
826 break;
827
828 case KeyPress:
829 case KeyRelease:
830 lastEventTime = xev.xkey.time;
831 break;
832
833 case EnterNotify:
834 case LeaveNotify:
835 lastEventTime = xev.xcrossing.time;
836 break;
837
838 case PropertyNotify:
839 lastEventTime = xev.xproperty.time;
840 break;
841
842 case SelectionClear:
843 lastEventTime = xev.xselectionclear.time;
844 break;
845
846 case SelectionRequest:
847 lastEventTime = xev.xselectionrequest.time;
848 break;
849
850 case SelectionNotify:
851 lastEventTime = xev.xselection.time;
852 break;
853 }
854 }
855
getEventTime(const char *) const856 Time YXApplication::getEventTime(const char *) const {
857 return lastEventTime;
858 }
859
haveColormaps(Display * dpy)860 bool YXApplication::haveColormaps(Display* dpy) {
861 XVisualInfo pattern = { nullptr, None, DefaultScreen(dpy), 0, };
862 int i = 0, num = 0, mask = VisualScreenMask;
863 xsmart<XVisualInfo> info(XGetVisualInfo(dpy, mask, &pattern, &num));
864 for (; i < num && notbit(info[i].c_class, 1); ++i);
865 return i < num;
866 }
867
visualForDepth(unsigned depth) const868 Visual* YXApplication::visualForDepth(unsigned depth) const {
869 Visual* vis =
870 depth == 32 ? fVisual32 :
871 depth == 24 ? fVisual24 :
872 depth == unsigned(DefaultDepth(display(), screen())) ?
873 DefaultVisual(display(), screen()) :
874 CopyFromParent;
875 return vis;
876 }
877
colormapForDepth(unsigned depth) const878 Colormap YXApplication::colormapForDepth(unsigned depth) const {
879 Colormap cmap =
880 depth == 32 ? fColormap32 :
881 depth == 24 ? fColormap24 :
882 depth == unsigned(DefaultDepth(display(), screen())) ?
883 DefaultColormap(display(), screen()) :
884 CopyFromParent;
885 return cmap;
886 }
887
colormapForVisual(Visual * visual) const888 Colormap YXApplication::colormapForVisual(Visual* visual) const {
889 Colormap cmap =
890 visual == fVisual32 ? fColormap32 :
891 visual == fVisual24 ? fColormap24 :
892 visual == DefaultVisual(display(), screen()) ?
893 DefaultColormap(display(), screen()) :
894 CopyFromParent;
895 return cmap;
896 }
897
formatForDepth(unsigned depth) const898 XRenderPictFormat* YXApplication::formatForDepth(unsigned depth) const {
899 XRenderPictFormat* format =
900 depth == 32 ? fFormat32 :
901 depth == 24 ? fFormat24 :
902 nullptr;
903 return format;
904 }
905
findFormat(int depth) const906 XRenderPictFormat* YXApplication::findFormat(int depth) const {
907 XRenderPictFormat* format = nullptr;
908 if (depth == 32)
909 format = XRenderFindStandardFormat(fDisplay, PictStandardARGB32);
910 if (depth == 24)
911 format = XRenderFindStandardFormat(fDisplay, PictStandardRGB24);
912 return format;
913 }
914
findVisual(int depth) const915 Visual* YXApplication::findVisual(int depth) const {
916 Visual* found = nullptr;
917 XRenderPictFormat* pictFormat = findFormat(depth);
918 if (pictFormat) {
919 XVisualInfo pattern = {
920 found, None, fScreen, depth, TrueColor, None, None, None, 0, 8
921 };
922 int count = 0, mask = VisualDepthMask | VisualScreenMask |
923 VisualClassMask | VisualBitsPerRGBMask;
924 xsmart<XVisualInfo> info(
925 XGetVisualInfo(fDisplay, mask, &pattern, &count));
926 for (int i = 0; i < count && found == nullptr; ++i) {
927 XRenderPictFormat* format =
928 XRenderFindVisualFormat(fDisplay, info[i].visual);
929 if (format == pictFormat) {
930 found = info[i].visual;
931 }
932 }
933 }
934 if (found == nullptr) {
935 XVisualInfo pattern = {
936 found, 0, fScreen, depth, TrueColor, 0xff0000, 0xff00, 0xff, 0, 8
937 };
938 int mask = VisualScreenMask | VisualDepthMask | VisualClassMask
939 | VisualRedMaskMask | VisualGreenMaskMask
940 | VisualBlueMaskMask | VisualBitsPerRGBMask;
941 int count = 0;
942 xsmart<XVisualInfo> info(
943 XGetVisualInfo(fDisplay, mask, &pattern, &count));
944 if (count && info) {
945 found = info->visual;
946 }
947 }
948 if (found == nullptr && depth == DefaultDepth(fDisplay, fScreen)) {
949 found = DefaultVisual(fDisplay, fScreen);
950 }
951 return found;
952 }
953
cmapError(Display * disp,XErrorEvent * xerr)954 int YXApplication::cmapError(Display *disp, XErrorEvent *xerr) {
955 // Ignore create colormap error.
956 // This may occur with Xdmx for 32-bit visuals.
957 // Ignore for now, unless problems do show up.
958 return Success;
959 }
960
getColormap(int depth) const961 Colormap YXApplication::getColormap(int depth) const {
962 Colormap cmap = None;
963 Visual* visual = depth == 32 ? fVisual32
964 : depth == 24 ? fVisual24 : nullptr;
965 if (visual == DefaultVisual(fDisplay, fScreen)) {
966 cmap = DefaultColormap(fDisplay, fScreen);
967 }
968 else if (visual) {
969 XErrorHandler old = XSetErrorHandler(cmapError);
970 cmap = XCreateColormap(fDisplay, fRoot, visual, AllocNone);
971 XSync(fDisplay, False);
972 XSetErrorHandler(old);
973 }
974 else if (depth == DefaultDepth(fDisplay, fScreen)) {
975 cmap = DefaultColormap(fDisplay, fScreen);
976 }
977 return cmap;
978 }
979
alert()980 void YXApplication::alert() {
981 XBell(display(), 100);
982 }
983
setClipboardText(mstring data)984 void YXApplication::setClipboardText(mstring data) {
985 fClip->setData(data);
986 }
987
dropClipboard()988 void YXApplication::dropClipboard() {
989 fClip = null;
990 }
991
getHelpText()992 const char* YXApplication::getHelpText() {
993 return _(
994 " -d, --display=NAME NAME of the X server to use.\n"
995 " --sync Synchronize X11 commands.\n"
996 );
997 }
998
999 const char*
parseArgs(int argc,char ** argv,const char * displayName)1000 YXApplication::parseArgs(int argc, char **argv, const char *displayName) {
1001 for (char ** arg = argv + 1; arg < argv + argc; ++arg) {
1002 if (**arg == '-') {
1003 char *value;
1004 if (is_help_switch(*arg)) {
1005 print_help_exit(getHelpText());
1006 }
1007 else if (is_version_switch(*arg)) {
1008 print_version_exit(VERSION);
1009 }
1010 else if (is_copying_switch(*arg)) {
1011 print_copying_exit();
1012 }
1013 else if (GetArgument(value, "d", "display", arg, argv + argc)) {
1014 if (isEmpty(displayName))
1015 displayName = value;
1016 }
1017 else if (is_long_switch(*arg, "sync"))
1018 synchronizeX11 = true;
1019 else if (is_long_switch(*arg, "alpha"))
1020 alphaBlending = true;
1021 }
1022 }
1023
1024 return displayName;
1025 }
1026
openDisplay(const char * displayName)1027 Display* YXApplication::openDisplay(const char* displayName) {
1028 if (nonempty(displayName))
1029 setenv("DISPLAY", displayName, True);
1030 else
1031 displayName = getenv("DISPLAY");
1032
1033 Display* display = XOpenDisplay(displayName);
1034 if (display == nullptr)
1035 die(1, _("Can't open display: %s. X must be running and $DISPLAY set."),
1036 displayName ? displayName : _("<none>"));
1037
1038 if (synchronizeX11)
1039 XSynchronize(display, True);
1040
1041 XSetErrorHandler(errorHandler);
1042
1043 initExtensions(display);
1044
1045 return display;
1046 }
1047
YXApplication(int * argc,char *** argv,const char * displayName)1048 YXApplication::YXApplication(int *argc, char ***argv, const char *displayName):
1049 YApplication(argc, argv),
1050
1051 fDisplay( openDisplay( parseArgs(*argc, *argv, displayName))),
1052 fScreen( DefaultScreen(fDisplay)),
1053 fRoot( RootWindow(fDisplay, fScreen)),
1054 fFormat32( findFormat(32)),
1055 fFormat24( findFormat(24)),
1056 fVisual32( findVisual(32)),
1057 fVisual24( findVisual(24)),
1058 fColormap32( getColormap(32)),
1059 fColormap24( getColormap(24)),
1060 fAlpha( alphaBlending && fVisual32 && fColormap32 ),
1061 fDepth( fAlpha ? 32 : fVisual24 ? 24 : DefaultDepth(fDisplay, fScreen)),
1062 fVisual( visualForDepth(fDepth)),
1063 fColormap( colormapForDepth(fDepth)),
1064 fHasColormaps( haveColormaps(display())),
1065 fBlack( BlackPixel(display(), screen())),
1066 fWhite( WhitePixel(display(), screen())),
1067
1068 lastEventTime(CurrentTime),
1069 fPopup(nullptr),
1070 xfd(this),
1071 fXGrabWindow(nullptr),
1072 fGrabWindow(nullptr),
1073 fGrabTree(false),
1074 fGrabMouse(false),
1075 fReplayEvent(false)
1076 {
1077 xapp = this;
1078 xfd.registerPoll(ConnectionNumber(display()));
1079
1080 new YDesktop(nullptr, root());
1081 extern void image_init();
1082 image_init();
1083
1084 initAtoms();
1085 initModifiers();
1086 }
1087
init(Display * dis,QueryFunc ext,QueryFunc ver)1088 void YExtension::init(Display* dis, QueryFunc ext, QueryFunc ver) {
1089 supported = (*ext)(dis, &eventBase, &errorBase)
1090 && (*ver)(dis, &versionMajor, &versionMinor);
1091 parameter = False;
1092 }
1093
init(Display * dis,ExistFunc ext,ParamFunc ver)1094 void YExtension::init(Display* dis, ExistFunc ext, ParamFunc ver) {
1095 supported = (*ext)(dis)
1096 && (*ver)(dis, &versionMajor, &versionMinor, ¶meter);
1097 eventBase = errorBase = 0;
1098 }
1099
initExtensions(Display * dpy)1100 void YXApplication::initExtensions(Display* dpy) {
1101
1102 composite.init(dpy, XCompositeQueryExtension, XCompositeQueryVersion);
1103 damage.init(dpy, XDamageQueryExtension, XDamageQueryVersion);
1104 fixes.init(dpy, XFixesQueryExtension, XFixesQueryVersion);
1105 render.init(dpy, XRenderQueryExtension, XRenderQueryVersion);
1106
1107 #ifdef CONFIG_SHAPE
1108 shapes.init(dpy, XShapeQueryExtension, XShapeQueryVersion);
1109 #endif
1110
1111 #ifdef CONFIG_XRANDR
1112 xrandr.init(dpy, XRRQueryExtension, XRRQueryVersion);
1113 xrandr.supported = (12 <= 10 * xrandr.versionMajor + xrandr.versionMinor);
1114 #endif
1115
1116 #ifdef XINERAMA
1117 xinerama.init(dpy, XineramaQueryExtension, XineramaQueryVersion);
1118 xinerama.supported = (xinerama.supported && XineramaIsActive(dpy));
1119 #endif
1120
1121 xshm.init(dpy, XShmQueryExtension, XShmQueryVersion);
1122 }
1123
~YXApplication()1124 YXApplication::~YXApplication() {
1125 if (fColormap32)
1126 XFreeColormap(display(), fColormap32);
1127
1128 xfd.unregisterPoll();
1129 XCloseDisplay(display());
1130 xapp = nullptr;
1131 }
1132
handleXEvents()1133 bool YXApplication::handleXEvents() {
1134 const int prratio = 3;
1135 int retrieved = 0;
1136 for (; retrieved < XPending(display()); retrieved += prratio - 1) {
1137 XEvent xev;
1138
1139 XNextEvent(display(), &xev);
1140 #ifdef DEBUG
1141 xeventcount++;
1142 #endif
1143 //msg("%d", xev.type);
1144
1145 saveEventTime(xev);
1146
1147 #if LOGEVENTS
1148 if (loggingEvents) {
1149 if (xev.type < LASTEvent)
1150 logEvent(xev);
1151 #ifdef CONFIG_SHAPE
1152 else if (shapes.isEvent(xev.type, ShapeNotify))
1153 logShape(xev);
1154 #endif
1155 #ifdef CONFIG_XRANDR
1156 else if (xrandr.isEvent(xev.type, RRScreenChangeNotify))
1157 logRandrScreen(xev);
1158 else if (xrandr.isEvent(xev.type, RRNotify))
1159 logRandrNotify(xev);
1160 #endif
1161 }
1162 #endif
1163
1164 if (filterEvent(xev)) {
1165 } else {
1166 bool ge = xev.type == ButtonPress ||
1167 xev.type == ButtonRelease ||
1168 xev.type == MotionNotify ||
1169 xev.type == KeyPress ||
1170 xev.type == KeyRelease /*||
1171 xev.type == EnterNotify ||
1172 xev.type == LeaveNotify*/;
1173
1174 fReplayEvent = false;
1175
1176 if (fPopup && ge) {
1177 handleGrabEvent(fPopup, xev);
1178 } else if (fGrabWindow && ge) {
1179 handleGrabEvent(fGrabWindow, xev);
1180 } else {
1181 handleWindowEvent(xev.xany.window, xev);
1182 }
1183 if (fGrabWindow) {
1184 if (xev.type == ButtonPress ||
1185 xev.type == ButtonRelease ||
1186 xev.type == MotionNotify)
1187 {
1188 if (!fReplayEvent) {
1189 XAllowEvents(xapp->display(), SyncPointer, CurrentTime);
1190 }
1191 }
1192 }
1193 }
1194 XFlush(display());
1195 }
1196 return retrieved > 0;
1197 }
1198
handleIdle()1199 bool YXApplication::handleIdle() {
1200 return handleXEvents();
1201 }
1202
handleWindowEvent(Window xwindow,XEvent & xev)1203 void YXApplication::handleWindowEvent(Window xwindow, XEvent &xev) {
1204 struct {
1205 YWindow *ptr;
1206 } window = { nullptr };
1207
1208 if (windowContext.find(xwindow, &window.ptr))
1209 {
1210 if ((xev.type == KeyPress || xev.type == KeyRelease)
1211 && window.ptr->toplevel())
1212 {
1213 YWindow *w = window.ptr->toplevel();
1214
1215 if (w->getFocusWindow())
1216 w = w->getFocusWindow();
1217
1218 dispatchEvent(w, xev);
1219 } else {
1220 window.ptr->handleEvent(xev);
1221 }
1222 } else {
1223 if (xev.type == MapRequest) {
1224 if (xev.xmaprequest.window != ignorable) {
1225 // !!! java seems to do this ugliness
1226 //YFrameWindow *f = getFrame(xev.xany.window);
1227 TLOG(("APP BUG? mapRequest for window %lX "
1228 "sent to destroyed frame %lX!",
1229 xev.xmaprequest.window,
1230 xev.xmaprequest.parent));
1231 desktop->handleEvent(xev);
1232 }
1233 } else if (xev.type == ConfigureRequest) {
1234 if (xev.xconfigurerequest.window != ignorable) {
1235 TLOG(("APP BUG? configureRequest for window %lX "
1236 "sent to destroyed frame %lX!",
1237 xev.xconfigurerequest.window,
1238 xev.xconfigurerequest.parent));
1239 desktop->handleEvent(xev);
1240 }
1241 }
1242 else if (xev.type == ClientMessage && desktop) {
1243 Atom mesg = xev.xclient.message_type;
1244 if (mesg == _XA_NET_REQUEST_FRAME_EXTENTS) {
1245 desktop->handleEvent(xev);
1246 }
1247 else
1248 {
1249 MSG(("Unknown client message %ld, win 0x%lX, data %ld,%ld",
1250 mesg, xev.xclient.window,
1251 xev.xclient.data.l[0], xev.xclient.data.l[1]));
1252 }
1253 }
1254 else if (xev.type != DestroyNotify) {
1255 MSG(("unknown window 0x%lX event=%d", xev.xany.window, xev.type));
1256 }
1257 }
1258 if (xev.type == KeyPress || xev.type == KeyRelease) ///!!!
1259 afterWindowEvent(xev);
1260 }
1261
flushXEvents()1262 void YXApplication::flushXEvents() {
1263 XFlush(display());
1264 }
1265
handleError(XErrorEvent * xev)1266 int YXApplication::handleError(XErrorEvent* xev) {
1267 return BadImplementation;
1268 }
1269
errorHandler(Display * display,XErrorEvent * xev)1270 int YXApplication::errorHandler(Display* display, XErrorEvent* xev) {
1271 int rc = xapp->handleError(xev);
1272 if (rc == Success)
1273 return rc;
1274
1275 XDBG if (xev->resourceid != ignorable) {
1276 char message[80], req[80], number[80];
1277
1278 snprintf(number, sizeof number, "%d", xev->request_code);
1279 XGetErrorDatabaseText(display, "XRequest", number, "", req, sizeof req);
1280 if (req[0] == 0)
1281 snprintf(req, sizeof req, "[request_code=%d]", xev->request_code);
1282
1283 if (XGetErrorText(display, xev->error_code, message, sizeof message))
1284 *message = '\0';
1285
1286 tlog("X error %s(0x%lx): %s, #%lu, %+ld, %+ld.",
1287 req, xev->resourceid, message, xev->serial,
1288 long(NextRequest(display)) - long(xev->serial),
1289 long(LastKnownRequestProcessed(display)) - long(xev->serial));
1290
1291 #if defined(DEBUG) || defined(PRECON)
1292 if (xapp->synchronized()) {
1293 switch (xev->request_code) {
1294 case X_GetWindowAttributes:
1295 break;
1296 case X_GetImage:
1297 case X_CreateGC:
1298 show_backtrace();
1299 break;
1300 default:
1301 show_backtrace();
1302 break;
1303 }
1304 }
1305 else if (ONCE) {
1306 TLOG(("unsynchronized"));
1307 }
1308 #endif
1309 }
1310
1311 if (rc == BadImplementation)
1312 xapp->exit(rc);
1313 return rc;
1314 }
1315
send(XClientMessageEvent & ev,Window win,long mask) const1316 void YXApplication::send(XClientMessageEvent& ev, Window win, long mask) const {
1317 XSendEvent(display(), win, False, mask, reinterpret_cast<XEvent*>(&ev));
1318 }
1319
parent(Window child) const1320 Window YXApplication::parent(Window child) const {
1321 Window paren = None;
1322 Window rootw = None;
1323 Window* data = nullptr;
1324 unsigned num = None;
1325 if (XQueryTree(display(), child, &rootw, &paren, &data, &num) && data) {
1326 XFree(data);
1327 }
1328 return paren;
1329 }
1330
children(Window win,Window ** data,unsigned * num) const1331 bool YXApplication::children(Window win, Window** data, unsigned* num) const {
1332 Window rootw;
1333 Window paren;
1334 return XQueryTree(display(), win, &rootw, &paren, data, num);
1335 }
1336
notifyRead()1337 void YXPoll::notifyRead() {
1338 owner()->handleXEvents();
1339 }
1340
atomize()1341 void YAtom::atomize() {
1342 if (screen) {
1343 char buf[256];
1344 snprintf(buf, sizeof buf, "%s%d", name, xapp->screen());
1345 atom = xapp->atom(buf);
1346 } else {
1347 atom = xapp->atom(name);
1348 }
1349 }
1350
operator Atom()1351 YAtom::operator Atom() {
1352 if (atom == None)
1353 atomize();
1354 return atom;
1355 }
1356
YTextProperty(const char * str)1357 YTextProperty::YTextProperty(const char* str) {
1358 encoding = XA_STRING;
1359 format = 8;
1360 if (str) {
1361 nitems = strlen(str);
1362 value = (unsigned char *) malloc(1 + nitems);
1363 if (value) memcpy(value, str, 1 + nitems);
1364 } else {
1365 nitems = 0;
1366 value = nullptr;
1367 }
1368 }
1369
~YTextProperty()1370 YTextProperty::~YTextProperty() {
1371 if (value) XFree(value);
1372 }
1373
discard()1374 void YProperty::discard() {
1375 if (fData) {
1376 XFree(fData);
1377 fData = nullptr;
1378 fSize = None;
1379 fType = None;
1380 }
1381 }
1382
update()1383 const YProperty& YProperty::update() {
1384 discard();
1385 int fmt = 0;
1386 if (XGetWindowProperty(xapp->display(), fWind, fProp, 0L, fLimit, fDelete,
1387 fKind, &fType, &fmt, &fSize, &fMore, &fData) ==
1388 Success && fData && fSize && fmt == fBits && (fKind == fType || !fKind))
1389 {
1390 } else {
1391 discard();
1392 }
1393 return *this;
1394 }
1395
append(void const * data,int count) const1396 void YProperty::append(void const* data, int count) const {
1397 unsigned char const* bytes = reinterpret_cast<unsigned char const*>(data);
1398 XChangeProperty(xapp->display(), fWind, fProp, fKind, fBits,
1399 PropModeAppend, bytes, count);
1400 }
1401
replace(void const * data,int count) const1402 void YProperty::replace(void const* data, int count) const {
1403 unsigned char const* bytes = reinterpret_cast<unsigned char const*>(data);
1404 XChangeProperty(xapp->display(), fWind, fProp, fKind, fBits,
1405 PropModeReplace, bytes, count);
1406 }
1407
1408 // vim: set sw=4 ts=4 et:
1409