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
23 #include <X11/Xatom.h>
27 #include "execcontext.h"
30 #include "eventmask.h"
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]
44 long conversion_targets
[MAX_TARGETS
];
46 long icccm_version
[] = { 2, 0 };
49 SetupICCCM2(Bool replace_wm
)
51 Window running_wm_win
;
52 XSetWindowAttributes attr
;
54 XClientMessageEvent ev
;
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
)
73 "another ICCCM 2.0 compliant WM is running");
78 "another ICCCM 2.0 compliant WM is running,"
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
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
)
99 "failed to acquire selection ownership");
103 /* Announce ourself as the new wm */
104 ev
.type
= ClientMessage
;
105 ev
.window
= Scr
.Root
;
106 ev
.message_type
= _XA_MANAGER
;
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");
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
);
129 /* We must make sure that we have released SubstructureRedirect
130 before we destroy manager_win, so that another wm can start
135 DBUG("CloseICCCM2", "good luck, new wm");
136 XSelectInput(dpy
, Scr
.Root
, NoEventMask
);
142 /* FIXME: property change actually succeeded */
144 convertProperty(Window w
, Atom target
, Atom property
)
146 if (target
== _XA_TARGETS
)
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
;
158 dpy
, w
, property
, XA_INTEGER
, 32, PropModeReplace
,
159 (unsigned char *)&local_managing_since
, 1);
161 else if (target
== _XA_VERSION
)
164 dpy
, w
, property
, XA_INTEGER
, 32, PropModeReplace
,
165 (unsigned char *)icccm_version
, 2);
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
182 icccm2_handle_selection_request(const XEvent
*e
)
185 unsigned long *adata
;
187 unsigned long num
, rest
;
189 XSelectionRequestEvent ev
= e
->xselectionrequest
;
190 XSelectionEvent reply
;
192 reply
.type
= SelectionNotify
;
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
)
205 dpy
, ev
.requestor
, ev
.property
, 0L, 256L, False
,
206 _XA_ATOM_PAIR
, &type
, &format
, &num
, &rest
,
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
213 adata
= (unsigned long *)data
;
214 for(i
= 0; i
< num
; i
+= 2)
216 if (!convertProperty(
217 ev
.requestor
, adata
[i
],
224 dpy
, ev
.requestor
, ev
.property
, _XA_ATOM_PAIR
,
225 32, PropModeReplace
, data
, num
);
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
);
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. */
251 icccm2_handle_selection_clear(void)
253 DBUG("HandleSelectionClear", "I lost my selection!");