~ubuntu-branches/ubuntu/maverick/xulrunner-1.9.1/maverick

« back to all changes in this revision

Viewing changes to debian/patches/bz499498_att397329_lp401055_bad_window.patch

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2009-10-07 10:23:28 UTC
  • Revision ID: james.westby@ubuntu.com-20091007102328-2ue92bwegoy8uevw
Tags: 1.9.1.3+build1+nobinonly-0ubuntu5
* fix LP: #401055 - Gdk-ERROR **: The program 'firefox-3.5' received
  an X Window System error (BadWindow); add patch from upstream bug
  (also LP: #411695)
  - add debian/patches/bz499498_att397329_lp401055_bad_window.patch
  - update debian/patches/series

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
diff --git a/widget/src/xremoteclient/XRemoteClient.cpp b/widget/src/xremoteclient/XRemoteClient.cpp
 
2
--- a/widget/src/xremoteclient/XRemoteClient.cpp
 
3
+++ b/widget/src/xremoteclient/XRemoteClient.cpp
 
4
@@ -1,10 +1,10 @@
 
5
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
6
-/* vim:expandtab:shiftwidth=4:tabstop=4:
 
7
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
8
+/* vim:expandtab:shiftwidth=2:tabstop=8:
 
9
  */
 
10
 /* vim:set ts=8 sw=2 et cindent: */
 
11
 /* ***** BEGIN LICENSE BLOCK *****
 
12
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
13
  *
 
14
  * The contents of this file are subject to the Mozilla Public License Version
 
15
  * 1.1 (the "License"); you may not use this file except in compliance with
 
16
  * the License. You may obtain a copy of the License at
 
17
@@ -83,16 +83,19 @@
 
18
 #define MAX_PATH 1024
 
19
 #endif
 
20
 #endif
 
21
 
 
22
 #define ARRAY_LENGTH(array_) (sizeof(array_)/sizeof(array_[0]))
 
23
 
 
24
 static PRLogModuleInfo *sRemoteLm = NULL;
 
25
 
 
26
+static int (*sOldHandler)(Display *, XErrorEvent *);
 
27
+static PRBool sGotBadWindow;
 
28
+
 
29
 XRemoteClient::XRemoteClient()
 
30
 {
 
31
   mDisplay = 0;
 
32
   mInitialized = PR_FALSE;
 
33
   mMozVersionAtom = 0;
 
34
   mMozLockAtom = 0;
 
35
   mMozCommandAtom = 0;
 
36
   mMozResponseAtom = 0;
 
37
@@ -178,93 +181,107 @@ XRemoteClient::Shutdown (void)
 
38
 nsresult
 
39
 XRemoteClient::SendCommand (const char *aProgram, const char *aUsername,
 
40
                             const char *aProfile, const char *aCommand,
 
41
                             const char* aDesktopStartupID,
 
42
                             char **aResponse, PRBool *aWindowFound)
 
43
 {
 
44
   PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
 
45
 
 
46
-  *aWindowFound = PR_FALSE;
 
47
-
 
48
-  Window w = FindBestWindow(aProgram, aUsername, aProfile, PR_FALSE);
 
49
-
 
50
-  nsresult rv = NS_OK;
 
51
-
 
52
-  if (w) {
 
53
-    // ok, let the caller know that we at least found a window.
 
54
-    *aWindowFound = PR_TRUE;
 
55
-
 
56
-    // make sure we get the right events on that window
 
57
-    XSelectInput(mDisplay, w,
 
58
-                 (PropertyChangeMask|StructureNotifyMask));
 
59
-        
 
60
-    PRBool destroyed = PR_FALSE;
 
61
-
 
62
-    // get the lock on the window
 
63
-    rv = GetLock(w, &destroyed);
 
64
-
 
65
-    if (NS_SUCCEEDED(rv)) {
 
66
-      // send our command
 
67
-      rv = DoSendCommand(w, aCommand, aDesktopStartupID, aResponse, &destroyed);
 
68
-
 
69
-      // if the window was destroyed, don't bother trying to free the
 
70
-      // lock.
 
71
-      if (!destroyed)
 
72
-          FreeLock(w); // doesn't really matter what this returns
 
73
-
 
74
-    }
 
75
-  }
 
76
-
 
77
-  PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommand returning 0x%x\n", rv));
 
78
-
 
79
-  return rv;
 
80
+  return SendCommandInternal(aProgram, aUsername, aProfile,
 
81
+                             aCommand, 0, nsnull,
 
82
+                             aDesktopStartupID,
 
83
+                             aResponse, aWindowFound);
 
84
 }
 
85
 
 
86
 nsresult
 
87
 XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
 
88
                                 const char *aProfile,
 
89
                                 PRInt32 argc, char **argv,
 
90
                                 const char* aDesktopStartupID,
 
91
                                 char **aResponse, PRBool *aWindowFound)
 
92
 {
 
93
   PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
 
94
 
 
95
+  return SendCommandInternal(aProgram, aUsername, aProfile,
 
96
+                             nsnull, argc, argv,
 
97
+                             aDesktopStartupID,
 
98
+                             aResponse, aWindowFound);
 
99
+}
 
100
+
 
101
+static int
 
102
+HandleBadWindow(Display *display, XErrorEvent *event)
 
103
+{
 
104
+  if (event->error_code == BadWindow) {
 
105
+    sGotBadWindow = PR_TRUE;
 
106
+    return 0; // ignored
 
107
+  }
 
108
+  else {
 
109
+    return (*sOldHandler)(display, event);
 
110
+  }
 
111
+}
 
112
+
 
113
+nsresult
 
114
+XRemoteClient::SendCommandInternal(const char *aProgram, const char *aUsername,
 
115
+                                   const char *aProfile, const char *aCommand,
 
116
+                                   PRInt32 argc, char **argv,
 
117
+                                   const char* aDesktopStartupID,
 
118
+                                   char **aResponse, PRBool *aWindowFound)
 
119
+{
 
120
   *aWindowFound = PR_FALSE;
 
121
+  PRBool isCommandLine = !aCommand;
 
122
 
 
123
-  Window w = FindBestWindow(aProgram, aUsername, aProfile, PR_TRUE);
 
124
+  // FindBestWindow() iterates down the window hierarchy, so catch X errors
 
125
+  // when windows get destroyed before being accessed.
 
126
+  sOldHandler = XSetErrorHandler(HandleBadWindow);
 
127
+
 
128
+  Window w = FindBestWindow(aProgram, aUsername, aProfile, isCommandLine);
 
129
 
 
130
   nsresult rv = NS_OK;
 
131
 
 
132
   if (w) {
 
133
     // ok, let the caller know that we at least found a window.
 
134
     *aWindowFound = PR_TRUE;
 
135
 
 
136
+    // Ignore BadWindow errors up to this point.  The last request from
 
137
+    // FindBestWindow() was a synchronous XGetWindowProperty(), so no need to
 
138
+    // Sync.  Leave the error handler installed to detect if w gets destroyed.
 
139
+    sGotBadWindow = PR_FALSE;
 
140
+
 
141
     // make sure we get the right events on that window
 
142
     XSelectInput(mDisplay, w,
 
143
                  (PropertyChangeMask|StructureNotifyMask));
 
144
-        
 
145
+
 
146
     PRBool destroyed = PR_FALSE;
 
147
 
 
148
     // get the lock on the window
 
149
     rv = GetLock(w, &destroyed);
 
150
 
 
151
     if (NS_SUCCEEDED(rv)) {
 
152
       // send our command
 
153
-      rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse, &destroyed);
 
154
+      if (isCommandLine) {
 
155
+        rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
 
156
+                               &destroyed);
 
157
+      }
 
158
+      else {
 
159
+        rv = DoSendCommand(w, aCommand, aDesktopStartupID, aResponse,
 
160
+                           &destroyed);
 
161
+      }
 
162
 
 
163
       // if the window was destroyed, don't bother trying to free the
 
164
       // lock.
 
165
       if (!destroyed)
 
166
           FreeLock(w); // doesn't really matter what this returns
 
167
 
 
168
     }
 
169
   }
 
170
 
 
171
-  PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommandLine returning 0x%x\n", rv));
 
172
+  XSetErrorHandler(sOldHandler);
 
173
+
 
174
+  PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommandInternal returning 0x%x\n", rv));
 
175
 
 
176
   return rv;
 
177
 }
 
178
 
 
179
 Window
 
180
 XRemoteClient::CheckWindow(Window aWindow)
 
181
 {
 
182
   Atom type = None;
 
183
@@ -333,16 +350,18 @@ XRemoteClient::CheckChildren(Window aWin
 
184
 
 
185
 nsresult
 
186
 XRemoteClient::GetLock(Window aWindow, PRBool *aDestroyed)
 
187
 {
 
188
   PRBool locked = PR_FALSE;
 
189
   PRBool waited = PR_FALSE;
 
190
   *aDestroyed = PR_FALSE;
 
191
 
 
192
+  nsresult rv = NS_OK;
 
193
+
 
194
   if (!mLockData) {
 
195
     
 
196
     char pidstr[32];
 
197
     char sysinfobuf[SYS_INFO_BUFFER_LENGTH];
 
198
     PR_snprintf(pidstr, sizeof(pidstr), "pid%d@", getpid());
 
199
     PRStatus status;
 
200
     status = PR_GetSystemInfo(PR_SI_HOSTNAME, sysinfobuf,
 
201
                              SYS_INFO_BUFFER_LENGTH);
 
202
@@ -372,29 +391,38 @@ XRemoteClient::GetLock(Window aWindow, P
 
203
 
 
204
     result = XGetWindowProperty (mDisplay, aWindow, mMozLockAtom,
 
205
                                 0, (65536 / sizeof (long)),
 
206
                                 False, /* don't delete */
 
207
                                 XA_STRING,
 
208
                                 &actual_type, &actual_format,
 
209
                                 &nitems, &bytes_after,
 
210
                                 &data);
 
