]> git.saurik.com Git - wxWidgets.git/blob - src/x11/reparent.cpp
Fixed #1338966.
[wxWidgets.git] / src / x11 / reparent.cpp
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 #include "wx/setup.h"
21
22 #if !wxUSE_NANOX
23
24 #include "wx/x11/reparent.h"
25 #include "wx/evtloop.h"
26 #include "wx/log.h"
27 #include "wx/app.h"
28 #include "wx/timer.h"
29
30 #include "wx/x11/private.h"
31 #include "X11/Xatom.h"
32
33 /*
34 * wxAdoptedWindow
35 */
36
37 wxAdoptedWindow::wxAdoptedWindow()
38 {
39 }
40
41 wxAdoptedWindow::wxAdoptedWindow(WXWindow window)
42 {
43 m_mainWindow = window;
44 }
45
46 wxAdoptedWindow::~wxAdoptedWindow()
47 {
48 }
49
50 /*
51 * wxReparenter
52 */
53
54 static bool Xerror;
55 static Atom WM_STATE = 0;
56 bool wxReparenter::sm_done = FALSE;
57 wxAdoptedWindow* wxReparenter::sm_toReparent = NULL;
58 wxWindow* wxReparenter::sm_newParent = NULL;
59 wxString wxReparenter::sm_name;
60 bool wxReparenter::sm_exactMatch = FALSE;
61
62 static int ErrorHandler(Display* dpy, XErrorEvent* event)
63 {
64 Xerror = True;
65 return False;
66 }
67
68 // We assume that toReparent has had its X window set
69 // appropriately.
70 bool wxReparenter::Reparent(wxWindow* newParent, wxAdoptedWindow* toReparent)
71 {
72 XWindowAttributes xwa;
73 Window *children;
74 unsigned int numchildren, each;
75 Window returnroot, returnparent;
76 XErrorHandler old;
77 int parentOffset = 0;
78
79 old = XSetErrorHandler(ErrorHandler);
80 XReparentWindow( wxGlobalDisplay(),
81 (Window) toReparent->GetMainWindow(),
82 (Window) newParent->GetMainWindow(),
83 0, 0);
84
85 if (!XQueryTree( wxGlobalDisplay(),
86 (Window) toReparent->GetMainWindow(),
87 &returnroot, &returnparent,
88 &children, &numchildren) || Xerror)
89 {
90 XSetErrorHandler(old);
91 return TRUE;
92 }
93
94 if (numchildren > 0)
95 {
96 // TEST: see if we can get away with reparenting just
97 // first one
98 if (numchildren > 1)
99 {
100 wxLogDebug(wxT("Found %d, but only reparenting 1 child."), numchildren);
101 numchildren = 1;
102 }
103 wxLogDebug(wxT("Reparenting %d children."), numchildren);
104 /* Stacking order is preserved since XQueryTree returns its children in
105 bottommost to topmost order
106 */
107 for (each=0; each<numchildren; each++)
108 {
109 XGetWindowAttributes( wxGlobalDisplay(),
110 children[each], &xwa);
111 fprintf(stderr,
112 "Reparenting child at offset %d and position %d, %d.\n",
113 parentOffset, parentOffset+xwa.x, parentOffset+xwa.y);
114 XReparentWindow( wxGlobalDisplay(),
115 children[each], (Window) newParent->GetMainWindow(),
116 xwa.x, xwa.y);
117 }
118 }
119
120 XSetErrorHandler(old);
121 return TRUE;
122 }
123
124 // Wait for an appropriate window to be created.
125 // If exactMatch is FALSE, a substring match is OK.
126 // If windowName is empty, then wait for the next overrideRedirect window.
127 bool wxReparenter::WaitAndReparent(wxWindow* newParent, wxAdoptedWindow* toReparent,
128 const wxString& windowName,
129 bool exactMatch)
130 {
131 sm_newParent = newParent;
132 sm_toReparent = toReparent;
133 sm_exactMatch = exactMatch;
134 sm_name = windowName;
135
136 Display* display = wxGlobalDisplay();
137 XSelectInput(display,
138 RootWindowOfScreen(DefaultScreenOfDisplay(display)),
139 SubstructureNotifyMask);
140
141 if (!WM_STATE)
142 WM_STATE = XInternAtom(display, "WM_STATE", False);
143
144 #ifdef __WXDEBUG__
145 if (!windowName.IsEmpty())
146 wxLogDebug(_T("Waiting for window %s"), windowName.c_str());
147 #endif
148
149 sm_done = FALSE;
150
151 wxEventLoop eventLoop;
152 while (!sm_done)
153 {
154 if (eventLoop.Pending())
155 {
156 XEvent xevent;
157 XNextEvent(display, & xevent);
158 if (!wxTheApp->ProcessXEvent((WXEvent*) & xevent))
159 {
160 // Do the local event processing
161 ProcessXEvent((WXEvent*) & xevent);
162 }
163 }
164 else
165 {
166 #if wxUSE_TIMER
167 wxTimer::NotifyTimers();
168 wxTheApp->ProcessIdle();
169 #endif
170 }
171 }
172 return TRUE;
173 }
174
175 bool wxReparenter::ProcessXEvent(WXEvent* event)
176 {
177 XEvent* xevent = (XEvent*) event;
178 Window client;
179
180 if (!sm_done)
181 {
182 if (xevent->type == MapNotify)
183 {
184 wxLogDebug(_T("Window was mapped"));
185 }
186
187 if (xevent->type == MapNotify && !xevent->xmap.override_redirect &&
188 (client = (Window) FindAClientWindow((WXWindow) xevent->xmap.window, sm_name)))
189 {
190 wxLogDebug(_T("Found a client window, about to reparent"));
191 wxASSERT(sm_toReparent->GetParent() == NULL);
192
193 sm_toReparent->SetHandle((WXWindow) client);
194 sm_newParent->AddChild(sm_toReparent);
195 sm_done = Reparent(sm_newParent, sm_toReparent);
196 return sm_done;
197 } else if (xevent->type == MapNotify &&
198 xevent->xmap.override_redirect &&
199 xevent->xmap.window)
200 {
201 wxLogDebug(_T("Found an override redirect window, about to reparent"));
202 sm_toReparent->SetHandle((WXWindow) xevent->xmap.window);
203 sm_newParent->AddChild(sm_toReparent);
204 wxASSERT(sm_toReparent->GetParent() == NULL);
205
206 sm_done = Reparent(sm_newParent, sm_toReparent);
207 return sm_done;
208 }
209 }
210 return FALSE;
211 }
212
213 WXWindow wxReparenter::FindAClientWindow(WXWindow window, const wxString& name)
214 {
215 int rvalue, i;
216 Atom actualtype;
217 int actualformat;
218 unsigned long nitems, bytesafter;
219 unsigned char *propreturn;
220 Window *children;
221 unsigned int numchildren;
222 Window returnroot, returnparent;
223 Window result = 0;
224 XErrorHandler old;
225 char *clientName;
226
227 Xerror = False;
228 old = XSetErrorHandler(ErrorHandler);
229 rvalue = XGetWindowProperty((Display*) wxGetDisplay(),
230 (Window) window, WM_STATE,
231 0, 1, False,
232 AnyPropertyType, &actualtype, &actualformat,
233 &nitems, &bytesafter, &propreturn);
234
235 XSetErrorHandler(old);
236
237 if (!Xerror && rvalue == Success && actualtype != None)
238 {
239 if (rvalue == Success)
240 {
241 XFree((char *) propreturn);
242 }
243 XFetchName((Display*) wxGetDisplay(), (Window) window, &clientName);
244
245 wxString str1(name);
246 wxString str2 = wxString::FromAscii(clientName);
247 str1.Lower();
248 str2.Lower();
249
250 bool matches;
251 if (sm_exactMatch)
252 matches = (name == wxString::FromAscii(clientName));
253 else
254 matches = (str1.Contains(str2) || str2.Contains(str1));
255
256 XFree(clientName);
257
258 if (matches)
259 return (WXWindow) window;
260 else
261 return NULL;
262 }
263
264 old = XSetErrorHandler(ErrorHandler);
265 if (!XQueryTree((Display*) wxGetDisplay(), (Window) window, &returnroot, &returnparent,
266 &children, &numchildren) || Xerror)
267 {
268 XSetErrorHandler(old);
269 return NULL;
270 }
271 XSetErrorHandler(old);
272
273 result = 0;
274 for (i=0; i<(int)numchildren && !result ;i++) {
275 result = (Window) FindAClientWindow((WXWindow) children[i], name);
276 }
277 if (numchildren) {
278 XFree((char *) children);
279 } return (WXWindow) result;
280 }
281
282 #endif