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