211
-    if (result != Success || actual_type == None) {
 
212
+
 
213
+    // aWindow may have been destroyed before XSelectInput was processed, in
 
214
+    // which case there may not be any DestroyNotify event in the queue to
 
215
+    // tell us.  XGetWindowProperty() was synchronous so error responses have
 
216
+    // now been processed, setting sGotBadWindow.
 
217
+    if (sGotBadWindow) {
 
218
+      *aDestroyed = PR_TRUE;
 
219
+      rv = NS_ERROR_FAILURE;
 
220
+    }
 
221
+    else if (result != Success || actual_type == None) {
 
222
       /* It's not now locked - lock it. */
 
223
       XChangeProperty (mDisplay, aWindow, mMozLockAtom, XA_STRING, 8,
 
224
                       PropModeReplace,
 
225
                       (unsigned char *)mLockData,
 
226
                       strlen(mLockData));
 
227
       locked = True;
 
228
     }
 
229
 
 
230
     XUngrabServer(mDisplay);
 
231
-    XSync(mDisplay, False);
 
232
+    XFlush(mDisplay); // ungrab now!
 
233
 
 
234
-    if (!locked) {
 
235
+    if (!locked && !NS_FAILED(rv)) {
 
236
       /* We tried to grab the lock this time, and failed because someone
 
237
         else is holding it already.  So, wait for a PropertyDelete event
 
238
         to come in, and try again. */
 
239
       PR_LOG(sRemoteLm, PR_LOG_DEBUG, 
 
240
             ("window 0x%x is locked by %s; waiting...\n",
 
241
              (unsigned int) aWindow, data));
 
242
       waited = True;
 
243
       while (1) {
 
244
@@ -415,50 +443,53 @@ XRemoteClient::GetLock(Window aWindow, P
 
245
        // add the x event queue to the select set
 
246
        FD_SET(ConnectionNumber(mDisplay), &select_set);
 
247
        select_retval = select(ConnectionNumber(mDisplay) + 1,
 
248
                               &select_set, NULL, NULL, &delay);
 
249
 #endif
 
250
        // did we time out?
 
251
        if (select_retval == 0) {
 
252
          PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("timed out waiting for window\n"));
 
253
-         return NS_ERROR_FAILURE;
 
254
+          rv = NS_ERROR_FAILURE;
 
255
+          break;
 
256
        }
 
257
        PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("xevent...\n"));
 
258
        XNextEvent (mDisplay, &event);
 
259
        if (event.xany.type == DestroyNotify &&
 
260
            event.xdestroywindow.window == aWindow) {
 
261
-         PR_LOG(sRemoteLm, PR_LOG_DEBUG,
 
262
-                ("window 0x%x unexpectedly destroyed.\n",
 
263
-                 (unsigned int) aWindow));
 
264
          *aDestroyed = PR_TRUE;
 
265
-         return NS_ERROR_FAILURE;
 
266
+          rv = NS_ERROR_FAILURE;
 
267
+          break;
 
268
        }
 
269
        else if (event.xany.type == PropertyNotify &&
 
270
                 event.xproperty.state == PropertyDelete &&
 
271
                 event.xproperty.window == aWindow &&
 
272
                 event.xproperty.atom == mMozLockAtom) {
 
273
          /* Ok!  Someone deleted their lock, so now we can try
 
274
             again. */
 
275
          PR_LOG(sRemoteLm, PR_LOG_DEBUG,
 
276
                 ("(0x%x unlocked, trying again...)\n",
 
277
                  (unsigned int) aWindow));
 
278
                  break;
 
279
        }
 
280
       }
 
281
     }
 
282
     if (data)
 
283
       XFree(data);
 
284
-  } while (!locked);
 
