1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "reparent.h"
24 #include "wx/x11/reparent.h"
28 #include "wx/evtloop.h"
33 #include "wx/x11/private.h"
34 #include "X11/Xatom.h"
38 Adapted from code by Mike Yang, as follows.
40 From: Mike Yang (mikey@eukanuba.wpd.sgi.com)
41 Subject: Re: Wrapping new widget around existing windows
42 Newsgroups: comp.windows.x
43 View: Complete Thread (17 articles) | Original Format
44 Date: 1991-08-09 09:45:48 PST
47 Enough people asked, so here's my test program which reparents another
48 window. It's a single file (reparent.c), and will work with Motif or
49 Xaw. Xaw users should comment out the "#define MOTIF" line.
51 The reparent program first prompts for the application name of the
52 client that it will reparent. If you're going to start the
53 application override_redirect (e.g. -xrm "*overrideRedirect: true"),
54 then this name is ignored and the first override_redirect window is
55 assumed to be the one.
57 Input focus is supposed to be correctly handled, as is resizing with
58 window manager hints. If you have input focus problems, try launching
59 your application override_redirect instead. This method is preferred
60 anyway, since you can map it off-screen and then avoid the "window
61 flash" effect as the application's top-level window is reparented.
63 -----------------------------------------------------------------------
64 Mike Yang Silicon Graphics, Inc.
65 mikey@sgi.com 415/335-1786
68 ------------------------------- cut here ------------------------------
73 Copyright 1991 by Mike Yang, mikey@sgi.com, Silicon Graphics, Inc.
75 Permission to use, copy, modify, distribute, and sell this software and its
76 documentation for any purpose is hereby granted without fee, provided that
77 the above copyright notice appear in all copies and that both that
78 copyright notice and this permission notice appear in supporting
79 documentation, and that the name of SGI not be used in advertising or
80 publicity pertaining to distribution of the software without specific,
81 written prior permission. SGI makes no representations about the
82 suitability of this software for any purpose. It is provided "as is"
83 without express or implied warranty.
91 wxAdoptedWindow::wxAdoptedWindow()
95 wxAdoptedWindow::wxAdoptedWindow(WXWindow window
)
97 m_mainWindow
= window
;
100 wxAdoptedWindow::~wxAdoptedWindow()
108 static Atom WM_STATE
= 0;
109 bool wxReparenter::sm_done
= FALSE
;
110 wxAdoptedWindow
* wxReparenter::sm_toReparent
= NULL
;
111 wxWindow
* wxReparenter::sm_newParent
= NULL
;
112 wxString
wxReparenter::sm_name
;
113 bool wxReparenter::sm_exactMatch
= FALSE
;
116 ErrorHandler(Display
* dpy
, XErrorEvent
* event
)
122 // We assume that toReparent has had its X window set
124 bool wxReparenter::Reparent(wxWindow
* newParent
, wxAdoptedWindow
* toReparent
)
126 XWindowAttributes xwa
;
128 unsigned int numchildren
, each
;
129 Window returnroot
, returnparent
;
131 int parentOffset
= 0;
133 old
= XSetErrorHandler(ErrorHandler
);
134 XReparentWindow( wxGlobalDisplay(),
135 (Window
) toReparent
->GetMainWindow(),
136 (Window
) newParent
->GetMainWindow(),
139 if (!XQueryTree( wxGlobalDisplay(),
140 (Window
) toReparent
->GetMainWindow(),
141 &returnroot
, &returnparent
,
142 &children
, &numchildren
) || Xerror
)
144 XSetErrorHandler(old
);
150 // TEST: see if we can get away with reparenting just
154 wxLogDebug(wxT("Found %d, but only reparenting 1 child."), numchildren
);
157 wxLogDebug(wxT("Reparenting %d children."), numchildren
);
158 /* Stacking order is preserved since XQueryTree returns its children in
159 bottommost to topmost order
161 for (each
=0; each
<numchildren
; each
++)
163 XGetWindowAttributes( wxGlobalDisplay(),
164 children
[each
], &xwa
);
166 "Reparenting child at offset %d and position %d, %d.\n",
167 parentOffset
, parentOffset
+xwa
.x
, parentOffset
+xwa
.y
);
168 XReparentWindow( wxGlobalDisplay(),
169 children
[each
], (Window
) newParent
->GetMainWindow(),
174 XSetErrorHandler(old
);
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.
181 bool wxReparenter::WaitAndReparent(wxWindow
* newParent
, wxAdoptedWindow
* toReparent
,
182 const wxString
& windowName
,
185 sm_newParent
= newParent
;
186 sm_toReparent
= toReparent
;
187 sm_exactMatch
= exactMatch
;
188 sm_name
= windowName
;
190 Display
* display
= wxGlobalDisplay();
191 XSelectInput(display
,
192 RootWindowOfScreen(DefaultScreenOfDisplay(display
)),
193 SubstructureNotifyMask
);
196 WM_STATE
= XInternAtom(display
, "WM_STATE", False
);
199 if (!windowName
.IsEmpty())
200 wxLogDebug(_T("Waiting for window %s"), windowName
.c_str());
205 wxEventLoop eventLoop
;
208 if (eventLoop
.Pending())
211 XNextEvent(display
, & xevent
);
212 if (!wxTheApp
->ProcessXEvent((WXEvent
*) & xevent
))
214 // Do the local event processing
215 ProcessXEvent((WXEvent
*) & xevent
);
221 wxTimer::NotifyTimers();
222 wxTheApp
->SendIdleEvents();
229 bool wxReparenter::ProcessXEvent(WXEvent
* event
)
231 XEvent
* xevent
= (XEvent
*) event
;
236 if (xevent
->type
== MapNotify
)
238 wxLogDebug(_T("Window was mapped"));
241 if (xevent
->type
== MapNotify
&& !xevent
->xmap
.override_redirect
&&
242 (client
= (Window
) FindAClientWindow((WXWindow
) xevent
->xmap
.window
, sm_name
)))
244 wxLogDebug(_T("Found a client window, about to reparent"));
245 wxASSERT(sm_toReparent
->GetParent() == NULL
);
247 sm_toReparent
->SetHandle((WXWindow
) client
);
248 sm_newParent
->AddChild(sm_toReparent
);
249 sm_done
= Reparent(sm_newParent
, sm_toReparent
);
251 } else if (xevent
->type
== MapNotify
&&
252 xevent
->xmap
.override_redirect
&&
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
);
260 sm_done
= Reparent(sm_newParent
, sm_toReparent
);
267 WXWindow
wxReparenter::FindAClientWindow(WXWindow window
, const wxString
& name
)
272 unsigned long nitems
, bytesafter
;
273 unsigned char *propreturn
;
275 unsigned int numchildren
;
276 Window returnroot
, returnparent
;
282 old
= XSetErrorHandler(ErrorHandler
);
283 rvalue
= XGetWindowProperty((Display
*) wxGetDisplay(),
284 (Window
) window
, WM_STATE
,
286 AnyPropertyType
, &actualtype
, &actualformat
,
287 &nitems
, &bytesafter
, &propreturn
);
288 XSetErrorHandler(old
);
289 if (!Xerror
&& rvalue
== Success
&& actualtype
!= None
)
291 if (rvalue
== Success
)
293 XFree((char *) propreturn
);
295 XFetchName((Display
*) wxGetDisplay(), (Window
) window
, &clientName
);
298 wxString
str2(clientName
);
304 matches
= (name
== clientName
);
306 matches
= (str1
.Contains(str2
) || str2
.Contains(str1
));
311 return (WXWindow
) window
;
316 old
= XSetErrorHandler(ErrorHandler
);
317 if (!XQueryTree((Display
*) wxGetDisplay(), (Window
) window
, &returnroot
, &returnparent
,
318 &children
, &numchildren
) || Xerror
) {
319 XSetErrorHandler(old
);
322 XSetErrorHandler(old
);
325 for (i
=0; i
<(int)numchildren
&& !result
;i
++) {
326 result
= (Window
) FindAClientWindow((WXWindow
) children
[i
], name
);
329 XFree((char *) children
);
330 } return (WXWindow
) result
;