]> git.saurik.com Git - wxWidgets.git/blame - src/x11/reparent.cpp
some wxArtProv docs
[wxWidgets.git] / src / x11 / reparent.cpp
CommitLineData
c978d361
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: reparent.cpp
3// Purpose: wxWindow
4// Author: Julian Smart
5// Modified by:
6// Created: 2002-03-09
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "reparent.h"
22#endif
23
24#include "wx/x11/reparent.h"
15d5a947
JS
25
26#if !wxUSE_NANOX
27
c978d361
JS
28#include "wx/evtloop.h"
29#include "wx/log.h"
30#include "wx/app.h"
31#include "wx/timer.h"
32
33#include "wx/x11/private.h"
34#include "X11/Xatom.h"
35
36/*
37
38 Adapted from code by Mike Yang, as follows.
39
40From: Mike Yang (mikey@eukanuba.wpd.sgi.com)
41Subject: Re: Wrapping new widget around existing windows
42Newsgroups: comp.windows.x
43View: Complete Thread (17 articles) | Original Format
44Date: 1991-08-09 09:45:48 PST
45
46
47Enough people asked, so here's my test program which reparents another
48window. It's a single file (reparent.c), and will work with Motif or
49Xaw. Xaw users should comment out the "#define MOTIF" line.
50
51The reparent program first prompts for the application name of the
52client that it will reparent. If you're going to start the
53application override_redirect (e.g. -xrm "*overrideRedirect: true"),
54then this name is ignored and the first override_redirect window is
55assumed to be the one.
56
57Input focus is supposed to be correctly handled, as is resizing with
58window manager hints. If you have input focus problems, try launching
59your application override_redirect instead. This method is preferred
60anyway, since you can map it off-screen and then avoid the "window
61flash" effect as the application's top-level window is reparented.
62
63-----------------------------------------------------------------------
64 Mike Yang Silicon Graphics, Inc.
65 mikey@sgi.com 415/335-1786
66
67
68------------------------------- cut here ------------------------------
69*/
70
71/*
72
73Copyright 1991 by Mike Yang, mikey@sgi.com, Silicon Graphics, Inc.
74
75Permission to use, copy, modify, distribute, and sell this software and its
76documentation for any purpose is hereby granted without fee, provided that
77the above copyright notice appear in all copies and that both that
78copyright notice and this permission notice appear in supporting
79documentation, and that the name of SGI not be used in advertising or
80publicity pertaining to distribution of the software without specific,
81written prior permission. SGI makes no representations about the
82suitability of this software for any purpose. It is provided "as is"
83without express or implied warranty.
84
85*/
86
87/*
88 * wxAdoptedWindow
89 */
90
91wxAdoptedWindow::wxAdoptedWindow()
92{
93}
94
95wxAdoptedWindow::wxAdoptedWindow(WXWindow window)
96{
ab6b6b15 97 m_mainWindow = window;
c978d361
JS
98}
99
100wxAdoptedWindow::~wxAdoptedWindow()
101{
102}
103/*
104 * wxReparenter
105 */
106
107static bool Xerror;
108static Atom WM_STATE = 0;
109bool wxReparenter::sm_done = FALSE;
110wxAdoptedWindow* wxReparenter::sm_toReparent = NULL;
111wxWindow* wxReparenter::sm_newParent = NULL;
112wxString wxReparenter::sm_name;
113bool wxReparenter::sm_exactMatch = FALSE;
114
115static int
116ErrorHandler(Display* dpy, XErrorEvent* event)
117{
118 Xerror = True;
119 return False;
120}
121
122// We assume that toReparent has had its X window set
123// appropriately.
124bool wxReparenter::Reparent(wxWindow* newParent, wxAdoptedWindow* toReparent)
125{
126 XWindowAttributes xwa;
127 Window *children;
128 unsigned int numchildren, each;
129 Window returnroot, returnparent;
130 XErrorHandler old;
131 int parentOffset = 0;
132
133 old = XSetErrorHandler(ErrorHandler);
ab6b6b15
RR
134 XReparentWindow( wxGlobalDisplay(),
135 (Window) toReparent->GetMainWindow(),
136 (Window) newParent->GetMainWindow(),
137 0, 0);
138
139 if (!XQueryTree( wxGlobalDisplay(),
140 (Window) toReparent->GetMainWindow(),
141 &returnroot, &returnparent,
142 &children, &numchildren) || Xerror)
c978d361
JS
143 {
144 XSetErrorHandler(old);
145 return TRUE;
146 }
147
148 if (numchildren > 0)
149 {
046ba576
JS
150 // TEST: see if we can get away with reparenting just
151 // first one
152 if (numchildren > 1)
153 {
154 wxLogDebug(wxT("Found %d, but only reparenting 1 child."), numchildren);
155 numchildren = 1;
156 }
157 wxLogDebug(wxT("Reparenting %d children."), numchildren);
c978d361
JS
158 /* Stacking order is preserved since XQueryTree returns its children in
159 bottommost to topmost order
160 */
161 for (each=0; each<numchildren; each++)
162 {
ab6b6b15
RR
163 XGetWindowAttributes( wxGlobalDisplay(),
164 children[each], &xwa);
c978d361
JS
165 fprintf(stderr,
166 "Reparenting child at offset %d and position %d, %d.\n",
167 parentOffset, parentOffset+xwa.x, parentOffset+xwa.y);
ab6b6b15
RR
168 XReparentWindow( wxGlobalDisplay(),
169 children[each], (Window) newParent->GetMainWindow(),
170 xwa.x, xwa.y);
c978d361
JS
171 }
172 }
173
174 XSetErrorHandler(old);
175 return TRUE;
176}
177
178// Wait for an appropriate window to be created.
179// If exactMatch is FALSE, a substring match is OK.
180// If windowName is empty, then wait for the next overrideRedirect window.
181bool wxReparenter::WaitAndReparent(wxWindow* newParent, wxAdoptedWindow* toReparent,
182 const wxString& windowName,
183 bool exactMatch)
184{
185 sm_newParent = newParent;
186 sm_toReparent = toReparent;
187 sm_exactMatch = exactMatch;
188 sm_name = windowName;
189
ab6b6b15 190 Display* display = wxGlobalDisplay();
c978d361
JS
191 XSelectInput(display,
192 RootWindowOfScreen(DefaultScreenOfDisplay(display)),
193 SubstructureNotifyMask);
194
195 if (!WM_STATE)
196 WM_STATE = XInternAtom(display, "WM_STATE", False);
197
198#ifdef __WXDEBUG__
199 if (!windowName.IsEmpty())
200 wxLogDebug(_T("Waiting for window %s"), windowName.c_str());
201#endif
202
203 sm_done = FALSE;
204
205 wxEventLoop eventLoop;
206 while (!sm_done)
207 {
208 if (eventLoop.Pending())
209 {
210 XEvent xevent;
211 XNextEvent(display, & xevent);
212 if (!wxTheApp->ProcessXEvent((WXEvent*) & xevent))
213 {
214 // Do the local event processing
215 ProcessXEvent((WXEvent*) & xevent);
216 }
217 }
218 else
219 {
220#if wxUSE_TIMER
221 wxTimer::NotifyTimers();
222 wxTheApp->SendIdleEvents();
223#endif
224 }
225 }
226 return TRUE;
227}
228
229bool wxReparenter::ProcessXEvent(WXEvent* event)
230{
231 XEvent* xevent = (XEvent*) event;
232 Window client;
233
234 if (!sm_done)
235 {
236 if (xevent->type == MapNotify)
237 {
238 wxLogDebug(_T("Window was mapped"));
239 }
240
241 if (xevent->type == MapNotify && !xevent->xmap.override_redirect &&
242 (client = (Window) FindAClientWindow((WXWindow) xevent->xmap.window, sm_name)))
243 {
244 wxLogDebug(_T("Found a client window, about to reparent"));
245 wxASSERT(sm_toReparent->GetParent() == NULL);
246
247 sm_toReparent->SetHandle((WXWindow) client);
248 sm_newParent->AddChild(sm_toReparent);
249 sm_done = Reparent(sm_newParent, sm_toReparent);
250 return sm_done;
251 } else if (xevent->type == MapNotify &&
252 xevent->xmap.override_redirect &&
253 xevent->xmap.window)
254 {
255 wxLogDebug(_T("Found an override redirect window, about to reparent"));
256 sm_toReparent->SetHandle((WXWindow) xevent->xmap.window);
257 sm_newParent->AddChild(sm_toReparent);
258 wxASSERT(sm_toReparent->GetParent() == NULL);
259
260 sm_done = Reparent(sm_newParent, sm_toReparent);
261 return sm_done;
262 }
263 }
264 return FALSE;
265}
266
267WXWindow wxReparenter::FindAClientWindow(WXWindow window, const wxString& name)
268{
269 int rvalue, i;
270 Atom actualtype;
271 int actualformat;
272 unsigned long nitems, bytesafter;
273 unsigned char *propreturn;
274 Window *children;
275 unsigned int numchildren;
276 Window returnroot, returnparent;
277 Window result = 0;
278 XErrorHandler old;
279 char *clientName;
280
281 Xerror = False;
282 old = XSetErrorHandler(ErrorHandler);
283 rvalue = XGetWindowProperty((Display*) wxGetDisplay(),
284 (Window) window, WM_STATE,
285 0, 1, False,
286 AnyPropertyType, &actualtype, &actualformat,
287 &nitems, &bytesafter, &propreturn);
288 XSetErrorHandler(old);
289 if (!Xerror && rvalue == Success && actualtype != None)
290 {
291 if (rvalue == Success)
292 {
293 XFree((char *) propreturn);
294 }
295 XFetchName((Display*) wxGetDisplay(), (Window) window, &clientName);
296
297 wxString str1(name);
298 wxString str2(clientName);
299 str1.Lower();
300 str2.Lower();
301
302 bool matches;
303 if (sm_exactMatch)
304 matches = (name == clientName);
305 else
306 matches = (str1.Contains(str2) || str2.Contains(str1));
307
308 XFree(clientName);
309
310 if (matches)
311 return (WXWindow) window;
312 else
313 return NULL;
314 }
315
316 old = XSetErrorHandler(ErrorHandler);
317 if (!XQueryTree((Display*) wxGetDisplay(), (Window) window, &returnroot, &returnparent,
318 &children, &numchildren) || Xerror) {
319 XSetErrorHandler(old);
320 return NULL;
321 }
322 XSetErrorHandler(old);
323
324 result = 0;
325 for (i=0; i<(int)numchildren && !result ;i++) {
326 result = (Window) FindAClientWindow((WXWindow) children[i], name);
327 }
328 if (numchildren) {
329 XFree((char *) children);
330 } return (WXWindow) result;
331}
332
15d5a947 333#endif