285
+  } while (!locked && !NS_FAILED(rv));
 
286
 
 
287
-  if (waited) {
 
288
+  if (waited && locked) {
 
289
     PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("obtained lock.\n"));
 
290
+  } else if (*aDestroyed) {
 
291
+    PR_LOG(sRemoteLm, PR_LOG_DEBUG,
 
292
+           ("window 0x%x unexpectedly destroyed.\n",
 
293
+            (unsigned int) aWindow));
 
294
   }
 
295
 
 
296
-  return NS_OK;
 
297
+  return rv;
 
298
 }
 
299
 
 
300
 Window
 
301
 XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
 
302
                               const char *aProfile,
 
303
                               PRBool aSupportsCommandLine)
 
304
 {
 
305
   Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
 
306
diff --git a/widget/src/xremoteclient/XRemoteClient.h b/widget/src/xremoteclient/XRemoteClient.h
 
307
--- a/widget/src/xremoteclient/XRemoteClient.h
 
308
+++ b/widget/src/xremoteclient/XRemoteClient.h
 
309
@@ -1,8 +1,9 @@
 
310
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
311
 /* ***** BEGIN LICENSE BLOCK *****
 
312
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
313
  *
 
314
  * The contents of this file are subject to the Mozilla Public License Version
 
315
  * 1.1 (the "License"); you may not use this file except in compliance with
 
316
  * the License. You may obtain a copy of the License at
 
317
  * http://www.mozilla.org/MPL/
 
318
  *
 
319
@@ -62,16 +63,21 @@ private:
 
320
   Window         CheckWindow      (Window aWindow);
 
321
   Window         CheckChildren    (Window aWindow);
 
322
   nsresult       GetLock          (Window aWindow, PRBool *aDestroyed);
 
323
   nsresult       FreeLock         (Window aWindow);
 
324
   Window         FindBestWindow   (const char *aProgram,
 
325
                                    const char *aUsername,
 
326
                                    const char *aProfile,
 
327
                                    PRBool aSupportsCommandLine);
 
328
+  nsresult     SendCommandInternal(const char *aProgram, const char *aUsername,
 
329
+                                   const char *aProfile, const char *aCommand,
 
330
+                                   PRInt32 argc, char **argv,
 
331
+                                   const char* aDesktopStartupID,
 
332
+                                   char **aResponse, PRBool *aWindowFound);
 
333
   nsresult       DoSendCommand    (Window aWindow,
 
334
                                    const char *aCommand,
 
335
                                    const char* aDesktopStartupID,
 
336
                                    char **aResponse,
 
337
                                    PRBool *aDestroyed);
 
338
   nsresult       DoSendCommandLine(Window aWindow,
 
339
                                    PRInt32 argc, char **argv,
 
340
                                    const char* aDesktopStartupID,