Propagate Layer changes via Style command on-the-fly.
[fvwm.git] / fvwm / icccm2.c
blobc87ba42fe6cd25cd68251ce130228788c0cdeb4f
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #include "config.h"
19 #include <stdio.h>
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
23 #include <X11/Xatom.h>
25 #include "fvwm.h"
26 #include "externs.h"
27 #include "execcontext.h"
28 #include "misc.h"
29 #include "screen.h"
30 #include "eventmask.h"
32 Time managing_since;
34 Atom _XA_WM_SX;
35 Atom _XA_MANAGER;
36 Atom _XA_ATOM_PAIR;
37 Atom _XA_WM_COLORMAP_NOTIFY;
38 #define _XA_TARGETS conversion_targets[0]
39 #define _XA_MULTIPLE conversion_targets[1]
40 #define _XA_TIMESTAMP conversion_targets[2]
41 #define _XA_VERSION conversion_targets[3]
42 #define MAX_TARGETS 4
44 long conversion_targets[MAX_TARGETS];
46 long icccm_version[] = { 2, 0 };
48 void
49 SetupICCCM2(Bool replace_wm)
51 Window running_wm_win;
52 XSetWindowAttributes attr;
53 XEvent xev;
54 XClientMessageEvent ev;
55 char wm_sx[20];
57 sprintf(wm_sx, "WM_S%lu", Scr.screen);
58 _XA_WM_SX = XInternAtom(dpy, wm_sx, False);
59 _XA_MANAGER = XInternAtom(dpy, "MANAGER", False);
60 _XA_ATOM_PAIR = XInternAtom(dpy, "ATOM_PAIR", False);
61 _XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
62 _XA_MULTIPLE = XInternAtom(dpy, "MULTIPLE", False);
63 _XA_TIMESTAMP = XInternAtom(dpy, "TIMESTAMP", False);
64 _XA_VERSION = XInternAtom(dpy, "VERSION", False);
65 _XA_WM_COLORMAP_NOTIFY = XInternAtom(dpy, "WM_COLORMAP_NOTIFY", False);
67 /* Check for a running ICCCM 2.0 compliant WM */
68 running_wm_win = XGetSelectionOwner(dpy, _XA_WM_SX);
69 if (running_wm_win != None)
71 DBUG(
72 "SetupICCCM2",
73 "another ICCCM 2.0 compliant WM is running");
74 if (!replace_wm)
76 fvwm_msg(
77 ERR, "SetupICCCM2",
78 "another ICCCM 2.0 compliant WM is running,"
79 " try -replace");
80 exit(1);
82 /* We need to know when the old manager is gone.
83 Thus we wait until it destroys running_wm_win. */
84 attr.event_mask = StructureNotifyMask;
85 XChangeWindowAttributes(
86 dpy, running_wm_win, CWEventMask, &attr);
89 /* We are not yet in the event loop, thus fev_get_evtime() will not
90 * be ready. Have to get a timestamp manually by provoking a
91 * PropertyNotify. */
92 managing_since = get_server_time();
94 XSetSelectionOwner(dpy, _XA_WM_SX, Scr.NoFocusWin, managing_since);
95 if (XGetSelectionOwner(dpy, _XA_WM_SX) != Scr.NoFocusWin)
97 fvwm_msg(
98 ERR, "SetupICCCM2",
99 "failed to acquire selection ownership");
100 exit(1);
103 /* Announce ourself as the new wm */
104 ev.type = ClientMessage;
105 ev.window = Scr.Root;
106 ev.message_type = _XA_MANAGER;
107 ev.format = 32;
108 ev.data.l[0] = managing_since;
109 ev.data.l[1] = _XA_WM_SX;
110 FSendEvent(dpy, Scr.Root, False, StructureNotifyMask,(XEvent*)&ev);
112 if (running_wm_win != None) {
113 /* Wait for the old wm to finish. */
114 /* FIXME: need a timeout here. */
115 DBUG("SetupICCCM2", "waiting for WM to give up");
116 do {
117 FWindowEvent(
118 dpy, running_wm_win, StructureNotifyMask, &xev);
119 } while (xev.type != DestroyNotify);
122 /* restore NoFocusWin event mask */
123 attr.event_mask = XEVMASK_NOFOCUSW;
124 XChangeWindowAttributes(dpy, Scr.NoFocusWin, CWEventMask, &attr);
126 return;
129 /* We must make sure that we have released SubstructureRedirect
130 before we destroy manager_win, so that another wm can start
131 successfully. */
132 void
133 CloseICCCM2(void)
135 DBUG("CloseICCCM2", "good luck, new wm");
136 XSelectInput(dpy, Scr.Root, NoEventMask);
137 XFlush(dpy);
139 return;
142 /* FIXME: property change actually succeeded */
143 static Bool
144 convertProperty(Window w, Atom target, Atom property)
146 if (target == _XA_TARGETS)
148 XChangeProperty(
149 dpy, w, property, XA_ATOM, 32, PropModeReplace,
150 (unsigned char *)conversion_targets, MAX_TARGETS);
152 else if (target == _XA_TIMESTAMP)
154 long local_managing_since;
156 local_managing_since = managing_since;
157 XChangeProperty(
158 dpy, w, property, XA_INTEGER, 32, PropModeReplace,
159 (unsigned char *)&local_managing_since, 1);
161 else if (target == _XA_VERSION)
163 XChangeProperty(
164 dpy, w, property, XA_INTEGER, 32, PropModeReplace,
165 (unsigned char *)icccm_version, 2);
167 else
169 return False;
171 /* FIXME: This is ugly. We should rather select for
172 PropertyNotify on the window, return to the main loop,
173 and send the SelectionNotify once we are sure the property
174 has arrived. Problem: this needs a list of pending
175 SelectionNotifys. */
176 XFlush(dpy);
178 return True;
181 void
182 icccm2_handle_selection_request(const XEvent *e)
184 Atom type;
185 unsigned long *adata;
186 int i, format;
187 unsigned long num, rest;
188 unsigned char *data;
189 XSelectionRequestEvent ev = e->xselectionrequest;
190 XSelectionEvent reply;
192 reply.type = SelectionNotify;
193 reply.display = dpy;
194 reply.requestor = ev.requestor;
195 reply.selection = ev.selection;
196 reply.target = ev.target;
197 reply.property = None;
198 reply.time = ev.time;
200 if (ev.target == _XA_MULTIPLE)
202 if (ev.property != None)
204 XGetWindowProperty(
205 dpy, ev.requestor, ev.property, 0L, 256L, False,
206 _XA_ATOM_PAIR, &type, &format, &num, &rest,
207 &data);
208 /* FIXME: to be 100% correct, should deal with
209 * rest > 0, but since we have 4 possible targets, we
210 * will hardly ever meet multiple requests with a
211 * length > 8
213 adata = (unsigned long *)data;
214 for(i = 0; i < num; i += 2)
216 if (!convertProperty(
217 ev.requestor, adata[i],
218 adata[i+1]))
220 adata[i+1] = None;
223 XChangeProperty(
224 dpy, ev.requestor, ev.property, _XA_ATOM_PAIR,
225 32, PropModeReplace, data, num);
226 XFree(data);
229 else
231 if (ev.property == None)
233 ev.property = ev.target;
235 if (convertProperty(ev.requestor, ev.target, ev.property))
237 reply.property = ev.property;
240 FSendEvent(dpy, ev.requestor, False, 0L,(XEvent*)&reply);
241 XFlush(dpy);
243 return;
246 /* If another wm is requesting ownership of the selection,
247 we receive a SelectionClear event. In that case, we have to
248 release all resources and destroy manager_win. Done() calls
249 CloseICCCM2() after undecorating all windows. */
250 void
251 icccm2_handle_selection_clear(void)
253 DBUG("HandleSelectionClear", "I lost my selection!");
254 Done(0, NULL);
256 return;