0 /*
1 * Inter-Client Communication Conventions Manual (ICCCM) hints
2 *
3 * NOTE: Since the ICCCM is so closely tied to window management, much
4 * of the standard is hardwired into "window.c".
5 */
6
7 /*
8 * Copyright 2006 Johan Veenhuizen
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29 #include <assert.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include <X11/Xatom.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37
38 #include "global.h"
39 #include "hints.h"
40 #include "lib.h"
41 #include "window.h"
42 #include "ewmh.h"
43
44 static Atom WM_CHANGE_STATE;
45 static Atom WM_DELETE_WINDOW;
46 static Atom WM_PROTOCOLS;
47 static Atom WM_STATE;
48 //static Atom WM_MOTIF;
49
50 static void icccm_init(void);
51 static void icccm_manage(struct window *);
52 static void icccm_map(struct window *);
53 static void icccm_unmap(struct window *);
54 static void icccm_withdraw(struct window *);
55 static void icccm_activate(struct window *);
56 static void icccm_deactivate(struct window *);
57 static void icccm_move(struct window *);
58 static int icccm_clientmessage(struct window *, XClientMessageEvent *);
59 static int icccm_propertynotify(struct window *, XPropertyEvent *);
60 static int icccm_delete(struct window *);
61 static int knowsproto(struct window *, Atom);
62 static void sendmesg(struct window *, Atom, long);
63 static void sendconf(struct window *);
64 static void setwmstate(struct window *, long);
65
66 struct hints icccm_hints = {
67 .name = "Inter-Client Communication Conventions Manual (ICCCM)",
68
69 .init = icccm_init,
70 .manage = icccm_manage,
71 .map = icccm_map,
72 .unmap = icccm_unmap,
73 .withdraw = icccm_withdraw,
74 .activate = icccm_activate,
75 .deactivate = icccm_deactivate,
76 .move = icccm_move,
77 .clientmessage = icccm_clientmessage,
78 .propertynotify = icccm_propertynotify,
79 .delete = icccm_delete,
80 };
81
82 static void icccm_init(void)
83 {
84 WM_CHANGE_STATE = XInternAtom(display, "WM_CHANGE_STATE", False);
85 WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False);
86 WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", False);
87 WM_STATE = XInternAtom(display, "WM_STATE", False);
88 //WM_MOTIF = XInternAtom(display, "MOTIF_WM_HINTS", False);
89 }
90
91 static void icccm_manage(struct window *win)
92 {
93 sendconf(win);
94 }
95
96 static void icccm_map(struct window *win)
97 {
98 setwmstate(win, NormalState);
99 }
100
101 static void icccm_unmap(struct window *win)
102 {
103 setwmstate(win, IconicState);
104 }
105
106 static void icccm_withdraw(struct window *win)
107 {
108 setwmstate(win, WithdrawnState);
109 }
110
111 static void icccm_activate(struct window *win)
112 {
113 if (win == NULL)
114 XInstallColormap(display, DefaultColormap(display, screen));
115 else
116 XInstallColormap(display, win->colormap);
117 }
118
119 static void icccm_deactivate(struct window *win)
120 {
121 XUninstallColormap(display, win->colormap);
122 }
123
124 static void icccm_move(struct window *win)
125 {
126 sendconf(win);
127 }
128
129 static int icccm_clientmessage(struct window *win, XClientMessageEvent *ep)
130 {
131 if (ep->message_type == WM_CHANGE_STATE && ep->format == 32) {
132 switch (ep->data.l[0]) {
133 case IconicState:
134 unmap_window(win);
135 return 1;
136 case NormalState:
137 map_window(win);
138 return 1;
139 }
140 }
141 if (ep->message_type == atom[NET_WM_STATE]) {
142 if (ep->data.l[1] == atom[NET_WM_STATE_FULLSCREEN] || ep->data.l[2] == atom[NET_WM_STATE_FULLSCREEN]) {
143 window_set_fullscreen(win, (ep->data.l[0] == 1 || (ep->data.l[0] == 2 && !win->fullscreen)));
144 return 1;
145 }
146 }
147 return 0;
148 }
149
150 static int icccm_propertynotify(struct window *win, XPropertyEvent *ep)
151 {
152 switch (ep->atom) {
153 case XA_WM_NAME:
154 if (ep->state != PropertyDelete)
155 fetch_window_name(win);
156 return 1;
157 case XA_WM_ICON_NAME:
158 if (ep->state != PropertyDelete)
159 fetch_icon_name(win);
160 return 1;
161 case XA_WM_NORMAL_HINTS:
162 fetch_wm_normal_hints(win);
163 return 1;
164 case XA_WM_HINTS:
165 fetch_wm_hints(win);
166 return 1;
167 case XA_WM_TRANSIENT_FOR:
168 fetch_wm_transient_for_hint(win);
169 return 1;
170 }
171 if (ep->atom == atom[NET_WM_WINDOW_TYPE]) {
172 update_window_type(win);
173 return 1;
174 }
175 return 0;
176 }
177
178 static int icccm_delete(struct window *win)
179 {
180 if (knowsproto(win, WM_DELETE_WINDOW)) {
181 sendmesg(win, WM_PROTOCOLS, WM_DELETE_WINDOW);
182 return 1;
183 } else
184 return 0;
185 }
186
187 static int knowsproto(struct window *win, Atom proto)
188 {
189 Atom *protocols;
190 int i, n;
191 int found;
192
193 found = 0;
194 clerr();
195 if (XGetWMProtocols(display, win->client, &protocols, &n)) {
196 for (i = 0; !found && i < n; i++) {
197 if (protocols[i] == proto)
198 found = 1;
199 }
200 if (protocols != NULL)
201 XFree(protocols);
202 }
203 sterr();
204 return found;
205 }
206
207 static void sendmesg(struct window *win, Atom type, long value)
208 {
209 XEvent ev;
210
211 memset(&ev, 0, sizeof ev);
212 ev.xclient.type = ClientMessage;
213 ev.xclient.window = win->client;
214 ev.xclient.message_type = type;
215 ev.xclient.format = 32;
216 ev.xclient.data.l[0] = value;
217 ev.xclient.data.l[1] = CurrentTime;
218
219 clerr();
220 XSendEvent(display, win->client, False, 0L, &ev);
221 sterr();
222 }
223
224 static void sendconf(struct window *win)
225 {
226 XConfigureEvent conf;
227
228 conf.type = ConfigureNotify;
229 conf.event = win->client;
230 conf.window = win->client;
231 conf.x = WIDGET_X(win) + border_width - win->cborder;
232 conf.y = WIDGET_Y(win) + border_width + button_size - win->cborder;
233 conf.width = WIDGET_WIDTH(win) - win->decoration*(2 * border_width);
234 conf.height = WIDGET_HEIGHT(win) - win->decoration*(2 * border_width + button_size);
235 conf.border_width = win->cborder;
236 conf.above = None;
237 conf.override_redirect = False;
238
239 clerr();
240 XSendEvent(display, win->client, False, StructureNotifyMask,
241 (XEvent *)&conf);
242 sterr();
243 }
244
245 static void setwmstate(struct window *win, long state)
246 {
247 long data[2];
248
249 data[0] = state;
250 data[1] = (long)None;
251
252 clerr();
253 XChangeProperty(display, win->client, WM_STATE, WM_STATE, 32,
254 PropModeReplace, (unsigned char *)data, 2);
255 sterr();
256 }
257