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